diff --git a/Core/AluMulDiv.cpp b/Core/AluMulDiv.cpp index 9ad0d41..c9a9167 100644 --- a/Core/AluMulDiv.cpp +++ b/Core/AluMulDiv.cpp @@ -17,22 +17,28 @@ void AluMulDiv::Run(bool isRead) { uint64_t cpuCycle = _cpu->GetCycleCount(); - if(isRead) { + if (isRead) + { //Run 1 cycle less for read operations, since they occur earlier within the CPU cycle, compared to a write cpuCycle--; } - if(_multCounter != 0 || _divCounter != 0) { + if (_multCounter != 0 || _divCounter != 0) + { uint64_t cyclesToRun = cpuCycle - _prevCpuCycle; - while(cyclesToRun--) { - if(!_multCounter && !_divCounter) { + while (cyclesToRun--) + { + if (!_multCounter && !_divCounter) + { break; } - if(_multCounter > 0) { + if (_multCounter > 0) + { _multCounter--; - if(_state.DivResult & 0x01) { + if (_state.DivResult & 0x01) + { _state.MultOrRemainderResult += _shift; } @@ -40,19 +46,21 @@ void AluMulDiv::Run(bool isRead) _state.DivResult >>= 1; } - if(_divCounter > 0) { + if (_divCounter > 0) + { _divCounter--; _shift >>= 1; _state.DivResult <<= 1; - if(_state.MultOrRemainderResult >= _shift) { + if (_state.MultOrRemainderResult >= _shift) + { _state.MultOrRemainderResult -= _shift; _state.DivResult |= 1; } } } } - + _prevCpuCycle = cpuCycle; } @@ -60,12 +68,13 @@ uint8_t AluMulDiv::Read(uint16_t addr) { Run(true); - switch(addr) { - case 0x4214: return (uint8_t)_state.DivResult; - case 0x4215: return (uint8_t)(_state.DivResult >> 8); + switch (addr) + { + case 0x4214: return (uint8_t)_state.DivResult; + case 0x4215: return (uint8_t)(_state.DivResult >> 8); - case 0x4216: return (uint8_t)_state.MultOrRemainderResult; - case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8); + case 0x4216: return (uint8_t)_state.MultOrRemainderResult; + case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8); } throw std::runtime_error("ALU: invalid address"); @@ -75,33 +84,39 @@ void AluMulDiv::Write(uint16_t addr, uint8_t value) { Run(false); - switch(addr) { - case 0x4202: _state.MultOperand1 = value; break; - case 0x4203: - _state.MultOrRemainderResult = 0; - if(!_divCounter && !_multCounter) { - _multCounter = 8; + switch (addr) + { + case 0x4202: _state.MultOperand1 = value; + break; + case 0x4203: + _state.MultOrRemainderResult = 0; + if (!_divCounter && !_multCounter) + { + _multCounter = 8; - _state.MultOperand2 = value; - _state.DivResult = (value << 8) | _state.MultOperand1; - _shift = value; - } - break; + _state.MultOperand2 = value; + _state.DivResult = (value << 8) | _state.MultOperand1; + _shift = value; + } + break; - case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value; break; - case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8); break; - - case 0x4206: - _state.MultOrRemainderResult = _state.Dividend; + case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value; + break; + case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8); + break; - if(!_divCounter && !_multCounter) { - _divCounter = 16; - _state.Divisor = value; - _shift = (value << 16); - } - break; + case 0x4206: + _state.MultOrRemainderResult = _state.Dividend; - default: throw std::runtime_error("ALU: invalid address"); + if (!_divCounter && !_multCounter) + { + _divCounter = 16; + _state.Divisor = value; + _shift = (value << 16); + } + break; + + default: throw std::runtime_error("ALU: invalid address"); } } @@ -110,10 +125,11 @@ AluState AluMulDiv::GetState() return _state; } -void AluMulDiv::Serialize(Serializer &s) +void AluMulDiv::Serialize(Serializer& s) { s.Stream( - _state.MultOperand1, _state.MultOperand2, _state.MultOrRemainderResult, _state.Dividend, _state.Divisor, _state.DivResult, + _state.MultOperand1, _state.MultOperand2, _state.MultOrRemainderResult, _state.Dividend, _state.Divisor, + _state.DivResult, _divCounter, _multCounter, _shift, _prevCpuCycle ); } diff --git a/Core/AluMulDiv.h b/Core/AluMulDiv.h index 82ad174..e219311 100644 --- a/Core/AluMulDiv.h +++ b/Core/AluMulDiv.h @@ -8,7 +8,7 @@ class Cpu; class AluMulDiv final : public ISerializable { private: - Cpu *_cpu; + Cpu* _cpu; uint64_t _prevCpuCycle = 0; @@ -17,10 +17,10 @@ private: uint32_t _shift = 0; uint8_t _multCounter = 0; uint8_t _divCounter = 0; - + public: void Initialize(Cpu* cpu); - + void Run(bool isRead); uint8_t Read(uint16_t addr); @@ -28,5 +28,5 @@ public: AluState GetState(); - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/Assembler.cpp b/Core/Assembler.cpp index 505243e..feec99d 100644 --- a/Core/Assembler.cpp +++ b/Core/Assembler.cpp @@ -9,60 +9,84 @@ #include "DisassemblyInfo.h" #include "LabelManager.h" -static const std::regex instRegex = std::regex("^\\s*([a-zA-Z]{3})[\\s]*(#%|#){0,1}([([]{0,1})[\\s]*([$]{0,1})([^\\[\\],)(;:]*)[\\s]*((,[$][0-9a-f]{1,2}|,x\\)|\\),y|,x|,y|,s\\),y|,s|\\)|\\],y|\\]){0,1})\\s*(;*)(.*)", std::regex_constants::icase); +static const std::regex instRegex = std::regex( + "^\\s*([a-zA-Z]{3})[\\s]*(#%|#){0,1}([([]{0,1})[\\s]*([$]{0,1})([^\\[\\],)(;:]*)[\\s]*((,[$][0-9a-f]{1,2}|,x\\)|\\),y|,x|,y|,s\\),y|,s|\\)|\\],y|\\]){0,1})\\s*(;*)(.*)", + std::regex_constants::icase); static const std::regex isCommentOrBlank = std::regex("^\\s*([;]+.*$|\\s*$)", std::regex_constants::icase); static const std::regex labelRegex = std::regex("^\\s*([@_a-zA-Z][@_a-zA-Z0-9]*):(.*)", std::regex_constants::icase); -static const std::regex byteRegex = std::regex("^\\s*[.]db\\s+((\\$[a-fA-F0-9]{1,2}[ ])*)(\\$[a-fA-F0-9]{1,2})+\\s*(;*)(.*)$", std::regex_constants::icase); +static const std::regex byteRegex = std::regex( + "^\\s*[.]db\\s+((\\$[a-fA-F0-9]{1,2}[ ])*)(\\$[a-fA-F0-9]{1,2})+\\s*(;*)(.*)$", std::regex_constants::icase); -void Assembler::ProcessLine(string code, uint32_t& instructionAddress, vector& output, std::unordered_map& labels, bool firstPass, std::unordered_map& currentPassLabels) +void Assembler::ProcessLine(string code, uint32_t& instructionAddress, vector& output, + std::unordered_map& labels, bool firstPass, + std::unordered_map& currentPassLabels) { //Remove extra spaces as part of processing size_t offset = code.find_first_of(',', 0); - if(offset != string::npos) { + if (offset != string::npos) + { code.erase(std::remove(code.begin() + offset + 1, code.end(), ' '), code.end()); } offset = code.find_first_of(')', 0); - if(offset != string::npos) { + if (offset != string::npos) + { code.erase(std::remove(code.begin() + offset + 1, code.end(), ' '), code.end()); } //Determine if the line is blank, a comment, a label or code std::smatch match; - if(std::regex_search(code, match, byteRegex)) { + if (std::regex_search(code, match, byteRegex)) + { vector bytes = StringUtilities::Split(match.str(1) + match.str(3), ' '); - for(string& byte : bytes) { + for (string& byte : bytes) + { output.push_back((uint8_t)(HexUtilities::FromHex(byte.substr(1)))); instructionAddress++; } output.push_back(AssemblerSpecialCodes::EndOfLine); - } else if(std::regex_search(code, match, labelRegex)) { + } + else if (std::regex_search(code, match, labelRegex)) + { string label = match.str(1); string afterLabel = match.str(2); - if(currentPassLabels.find(match.str(1)) != currentPassLabels.end()) { + if (currentPassLabels.find(match.str(1)) != currentPassLabels.end()) + { output.push_back(AssemblerSpecialCodes::LabelRedefinition); - } else { + } + else + { labels[match.str(1)] = instructionAddress; currentPassLabels[match.str(1)] = instructionAddress; ProcessLine(afterLabel, instructionAddress, output, labels, firstPass, currentPassLabels); } return; - } else if(std::regex_search(code, match, isCommentOrBlank)) { + } + else if (std::regex_search(code, match, isCommentOrBlank)) + { output.push_back(AssemblerSpecialCodes::EndOfLine); return; - } else if(std::regex_search(code, match, instRegex) && match.size() > 1) { + } + else if (std::regex_search(code, match, instRegex) && match.size() > 1) + { LineData lineData; AssemblerSpecialCodes result = GetLineData(match, lineData, labels, firstPass); - if(result == AssemblerSpecialCodes::OK) { + if (result == AssemblerSpecialCodes::OK) + { AssembleInstruction(lineData, instructionAddress, output, firstPass); - } else { + } + else + { output.push_back(result); } - } else { + } + else + { output.push_back(AssemblerSpecialCodes::ParsingError); } } -AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineData, std::unordered_map& labels, bool firstPass) +AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineData, + std::unordered_map& labels, bool firstPass) { bool isBinary = match.str(2).length() > 1 && match.str(2)[1] == '%'; //Immediate + binary: "#%" @@ -74,68 +98,93 @@ AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineDa lineData.HasOpeningParenthesis = match.str(3) == "("; lineData.HasOpeningBracket = match.str(3) == "["; - std::transform(lineData.OperandSuffix.begin(), lineData.OperandSuffix.end(), lineData.OperandSuffix.begin(), ::toupper); + std::transform(lineData.OperandSuffix.begin(), lineData.OperandSuffix.end(), lineData.OperandSuffix.begin(), + ::toupper); std::transform(lineData.OpCode.begin(), lineData.OpCode.end(), lineData.OpCode.begin(), ::toupper); bool foundSpace = false; - for(char c : match.str(5)) { - if(c != ' ' && c != '\t') { - if(foundSpace) { + for (char c : match.str(5)) + { + if (c != ' ' && c != '\t') + { + if (foundSpace) + { //can't have spaces in operands (except at the very end) return AssemblerSpecialCodes::InvalidSpaces; - } else if(lineData.IsHex && !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) { + } + else if (lineData.IsHex && !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) + { //invalid hex return AssemblerSpecialCodes::InvalidHex; - } else if(isBinary && c != '0' && c != '1') { + } + else if (isBinary && c != '0' && c != '1') + { return AssemblerSpecialCodes::InvalidBinaryValue; } lineData.Operand.push_back(c); - } else { + } + else + { foundSpace = true; } } - if(isBinary) { + if (isBinary) + { //Convert the binary value to hex - if(lineData.Operand.size() == 0) { + if (lineData.Operand.size() == 0) + { return AssemblerSpecialCodes::MissingOperand; - } else if(lineData.Operand.size() <= 8) { + } + else if (lineData.Operand.size() <= 8) + { lineData.IsHex = true; int value = 0; - for(size_t i = 0; i < lineData.Operand.size(); i++) { + for (size_t i = 0; i < lineData.Operand.size(); i++) + { value <<= 1; value |= lineData.Operand[i] == '1' ? 1 : 0; } lineData.Operand = HexUtilities::ToHex(value, false); - } else { + } + else + { return AssemblerSpecialCodes::OperandOutOfRange; } } - if(!lineData.HasComment && !match.str(9).empty()) { + if (!lineData.HasComment && !match.str(9).empty()) + { //something is trailing at the end of the line, and it's not a comment return AssemblerSpecialCodes::TrailingText; } - if(!lineData.IsHex) { + if (!lineData.IsHex) + { bool allNumeric = true; - for(size_t i = 0; i < lineData.Operand.size(); i++) { - if(lineData.Operand[i] == '-' && i == 0 && lineData.Operand.size() > 1) { + for (size_t i = 0; i < lineData.Operand.size(); i++) + { + if (lineData.Operand[i] == '-' && i == 0 && lineData.Operand.size() > 1) + { //First char is a minus sign, and more characters follow, continue continue; } - if((lineData.Operand[i] < '0' || lineData.Operand[i] > '9')) { + if ((lineData.Operand[i] < '0' || lineData.Operand[i] > '9')) + { allNumeric = false; break; } } - if(allNumeric && !lineData.Operand.empty()) { + if (allNumeric && !lineData.Operand.empty()) + { //Operand is not empty, and it only contains decimal values lineData.IsDecimal = true; - } else { + } + else + { lineData.IsDecimal = false; } } @@ -143,175 +192,292 @@ AssemblerSpecialCodes Assembler::GetLineData(std::smatch match, LineData& lineDa return GetAddrModeAndOperandSize(lineData, labels, firstPass); } -AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map& labels, bool firstPass) +AssemblerSpecialCodes Assembler::GetAddrModeAndOperandSize(LineData& lineData, + std::unordered_map& labels, bool firstPass) { int opSize = 0; bool invalid = false; string operand = lineData.Operand; - if(lineData.IsHex) { - if(operand.size() == 0) { + if (lineData.IsHex) + { + if (operand.size() == 0) + { return AssemblerSpecialCodes::MissingOperand; - } else if(operand.size() <= 2) { + } + else if (operand.size() <= 2) + { opSize = 1; - } else if(operand.size() <= 4) { + } + else if (operand.size() <= 4) + { opSize = 2; - } else if(operand.size() <= 6) { + } + else if (operand.size() <= 6) + { opSize = 3; - } else { + } + else + { return AssemblerSpecialCodes::OperandOutOfRange; } - } else if(lineData.IsDecimal) { + } + else if (lineData.IsDecimal) + { int value = std::stoi(operand.c_str()); - if(value < -0x800000) { + if (value < -0x800000) + { //< -2^23 is invalid return AssemblerSpecialCodes::OperandOutOfRange; - } else if(value < -0x8000) { + } + else if (value < -0x8000) + { opSize = 3; - } else if(value < -0x80) { + } + else if (value < -0x80) + { opSize = 2; - } else if(value <= 0xFF) { + } + else if (value <= 0xFF) + { opSize = 1; - } else if(value <= 0xFFFF) { + } + else if (value <= 0xFFFF) + { opSize = 2; - } else if(value <= 0xFFFFFF) { + } + else if (value <= 0xFFFFFF) + { opSize = 3; - } else { + } + else + { //>= 2^23 is invalid return AssemblerSpecialCodes::OperandOutOfRange; } - } else if(!operand.empty()) { + } + else if (!operand.empty()) + { //Check if the operand is a known label auto findResult = labels.find(operand); - if(findResult != labels.end()) { + if (findResult != labels.end()) + { lineData.Operand = HexUtilities::ToHex((uint16_t)findResult->second); lineData.IsHex = true; opSize = 2; - } else if(operand.size() == 1 && (operand[0] == 'A' || operand[0] == 'a') && lineData.OperandSuffix.empty() && !lineData.IsHex && !lineData.IsImmediate && !lineData.HasOpeningParenthesis && !lineData.HasOpeningBracket) { + } + else if (operand.size() == 1 && (operand[0] == 'A' || operand[0] == 'a') && lineData.OperandSuffix.empty() && ! + lineData.IsHex && !lineData.IsImmediate && !lineData.HasOpeningParenthesis && !lineData.HasOpeningBracket) + { //Allow optional "A" after AddrMode == Accumulator instructions lineData.Mode = AddrMode::Acc; opSize = 0; - } else { + } + else + { int32_t addr = _labelManager->GetLabelRelativeAddress(operand); - if(addr > 0xFFFF) { + if (addr > 0xFFFF) + { lineData.Operand = HexUtilities::ToHex24(addr); lineData.IsHex = true; opSize = 3; - } else if(addr > 0xFF) { + } + else if (addr > 0xFF) + { lineData.Operand = HexUtilities::ToHex((uint16_t)addr); lineData.IsHex = true; opSize = 2; - } else if(addr >= 0) { + } + else if (addr >= 0) + { lineData.Operand = HexUtilities::ToHex((uint8_t)addr); lineData.IsHex = true; opSize = 1; - } else { - if(firstPass) { + } + else + { + if (firstPass) + { //First pass, we couldn't find a matching label, so it might be defined later on //Pretend it exists for now _needSecondPass = true; lineData.Operand = "FFFF"; lineData.IsHex = true; opSize = 2; - } else { + } + else + { return AssemblerSpecialCodes::UnknownLabel; } } } - } else { + } + else + { //No operand opSize = 0; } - if(lineData.Mode == AddrMode::Imp) { - if(lineData.OperandSuffix.substr(0, 2) == ",$") { + if (lineData.Mode == AddrMode::Imp) + { + if (lineData.OperandSuffix.substr(0, 2) == ",$") + { //Used by MVP, MVN opSize = 2; lineData.Mode = AddrMode::BlkMov; uint8_t dest = HexUtilities::FromHex(lineData.OperandSuffix.substr(2)); lineData.Operand += HexUtilities::ToHex(dest); - } else if(lineData.IsImmediate) { - if(lineData.HasOpeningParenthesis || lineData.HasOpeningBracket|| opSize == 0) { + } + else if (lineData.IsImmediate) + { + if (lineData.HasOpeningParenthesis || lineData.HasOpeningBracket || opSize == 0) + { invalid = true; - } else if(opSize >= 3) { + } + else if (opSize >= 3) + { invalid = true; } lineData.Mode = opSize == 2 ? AddrMode::Imm16 : AddrMode::Imm8; //or Rel - } else if(lineData.HasOpeningBracket) { - if(lineData.OperandSuffix == "]") { - switch(opSize){ - case 1: lineData.Mode = AddrMode::DirIndLng; break; - case 2: lineData.Mode = AddrMode::AbsIndLng; break; - default: invalid = true; break; + } + else if (lineData.HasOpeningBracket) + { + if (lineData.OperandSuffix == "]") + { + switch (opSize) + { + case 1: lineData.Mode = AddrMode::DirIndLng; + break; + case 2: lineData.Mode = AddrMode::AbsIndLng; + break; + default: invalid = true; + break; } - } else if(lineData.OperandSuffix == "],Y") { - if(opSize == 1) { + } + else if (lineData.OperandSuffix == "],Y") + { + if (opSize == 1) + { lineData.Mode = AddrMode::DirIndLngIdxY; - } else { + } + else + { invalid = true; } } - } else if(lineData.HasOpeningParenthesis) { - if(lineData.OperandSuffix == ")") { + } + else if (lineData.HasOpeningParenthesis) + { + if (lineData.OperandSuffix == ")") + { lineData.Mode = opSize == 1 ? AddrMode::DirInd : AddrMode::AbsInd; - } else if(lineData.OperandSuffix == ",X)") { + } + else if (lineData.OperandSuffix == ",X)") + { lineData.Mode = opSize == 1 ? AddrMode::DirIdxIndX : AddrMode::AbsIdxXInd; - } else if(lineData.OperandSuffix == "),Y") { - if(opSize == 1) { + } + else if (lineData.OperandSuffix == "),Y") + { + if (opSize == 1) + { lineData.Mode = AddrMode::DirIndIdxY; - } else { + } + else + { return AssemblerSpecialCodes::OperandOutOfRange; } - } else if(lineData.OperandSuffix == ",S),Y") { - if(opSize == 1) { + } + else if (lineData.OperandSuffix == ",S),Y") + { + if (opSize == 1) + { lineData.Mode = AddrMode::StkRelIndIdxY; - } else { + } + else + { return AssemblerSpecialCodes::OperandOutOfRange; } - } else { + } + else + { invalid = true; } - } else { - if(lineData.OperandSuffix == ",X") { - if(opSize == 3) { + } + else + { + if (lineData.OperandSuffix == ",X") + { + if (opSize == 3) + { lineData.Mode = AddrMode::AbsLngIdxX; - } else if(opSize == 2) { + } + else if (opSize == 2) + { lineData.Mode = AddrMode::AbsIdxX; - } else if(opSize == 1) { + } + else if (opSize == 1) + { //Sometimes zero page addressing is not available, even if the operand is in the zero page lineData.Mode = AddrMode::DirIdxX; - } else { + } + else + { invalid = true; } - } else if(lineData.OperandSuffix == ",Y") { - if(opSize == 2) { + } + else if (lineData.OperandSuffix == ",Y") + { + if (opSize == 2) + { lineData.Mode = AddrMode::AbsIdxY; - } else if(opSize == 1) { + } + else if (opSize == 1) + { //Sometimes zero page addressing is not available, even if the operand is in the zero page lineData.Mode = AddrMode::DirIdxY; - } else { + } + else + { invalid = true; } - } else if(lineData.OperandSuffix == ",S") { - if(opSize == 1) { + } + else if (lineData.OperandSuffix == ",S") + { + if (opSize == 1) + { lineData.Mode = AddrMode::StkRel; - } else { + } + else + { return AssemblerSpecialCodes::OperandOutOfRange; } - } else if(lineData.OperandSuffix.empty()) { - if(opSize == 0) { + } + else if (lineData.OperandSuffix.empty()) + { + if (opSize == 0) + { lineData.Mode = AddrMode::Imp; //or Acc - } else if(opSize == 3) { + } + else if (opSize == 3) + { lineData.Mode = AddrMode::AbsLng; - } else if(opSize == 2) { + } + else if (opSize == 2) + { lineData.Mode = AddrMode::Abs; - } else if(opSize == 1) { + } + else if (opSize == 1) + { //Sometimes zero page addressing is not available, even if the operand is in the zero page lineData.Mode = AddrMode::Dir; - } else { + } + else + { invalid = true; } - } else { + } + else + { invalid = true; } } @@ -331,41 +497,60 @@ bool Assembler::IsOpModeAvailable(string& opCode, AddrMode mode) return _availableModesByOpName[opCode].find((int)mode) != _availableModesByOpName[opCode].end(); } -void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector& output, bool firstPass) +void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector& output, + bool firstPass) { bool foundMatch = false; - for(int i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) + { AddrMode opMode = CpuDisUtils::OpMode[i]; - if(lineData.OpCode == CpuDisUtils::OpName[i]) { + if (lineData.OpCode == CpuDisUtils::OpName[i]) + { bool modeMatch = opMode == lineData.Mode; - if(!modeMatch) { - if(lineData.Mode == AddrMode::Imp && (opMode == AddrMode::Acc || opMode == AddrMode::Stk)) { + if (!modeMatch) + { + if (lineData.Mode == AddrMode::Imp && (opMode == AddrMode::Acc || opMode == AddrMode::Stk)) + { modeMatch = true; - } else if(lineData.Mode == AddrMode::Imm8 && opMode == AddrMode::Sig8) { + } + else if (lineData.Mode == AddrMode::Imm8 && opMode == AddrMode::Sig8) + { modeMatch = true; - } else if((lineData.Mode == AddrMode::Imm8 || lineData.Mode == AddrMode::Imm16) && (opMode == AddrMode::ImmX || opMode == AddrMode::ImmM)) { + } + else if ((lineData.Mode == AddrMode::Imm8 || lineData.Mode == AddrMode::Imm16) && (opMode == AddrMode::ImmX + || opMode == AddrMode::ImmM)) + { modeMatch = true; - } else if((opMode == AddrMode::Rel || opMode == AddrMode::RelLng) && (lineData.Mode == AddrMode::AbsLng || lineData.Mode == AddrMode::Abs || lineData.Mode == AddrMode::Dir)) { + } + else if ((opMode == AddrMode::Rel || opMode == AddrMode::RelLng) && (lineData.Mode == AddrMode::AbsLng || + lineData.Mode == AddrMode::Abs || lineData.Mode == AddrMode::Dir)) + { bool lngBranch = opMode == AddrMode::RelLng; modeMatch = true; //Convert "absolute" jump to a relative jump int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand); - if(lineData.Mode == AddrMode::Abs) { + if (lineData.Mode == AddrMode::Abs) + { value |= (instructionAddress & 0xFF0000); } int32_t addressGap; - if(lineData.Mode == AddrMode::Dir) { + if (lineData.Mode == AddrMode::Dir) + { addressGap = (int8_t)value; - } else { + } + else + { addressGap = value - (instructionAddress + (lngBranch ? 3 : 2)); } - if(addressGap > (lngBranch ? 32767 : 127) || addressGap < (lngBranch ? -32768 : -128)) { + if (addressGap > (lngBranch ? 32767 : 127) || addressGap < (lngBranch ? -32768 : -128)) + { //Gap too long, can't jump that far - if(!firstPass) { + if (!firstPass) + { //Pretend this is ok on first pass, we're just trying to find all labels output.push_back(AssemblerSpecialCodes::OutOfRangeJump); return; @@ -375,22 +560,30 @@ void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAdd //Update data to match relative jump lineData.OperandSize = lngBranch ? 2 : 1; lineData.IsHex = true; - lineData.Operand = lngBranch ? HexUtilities::ToHex((uint16_t)addressGap) : HexUtilities::ToHex((uint8_t)addressGap); + lineData.Operand = lngBranch + ? HexUtilities::ToHex((uint16_t)addressGap) + : HexUtilities::ToHex((uint8_t)addressGap); } } - if(modeMatch) { + if (modeMatch) + { output.push_back(i); instructionAddress += (lineData.OperandSize + 1); - if(lineData.OperandSize == 1) { + if (lineData.OperandSize == 1) + { int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand); output.push_back(value & 0xFF); - } else if(lineData.OperandSize == 2) { + } + else if (lineData.OperandSize == 2) + { int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand); output.push_back(value & 0xFF); output.push_back((value >> 8) & 0xFF); - } else if(lineData.OperandSize == 3) { + } + else if (lineData.OperandSize == 3) + { int value = lineData.IsHex ? HexUtilities::FromHex(lineData.Operand) : std::stoi(lineData.Operand); output.push_back(value & 0xFF); output.push_back((value >> 8) & 0xFF); @@ -403,9 +596,12 @@ void Assembler::AssembleInstruction(LineData& lineData, uint32_t& instructionAdd } } - if(!foundMatch) { + if (!foundMatch) + { output.push_back(AssemblerSpecialCodes::InvalidInstruction); - } else { + } + else + { output.push_back(AssemblerSpecialCodes::EndOfLine); } } @@ -421,8 +617,10 @@ Assembler::~Assembler() uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode) { - for(uint8_t i = 0; i < 255; i++) { - if(_availableModesByOpName.find(CpuDisUtils::OpName[i]) == _availableModesByOpName.end()) { + for (uint8_t i = 0; i < 255; i++) + { + if (_availableModesByOpName.find(CpuDisUtils::OpName[i]) == _availableModesByOpName.end()) + { _availableModesByOpName[CpuDisUtils::OpName[i]] = std::unordered_set(); } _availableModesByOpName[CpuDisUtils::OpName[i]].emplace((int)CpuDisUtils::OpMode[i]); @@ -439,13 +637,17 @@ uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* as vector codeLines; codeLines.reserve(100); - while(i < code.size()) { + while (i < code.size()) + { size_t offset = code.find_first_of('\n', i); string line; - if(offset != string::npos) { + if (offset != string::npos) + { line = code.substr(i, offset - i); i = offset + 1; - } else { + } + else + { line = code.substr(i); i = code.size(); } @@ -454,15 +656,18 @@ uint32_t Assembler::AssembleCode(string code, uint32_t startAddress, int16_t* as //Make 2 passes - first one to find all labels, second to assemble _needSecondPass = false; - for(string& line : codeLines) { + for (string& line : codeLines) + { ProcessLine(line, startAddress, output, temporaryLabels, true, currentPassLabels); } - if(_needSecondPass) { + if (_needSecondPass) + { currentPassLabels.clear(); output.clear(); startAddress = originalStartAddr; - for(string& line : codeLines) { + for (string& line : codeLines) + { ProcessLine(line, startAddress, output, temporaryLabels, false, currentPassLabels); } } diff --git a/Core/Assembler.h b/Core/Assembler.h index e73995d..e344852 100644 --- a/Core/Assembler.h +++ b/Core/Assembler.h @@ -28,9 +28,13 @@ private: bool _needSecondPass; shared_ptr _labelManager; - void ProcessLine(string code, uint32_t& instructionAddress, vector& output, std::unordered_map& labels, bool firstPass, std::unordered_map& currentPassLabels); - AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, std::unordered_map& labels, bool firstPass); - AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map& labels, bool firstPass); + void ProcessLine(string code, uint32_t& instructionAddress, vector& output, + std::unordered_map& labels, bool firstPass, + std::unordered_map& currentPassLabels); + AssemblerSpecialCodes GetLineData(std::smatch match, LineData& lineData, + std::unordered_map& labels, bool firstPass); + AssemblerSpecialCodes GetAddrModeAndOperandSize(LineData& lineData, std::unordered_map& labels, + bool firstPass); void AssembleInstruction(LineData& lineData, uint32_t& instructionAddress, vector& output, bool firstPass); bool IsOpModeAvailable(string& opCode, AddrMode mode); @@ -40,4 +44,4 @@ public: virtual ~Assembler(); uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode); -}; \ No newline at end of file +}; diff --git a/Core/BaseCartridge.cpp b/Core/BaseCartridge.cpp index 0e10dcf..c06327d 100644 --- a/Core/BaseCartridge.cpp +++ b/Core/BaseCartridge.cpp @@ -38,13 +38,16 @@ BaseCartridge::~BaseCartridge() delete[] _saveRam; } -shared_ptr BaseCartridge::CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile) +shared_ptr BaseCartridge::CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile) { - if(romFile.IsValid()) { + if (romFile.IsValid()) + { shared_ptr cart(new BaseCartridge()); - if(patchFile.IsValid()) { + if (patchFile.IsValid()) + { cart->_patchPath = patchFile; - if(romFile.ApplyPatch(patchFile)) { + if (romFile.ApplyPatch(patchFile)) + { MessageManager::DisplayMessage("Patch", "ApplyingPatch", patchFile.GetFileName()); } } @@ -52,7 +55,8 @@ shared_ptr BaseCartridge::CreateCartridge(Console* console, Virtu vector romData; romFile.ReadFile(romData); - if(romData.size() < 0x4000) { + if (romData.size() < 0x4000) + { return nullptr; } @@ -60,24 +64,35 @@ shared_ptr BaseCartridge::CreateCartridge(Console* console, Virtu cart->_romPath = romFile; string fileExt = FolderUtilities::GetExtension(romFile.GetFileName()); - if(fileExt == ".bs") { + if (fileExt == ".bs") + { cart->_bsxMemPack.reset(new BsxMemoryPack(console, romData, false)); - if(!FirmwareHelper::LoadBsxFirmware(console, &cart->_prgRom, cart->_prgRomSize)) { + if (!FirmwareHelper::LoadBsxFirmware(console, &cart->_prgRom, cart->_prgRomSize)) + { return nullptr; } - } else if(fileExt == ".gb" || fileExt == ".gbc") { - if(cart->LoadGameboy(romFile, true)) { + } + else if (fileExt == ".gb" || fileExt == ".gbc") + { + if (cart->LoadGameboy(romFile, true)) + { return cart; - } else { + } + else + { return nullptr; - } - } else { - if(romData.size() < 0x8000) { + } + } + else + { + if (romData.size() < 0x8000) + { return nullptr; } cart->_prgRomSize = (uint32_t)romData.size(); - if((cart->_prgRomSize & 0xFFF) != 0) { + if ((cart->_prgRomSize & 0xFFF) != 0) + { //Round up to the next 4kb size, to ensure we have access to all the rom's data cart->_prgRomSize = (cart->_prgRomSize & ~0xFFF) + 0x1000; } @@ -86,19 +101,27 @@ shared_ptr BaseCartridge::CreateCartridge(Console* console, Virtu memcpy(cart->_prgRom, romData.data(), romData.size()); } - if(memcmp(cart->_prgRom, "SNES-SPC700 Sound File Data", 27) == 0) { - if(cart->_prgRomSize >= 0x10200) { + if (memcmp(cart->_prgRom, "SNES-SPC700 Sound File Data", 27) == 0) + { + if (cart->_prgRomSize >= 0x10200) + { //SPC files must be 0x10200 bytes long at minimum cart->LoadSpc(); - } else { + } + else + { return nullptr; } - } else { + } + else + { cart->LoadRom(); } return cart; - } else { + } + else + { return nullptr; } } @@ -106,51 +129,65 @@ shared_ptr BaseCartridge::CreateCartridge(Console* console, Virtu int32_t BaseCartridge::GetHeaderScore(uint32_t addr) { //Try to figure out where the header is by using a scoring system - if(_prgRomSize < addr + 0x7FFF) { + if (_prgRomSize < addr + 0x7FFF) + { return -1; } SnesCartInformation cartInfo; memcpy(&cartInfo, _prgRom + addr + 0x7FB0, sizeof(SnesCartInformation)); - + uint32_t score = 0; uint8_t mode = (cartInfo.MapMode & ~0x10); - if((mode == 0x20 || mode == 0x22) && addr < 0x8000) { + if ((mode == 0x20 || mode == 0x22) && addr < 0x8000) + { score++; - } else if((mode == 0x21 || mode == 0x25) && addr >= 0x8000) { + } + else if ((mode == 0x21 || mode == 0x25) && addr >= 0x8000) + { score++; } - if(cartInfo.RomType < 0x08) { + if (cartInfo.RomType < 0x08) + { score++; } - if(cartInfo.RomSize < 0x10) { + if (cartInfo.RomSize < 0x10) + { score++; } - if(cartInfo.SramSize < 0x08) { + if (cartInfo.SramSize < 0x08) + { score++; } uint16_t checksum = cartInfo.Checksum[0] | (cartInfo.Checksum[1] << 8); uint16_t complement = cartInfo.ChecksumComplement[0] | (cartInfo.ChecksumComplement[1] << 8); - if(checksum + complement == 0xFFFF && checksum != 0 && complement != 0) { + if (checksum + complement == 0xFFFF && checksum != 0 && complement != 0) + { score += 8; } uint32_t resetVectorAddr = addr + 0x7FFC; uint32_t resetVector = _prgRom[resetVectorAddr] | (_prgRom[resetVectorAddr + 1] << 8); - if(resetVector < 0x8000) { + if (resetVector < 0x8000) + { return -1; } - + uint8_t op = _prgRom[addr + (resetVector & 0x7FFF)]; - if(op == 0x18 || op == 0x78 || op == 0x4C || op == 0x5C || op == 0x20 || op == 0x22 || op == 0x9C) { + if (op == 0x18 || op == 0x78 || op == 0x4C || op == 0x5C || op == 0x20 || op == 0x22 || op == 0x9C) + { //CLI, SEI, JMP, JML, JSR, JSl, STZ score += 8; - } else if(op == 0xC2 || op == 0xE2 || op == 0xA9 || op == 0xA2 || op == 0xA0) { + } + else if (op == 0xC2 || op == 0xE2 || op == 0xA9 || op == 0xA2 || op == 0xA0) + { //REP, SEP, LDA, LDX, LDY score += 4; - } else if(op == 0x00 || op == 0xFF || op == 0xCC) { + } + else if (op == 0x00 || op == 0xFF || op == 0xCC) + { //BRK, SBC, CPY score -= 8; } @@ -161,14 +198,16 @@ int32_t BaseCartridge::GetHeaderScore(uint32_t addr) void BaseCartridge::LoadRom() { //Find the best potential header among lorom/hirom + headerless/headered combinations - vector baseAddresses = { 0, 0x200, 0x8000, 0x8200, 0x408000, 0x408200 }; + vector baseAddresses = {0, 0x200, 0x8000, 0x8200, 0x408000, 0x408200}; int32_t bestScore = -1; bool hasHeader = false; bool isLoRom = true; bool isExRom = true; - for(uint32_t baseAddress : baseAddresses) { + for (uint32_t baseAddress : baseAddresses) + { int32_t score = GetHeaderScore(baseAddress); - if(score >= 0 && score >= bestScore) { + if (score >= 0 && score >= bestScore) + { bestScore = score; isLoRom = (baseAddress & 0x8000) == 0; isExRom = (baseAddress & 0x400000) != 0; @@ -180,44 +219,57 @@ void BaseCartridge::LoadRom() } uint32_t flags = 0; - if(isLoRom) { - if(hasHeader) { + if (isLoRom) + { + if (hasHeader) + { flags |= CartFlags::CopierHeader; } flags |= CartFlags::LoRom; - } else { - if(hasHeader) { + } + else + { + if (hasHeader) + { flags |= CartFlags::CopierHeader; } flags |= isExRom ? CartFlags::ExHiRom : CartFlags::HiRom; } - if(flags & CartFlags::CopierHeader) { + if (flags & CartFlags::CopierHeader) + { //Remove the copier header memmove(_prgRom, _prgRom + 512, _prgRomSize - 512); _prgRomSize -= 512; _headerOffset -= 512; } - - if((flags & CartFlags::HiRom) && (_cartInfo.MapMode & 0x27) == 0x25) { + + if ((flags & CartFlags::HiRom) && (_cartInfo.MapMode & 0x27) == 0x25) + { flags |= CartFlags::ExHiRom; - } else if((flags & CartFlags::LoRom) && (_cartInfo.MapMode & 0x27) == 0x22) { + } + else if ((flags & CartFlags::LoRom) && (_cartInfo.MapMode & 0x27) == 0x22) + { flags |= CartFlags::ExLoRom; } - if(_cartInfo.MapMode & 0x10) { + if (_cartInfo.MapMode & 0x10) + { flags |= CartFlags::FastRom; } _flags = (CartFlags::CartFlags)flags; - _hasBattery = (_cartInfo.RomType & 0x0F) == 0x02 || (_cartInfo.RomType & 0x0F) == 0x05 || (_cartInfo.RomType & 0x0F) == 0x06 || (_cartInfo.RomType & 0x0F) == 0x09 || (_cartInfo.RomType & 0x0F) == 0x0A; + _hasBattery = (_cartInfo.RomType & 0x0F) == 0x02 || (_cartInfo.RomType & 0x0F) == 0x05 || (_cartInfo.RomType & 0x0F) + == 0x06 || (_cartInfo.RomType & 0x0F) == 0x09 || (_cartInfo.RomType & 0x0F) == 0x0A; _coprocessorType = GetCoprocessorType(); - if(_coprocessorType != CoprocessorType::None && _cartInfo.ExpansionRamSize > 0 && _cartInfo.ExpansionRamSize <= 7) { + if (_coprocessorType != CoprocessorType::None && _cartInfo.ExpansionRamSize > 0 && _cartInfo.ExpansionRamSize <= 7) + { _coprocessorRamSize = _cartInfo.ExpansionRamSize > 0 ? 1024 * (1 << _cartInfo.ExpansionRamSize) : 0; } - if(_coprocessorType == CoprocessorType::GSU && _coprocessorRamSize == 0) { + if (_coprocessorType == CoprocessorType::GSU && _coprocessorRamSize == 0) + { //Use a min of 64kb by default for GSU games _coprocessorRamSize = 0x10000; } @@ -236,42 +288,48 @@ void BaseCartridge::LoadRom() CoprocessorType BaseCartridge::GetCoprocessorType() { - if((_cartInfo.RomType & 0x0F) >= 0x03) { - switch((_cartInfo.RomType & 0xF0) >> 4) { - case 0x00: return GetDspVersion(); - case 0x01: return CoprocessorType::GSU; - case 0x02: return CoprocessorType::OBC1; - case 0x03: return CoprocessorType::SA1; - case 0x04: return CoprocessorType::SDD1; - case 0x05: return CoprocessorType::RTC; - case 0x0E: - switch(_cartInfo.RomType) { - case 0xE3: return CoprocessorType::SGB; - case 0xE5: return CoprocessorType::Satellaview; - default: return CoprocessorType::None; - } - break; + if ((_cartInfo.RomType & 0x0F) >= 0x03) + { + switch ((_cartInfo.RomType & 0xF0) >> 4) + { + case 0x00: return GetDspVersion(); + case 0x01: return CoprocessorType::GSU; + case 0x02: return CoprocessorType::OBC1; + case 0x03: return CoprocessorType::SA1; + case 0x04: return CoprocessorType::SDD1; + case 0x05: return CoprocessorType::RTC; + case 0x0E: + switch (_cartInfo.RomType) + { + case 0xE3: return CoprocessorType::SGB; + case 0xE5: return CoprocessorType::Satellaview; + default: return CoprocessorType::None; + } + break; - case 0x0F: - switch(_cartInfo.CartridgeType) { - case 0x00: - _hasBattery = true; - _hasRtc = (_cartInfo.RomType & 0x0F) == 0x09; - return CoprocessorType::SPC7110; + case 0x0F: + switch (_cartInfo.CartridgeType) + { + case 0x00: + _hasBattery = true; + _hasRtc = (_cartInfo.RomType & 0x0F) == 0x09; + return CoprocessorType::SPC7110; - case 0x01: - _hasBattery = true; - return GetSt01xVersion(); + case 0x01: + _hasBattery = true; + return GetSt01xVersion(); - case 0x02: - _hasBattery = true; - return CoprocessorType::ST018; + case 0x02: + _hasBattery = true; + return CoprocessorType::ST018; - case 0x10: return CoprocessorType::CX4; - } - break; + case 0x10: return CoprocessorType::CX4; + } + break; } - } else if(GetGameCode() == "042J") { + } + else if (GetGameCode() == "042J") + { return CoprocessorType::SGB; } @@ -281,7 +339,8 @@ CoprocessorType BaseCartridge::GetCoprocessorType() CoprocessorType BaseCartridge::GetSt01xVersion() { string cartName = GetCartName(); - if(cartName == "2DAN MORITA SHOUGI") { + if (cartName == "2DAN MORITA SHOUGI") + { return CoprocessorType::ST011; } @@ -291,27 +350,36 @@ CoprocessorType BaseCartridge::GetSt01xVersion() CoprocessorType BaseCartridge::GetDspVersion() { string cartName = GetCartName(); - if(cartName == "DUNGEON MASTER") { + if (cartName == "DUNGEON MASTER") + { return CoprocessorType::DSP2; - } if(cartName == "PILOTWINGS") { + } + if (cartName == "PILOTWINGS") + { return CoprocessorType::DSP1; - } else if(cartName == "SD\xB6\xDE\xDD\xC0\xDE\xD1GX") { + } + else if (cartName == "SD\xB6\xDE\xDD\xC0\xDE\xD1GX") + { //SD Gundam GX return CoprocessorType::DSP3; - } else if(cartName == "PLANETS CHAMP TG3000" || cartName == "TOP GEAR 3000") { + } + else if (cartName == "PLANETS CHAMP TG3000" || cartName == "TOP GEAR 3000") + { return CoprocessorType::DSP4; } - + //Default to DSP1B return CoprocessorType::DSP1B; } void BaseCartridge::Reset() { - if(_coprocessor) { + if (_coprocessor) + { _coprocessor->Reset(); } - if(_bsxMemPack) { + if (_bsxMemPack) + { _bsxMemPack->Reset(); } } @@ -330,30 +398,43 @@ RomInfo BaseCartridge::GetRomInfo() vector BaseCartridge::GetOriginalPrgRom() { RomInfo romInfo = GetRomInfo(); - shared_ptr originalCart = BaseCartridge::CreateCartridge(_console, romInfo.RomFile, romInfo.PatchFile); - if(originalCart->_gameboy) { + shared_ptr originalCart = + BaseCartridge::CreateCartridge(_console, romInfo.RomFile, romInfo.PatchFile); + if (originalCart->_gameboy) + { uint8_t* orgPrgRom = originalCart->_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom); uint32_t orgRomSize = originalCart->_gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom); return vector(orgPrgRom, orgPrgRom + orgRomSize); - } else { - return vector(originalCart->DebugGetPrgRom(), originalCart->DebugGetPrgRom() + originalCart->DebugGetPrgRomSize()); + } + else + { + return vector(originalCart->DebugGetPrgRom(), + originalCart->DebugGetPrgRom() + originalCart->DebugGetPrgRomSize()); } } uint32_t BaseCartridge::GetCrc32() { - if(_gameboy) { - return CRC32::GetCRC(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom), _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom)); - } else { + if (_gameboy) + { + return CRC32::GetCRC(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom), + _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom)); + } + else + { return CRC32::GetCRC(_prgRom, _prgRomSize); } } string BaseCartridge::GetSha1Hash() { - if(_gameboy) { - return SHA1::GetHash(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom), _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom)); - } else { + if (_gameboy) + { + return SHA1::GetHash(_gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom), + _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom)); + } + else + { return SHA1::GetHash(_prgRom, _prgRomSize); } } @@ -365,97 +446,122 @@ CartFlags::CartFlags BaseCartridge::GetCartFlags() void BaseCartridge::LoadBattery() { - if(_saveRamSize > 0) { + if (_saveRamSize > 0) + { _console->GetBatteryManager()->LoadBattery(".srm", _saveRam, _saveRamSize); - } - - if(_coprocessor && _hasBattery) { + } + + if (_coprocessor && _hasBattery) + { _coprocessor->LoadBattery(); } - if(_gameboy) { + if (_gameboy) + { _gameboy->LoadBattery(); } } void BaseCartridge::SaveBattery() { - if(_saveRamSize > 0) { + if (_saveRamSize > 0) + { _console->GetBatteryManager()->SaveBattery(".srm", _saveRam, _saveRamSize); - } - - if(_coprocessor && _hasBattery) { + } + + if (_coprocessor && _hasBattery) + { _coprocessor->SaveBattery(); } - if(_bsxMemPack) { + if (_bsxMemPack) + { _bsxMemPack->SaveBattery(); } - if(_gameboy) { + if (_gameboy) + { _gameboy->SaveBattery(); } } -void BaseCartridge::Init(MemoryMappings &mm) +void BaseCartridge::Init(MemoryMappings& mm) { _prgRomHandlers.clear(); _saveRamHandlers.clear(); - for(uint32_t i = 0; i < _prgRomSize; i += 0x1000) { - _prgRomHandlers.push_back(unique_ptr(new RomHandler(_prgRom, i, _prgRomSize, SnesMemoryType::PrgRom))); + for (uint32_t i = 0; i < _prgRomSize; i += 0x1000) + { + _prgRomHandlers. + push_back(unique_ptr(new RomHandler(_prgRom, i, _prgRomSize, SnesMemoryType::PrgRom))); } uint32_t power = (uint32_t)std::log2(_prgRomSize); - if(_prgRomSize >(1u << power)) { + if (_prgRomSize > (1u << power)) + { //If size isn't a power of 2, mirror the part above the nearest (lower) power of 2 until the size reaches the next power of 2. uint32_t halfSize = 1 << power; uint32_t fullSize = 1 << (power + 1); uint32_t extraHandlers = std::max((_prgRomSize - halfSize) / 0x1000, 1); - while(_prgRomHandlers.size() < fullSize / 0x1000) { - for(uint32_t i = 0; i < extraHandlers; i += 0x1000) { - _prgRomHandlers.push_back(unique_ptr(new RomHandler(_prgRom, halfSize + i, _prgRomSize, SnesMemoryType::PrgRom))); + while (_prgRomHandlers.size() < fullSize / 0x1000) + { + for (uint32_t i = 0; i < extraHandlers; i += 0x1000) + { + _prgRomHandlers.push_back( + unique_ptr(new RomHandler(_prgRom, halfSize + i, _prgRomSize, SnesMemoryType::PrgRom))); } } } - for(uint32_t i = 0; i < _saveRamSize; i += 0x1000) { - _saveRamHandlers.push_back(unique_ptr(new RamHandler(_saveRam, i, _saveRamSize, SnesMemoryType::SaveRam))); + for (uint32_t i = 0; i < _saveRamSize; i += 0x1000) + { + _saveRamHandlers.push_back( + unique_ptr(new RamHandler(_saveRam, i, _saveRamSize, SnesMemoryType::SaveRam))); } RegisterHandlers(mm); - - if(_coprocessorType != CoprocessorType::Gameboy) { + + if (_coprocessorType != CoprocessorType::Gameboy) + { InitCoprocessor(); } LoadBattery(); } -void BaseCartridge::RegisterHandlers(MemoryMappings &mm) +void BaseCartridge::RegisterHandlers(MemoryMappings& mm) { - if(MapSpecificCarts(mm) || _coprocessorType == CoprocessorType::GSU || _coprocessorType == CoprocessorType::SDD1 || _coprocessorType == CoprocessorType::SPC7110 || _coprocessorType == CoprocessorType::CX4) { + if (MapSpecificCarts(mm) || _coprocessorType == CoprocessorType::GSU || _coprocessorType == CoprocessorType::SDD1 || + _coprocessorType == CoprocessorType::SPC7110 || _coprocessorType == CoprocessorType::CX4) + { MapBsxMemoryPack(mm); return; } - if(_flags & CartFlags::LoRom) { + if (_flags & CartFlags::LoRom) + { mm.RegisterHandler(0x00, 0x7D, 0x8000, 0xFFFF, _prgRomHandlers); mm.RegisterHandler(0x80, 0xFF, 0x8000, 0xFFFF, _prgRomHandlers); - if(_saveRamSize > 0) { - if(_prgRomSize >= 1024 * 1024 * 2) { + if (_saveRamSize > 0) + { + if (_prgRomSize >= 1024 * 1024 * 2) + { //For games >= 2mb in size, put ROM at 70-7D/F0-FF:0000-7FFF (e.g: Fire Emblem: Thracia 776) mm.RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _saveRamHandlers); mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _saveRamHandlers); - } else { + } + else + { //For games < 2mb in size, put save RAM at 70-7D/F0-FF:0000-FFFF (e.g: Wanderers from Ys) mm.RegisterHandler(0x70, 0x7D, 0x0000, 0xFFFF, _saveRamHandlers); mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0xFFFF, _saveRamHandlers); } } - } else if(_flags & CartFlags::HiRom) { + } + else if (_flags & CartFlags::HiRom) + { mm.RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, _prgRomHandlers, 8); mm.RegisterHandler(0x40, 0x7D, 0x0000, 0xFFFF, _prgRomHandlers, 0); mm.RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, _prgRomHandlers, 8); @@ -463,7 +569,9 @@ void BaseCartridge::RegisterHandlers(MemoryMappings &mm) mm.RegisterHandler(0x20, 0x3F, 0x6000, 0x7FFF, _saveRamHandlers); mm.RegisterHandler(0xA0, 0xBF, 0x6000, 0x7FFF, _saveRamHandlers); - } else if(_flags & CartFlags::ExHiRom) { + } + else if (_flags & CartFlags::ExHiRom) + { //First half is at the end mm.RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, _prgRomHandlers, 0); mm.RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, _prgRomHandlers, 8); //mirror @@ -484,11 +592,16 @@ void BaseCartridge::RegisterHandlers(MemoryMappings &mm) void BaseCartridge::LoadEmbeddedFirmware() { //Attempt to detect/load the firmware from the end of the rom file, if it exists - if((_coprocessorType >= CoprocessorType::DSP1 && _coprocessorType <= CoprocessorType::DSP4) || (_coprocessorType >= CoprocessorType::ST010 && _coprocessorType <= CoprocessorType::ST011)) { + if ((_coprocessorType >= CoprocessorType::DSP1 && _coprocessorType <= CoprocessorType::DSP4) || (_coprocessorType >= + CoprocessorType::ST010 && _coprocessorType <= CoprocessorType::ST011)) + { uint32_t firmwareSize = 0; - if((_prgRomSize & 0x7FFF) == 0x2000) { + if ((_prgRomSize & 0x7FFF) == 0x2000) + { firmwareSize = 0x2000; - } else if((_prgRomSize & 0xFFFF) == 0xD000) { + } + else if ((_prgRomSize & 0xFFFF) == 0xD000) + { firmwareSize = 0xD000; } @@ -503,23 +616,33 @@ void BaseCartridge::InitCoprocessor() _coprocessor.reset(NecDsp::InitCoprocessor(_coprocessorType, _console, _embeddedFirmware)); _necDsp = dynamic_cast(_coprocessor.get()); - if(_coprocessorType == CoprocessorType::SA1) { + if (_coprocessorType == CoprocessorType::SA1) + { _coprocessor.reset(new Sa1(_console)); _sa1 = dynamic_cast(_coprocessor.get()); _needCoprocSync = true; - } else if(_coprocessorType == CoprocessorType::GSU) { + } + else if (_coprocessorType == CoprocessorType::GSU) + { _coprocessor.reset(new Gsu(_console, _coprocessorRamSize)); _gsu = dynamic_cast(_coprocessor.get()); _needCoprocSync = true; - } else if(_coprocessorType == CoprocessorType::SDD1) { + } + else if (_coprocessorType == CoprocessorType::SDD1) + { _coprocessor.reset(new Sdd1(_console)); - } else if(_coprocessorType == CoprocessorType::SPC7110) { + } + else if (_coprocessorType == CoprocessorType::SPC7110) + { _coprocessor.reset(new Spc7110(_console, _hasRtc)); - } else if(_coprocessorType == CoprocessorType::Satellaview) { + } + else if (_coprocessorType == CoprocessorType::Satellaview) + { //Share save file across all .bs files that use the BS-X bios _console->GetBatteryManager()->Initialize("BsxBios"); - if(!_bsxMemPack) { + if (!_bsxMemPack) + { //Create an empty memory pack if the BIOS was loaded directly (instead of a .bs file) vector emptyMemPack; _bsxMemPack.reset(new BsxMemoryPack(_console, emptyMemPack, false)); @@ -527,24 +650,31 @@ void BaseCartridge::InitCoprocessor() _coprocessor.reset(new BsxCart(_console, _bsxMemPack.get())); _bsx = dynamic_cast(_coprocessor.get()); - } else if(_coprocessorType == CoprocessorType::CX4) { + } + else if (_coprocessorType == CoprocessorType::CX4) + { _coprocessor.reset(new Cx4(_console)); _cx4 = dynamic_cast(_coprocessor.get()); _needCoprocSync = true; - } else if(_coprocessorType == CoprocessorType::OBC1 && _saveRamSize > 0) { + } + else if (_coprocessorType == CoprocessorType::OBC1 && _saveRamSize > 0) + { _coprocessor.reset(new Obc1(_console, _saveRam, _saveRamSize)); - } else if(_coprocessorType == CoprocessorType::SGB) { + } + else if (_coprocessorType == CoprocessorType::SGB) + { _coprocessor.reset(new SuperGameboy(_console)); _sgb = dynamic_cast(_coprocessor.get()); _needCoprocSync = true; } } -bool BaseCartridge::MapSpecificCarts(MemoryMappings &mm) +bool BaseCartridge::MapSpecificCarts(MemoryMappings& mm) { string name = GetCartName(); string code = GetGameCode(); - if(GetCartName() == "DEZAEMON") { + if (GetCartName() == "DEZAEMON") + { //LOROM with mirrored SRAM? mm.RegisterHandler(0x00, 0x7D, 0x8000, 0xFFFF, _prgRomHandlers); mm.RegisterHandler(0x80, 0xFF, 0x8000, 0xFFFF, _prgRomHandlers); @@ -557,13 +687,16 @@ bool BaseCartridge::MapSpecificCarts(MemoryMappings &mm) mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _saveRamHandlers); return true; - } else if(code == "ZDBJ" || code == "ZR2J" || code == "ZSNJ") { + } + else if (code == "ZDBJ" || code == "ZR2J" || code == "ZSNJ") + { //BSC-1A5M-02, BSC-1A7M-01 //Games: Sound Novel Tsukuuru, RPG Tsukuuru, Derby Stallion 96 mm.RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, _prgRomHandlers); mm.RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, _prgRomHandlers, 0, 0x200); mm.RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _prgRomHandlers, 0, 0x100); - if(_saveRamSize > 0) { + if (_saveRamSize > 0) + { mm.RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _saveRamHandlers); mm.RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _saveRamHandlers); } @@ -575,19 +708,24 @@ bool BaseCartridge::MapSpecificCarts(MemoryMappings &mm) void BaseCartridge::MapBsxMemoryPack(MemoryMappings& mm) { string code = GetGameCode(); - if(!_bsxMemPack && code.size() == 4 && code[0] == 'Z' && _cartInfo.DeveloperId == 0x33) { + if (!_bsxMemPack && code.size() == 4 && code[0] == 'Z' && _cartInfo.DeveloperId == 0x33) + { //Game with data pack slot (e.g Sound Novel Tsukuuru, etc.) vector saveData = _console->GetBatteryManager()->LoadBattery(".bs"); - if(saveData.empty()) { + if (saveData.empty()) + { //Make a 1 megabyte flash cartridge by default (use $FF for all bytes) saveData.resize(0x100000, 0xFF); } _bsxMemPack.reset(new BsxMemoryPack(_console, saveData, true)); - if(_flags & CartFlags::LoRom) { + if (_flags & CartFlags::LoRom) + { mm.RegisterHandler(0xC0, 0xEF, 0x0000, 0x7FFF, _bsxMemPack->GetMemoryHandlers()); mm.RegisterHandler(0xC0, 0xEF, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers()); - } else { + } + else + { mm.RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers(), 8); mm.RegisterHandler(0x60, 0x7D, 0x0000, 0xFFFF, _bsxMemPack->GetMemoryHandlers()); mm.RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _bsxMemPack->GetMemoryHandlers(), 8); @@ -601,12 +739,15 @@ void BaseCartridge::MapBsxMemoryPack(MemoryMappings& mm) void BaseCartridge::ApplyConfigOverrides() { string name = GetCartName(); - if(name == "POWERDRIVE" || name == "DEATH BRADE" || name == "RPG SAILORMOON") { + if (name == "POWERDRIVE" || name == "DEATH BRADE" || name == "RPG SAILORMOON") + { //These games work better when ram is initialized to $FF EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig(); cfg.RamPowerOnState = RamState::AllOnes; _console->GetSettings()->SetEmulationConfig(cfg); - } else if(name == "SUPER KEIBA 2") { + } + else if (name == "SUPER KEIBA 2") + { //Super Keiba 2 behaves incorrectly if save ram is filled with 0s EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig(); cfg.RamPowerOnState = RamState::Random; @@ -620,29 +761,37 @@ void BaseCartridge::LoadSpc() SetupCpuHalt(); } -bool BaseCartridge::LoadGameboy(VirtualFile &romFile, bool sgbEnabled) +bool BaseCartridge::LoadGameboy(VirtualFile& romFile, bool sgbEnabled) { _gameboy.reset(Gameboy::Create(_console, romFile, sgbEnabled)); - if(!_gameboy) { + if (!_gameboy) + { return false; } - _cartInfo = { }; + _cartInfo = {}; _headerOffset = Gameboy::HeaderOffset; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { GameboyConfig cfg = _console->GetSettings()->GetGameboyConfig(); - if(FirmwareHelper::LoadSgbFirmware(_console, &_prgRom, _prgRomSize, cfg.UseSgb2)) { + if (FirmwareHelper::LoadSgbFirmware(_console, &_prgRom, _prgRomSize, cfg.UseSgb2)) + { LoadRom(); - if(_coprocessorType != CoprocessorType::SGB) { + if (_coprocessorType != CoprocessorType::SGB) + { //SGB bios file isn't a recognized SGB bios, try again without SGB mode return LoadGameboy(romFile, false); } - } else { + } + else + { //Couldn't load the SGB bios, try again with in GB/GBC mode return LoadGameboy(romFile, false); } - } else { + } + else + { _coprocessorType = CoprocessorType::Gameboy; SetupCpuHalt(); } @@ -670,16 +819,19 @@ void BaseCartridge::SetupCpuHalt() _prgRom[3] = 0x00; } -void BaseCartridge::Serialize(Serializer &s) +void BaseCartridge::Serialize(Serializer& s) { s.StreamArray(_saveRam, _saveRamSize); - if(_coprocessor) { + if (_coprocessor) + { s.Stream(_coprocessor.get()); } - if(_bsxMemPack) { + if (_bsxMemPack) + { s.Stream(_bsxMemPack.get()); } - if(_gameboy) { + if (_gameboy) + { s.Stream(_gameboy.get()); } } @@ -687,16 +839,20 @@ void BaseCartridge::Serialize(Serializer &s) string BaseCartridge::GetGameCode() { string code; - if(_cartInfo.GameCode[0] > ' ') { + if (_cartInfo.GameCode[0] > ' ') + { code += _cartInfo.GameCode[0]; } - if(_cartInfo.GameCode[1] > ' ') { + if (_cartInfo.GameCode[1] > ' ') + { code += _cartInfo.GameCode[1]; } - if(_cartInfo.GameCode[2] > ' ') { + if (_cartInfo.GameCode[2] > ' ') + { code += _cartInfo.GameCode[2]; } - if(_cartInfo.GameCode[3] > ' ') { + if (_cartInfo.GameCode[3] > ' ') + { code += _cartInfo.GameCode[3]; } return code; @@ -705,8 +861,10 @@ string BaseCartridge::GetGameCode() string BaseCartridge::GetCartName() { int nameLength = 21; - for(int i = 0; i < 21; i++) { - if(_cartInfo.CartName[i] == 0) { + for (int i = 0; i < 21; i++) + { + if (_cartInfo.CartName[i] == 0) + { nameLength = i; break; } @@ -714,9 +872,12 @@ string BaseCartridge::GetCartName() string name = string(_cartInfo.CartName, nameLength); size_t lastNonSpace = name.find_last_not_of(' '); - if(lastNonSpace != string::npos) { + if (lastNonSpace != string::npos) + { return name.substr(0, lastNonSpace + 1); - } else { + } + else + { return name; } } @@ -724,7 +885,8 @@ string BaseCartridge::GetCartName() ConsoleRegion BaseCartridge::GetRegion() { uint8_t destCode = _cartInfo.DestinationCode; - if((destCode >= 0x02 && destCode <= 0x0C) || destCode == 0x11 || destCode == 0x12) { + if ((destCode >= 0x02 && destCode <= 0x0C) || destCode == 0x11 || destCode == 0x12) + { return ConsoleRegion::Pal; } return ConsoleRegion::Ntsc; @@ -736,50 +898,81 @@ void BaseCartridge::DisplayCartInfo() MessageManager::Log("File: " + VirtualFile(_romPath).GetFileName()); MessageManager::Log("Game: " + GetCartName()); string gameCode = GetGameCode(); - if(!gameCode.empty()) { + if (!gameCode.empty()) + { MessageManager::Log("Game code: " + gameCode); } - if(_flags & CartFlags::ExHiRom) { + if (_flags & CartFlags::ExHiRom) + { MessageManager::Log("Type: ExHiROM"); - } else if(_flags & CartFlags::ExLoRom) { + } + else if (_flags & CartFlags::ExLoRom) + { MessageManager::Log("Type: ExLoROM"); - } else if(_flags & CartFlags::HiRom) { + } + else if (_flags & CartFlags::HiRom) + { MessageManager::Log("Type: HiROM"); - } else if(_flags & CartFlags::LoRom) { + } + else if (_flags & CartFlags::LoRom) + { MessageManager::Log("Type: LoROM"); } - if(_coprocessorType != CoprocessorType::None) { + if (_coprocessorType != CoprocessorType::None) + { string coProcMessage = "Coprocessor: "; - switch(_coprocessorType) { - case CoprocessorType::None: coProcMessage += ""; break; - case CoprocessorType::CX4: coProcMessage += "CX4"; break; - case CoprocessorType::SDD1: coProcMessage += "S-DD1"; break; - case CoprocessorType::DSP1: coProcMessage += "DSP1"; break; - case CoprocessorType::DSP1B: coProcMessage += "DSP1B"; break; - case CoprocessorType::DSP2: coProcMessage += "DSP2"; break; - case CoprocessorType::DSP3: coProcMessage += "DSP3"; break; - case CoprocessorType::DSP4: coProcMessage += "DSP4"; break; - case CoprocessorType::GSU: coProcMessage += "Super FX (GSU1/2)"; break; - case CoprocessorType::OBC1: coProcMessage += "OBC1"; break; - case CoprocessorType::RTC: coProcMessage += "RTC"; break; - case CoprocessorType::SA1: coProcMessage += "SA1"; break; - case CoprocessorType::Satellaview: coProcMessage += "Satellaview"; break; - case CoprocessorType::SPC7110: coProcMessage += "SPC7110"; break; - case CoprocessorType::ST010: coProcMessage += "ST010"; break; - case CoprocessorType::ST011: coProcMessage += "ST011"; break; - case CoprocessorType::ST018: coProcMessage += "ST018"; break; - case CoprocessorType::Gameboy: coProcMessage += "Game Boy"; break; - case CoprocessorType::SGB: coProcMessage += "Super Game Boy"; break; + switch (_coprocessorType) + { + case CoprocessorType::None: coProcMessage += ""; + break; + case CoprocessorType::CX4: coProcMessage += "CX4"; + break; + case CoprocessorType::SDD1: coProcMessage += "S-DD1"; + break; + case CoprocessorType::DSP1: coProcMessage += "DSP1"; + break; + case CoprocessorType::DSP1B: coProcMessage += "DSP1B"; + break; + case CoprocessorType::DSP2: coProcMessage += "DSP2"; + break; + case CoprocessorType::DSP3: coProcMessage += "DSP3"; + break; + case CoprocessorType::DSP4: coProcMessage += "DSP4"; + break; + case CoprocessorType::GSU: coProcMessage += "Super FX (GSU1/2)"; + break; + case CoprocessorType::OBC1: coProcMessage += "OBC1"; + break; + case CoprocessorType::RTC: coProcMessage += "RTC"; + break; + case CoprocessorType::SA1: coProcMessage += "SA1"; + break; + case CoprocessorType::Satellaview: coProcMessage += "Satellaview"; + break; + case CoprocessorType::SPC7110: coProcMessage += "SPC7110"; + break; + case CoprocessorType::ST010: coProcMessage += "ST010"; + break; + case CoprocessorType::ST011: coProcMessage += "ST011"; + break; + case CoprocessorType::ST018: coProcMessage += "ST018"; + break; + case CoprocessorType::Gameboy: coProcMessage += "Game Boy"; + break; + case CoprocessorType::SGB: coProcMessage += "Super Game Boy"; + break; } MessageManager::Log(coProcMessage); } - if(_flags & CartFlags::FastRom) { + if (_flags & CartFlags::FastRom) + { MessageManager::Log("FastROM"); } - if(_flags & CartFlags::CopierHeader) { + if (_flags & CartFlags::CopierHeader) + { MessageManager::Log("Copier header found."); } @@ -788,13 +981,17 @@ void BaseCartridge::DisplayCartInfo() MessageManager::Log("File size: " + std::to_string(_prgRomSize / 1024) + " KB"); MessageManager::Log("ROM size: " + std::to_string((0x400 << _cartInfo.RomSize) / 1024) + " KB"); - if(_saveRamSize > 0) { - MessageManager::Log("SRAM size: " + std::to_string(_saveRamSize / 1024) + " KB" + (_hasBattery ? " (with battery)" : "")); + if (_saveRamSize > 0) + { + MessageManager::Log( + "SRAM size: " + std::to_string(_saveRamSize / 1024) + " KB" + (_hasBattery ? " (with battery)" : "")); } - if(_coprocessorRamSize > 0) { + if (_coprocessorRamSize > 0) + { MessageManager::Log("Coprocessor RAM size: " + std::to_string(_coprocessorRamSize / 1024) + " KB"); } - if(_hasBattery) { + if (_hasBattery) + { MessageManager::Log("Battery: yes"); } MessageManager::Log("-----------------------------"); @@ -843,7 +1040,8 @@ Gameboy* BaseCartridge::GetGameboy() void BaseCartridge::RunCoprocessors() { //These coprocessors are run at the end of the frame, or as needed - if(_necDsp) { + if (_necDsp) + { _necDsp->Run(); } } @@ -866,4 +1064,4 @@ vector>& BaseCartridge::GetSaveRamHandlers() SpcFileData* BaseCartridge::GetSpcData() { return _spcData.get(); -} \ No newline at end of file +} diff --git a/Core/BaseCartridge.h b/Core/BaseCartridge.h index e54590b..a6705b4 100644 --- a/Core/BaseCartridge.h +++ b/Core/BaseCartridge.h @@ -23,7 +23,7 @@ enum class ConsoleRegion; class BaseCartridge : public ISerializable { private: - Console *_console; + Console* _console; vector> _prgRomHandlers; vector> _saveRamHandlers; @@ -32,12 +32,12 @@ private: bool _needCoprocSync = false; unique_ptr _coprocessor; - - NecDsp *_necDsp = nullptr; - Sa1 *_sa1 = nullptr; - Gsu *_gsu = nullptr; - Cx4 *_cx4 = nullptr; - SuperGameboy *_sgb = nullptr; + + NecDsp* _necDsp = nullptr; + Sa1* _sa1 = nullptr; + Gsu* _gsu = nullptr; + Cx4* _cx4 = nullptr; + SuperGameboy* _sgb = nullptr; BsxCart* _bsx = nullptr; unique_ptr _bsxMemPack; unique_ptr _gameboy; @@ -51,11 +51,11 @@ private: uint8_t* _prgRom = nullptr; uint8_t* _saveRam = nullptr; - + uint32_t _prgRomSize = 0; uint32_t _saveRamSize = 0; uint32_t _coprocessorRamSize = 0; - + shared_ptr _spcData; vector _embeddedFirmware; @@ -71,7 +71,7 @@ private: bool MapSpecificCarts(MemoryMappings& mm); void MapBsxMemoryPack(MemoryMappings& mm); void ApplyConfigOverrides(); - + void LoadRom(); void LoadSpc(); bool LoadGameboy(VirtualFile& romFile, bool sgbEnabled); @@ -85,13 +85,13 @@ private: public: virtual ~BaseCartridge(); - static shared_ptr CreateCartridge(Console* console, VirtualFile &romFile, VirtualFile &patchFile); + static shared_ptr CreateCartridge(Console* console, VirtualFile& romFile, VirtualFile& patchFile); void Reset(); void SaveBattery(); - void Init(MemoryMappings &mm); + void Init(MemoryMappings& mm); RomInfo GetRomInfo(); vector GetOriginalPrgRom(); @@ -100,7 +100,7 @@ public: string GetSha1Hash(); CartFlags::CartFlags GetCartFlags(); - void RegisterHandlers(MemoryMappings &mm); + void RegisterHandlers(MemoryMappings& mm); uint8_t* DebugGetPrgRom() { return _prgRom; } uint8_t* DebugGetSaveRam() { return _saveRam; } @@ -117,10 +117,11 @@ public: Gameboy* GetGameboy(); void RunCoprocessors(); - + __forceinline void SyncCoprocessors() { - if(_needCoprocSync) { + if (_needCoprocSync) + { _coprocessor->Run(); } } @@ -132,5 +133,5 @@ public: SpcFileData* GetSpcData(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; diff --git a/Core/BaseControlDevice.cpp b/Core/BaseControlDevice.cpp index a500918..124f7d7 100644 --- a/Core/BaseControlDevice.cpp +++ b/Core/BaseControlDevice.cpp @@ -44,7 +44,8 @@ bool BaseControlDevice::IsExpansionDevice() void BaseControlDevice::StrobeProcessRead() { - if(_strobe) { + if (_strobe) + { RefreshStateBuffer(); } } @@ -54,7 +55,8 @@ void BaseControlDevice::StrobeProcessWrite(uint8_t value) bool prevStrobe = _strobe; _strobe = (value & 0x01) == 0x01; - if(prevStrobe && !_strobe) { + if (prevStrobe && !_strobe) + { RefreshStateBuffer(); } } @@ -82,17 +84,25 @@ void BaseControlDevice::SetTextState(string textState) auto lock = _stateLock.AcquireSafe(); ClearState(); - if(IsRawString()) { + if (IsRawString()) + { _state.State.insert(_state.State.end(), textState.begin(), textState.end()); - } else { - if(HasCoordinates()) { + } + else + { + if (HasCoordinates()) + { vector data = StringUtilities::Split(textState, ' '); - if(data.size() >= 3) { + if (data.size() >= 3) + { MousePosition pos; - try { + try + { pos.X = (int16_t)std::stol(data[0]); pos.Y = (int16_t)std::stol(data[1]); - } catch(std::exception&) { + } + catch (std::exception&) + { pos.X = -1; pos.Y = -1; } @@ -102,10 +112,13 @@ void BaseControlDevice::SetTextState(string textState) } int i = 0; - for(char c : textState) { - if(c != ':') { + for (char c : textState) + { + if (c != ':') + { //Ignore colons (used by multitap to separate inputs) - if(c != '.') { + if (c != '.') + { SetBit(i); } i++; @@ -117,24 +130,32 @@ void BaseControlDevice::SetTextState(string textState) string BaseControlDevice::GetTextState() { auto lock = _stateLock.AcquireSafe(); - if(IsRawString()) { + if (IsRawString()) + { return string((char*)_state.State.data(), _state.State.size()); - } else { + } + else + { string keyNames = GetKeyNames(); string output = ""; - if(HasCoordinates()) { + if (HasCoordinates()) + { MousePosition pos = GetCoordinates(); output += std::to_string(pos.X) + " " + std::to_string(pos.Y) + " "; } int keyNumber = 0; - for(size_t i = 0; i < keyNames.size(); i++) { - if(keyNames[i] != ':') { + for (size_t i = 0; i < keyNames.size(); i++) + { + if (keyNames[i] != ':') + { //Ignore colons in string (used by multitap to split controllers) output += IsPressed((uint8_t)keyNumber) ? keyNames[i] : '.'; keyNumber++; - } else { + } + else + { output += ':'; } } @@ -149,7 +170,8 @@ void BaseControlDevice::EnsureCapacity(int32_t minBitCount) uint32_t minByteCount = minBitCount / 8 + 1 + (HasCoordinates() ? 32 : 0); int32_t gap = minByteCount - (int32_t)_state.State.size(); - if(gap > 0) { + if (gap > 0) + { _state.State.insert(_state.State.end(), gap, 0); } } @@ -179,9 +201,12 @@ bool BaseControlDevice::IsPressed(uint8_t bit) void BaseControlDevice::SetBitValue(uint8_t bit, bool set) { - if(set) { + if (set) + { SetBit(bit); - } else { + } + else + { ClearBit(bit); } } @@ -204,23 +229,28 @@ void BaseControlDevice::ClearBit(uint8_t bit) void BaseControlDevice::InvertBit(uint8_t bit) { - if(IsPressed(bit)) { + if (IsPressed(bit)) + { ClearBit(bit); - } else { + } + else + { SetBit(bit); } } void BaseControlDevice::SetPressedState(uint8_t bit, uint32_t keyCode) { - if(KeyManager::IsKeyPressed(keyCode)) { + if (KeyManager::IsKeyPressed(keyCode)) + { SetBit(bit); } } void BaseControlDevice::SetPressedState(uint8_t bit, bool enabled) { - if(enabled) { + if (enabled) + { SetBit(bit); } } @@ -252,17 +282,18 @@ void BaseControlDevice::SetMovement(MouseMovement mov) MouseMovement prev = GetMovement(); mov.dx += prev.dx; mov.dy += prev.dy; - SetCoordinates({ mov.dx, mov.dy }); + SetCoordinates({mov.dx, mov.dy}); } MouseMovement BaseControlDevice::GetMovement() { MousePosition pos = GetCoordinates(); - SetCoordinates({ 0, 0 }); - return { pos.X, pos.Y }; + SetCoordinates({0, 0}); + return {pos.X, pos.Y}; } -void BaseControlDevice::SwapButtons(shared_ptr state1, uint8_t button1, shared_ptr state2, uint8_t button2) +void BaseControlDevice::SwapButtons(shared_ptr state1, uint8_t button1, + shared_ptr state2, uint8_t button2) { bool pressed1 = state1->IsPressed(button1); bool pressed2 = state2->IsPressed(button2); @@ -270,15 +301,17 @@ void BaseControlDevice::SwapButtons(shared_ptr state1, uint8_ state1->ClearBit(button1); state2->ClearBit(button2); - if(pressed1) { + if (pressed1) + { state2->SetBit(button2); } - if(pressed2) { + if (pressed2) + { state1->SetBit(button1); } } -void BaseControlDevice::Serialize(Serializer &s) +void BaseControlDevice::Serialize(Serializer& s) { auto lock = _stateLock.AcquireSafe(); s.Stream(_strobe); diff --git a/Core/BaseControlDevice.h b/Core/BaseControlDevice.h index f73218f..920d464 100644 --- a/Core/BaseControlDevice.h +++ b/Core/BaseControlDevice.h @@ -20,8 +20,10 @@ protected: uint8_t _port; SimpleLock _stateLock; - virtual void RefreshStateBuffer() { } - + virtual void RefreshStateBuffer() + { + } + void EnsureCapacity(int32_t minBitCount); uint32_t GetByteIndex(uint8_t bit); virtual bool HasCoordinates(); @@ -41,9 +43,9 @@ protected: void SetMovement(MouseMovement mov); MouseMovement GetMovement(); - + virtual void InternalSetStateFromInput(); - + public: static constexpr uint8_t ExpDevicePort = 4; static constexpr uint8_t ConsoleInputPort = 5; @@ -58,27 +60,31 @@ public: bool IsPressed(uint8_t bit); MousePosition GetCoordinates(); - + void ClearState(); void SetBit(uint8_t bit); void ClearBit(uint8_t bit); void InvertBit(uint8_t bit); void SetBitValue(uint8_t bit, bool set); - + void SetTextState(string state); string GetTextState(); void SetStateFromInput(); - virtual void OnAfterSetState() { } - + + virtual void OnAfterSetState() + { + } + void SetRawState(ControlDeviceState state); ControlDeviceState GetRawState(); virtual ControllerType GetControllerType() = 0; virtual uint8_t ReadRam(uint16_t addr) = 0; virtual void WriteRam(uint16_t addr, uint8_t value) = 0; - - void static SwapButtons(shared_ptr state1, uint8_t button1, shared_ptr state2, uint8_t button2); - void Serialize(Serializer &s) override; + void static SwapButtons(shared_ptr state1, uint8_t button1, shared_ptr state2, + uint8_t button2); + + void Serialize(Serializer& s) override; }; diff --git a/Core/BaseCoprocessor.h b/Core/BaseCoprocessor.h index dbbd9bb..cb87901 100644 --- a/Core/BaseCoprocessor.h +++ b/Core/BaseCoprocessor.h @@ -10,8 +10,19 @@ public: virtual void Reset() = 0; - virtual void Run() { } - virtual void ProcessEndOfFrame() { } - virtual void LoadBattery() { } - virtual void SaveBattery() { } -}; \ No newline at end of file + virtual void Run() + { + } + + virtual void ProcessEndOfFrame() + { + } + + virtual void LoadBattery() + { + } + + virtual void SaveBattery() + { + } +}; diff --git a/Core/BaseRenderer.cpp b/Core/BaseRenderer.cpp index ceae15b..2c84932 100644 --- a/Core/BaseRenderer.cpp +++ b/Core/BaseRenderer.cpp @@ -9,7 +9,8 @@ BaseRenderer::BaseRenderer(shared_ptr console, bool registerAsMessageMa { _console = console; - if(registerAsMessageManager) { + if (registerAsMessageManager) + { //Only display messages on the master CPU's screen MessageManager::RegisterMessageManager(this); } @@ -37,34 +38,44 @@ void BaseRenderer::DrawToasts() int counter = 0; int lastHeight = 5; - for(shared_ptr toast : _toasts) { - if(counter < 6) { + for (shared_ptr toast : _toasts) + { + if (counter < 6) + { DrawToast(toast, lastHeight); - } else { + } + else + { break; } counter++; } } -std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount) +std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t& lineCount) { using std::wstring; wstring text = utf8::utf8::decode(utf8Text); wstring wrappedText; list words; wstring currentWord; - for(size_t i = 0, len = text.length(); i < len; i++) { - if(text[i] == L' ' || text[i] == L'\n') { - if(currentWord.length() > 0) { + for (size_t i = 0, len = text.length(); i < len; i++) + { + if (text[i] == L' ' || text[i] == L'\n') + { + if (currentWord.length() > 0) + { words.push_back(currentWord); currentWord.clear(); } - } else { + } + else + { currentWord += text[i]; } } - if(currentWord.length() > 0) { + if (currentWord.length() > 0) + { words.push_back(currentWord); } @@ -72,19 +83,25 @@ std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_ float spaceWidth = MeasureString(L" "); float lineWidth = 0.0f; - for(wstring word : words) { - for(unsigned int i = 0; i < word.size(); i++) { - if(!ContainsCharacter(word[i])) { + for (wstring word : words) + { + for (unsigned int i = 0; i < word.size(); i++) + { + if (!ContainsCharacter(word[i])) + { word[i] = L'?'; } } float wordWidth = MeasureString(word.c_str()); - if(lineWidth + wordWidth < maxLineWidth) { + if (lineWidth + wordWidth < maxLineWidth) + { wrappedText += word + L" "; lineWidth += wordWidth + spaceWidth; - } else { + } + else + { wrappedText += L"\n" + word + L" "; lineWidth = wordWidth + spaceWidth; lineCount++; @@ -94,10 +111,10 @@ std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_ return wrappedText; } -void BaseRenderer::DrawToast(shared_ptr toast, int &lastHeight) +void BaseRenderer::DrawToast(shared_ptr toast, int& lastHeight) { //Get opacity for fade in/out effect - uint8_t opacity = (uint8_t)(toast->GetOpacity()*255); + uint8_t opacity = (uint8_t)(toast->GetOpacity() * 255); int textLeftMargin = 4; int lineHeight = 25; @@ -117,24 +134,31 @@ void BaseRenderer::DrawString(std::string message, int x, int y, uint8_t r, uint void BaseRenderer::ShowFpsCounter(int lineNumber) { int yPos = 13 + 24 * lineNumber; - if(_fpsTimer.GetElapsedMS() > 1000) { + if (_fpsTimer.GetElapsedMS() > 1000) + { //Update fps every sec uint32_t frameCount = _console->GetFrameCount(); - if(_lastFrameCount > frameCount) { + if (_lastFrameCount > frameCount) + { _currentFPS = 0; - } else { + } + else + { _currentFPS = (int)(std::round((double)(frameCount - _lastFrameCount) / (_fpsTimer.GetElapsedMS() / 1000))); - _currentRenderedFPS = (int)(std::round((double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000))); + _currentRenderedFPS = (int)(std::round( + (double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000))); } _lastFrameCount = frameCount; _lastRenderedFrameCount = _renderedFrameCount; _fpsTimer.Reset(); } - if(_currentFPS > 5000) { + if (_currentFPS > 5000) + { _currentFPS = 0; } - if(_currentRenderedFPS > 5000) { + if (_currentRenderedFPS > 5000) + { _currentRenderedFPS = 0; } @@ -171,13 +195,16 @@ void BaseRenderer::DrawCounters() { int lineNumber = 0; PreferencesConfig cfg = _console->GetSettings()->GetPreferences(); - if(cfg.ShowGameTimer) { + if (cfg.ShowGameTimer) + { ShowGameTimer(lineNumber++); } - if(cfg.ShowFps) { + if (cfg.ShowFps) + { ShowFpsCounter(lineNumber++); } - if(cfg.ShowFrameCounter) { + if (cfg.ShowFrameCounter) + { ShowFrameCounter(lineNumber++); } } @@ -185,4 +212,4 @@ void BaseRenderer::DrawCounters() bool BaseRenderer::IsMessageShown() { return !_toasts.empty(); -} +} diff --git a/Core/BaseRenderer.h b/Core/BaseRenderer.h index 7ccc297..dbe97e7 100644 --- a/Core/BaseRenderer.h +++ b/Core/BaseRenderer.h @@ -17,7 +17,7 @@ private: uint32_t _currentRenderedFPS = 0; void RemoveOldToasts(); - std::wstring WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount); + std::wstring WrapText(string utf8Text, float maxLineWidth, uint32_t& lineCount); virtual float MeasureString(std::wstring text) = 0; virtual bool ContainsCharacter(wchar_t character) = 0; @@ -26,19 +26,20 @@ protected: uint32_t _screenWidth = 0; uint32_t _screenHeight = 0; - uint32_t _renderedFrameCount = 0; + uint32_t _renderedFrameCount = 0; BaseRenderer(shared_ptr console, bool registerAsMessageManager); virtual ~BaseRenderer(); - bool IsMessageShown(); + bool IsMessageShown(); void DisplayMessage(string title, string message); void DrawToasts(); - - void DrawToast(shared_ptr toast, int &lastHeight); - void DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity = 255); - virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t opacity = 255) = 0; + + void DrawToast(shared_ptr toast, int& lastHeight); + void DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity = 255); + virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, + uint8_t opacity = 255) = 0; void ShowFpsCounter(int lineNumber); void ShowLagCounter(int lineNumber); diff --git a/Core/BaseSoundManager.cpp b/Core/BaseSoundManager.cpp index dc95920..18ca558 100644 --- a/Core/BaseSoundManager.cpp +++ b/Core/BaseSoundManager.cpp @@ -5,25 +5,31 @@ void BaseSoundManager::ProcessLatency(uint32_t readPosition, uint32_t writePosit { //Record latency between read & write cursors once per frame int32_t cursorGap; - if(writePosition < readPosition) { + if (writePosition < readPosition) + { cursorGap = writePosition - readPosition + _bufferSize; - } else { + } + else + { cursorGap = writePosition - readPosition; } _cursorGaps[_cursorGapIndex] = cursorGap; _cursorGapIndex = (_cursorGapIndex + 1) % 60; - if(_cursorGapIndex == 0) { + if (_cursorGapIndex == 0) + { _cursorGapFilled = true; } - if(_cursorGapFilled) { + if (_cursorGapFilled) + { //Once we have 60+ frames worth of data to work with, adjust playback frequency by +/- 0.5% //To speed up or slow down playback in order to reach our latency goal. uint32_t bytesPerSample = _isStereo ? 4 : 2; int32_t gapSum = 0; - for(int i = 0; i < 60; i++) { + for (int i = 0; i < 60; i++) + { gapSum += _cursorGaps[i]; } int32_t gapAverage = gapSum / 60; diff --git a/Core/BaseVideoFilter.cpp b/Core/BaseVideoFilter.cpp index 9318ced..c6a3916 100644 --- a/Core/BaseVideoFilter.cpp +++ b/Core/BaseVideoFilter.cpp @@ -36,8 +36,9 @@ FrameInfo BaseVideoFilter::GetFrameInfo() void BaseVideoFilter::UpdateBufferSize() { - uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height; - if(_bufferSize != newBufferSize) { + uint32_t newBufferSize = GetFrameInfo().Width * GetFrameInfo().Height; + if (_bufferSize != newBufferSize) + { _frameLock.Acquire(); delete[] _outputBuffer; _bufferSize = newBufferSize; @@ -65,7 +66,7 @@ uint32_t BaseVideoFilter::GetBufferSize() return _bufferSize * sizeof(uint32_t); } -void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber) +void BaseVideoFilter::SendFrame(uint16_t* ppuOutputBuffer, uint32_t frameNumber) { _frameLock.Acquire(); _overscan = _console->GetSettings()->GetOverscan(); @@ -91,14 +92,15 @@ uint32_t BaseVideoFilter::ApplyScanlineEffect(uint32_t argb, uint8_t scanlineInt return 0xFF000000 | (r << 16) | (g << 8) | b; } -void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream) +void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream* stream) { uint32_t* pngBuffer; FrameInfo frameInfo; uint32_t* frameBuffer = nullptr; { auto lock = _frameLock.AcquireSafe(); - if(_bufferSize == 0 || !GetOutputBuffer()) { + if (_bufferSize == 0 || !GetOutputBuffer()) + { return; } @@ -110,14 +112,19 @@ void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename pngBuffer = frameBuffer; shared_ptr scaleFilter = ScaleFilter::GetScaleFilter(filterType); - if(scaleFilter) { - pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetVideoConfig().ScanlineIntensity); + if (scaleFilter) + { + pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height, + _console->GetSettings()->GetVideoConfig().ScanlineIntensity); frameInfo = scaleFilter->GetFrameInfo(frameInfo); } - - if(!filename.empty()) { + + if (!filename.empty()) + { PNGHelper::WritePNG(filename, pngBuffer, frameInfo.Width, frameInfo.Height); - } else { + } + else + { PNGHelper::WritePNG(*stream, pngBuffer, frameInfo.Width, frameInfo.Height); } @@ -131,16 +138,21 @@ void BaseVideoFilter::TakeScreenshot(string romName, VideoFilterType filterType) int counter = 0; string baseFilename = FolderUtilities::CombinePath(FolderUtilities::GetScreenshotFolder(), romFilename); string ssFilename; - while(true) { + while (true) + { string counterStr = std::to_string(counter); - while(counterStr.length() < 3) { + while (counterStr.length() < 3) + { counterStr = "0" + counterStr; } ssFilename = baseFilename + "_" + counterStr + ".png"; ifstream file(ssFilename, ios::in); - if(file) { + if (file) + { file.close(); - } else { + } + else + { break; } counter++; @@ -150,4 +162,3 @@ void BaseVideoFilter::TakeScreenshot(string romName, VideoFilterType filterType) MessageManager::DisplayMessage("ScreenshotSaved", FolderUtilities::GetFilename(ssFilename, true)); } - diff --git a/Core/BaseVideoFilter.h b/Core/BaseVideoFilter.h index ccfdde3..c557bac 100644 --- a/Core/BaseVideoFilter.h +++ b/Core/BaseVideoFilter.h @@ -20,7 +20,7 @@ protected: shared_ptr _console; FrameInfo _baseFrameInfo; - virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0; + virtual void ApplyFilter(uint16_t* ppuOutputBuffer) = 0; virtual void OnBeforeApplyFilter(); bool IsOddFrame(); uint32_t GetBufferSize(); @@ -31,12 +31,12 @@ public: virtual ~BaseVideoFilter(); uint32_t* GetOutputBuffer(); - void SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber); + void SendFrame(uint16_t* ppuOutputBuffer, uint32_t frameNumber); void TakeScreenshot(string romName, VideoFilterType filterType); - void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr); + void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream* stream = nullptr); virtual OverscanDimensions GetOverscan(); - + void SetBaseFrameInfo(FrameInfo frameInfo); virtual FrameInfo GetFrameInfo(); -}; \ No newline at end of file +}; diff --git a/Core/BatteryManager.cpp b/Core/BatteryManager.cpp index 2d5926f..a969164 100644 --- a/Core/BatteryManager.cpp +++ b/Core/BatteryManager.cpp @@ -31,7 +31,8 @@ void BatteryManager::SetBatteryRecorder(shared_ptr recorder) void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t length) { - if (_saveEnabled) { + if (_saveEnabled) + { #ifdef LIBRETRO if (extension == ".srm") { //Disable .srm files for libretro, let the frontend handle save ram @@ -40,7 +41,8 @@ void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t lengt #endif ofstream out(GetBasePath() + extension, ios::binary); - if (out) { + if (out) + { out.write((char*)data, length); } } @@ -49,21 +51,27 @@ void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t lengt vector BatteryManager::LoadBattery(string extension) { shared_ptr provider = _provider.lock(); - + vector batteryData; - if(provider) { + if (provider) + { //Used by movie player to provider initial state of ram at startup batteryData = provider->LoadBattery(extension); - } else { + } + else + { VirtualFile file = GetBasePath() + extension; - if(file.IsValid()) { + if (file.IsValid()) + { file.ReadFile(batteryData); } } - if(!batteryData.empty()) { + if (!batteryData.empty()) + { shared_ptr recorder = _recorder.lock(); - if(recorder) { + if (recorder) + { //Used by movies to record initial state of battery-backed ram at power on recorder->OnLoadBattery(extension, batteryData); } @@ -76,4 +84,4 @@ void BatteryManager::LoadBattery(string extension, uint8_t* data, uint32_t lengt { vector batteryData = LoadBattery(extension); memcpy(data, batteryData.data(), std::min((uint32_t)batteryData.size(), length)); -} \ No newline at end of file +} diff --git a/Core/BatteryManager.h b/Core/BatteryManager.h index 5dc8e2a..a2e3b1c 100644 --- a/Core/BatteryManager.h +++ b/Core/BatteryManager.h @@ -30,9 +30,9 @@ public: void SetBatteryProvider(shared_ptr provider); void SetBatteryRecorder(shared_ptr recorder); - + void SaveBattery(string extension, uint8_t* data, uint32_t length); - + vector LoadBattery(string extension); void LoadBattery(string extension, uint8_t* data, uint32_t length); -}; \ No newline at end of file +}; diff --git a/Core/Breakpoint.cpp b/Core/Breakpoint.cpp index c2ffedf..c4637ce 100644 --- a/Core/Breakpoint.cpp +++ b/Core/Breakpoint.cpp @@ -3,22 +3,35 @@ #include "DebugTypes.h" #include "DebugUtilities.h" -bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info) +bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo& info) { - if(memoryType <= DebugUtilities::GetLastCpuMemoryType() && !DebugUtilities::IsPpuMemory(info.Type)) { - if(startAddr == -1) { + if (memoryType <= DebugUtilities::GetLastCpuMemoryType() && !DebugUtilities::IsPpuMemory(info.Type)) + { + if (startAddr == -1) + { return true; - } else if(endAddr == -1) { + } + else if (endAddr == -1) + { return (int32_t)memoryAddr == startAddr; - } else { + } + else + { return (int32_t)memoryAddr >= startAddr && (int32_t)memoryAddr <= endAddr; } - } else if(memoryType == info.Type) { - if(startAddr == -1) { + } + else if (memoryType == info.Type) + { + if (startAddr == -1) + { return true; - } else if(endAddr == -1) { + } + else if (endAddr == -1) + { return info.Address == startAddr; - } else { + } + else + { return info.Address >= startAddr && info.Address <= endAddr; } } @@ -28,11 +41,12 @@ bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info) bool Breakpoint::HasBreakpointType(BreakpointType bpType) { - switch(bpType) { - default: - case BreakpointType::Execute: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Execute) != 0; - case BreakpointType::Read: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Read) != 0; - case BreakpointType::Write: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Write) != 0; + switch (bpType) + { + default: + case BreakpointType::Execute: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Execute) != 0; + case BreakpointType::Read: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Read) != 0; + case BreakpointType::Write: return ((uint8_t)type & (uint8_t)BreakpointTypeFlags::Write) != 0; } } diff --git a/Core/Breakpoint.h b/Core/Breakpoint.h index dc34199..ba8fe30 100644 --- a/Core/Breakpoint.h +++ b/Core/Breakpoint.h @@ -1,7 +1,7 @@ #pragma once #include "stdafx.h" -enum class CpuType : uint8_t; +enum class CpuType : uint8_t; enum class SnesMemoryType; struct AddressInfo; enum class BreakpointType; @@ -11,7 +11,7 @@ enum class BreakpointCategory; class Breakpoint { public: - bool Matches(uint32_t memoryAddr, AddressInfo &info); + bool Matches(uint32_t memoryAddr, AddressInfo& info); bool HasBreakpointType(BreakpointType bpType); string GetCondition(); bool HasCondition(); @@ -28,4 +28,4 @@ public: bool enabled; bool markEvent; char condition[1000]; -}; \ No newline at end of file +}; diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index 53f0c27..b507d59 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -7,7 +7,7 @@ #include "ExpressionEvaluator.h" #include "EventManager.h" -BreakpointManager::BreakpointManager(Debugger *debugger, CpuType cpuType, IEventManager* eventManager) +BreakpointManager::BreakpointManager(Debugger* debugger, CpuType cpuType, IEventManager* eventManager) { _debugger = debugger; _cpuType = cpuType; @@ -18,7 +18,8 @@ BreakpointManager::BreakpointManager(Debugger *debugger, CpuType cpuType, IEvent void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) { _hasBreakpoint = false; - for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) { + for (int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) + { _breakpoints[i].clear(); _rpnList[i].clear(); _hasBreakpointType[i] = false; @@ -26,27 +27,34 @@ void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) _bpExpEval.reset(new ExpressionEvaluator(_debugger, _cpuType)); - for(uint32_t j = 0; j < count; j++) { - Breakpoint &bp = breakpoints[j]; - for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) { + for (uint32_t j = 0; j < count; j++) + { + Breakpoint& bp = breakpoints[j]; + for (int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) + { BreakpointType bpType = (BreakpointType)i; - if((bp.IsMarked() || bp.IsEnabled()) && bp.HasBreakpointType(bpType)) { + if ((bp.IsMarked() || bp.IsEnabled()) && bp.HasBreakpointType(bpType)) + { CpuType cpuType = bp.GetCpuType(); - if(_cpuType != cpuType) { + if (_cpuType != cpuType) + { continue; } int curIndex = _breakpoints[i].size(); _breakpoints[i].insert(std::make_pair(curIndex, bp)); - if(bp.HasCondition()) { + if (bp.HasCondition()) + { bool success = true; ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success); _rpnList[i].insert(std::make_pair(curIndex, success ? data : ExpressionData())); - } else { + } + else + { _rpnList[i].insert(std::make_pair(curIndex, ExpressionData())); } - + _hasBreakpoint = true; _hasBreakpointType[i] = true; } @@ -60,61 +68,76 @@ void BreakpointManager::GetBreakpoints(Breakpoint* breakpoints, int& execs, int& reads = _breakpoints[static_cast(BreakpointType::Read)].size(); writes = _breakpoints[static_cast(BreakpointType::Write)].size(); - if (breakpoints == NULL) { + if (breakpoints == NULL) + { return; } int offset = 0; - for (auto it = _breakpoints[static_cast(BreakpointType::Execute)].cbegin(); it != _breakpoints[static_cast(BreakpointType::Execute)].cend(); it++) { + for (auto it = _breakpoints[static_cast(BreakpointType::Execute)].cbegin(); it != _breakpoints[static_cast( + BreakpointType::Execute)].cend(); it++) + { breakpoints[offset++] = it->second; } - for (auto it = _breakpoints[static_cast(BreakpointType::Read)].cbegin(); it != _breakpoints[static_cast(BreakpointType::Read)].cend(); it++) { + for (auto it = _breakpoints[static_cast(BreakpointType::Read)].cbegin(); it != _breakpoints[static_cast( + BreakpointType::Read)].cend(); it++) + { breakpoints[offset++] = it->second; } - for (auto it = _breakpoints[static_cast(BreakpointType::Write)].cbegin(); it != _breakpoints[static_cast(BreakpointType::Write)].cend(); it++) { + for (auto it = _breakpoints[static_cast(BreakpointType::Write)].cbegin(); it != _breakpoints[static_cast( + BreakpointType::Write)].cend(); it++) + { breakpoints[offset++] = it->second; } } BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type) { - switch(type) { - default: - case MemoryOperationType::ExecOperand: - case MemoryOperationType::ExecOpCode: - return BreakpointType::Execute; + switch (type) + { + default: + case MemoryOperationType::ExecOperand: + case MemoryOperationType::ExecOpCode: + return BreakpointType::Execute; - case MemoryOperationType::DmaRead: - case MemoryOperationType::Read: - return BreakpointType::Read; + case MemoryOperationType::DmaRead: + case MemoryOperationType::Read: + return BreakpointType::Read; - case MemoryOperationType::DmaWrite: - case MemoryOperationType::Write: - return BreakpointType::Write; + case MemoryOperationType::DmaWrite: + case MemoryOperationType::Write: + return BreakpointType::Write; } } -int BreakpointManager::InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address) +int BreakpointManager::InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address) { BreakpointType type = GetBreakpointType(operationInfo.Type); - if(!_hasBreakpointType[(int)type]) { + if (!_hasBreakpointType[(int)type]) + { return -1; } DebugState state; _debugger->GetState(state, false); EvalResultType resultType; - unordered_map &breakpoints = _breakpoints[(int)type]; - for (auto it = breakpoints.begin(); it != breakpoints.end(); it++) { - if (it->second.Matches(operationInfo.Address, address)) { - if (!it->second.HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)type][it->first], state, resultType, operationInfo)) { - if (it->second.IsMarked()) { + unordered_map& breakpoints = _breakpoints[(int)type]; + for (auto it = breakpoints.begin(); it != breakpoints.end(); it++) + { + if (it->second.Matches(operationInfo.Address, address)) + { + if (!it->second.HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)type][it->first], state, resultType, + operationInfo)) + { + if (it->second.IsMarked()) + { _eventManager->AddEvent(DebugEventType::Breakpoint, operationInfo, it->first); } - if (it->second.IsEnabled()) { + if (it->second.IsEnabled()) + { return it->first; } } diff --git a/Core/BreakpointManager.h b/Core/BreakpointManager.h index f4a5ed8..1fb34c5 100644 --- a/Core/BreakpointManager.h +++ b/Core/BreakpointManager.h @@ -15,10 +15,10 @@ class BreakpointManager private: static constexpr int BreakpointTypeCount = 3; //Read, Write, Exec - Debugger *_debugger; + Debugger* _debugger; CpuType _cpuType; - IEventManager *_eventManager; - + IEventManager* _eventManager; + unordered_map _breakpoints[BreakpointTypeCount]; unordered_map _rpnList[BreakpointTypeCount]; bool _hasBreakpoint; @@ -27,20 +27,21 @@ private: unique_ptr _bpExpEval; BreakpointType GetBreakpointType(MemoryOperationType type); - int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); + int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address); public: - BreakpointManager(Debugger *debugger, CpuType cpuType, IEventManager* eventManager = nullptr); + BreakpointManager(Debugger* debugger, CpuType cpuType, IEventManager* eventManager = nullptr); void SetBreakpoints(Breakpoint breakpoints[], uint32_t count); void GetBreakpoints(Breakpoint* breakpoints, int& execs, int& reads, int& writes); - __forceinline int CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); + __forceinline int CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address); }; -__forceinline int BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address) +__forceinline int BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo& address) { - if(!_hasBreakpoint) { + if (!_hasBreakpoint) + { return -1; } return InternalCheckBreakpoint(operationInfo, address); -} \ No newline at end of file +} diff --git a/Core/BsxCart.cpp b/Core/BsxCart.cpp index 18d736c..a5ed890 100644 --- a/Core/BsxCart.cpp +++ b/Core/BsxCart.cpp @@ -28,13 +28,15 @@ BsxCart::BsxCart(Console* console, BsxMemoryPack* memPack) : BaseCoprocessor(Sne _psRam = new uint8_t[_psRamSize]; console->GetSettings()->InitializeRam(_psRam, _psRamSize); - for(uint32_t i = 0; i < _psRamSize / 0x1000; i++) { - _psRamHandlers.push_back(unique_ptr(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam))); + for (uint32_t i = 0; i < _psRamSize / 0x1000; i++) + { + _psRamHandlers.push_back( + unique_ptr(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam))); } Reset(); } - + BsxCart::~BsxCart() { delete[] _psRam; @@ -43,14 +45,20 @@ BsxCart::~BsxCart() uint8_t BsxCart::Read(uint32_t addr) { uint8_t openBus = _memoryManager->GetOpenBus(); - if((addr & 0xFFFF) != 0x5000) { + if ((addr & 0xFFFF) != 0x5000) + { return openBus; - } else { + } + else + { uint8_t reg = (addr >> 16) & 0x0F; - - if(reg <= 0x0D) { + + if (reg <= 0x0D) + { return (_regs[reg] << 7) | (openBus & 0x7F); - } else { + } + else + { //E & F are write-only return openBus & 0x7F; } @@ -59,20 +67,26 @@ uint8_t BsxCart::Read(uint32_t addr) void BsxCart::Write(uint32_t addr, uint8_t value) { - if((addr & 0xFFFF) != 0x5000) { + if ((addr & 0xFFFF) != 0x5000) + { return; } uint8_t reg = (addr >> 16) & 0x0F; - if(reg == 0x0E) { - if(_dirty) { + if (reg == 0x0E) + { + if (_dirty) + { memcpy(_regs, _dirtyRegs, sizeof(_regs)); UpdateMemoryMappings(); _dirty = false; } - } else { + } + else + { uint8_t regValue = (value >> 7); - if(_regs[reg] != regValue) { + if (_regs[reg] != regValue) + { _dirtyRegs[reg] = regValue; _dirty = true; } @@ -88,7 +102,8 @@ void BsxCart::UpdateMemoryMappings() uint8_t unmappedBank = (_regs[0x0B] << 5); uint8_t psRamBank = (_regs[0x05] << 4) | (_regs[0x06] << 5); - if(!_regs[0x02]) { + if (!_regs[0x02]) + { //LoROM //Memory pack mapping @@ -99,28 +114,34 @@ void BsxCart::UpdateMemoryMappings() //Memory hole mapping uint16_t unmappedAddr = _regs[0x0B] ? 0x0000 : 0x8000; - if(_regs[0x09]) { + if (_regs[0x09]) + { mm->RegisterHandler(0x00 | (unmappedBank << 1), 0x1F | (unmappedBank << 1), unmappedAddr, 0xFFFF, nullptr); } - if(_regs[0x0A]) { + if (_regs[0x0A]) + { mm->RegisterHandler(0x80 | (unmappedBank << 1), 0x9F | (unmappedBank << 1), unmappedAddr, 0xFFFF, nullptr); } //PSRAM mapping uint16_t psRamAddr = (psRamBank & 0x20) ? 0x0000 : 0x8000; - if(_regs[0x03]) { + if (_regs[0x03]) + { mm->RegisterHandler(0x00 | (psRamBank << 1), 0x0F | (psRamBank << 1), psRamAddr, 0xFFFF, _psRamHandlers); mm->RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _psRamHandlers); } - if(_regs[0x04]) { + if (_regs[0x04]) + { mm->RegisterHandler(0x80 | (psRamBank << 1), 0x8F | (psRamBank << 1), psRamAddr, 0xFFFF, _psRamHandlers); mm->RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _psRamHandlers); } - } else { + } + else + { //HiROM - + //Memory pack mapping mm->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, memPackHandlers, 8); mm->RegisterHandler(0x40, 0x7D, 0x0000, 0xFFFF, memPackHandlers, 0); @@ -128,25 +149,29 @@ void BsxCart::UpdateMemoryMappings() mm->RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, memPackHandlers, 0); //Memory hole mapping - if(_regs[0x09]) { + if (_regs[0x09]) + { mm->RegisterHandler(0x00 | unmappedBank, 0x0F | unmappedBank, 0x8000, 0xFFFF, nullptr); mm->RegisterHandler(0x40 | unmappedBank, 0x4F | unmappedBank, 0x0000, 0xFFFF, nullptr); } - if(_regs[0x0A]) { + if (_regs[0x0A]) + { mm->RegisterHandler(0x80 | unmappedBank, 0x8F | unmappedBank, 0x8000, 0xFFFF, nullptr); mm->RegisterHandler(0xC0 | unmappedBank, 0xCF | unmappedBank, 0x0000, 0xFFFF, nullptr); } //PSRAM mapping - if(_regs[0x03]) { + if (_regs[0x03]) + { //Lower Banks (0x00-0x7D) mm->RegisterHandler(0x00 | psRamBank, 0x07 | psRamBank, 0x8000, 0xFFFF, _psRamHandlers, 8); mm->RegisterHandler(0x40 | psRamBank, 0x47 | psRamBank, 0x0000, 0xFFFF, _psRamHandlers); mm->RegisterHandler(0x20, 0x3F, 0x6000, 0x7FFF, _psRamHandlers, 6); } - if(_regs[0x04]) { + if (_regs[0x04]) + { //Higher Banks (0x80-0xFF) mm->RegisterHandler(0x80 | psRamBank, 0x87 | psRamBank, 0x8000, 0xFFFF, _psRamHandlers, 8); mm->RegisterHandler(0xC0 | psRamBank, 0xC7 | psRamBank, 0x0000, 0xFFFF, _psRamHandlers); @@ -155,17 +180,20 @@ void BsxCart::UpdateMemoryMappings() } //BS-X BIOS mapping (can override other mappings above) - if(_regs[0x07]) { + if (_regs[0x07]) + { mm->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, prgHandlers); } - if(_regs[0x08]) { + if (_regs[0x08]) + { mm->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, prgHandlers); } } void BsxCart::Reset() { - for(int i = 0; i < 0x10; i++) { + for (int i = 0; i < 0x10; i++) + { _regs[i] = true; } @@ -184,13 +212,14 @@ void BsxCart::Reset() void BsxCart::Serialize(Serializer& s) { - ArrayInfo psRam = { _psRam, _psRamSize }; - ArrayInfo regs = { _regs, 0x10 }; - ArrayInfo dirtyRegs = { _dirtyRegs, 0x10 }; + ArrayInfo psRam = {_psRam, _psRamSize}; + ArrayInfo regs = {_regs, 0x10}; + ArrayInfo dirtyRegs = {_dirtyRegs, 0x10}; s.Stream(psRam, regs, dirtyRegs, _dirty); s.Stream(_satellaview.get()); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { UpdateMemoryMappings(); } } @@ -207,7 +236,7 @@ void BsxCart::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo BsxCart::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } uint8_t* BsxCart::DebugGetPsRam() diff --git a/Core/BsxCart.h b/Core/BsxCart.h index c724073..63532f8 100644 --- a/Core/BsxCart.h +++ b/Core/BsxCart.h @@ -22,7 +22,7 @@ private: uint8_t _regs[0x10] = {}; uint8_t _dirtyRegs[0x10] = {}; bool _dirty = false; - + void UpdateMemoryMappings(); public: @@ -41,4 +41,4 @@ public: uint8_t* DebugGetPsRam(); uint32_t DebugGetPsRamSize(); -}; \ No newline at end of file +}; diff --git a/Core/BsxMemoryPack.cpp b/Core/BsxMemoryPack.cpp index 30e219f..861a35f 100644 --- a/Core/BsxMemoryPack.cpp +++ b/Core/BsxMemoryPack.cpp @@ -15,7 +15,8 @@ BsxMemoryPack::BsxMemoryPack(Console* console, vector& data, bool persi _calculatedSize = std::min(0x0C, (uint8_t)log2(_dataSize >> 10)); - for(uint32_t i = 0; i < _dataSize / 0x1000; i++) { + for (uint32_t i = 0; i < _dataSize / 0x1000; i++) + { _handlers.push_back(unique_ptr(new BsxMemoryPackHandler(this, i * 0x1000))); } } @@ -27,7 +28,8 @@ BsxMemoryPack::~BsxMemoryPack() void BsxMemoryPack::SaveBattery() { - if(_persistFlash) { + if (_persistFlash) + { _console->GetBatteryManager()->SaveBattery(".bs", _data, _dataSize); } } @@ -35,20 +37,24 @@ void BsxMemoryPack::SaveBattery() void BsxMemoryPack::Serialize(Serializer& s) { s.Stream(_enableCsr, _enableEsr, _enableVendorInfo, _writeByte, _command); - - if(s.IsSaving()) { + + if (s.IsSaving()) + { //Save content of memory pack as an IPS patch vector newData(_data, _data + _dataSize); vector ipsData = IpsPatcher::CreatePatch(_orgData, newData); - VectorInfo data { &ipsData }; + VectorInfo data{&ipsData}; s.Stream(data); - } else { + } + else + { //Apply IPS patch to original data and overwrite the current data vector ipsData; - VectorInfo data { &ipsData }; + VectorInfo data{&ipsData}; s.Stream(data); - if(ipsData.size() > 8) { + if (ipsData.size() > 8) + { vector output; IpsPatcher::PatchBuffer(ipsData, _orgData, output); memcpy(_data, output.data(), _dataSize); @@ -60,27 +66,34 @@ void BsxMemoryPack::ProcessCommand(uint8_t value, uint32_t page) { _command = (_command << 8) | value; - switch(value) { - case 0x00: - case 0xFF: - _enableCsr = false; - _enableEsr = false; - _enableVendorInfo = false; - break; + switch (value) + { + case 0x00: + case 0xFF: + _enableCsr = false; + _enableEsr = false; + _enableVendorInfo = false; + break; - case 0x10: - case 0x40: - _writeByte = true; - break; + case 0x10: + case 0x40: + _writeByte = true; + break; - case 0x70: _enableCsr = true; break; - case 0x71: _enableEsr = true; break; - case 0x75: _enableVendorInfo = true; break; + case 0x70: _enableCsr = true; + break; + case 0x71: _enableEsr = true; + break; + case 0x75: _enableVendorInfo = true; + break; } - switch(_command) { - case 0x20D0: memset(_data + page * 0x10000, 0xFF, 0x10000); break; //Page erase - case 0xA7D0: memset(_data, 0xFF, _dataSize); break; //Chip erase + switch (_command) + { + case 0x20D0: memset(_data + page * 0x10000, 0xFF, 0x10000); + break; //Page erase + case 0xA7D0: memset(_data, 0xFF, _dataSize); + break; //Chip erase } } @@ -108,7 +121,8 @@ uint32_t BsxMemoryPack::DebugGetMemoryPackSize() return _dataSize; } -BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack, uint32_t offset) : RamHandler(memPack->_data, offset, memPack->_dataSize, SnesMemoryType::BsxMemoryPack) +BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack, uint32_t offset) : RamHandler( + memPack->_data, offset, memPack->_dataSize, SnesMemoryType::BsxMemoryPack) { _memPack = memPack; _page = offset / 0x10000; @@ -116,30 +130,35 @@ BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr) { - if(_offset == 0 && _memPack->_enableEsr) { - switch(addr & 0xFFF) { - case 0x0002: return 0xC0; - case 0x0004: return 0x82; + if (_offset == 0 && _memPack->_enableEsr) + { + switch (addr & 0xFFF) + { + case 0x0002: return 0xC0; + case 0x0004: return 0x82; } } - if(_memPack->_enableCsr) { + if (_memPack->_enableCsr) + { _memPack->_enableCsr = false; return 0x80; } - if(_memPack->_enableVendorInfo && ((addr & 0x7FFF) >= 0x7F00) && ((addr & 0x7FFF) <= 0x7F13)) { + if (_memPack->_enableVendorInfo && ((addr & 0x7FFF) >= 0x7F00) && ((addr & 0x7FFF) <= 0x7F13)) + { //Flash cartridge vendor information - switch(addr & 0xFF) { - case 0x00: return 0x4d; - case 0x01: return 0x00; - case 0x02: return 0x50; - case 0x03: return 0x00; - case 0x04: return 0x00; - case 0x05: return 0x00; - case 0x06: return 0x10 | _memPack->_calculatedSize; //Memory Pack Type 1 - case 0x07: return 0x00; - default: return 0x00; + switch (addr & 0xFF) + { + case 0x00: return 0x4d; + case 0x01: return 0x00; + case 0x02: return 0x50; + case 0x03: return 0x00; + case 0x04: return 0x00; + case 0x05: return 0x00; + case 0x06: return 0x10 | _memPack->_calculatedSize; //Memory Pack Type 1 + case 0x07: return 0x00; + default: return 0x00; } } @@ -148,11 +167,14 @@ uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr) void BsxMemoryPack::BsxMemoryPackHandler::Write(uint32_t addr, uint8_t value) { - if(_memPack->_writeByte) { + if (_memPack->_writeByte) + { uint8_t currentByte = RamHandler::Read(addr); RamHandler::Write(addr, value & currentByte); _memPack->_writeByte = false; - } else if(_offset == 0 && (addr & 0xFFF) == 0) { + } + else if (_offset == 0 && (addr & 0xFFF) == 0) + { _memPack->ProcessCommand(value, _page); } } diff --git a/Core/BsxMemoryPack.h b/Core/BsxMemoryPack.h index f49ccfc..67292f6 100644 --- a/Core/BsxMemoryPack.h +++ b/Core/BsxMemoryPack.h @@ -35,11 +35,11 @@ public: void ProcessCommand(uint8_t value, uint32_t page); void Reset(); - + vector>& GetMemoryHandlers(); uint8_t* DebugGetMemoryPack(); uint32_t DebugGetMemoryPackSize(); - + class BsxMemoryPackHandler : public RamHandler { BsxMemoryPack* _memPack; diff --git a/Core/BsxSatellaview.cpp b/Core/BsxSatellaview.cpp index c6e5cd7..40d6b73 100644 --- a/Core/BsxSatellaview.cpp +++ b/Core/BsxSatellaview.cpp @@ -21,9 +21,12 @@ void BsxSatellaview::Reset() _extOutput = 0xFF; time_t resetDate; - if(_customDate >= 0) { + if (_customDate >= 0) + { resetDate = (time_t)_customDate; - } else { + } + else + { //Use the current date/time as the BS-X date/time time(&resetDate); } @@ -35,35 +38,37 @@ void BsxSatellaview::Reset() uint8_t BsxSatellaview::Read(uint32_t addr) { addr &= 0xFFFF; - if(addr >= 0x2188 && addr <= 0x219F) { + if (addr >= 0x2188 && addr <= 0x219F) + { //Handle BS-X $2188-219F registers ProcessClocks(); - switch(addr) { - case 0x2188: return _stream[0].GetChannel() & 0xFF; - case 0x2189: return (_stream[0].GetChannel()) >> 8; - case 0x218A: return _stream[0].GetPrefixCount(); - case 0x218B: return _stream[0].GetPrefix(); - case 0x218C: return _stream[0].GetData(); - case 0x218D: return _stream[0].GetStatus((_streamReg & 0x01) != 0); - - case 0x218E: return _stream[1].GetChannel() & 0xFF; - case 0x218F: return (_stream[1].GetChannel()) >> 8; - case 0x2190: return _stream[1].GetPrefixCount(); - case 0x2191: return _stream[1].GetPrefix(); - case 0x2192: return _stream[1].GetData(); - case 0x2193: return _stream[1].GetStatus((_streamReg & 0x01) != 0); + switch (addr) + { + case 0x2188: return _stream[0].GetChannel() & 0xFF; + case 0x2189: return (_stream[0].GetChannel()) >> 8; + case 0x218A: return _stream[0].GetPrefixCount(); + case 0x218B: return _stream[0].GetPrefix(); + case 0x218C: return _stream[0].GetData(); + case 0x218D: return _stream[0].GetStatus((_streamReg & 0x01) != 0); - case 0x2194: return _streamReg; //LED and Stream register - case 0x2195: return 0; //Unknown - case 0x2196: return 0x10; //Satellaview status - case 0x2197: return _extOutput; //Soundlink / EXT output - case 0x2198: return 0x80; //Serial IO (Serial number) - case 0x2199: return 0x01; //Serial IO (???) - case 0x219A: return 0x10; //Unknown + case 0x218E: return _stream[1].GetChannel() & 0xFF; + case 0x218F: return (_stream[1].GetChannel()) >> 8; + case 0x2190: return _stream[1].GetPrefixCount(); + case 0x2191: return _stream[1].GetPrefix(); + case 0x2192: return _stream[1].GetData(); + case 0x2193: return _stream[1].GetStatus((_streamReg & 0x01) != 0); + + case 0x2194: return _streamReg; //LED and Stream register + case 0x2195: return 0; //Unknown + case 0x2196: return 0x10; //Satellaview status + case 0x2197: return _extOutput; //Soundlink / EXT output + case 0x2198: return 0x80; //Serial IO (Serial number) + case 0x2199: return 0x01; //Serial IO (???) + case 0x219A: return 0x10; //Unknown } - } - + } + //Use regular B-bus handler for everything else return _bBusHandler->Read(addr); } @@ -71,25 +76,39 @@ uint8_t BsxSatellaview::Read(uint32_t addr) void BsxSatellaview::Write(uint32_t addr, uint8_t value) { addr &= 0xFFFF; - if(addr >= 0x2188 && addr <= 0x219F) { + if (addr >= 0x2188 && addr <= 0x219F) + { //Handle BS-X register writes ProcessClocks(); - switch(addr) { - case 0x2188: _stream[0].SetChannelLow(value); break; - case 0x2189: _stream[0].SetChannelHigh(value); break; - case 0x218B: _stream[0].SetPrefixLatch(value); break; - case 0x218C: _stream[0].SetDataLatch(value); break; + switch (addr) + { + case 0x2188: _stream[0].SetChannelLow(value); + break; + case 0x2189: _stream[0].SetChannelHigh(value); + break; + case 0x218B: _stream[0].SetPrefixLatch(value); + break; + case 0x218C: _stream[0].SetDataLatch(value); + break; - case 0x218E: _stream[1].SetChannelLow(value); break; - case 0x218F: _stream[1].SetChannelHigh(value); break; - case 0x2191: _stream[1].SetPrefixLatch(value); break; - case 0x2192: _stream[1].SetDataLatch(value); break; + case 0x218E: _stream[1].SetChannelLow(value); + break; + case 0x218F: _stream[1].SetChannelHigh(value); + break; + case 0x2191: _stream[1].SetPrefixLatch(value); + break; + case 0x2192: _stream[1].SetDataLatch(value); + break; - case 0x2194: _streamReg = value; break; - case 0x2197: _extOutput = value; break; + case 0x2194: _streamReg = value; + break; + case 0x2197: _extOutput = value; + break; } - } else { + } + else + { //Regular B-bus handler _bBusHandler->Write(addr, value); } @@ -97,13 +116,16 @@ void BsxSatellaview::Write(uint32_t addr, uint8_t value) void BsxSatellaview::ProcessClocks() { - if(_stream[0].NeedUpdate() || _stream[1].NeedUpdate()) { + if (_stream[0].NeedUpdate() || _stream[1].NeedUpdate()) + { uint64_t gap = _memoryManager->GetMasterClock() - _prevMasterClock; uint64_t clocksPerFrame = _console->GetMasterClockRate() / 1000; //1000 frames/sec (224kbits/sec) - while(gap >= clocksPerFrame) { + while (gap >= clocksPerFrame) + { bool needUpdate = _stream[0].FillQueues() || _stream[1].FillQueues(); - if(!needUpdate) { + if (!needUpdate) + { gap = 0; break; } @@ -111,7 +133,9 @@ void BsxSatellaview::ProcessClocks() } _prevMasterClock = _memoryManager->GetMasterClock() - gap; - } else { + } + else + { _prevMasterClock = _memoryManager->GetMasterClock(); } } @@ -128,7 +152,7 @@ void BsxSatellaview::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo BsxSatellaview::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void BsxSatellaview::Serialize(Serializer& s) diff --git a/Core/BsxSatellaview.h b/Core/BsxSatellaview.h index 79548b2..72a5b9c 100644 --- a/Core/BsxSatellaview.h +++ b/Core/BsxSatellaview.h @@ -24,7 +24,7 @@ private: void ProcessClocks(); public: - BsxSatellaview(Console* console, IMemoryHandler *bBusHandler); + BsxSatellaview(Console* console, IMemoryHandler* bBusHandler); void Reset(); @@ -35,4 +35,4 @@ public: AddressInfo GetAbsoluteAddress(uint32_t address) override; void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/BsxStream.cpp b/Core/BsxStream.cpp index b7f9f3c..c4b1aeb 100644 --- a/Core/BsxStream.cpp +++ b/Core/BsxStream.cpp @@ -53,12 +53,15 @@ bool BsxStream::NeedUpdate() bool BsxStream::FillQueues() { - if(_queueLength > 0) { + if (_queueLength > 0) + { _queueLength--; - if(_prefixLatch && _prefixQueueLength < 0x80) { + if (_prefixLatch && _prefixQueueLength < 0x80) + { _prefixQueueLength++; } - if(_dataLatch && _dataQueueLength < 0x80) { + if (_dataLatch && _dataQueueLength < 0x80) + { _dataQueueLength++; } } @@ -80,18 +83,23 @@ bool BsxStream::LoadStreamFile() OpenStreamFile(); - if(_file) { + if (_file) + { _firstPacket = true; _file.seekg(0, ios::end); _queueLength = (uint16_t)std::ceil(_file.tellg() / 22.0); _file.seekg(0, ios::beg); _fileIndex++; return true; - } else { - if(_fileIndex > 0) { + } + else + { + if (_fileIndex > 0) + { //Go back to file #0 and try again _fileIndex = 0; - if(LoadStreamFile()) { + if (LoadStreamFile()) + { return true; } } @@ -104,19 +112,24 @@ bool BsxStream::LoadStreamFile() uint8_t BsxStream::GetPrefixCount() { - if(!_prefixLatch || !_dataLatch) { + if (!_prefixLatch || !_dataLatch) + { //Stream is disabled return 0; } - if(_prefixQueueLength == 0 && _dataQueueLength == 0) { + if (_prefixQueueLength == 0 && _dataQueueLength == 0) + { //Queue is empty, try to load in new data _fileOffset = 0; - if(_channel == 0) { + if (_channel == 0) + { //Time channel _queueLength = 1; _firstPacket = true; - } else { + } + else + { LoadStreamFile(); } } @@ -126,19 +139,23 @@ uint8_t BsxStream::GetPrefixCount() uint8_t BsxStream::GetPrefix() { - if(!_prefixLatch) { + if (!_prefixLatch) + { return 0; } - if(_prefixQueueLength > 0) { + if (_prefixQueueLength > 0) + { _prefix = 0; - if(_firstPacket) { + if (_firstPacket) + { _prefix |= 0x10; _firstPacket = false; } _prefixQueueLength--; - if(_queueLength == 0 && _prefixQueueLength == 0) { + if (_queueLength == 0 && _prefixQueueLength == 0) + { //Last packet _prefix |= 0x80; } @@ -151,15 +168,20 @@ uint8_t BsxStream::GetPrefix() uint8_t BsxStream::GetData() { - if(!_dataLatch) { + if (!_dataLatch) + { return 0; } - if(_dataQueueLength > 0) { - if(_channel == 0) { + if (_dataQueueLength > 0) + { + if (_channel == 0) + { //Return Time _data = GetTime(); - } else if(_file) { + } + else if (_file) + { //Read byte from stream file char byte; _file.get(byte); @@ -167,7 +189,8 @@ uint8_t BsxStream::GetData() } _fileOffset++; - if(_fileOffset % 22 == 0) { + if (_fileOffset % 22 == 0) + { //Finished reading current packet _dataQueueLength--; } @@ -179,7 +202,8 @@ uint8_t BsxStream::GetData() uint8_t BsxStream::GetStatus(bool reset) { uint8_t status = _status; - if(reset) { + if (reset) + { _status = 0; } return status; @@ -187,7 +211,8 @@ uint8_t BsxStream::GetStatus(bool reset) void BsxStream::SetChannelLow(uint8_t value) { - if((_channel & 0xFF) != 0xFF) { + if ((_channel & 0xFF) != 0xFF) + { _fileIndex = 0; } _channel = (_channel & 0xFF00) | value; @@ -195,7 +220,8 @@ void BsxStream::SetChannelLow(uint8_t value) void BsxStream::SetChannelHigh(uint8_t value) { - if((_channel >> 8) != (value & 0x3F)) { + if ((_channel >> 8) != (value & 0x3F)) + { _fileIndex = 0; } _channel = (_channel & 0xFF) | ((value & 0x3F) << 8); @@ -215,7 +241,8 @@ void BsxStream::SetDataLatch(uint8_t value) void BsxStream::InitTimeStruct() { - time_t dateTime = _resetDate + ((_memoryManager->GetMasterClock() - _resetMasterClock) / _console->GetMasterClockRate()); + time_t dateTime = _resetDate + ((_memoryManager->GetMasterClock() - _resetMasterClock) / _console-> + GetMasterClockRate()); #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) localtime_s(&_tm, &dateTime); @@ -230,30 +257,32 @@ void BsxStream::InitTimeStruct() uint8_t BsxStream::GetTime() { - if(_fileOffset == 0) { + if (_fileOffset == 0) + { InitTimeStruct(); } - switch(_fileOffset) { - case 0: return 0x00; //Data Group ID / Repetition - case 1: return 0x00; //Data Group Link / Continuity - case 2: return 0x00; //Data Group Size (24-bit) - case 3: return 0x00; - case 4: return 0x10; - case 5: return 0x01; //Must be 0x01 - case 6: return 0x01; //Amount of packets (1) - case 7: return 0x00; //Offset (24-bit) - case 8: return 0x00; - case 9: return 0x00; - case 10: return _tm.tm_sec; - case 11: return _tm.tm_min; - case 12: return _tm.tm_hour; - case 13: return _tm.tm_wday; - case 14: return _tm.tm_mday; - case 15: return _tm.tm_mon; - case 16: return _tm.tm_year >> 0; - case 17: return _tm.tm_year >> 8; - default: return 0x00; + switch (_fileOffset) + { + case 0: return 0x00; //Data Group ID / Repetition + case 1: return 0x00; //Data Group Link / Continuity + case 2: return 0x00; //Data Group Size (24-bit) + case 3: return 0x00; + case 4: return 0x10; + case 5: return 0x01; //Must be 0x01 + case 6: return 0x01; //Amount of packets (1) + case 7: return 0x00; //Offset (24-bit) + case 8: return 0x00; + case 9: return 0x00; + case 10: return _tm.tm_sec; + case 11: return _tm.tm_min; + case 12: return _tm.tm_hour; + case 13: return _tm.tm_wday; + case 14: return _tm.tm_mday; + case 15: return _tm.tm_mon; + case 16: return _tm.tm_year >> 0; + case 17: return _tm.tm_year >> 8; + default: return 0x00; } } @@ -261,14 +290,17 @@ void BsxStream::Serialize(Serializer& s) { s.Stream( _channel, _prefix, _data, _status, _prefixLatch, _dataLatch, _firstPacket, _fileOffset, _fileIndex, - _queueLength, _prefixQueueLength, _dataQueueLength, _resetDate, _resetMasterClock, _activeChannel, _activeFileIndex + _queueLength, _prefixQueueLength, _dataQueueLength, _resetDate, _resetMasterClock, _activeChannel, + _activeFileIndex ); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { InitTimeStruct(); OpenStreamFile(); - if(_file) { + if (_file) + { //Seek back to the previous location _file.seekg(_fileOffset, ios::beg); } diff --git a/Core/CallstackManager.cpp b/Core/CallstackManager.cpp index 19df7d7..f87b616 100644 --- a/Core/CallstackManager.cpp +++ b/Core/CallstackManager.cpp @@ -14,9 +14,11 @@ CallstackManager::~CallstackManager() { } -void CallstackManager::Push(AddressInfo &src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, uint32_t returnAddress, StackFrameFlags flags) +void CallstackManager::Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, + uint32_t returnAddress, StackFrameFlags flags) { - if(_callstack.size() >= 511) { + if (_callstack.size() >= 511) + { //Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow _callstack.pop_front(); } @@ -36,7 +38,8 @@ void CallstackManager::Push(AddressInfo &src, uint32_t srcAddr, AddressInfo& des void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress) { - if(_callstack.empty()) { + if (_callstack.empty()) + { return; } @@ -46,14 +49,18 @@ void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress) uint32_t returnAddr = prevFrame.Return; - if(!_callstack.empty() && destAddress != returnAddr) { + if (!_callstack.empty() && destAddress != returnAddr) + { //Mismatch, pop that stack frame and add the new one bool foundMatch = false; - for(int i = (int)_callstack.size() - 1; i >= 0; i--) { - if(destAddress == _callstack[i].Return) { + for (int i = (int)_callstack.size() - 1; i >= 0; i--) + { + if (destAddress == _callstack[i].Return) + { //Found a matching stack frame, unstack until that point foundMatch = true; - for(int j = (int)_callstack.size() - i - 1; j >= 0; j--) { + for (int j = (int)_callstack.size() - i - 1; j >= 0; j--) + { _callstack.pop_back(); _profiler->UnstackFunction(); } @@ -61,18 +68,21 @@ void CallstackManager::Pop(AddressInfo& dest, uint32_t destAddress) } } - if(!foundMatch) { + if (!foundMatch) + { //Couldn't find a matching frame, replace the current one - Push(prevFrame.AbsReturn, returnAddr, dest, destAddress, prevFrame.AbsReturn, returnAddr, StackFrameFlags::None); + Push(prevFrame.AbsReturn, returnAddr, dest, destAddress, prevFrame.AbsReturn, returnAddr, + StackFrameFlags::None); } } } -void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize) +void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t& callstackSize) { DebugBreakHelper helper(_debugger); int i = 0; - for(StackFrameInfo &info : _callstack) { + for (StackFrameInfo& info : _callstack) + { callstackArray[i] = info; i++; } @@ -82,7 +92,8 @@ void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t &ca int32_t CallstackManager::GetReturnAddress() { DebugBreakHelper helper(_debugger); - if(_callstack.empty()) { + if (_callstack.empty()) + { return -1; } return _callstack.back().Return; diff --git a/Core/CallstackManager.h b/Core/CallstackManager.h index fb15e4d..3189979 100644 --- a/Core/CallstackManager.h +++ b/Core/CallstackManager.h @@ -16,10 +16,11 @@ public: CallstackManager(Debugger* debugger); ~CallstackManager(); - void Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, uint32_t returnAddress, StackFrameFlags flags); + void Push(AddressInfo& src, uint32_t srcAddr, AddressInfo& dest, uint32_t destAddr, AddressInfo& ret, + uint32_t returnAddress, StackFrameFlags flags); void Pop(AddressInfo& dest, uint32_t destAddr); - void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize); + void GetCallstack(StackFrameInfo* callstackArray, uint32_t& callstackSize); int32_t GetReturnAddress(); Profiler* GetProfiler(); -}; \ No newline at end of file +}; diff --git a/Core/CheatManager.cpp b/Core/CheatManager.cpp index 73fdbf7..5e9211e 100644 --- a/Core/CheatManager.cpp +++ b/Core/CheatManager.cpp @@ -17,11 +17,13 @@ void CheatManager::AddCheat(CheatCode code) _hasCheats = true; _bankHasCheats[code.Address >> 16] = true; - if(code.Address >= 0x7E0000 && code.Address < 0x7E2000) { + if (code.Address >= 0x7E0000 && code.Address < 0x7E2000) + { //Mirror codes for the first 2kb of workram across all workram mirrors CheatCode mirror; mirror.Value = code.Value; - for(int i = 0; i < 0x3F; i++) { + for (int i = 0; i < 0x3F; i++) + { mirror.Address = (i << 16) | (code.Address & 0xFFFF); AddCheat(mirror); mirror.Address |= 0x800000; @@ -36,15 +38,21 @@ void CheatManager::SetCheats(vector codes) bool hasCheats = !_cheats.empty(); ClearCheats(false); - for(CheatCode &code : codes) { + for (CheatCode& code : codes) + { AddCheat(code); } - if(codes.size() > 1) { + if (codes.size() > 1) + { MessageManager::DisplayMessage("Cheats", "CheatsApplied", std::to_string(codes.size())); - } else if(codes.size() == 1) { + } + else if (codes.size() == 1) + { MessageManager::DisplayMessage("Cheats", "CheatApplied"); - } else if(hasCheats) { + } + else if (hasCheats) + { MessageManager::DisplayMessage("Cheats", "CheatsDisabled"); } @@ -55,7 +63,8 @@ void CheatManager::SetCheats(uint32_t codes[], uint32_t length) { vector cheats; cheats.reserve(length); - for(uint32_t i = 0; i < length; i++) { + for (uint32_t i = 0; i < length; i++) + { CheatCode code; code.Address = codes[i] >> 8; code.Value = codes[i] & 0xFF; @@ -75,7 +84,8 @@ void CheatManager::ClearCheats(bool showMessage) _hasCheats = false; memset(_bankHasCheats, 0, sizeof(_bankHasCheats)); - if(showMessage && hadCheats) { + if (showMessage && hadCheats) + { MessageManager::DisplayMessage("Cheats", "CheatsDisabled"); //Used by net play @@ -86,18 +96,22 @@ void CheatManager::ClearCheats(bool showMessage) void CheatManager::AddStringCheat(string code) { static string _convertTable = "DF4709156BC8A23E"; - + auto lock = _console->AcquireLock(); - + std::transform(code.begin(), code.end(), code.begin(), ::toupper); - if(code.size() == 9 && code[4] == '-') { + if (code.size() == 9 && code[4] == '-') + { uint32_t rawValue = 0; - for(int i = 0; i < (int)code.size(); i++) { - if(code[i] != '-') { + for (int i = 0; i < (int)code.size(); i++) + { + if (code[i] != '-') + { rawValue <<= 4; size_t pos = _convertTable.find_first_of(code[i]); - if(pos == string::npos) { + if (pos == string::npos) + { //Invalid code return; } @@ -119,9 +133,13 @@ void CheatManager::AddStringCheat(string code) cheat.Value = rawValue >> 24; AddCheat(cheat); - } else if(code.size() == 8) { - for(int i = 0; i < (int)code.size(); i++) { - if((code[i] < 'A' || code[i] > 'F') && (code[i] < '0' || code[i] > '9')) { + } + else if (code.size() == 8) + { + for (int i = 0; i < (int)code.size(); i++) + { + if ((code[i] < 'A' || code[i] > 'F') && (code[i] < '0' || code[i] > '9')) + { //Invalid code return; } @@ -138,4 +156,4 @@ void CheatManager::AddStringCheat(string code) vector CheatManager::GetCheats() { return _cheats; -} \ No newline at end of file +} diff --git a/Core/CheatManager.h b/Core/CheatManager.h index ce2fd6a..0d0226a 100644 --- a/Core/CheatManager.h +++ b/Core/CheatManager.h @@ -17,7 +17,7 @@ private: bool _bankHasCheats[0x100] = {}; vector _cheats; unordered_map _cheatsByAddress; - + void AddCheat(CheatCode code); public: @@ -31,14 +31,16 @@ public: vector GetCheats(); - __forceinline void ApplyCheat(uint32_t addr, uint8_t &value); + __forceinline void ApplyCheat(uint32_t addr, uint8_t& value); }; -__forceinline void CheatManager::ApplyCheat(uint32_t addr, uint8_t &value) +__forceinline void CheatManager::ApplyCheat(uint32_t addr, uint8_t& value) { - if(_hasCheats && _bankHasCheats[addr >> 16]) { + if (_hasCheats && _bankHasCheats[addr >> 16]) + { auto result = _cheatsByAddress.find(addr); - if(result != _cheatsByAddress.end()) { + if (result != _cheatsByAddress.end()) + { value = result->second.Value; } } diff --git a/Core/ClientConnectionData.h b/Core/ClientConnectionData.h index 0df67f0..9894611 100644 --- a/Core/ClientConnectionData.h +++ b/Core/ClientConnectionData.h @@ -11,7 +11,9 @@ public: string PlayerName; bool Spectator; - ClientConnectionData() {} + ClientConnectionData() + { + } ClientConnectionData(string host, uint16_t port, string password, string playerName, bool spectator) : Host(host), Port(port), Password(password), PlayerName(playerName), Spectator(spectator) @@ -21,4 +23,4 @@ public: ~ClientConnectionData() { } -}; \ No newline at end of file +}; diff --git a/Core/CodeDataLogger.cpp b/Core/CodeDataLogger.cpp index 6c37319..65aec63 100644 --- a/Core/CodeDataLogger.cpp +++ b/Core/CodeDataLogger.cpp @@ -30,29 +30,37 @@ uint32_t CodeDataLogger::GetPrgSize() bool CodeDataLogger::LoadCdlFile(string cdlFilepath, bool autoResetCdl, uint32_t romCrc) { VirtualFile cdlFile = cdlFilepath; - if(cdlFile.IsValid()) { + if (cdlFile.IsValid()) + { uint32_t fileSize = (uint32_t)cdlFile.GetSize(); vector cdlData; cdlFile.ReadFile(cdlData); - if(fileSize >= _prgSize) { + if (fileSize >= _prgSize) + { Reset(); constexpr int headerSize = 9; //"CDLv2" + 4-byte CRC32 value - if(memcmp(cdlData.data(), "CDLv2", 5) == 0) { + if (memcmp(cdlData.data(), "CDLv2", 5) == 0) + { uint32_t savedCrc = cdlData[5] | (cdlData[6] << 8) | (cdlData[7] << 16) | (cdlData[8] << 24); - if((autoResetCdl && savedCrc != romCrc) || fileSize < _prgSize + headerSize) { + if ((autoResetCdl && savedCrc != romCrc) || fileSize < _prgSize + headerSize) + { memset(_cdlData, 0, _prgSize); - } else { + } + else + { memcpy(_cdlData, cdlData.data() + headerSize, _prgSize); } - } else { + } + else + { //Older CRC-less CDL file, use as-is without checking CRC to avoid data loss memcpy(_cdlData, cdlData.data(), _prgSize); } CalculateStats(); - + return true; } } @@ -62,7 +70,8 @@ bool CodeDataLogger::LoadCdlFile(string cdlFilepath, bool autoResetCdl, uint32_t bool CodeDataLogger::SaveCdlFile(string cdlFilepath, uint32_t romCrc) { ofstream cdlFile(cdlFilepath, ios::out | ios::binary); - if(cdlFile) { + if (cdlFile) + { cdlFile.write("CDLv2", 5); cdlFile.put(romCrc & 0xFF); cdlFile.put((romCrc >> 8) & 0xFF); @@ -80,10 +89,14 @@ void CodeDataLogger::CalculateStats() uint32_t codeSize = 0; uint32_t dataSize = 0; - for(int i = 0, len = _prgSize; i < len; i++) { - if(IsCode(i)) { + for (int i = 0, len = _prgSize; i < len; i++) + { + if (IsCode(i)) + { codeSize++; - } else if(IsData(i)) { + } + else if (IsData(i)) + { dataSize++; } } @@ -94,15 +107,24 @@ void CodeDataLogger::CalculateStats() void CodeDataLogger::SetFlags(int32_t absoluteAddr, uint8_t flags) { - if(absoluteAddr >= 0 && absoluteAddr < (int32_t)_prgSize) { - if((_cdlData[absoluteAddr] & flags) != flags) { - if(flags & CdlFlags::Code) { - _cdlData[absoluteAddr] = flags | (_cdlData[absoluteAddr] & ~(CdlFlags::Data | CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)); - } else if(flags & CdlFlags::Data) { - if(!IsCode(absoluteAddr)) { + if (absoluteAddr >= 0 && absoluteAddr < (int32_t)_prgSize) + { + if ((_cdlData[absoluteAddr] & flags) != flags) + { + if (flags & CdlFlags::Code) + { + _cdlData[absoluteAddr] = flags | (_cdlData[absoluteAddr] & ~(CdlFlags::Data | CdlFlags::IndexMode8 | + CdlFlags::MemoryMode8)); + } + else if (flags & CdlFlags::Data) + { + if (!IsCode(absoluteAddr)) + { _cdlData[absoluteAddr] |= flags; } - } else { + } + else + { _cdlData[absoluteAddr] |= flags; } } @@ -147,25 +169,31 @@ uint8_t CodeDataLogger::GetCpuFlags(uint32_t absoluteAddr) CpuType CodeDataLogger::GetCpuType(uint32_t absoluteAddr) { - if(_cpuType == CpuType::Gameboy) { + if (_cpuType == CpuType::Gameboy) + { return _cpuType; - } else if(_cdlData[absoluteAddr] & CdlFlags::Gsu) { + } + else if (_cdlData[absoluteAddr] & CdlFlags::Gsu) + { return CpuType::Gsu; - } else if(_cdlData[absoluteAddr] & CdlFlags::Cx4) { + } + else if (_cdlData[absoluteAddr] & CdlFlags::Cx4) + { return CpuType::Cx4; } return CpuType::Cpu; } -void CodeDataLogger::SetCdlData(uint8_t *cdlData, uint32_t length) +void CodeDataLogger::SetCdlData(uint8_t* cdlData, uint32_t length) { - if(length <= _prgSize) { + if (length <= _prgSize) + { memcpy(_cdlData, cdlData, length); } } -void CodeDataLogger::GetCdlData(uint32_t offset, uint32_t length, uint8_t *cdlData) +void CodeDataLogger::GetCdlData(uint32_t offset, uint32_t length, uint8_t* cdlData) { memcpy(cdlData, _cdlData + offset, length); } @@ -177,24 +205,32 @@ uint8_t CodeDataLogger::GetFlags(uint32_t addr) void CodeDataLogger::MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags) { - for(uint32_t i = start; i <= end; i++) { + for (uint32_t i = start; i <= end; i++) + { _cdlData[i] = (_cdlData[i] & 0xFC) | (int)flags; } } void CodeDataLogger::StripData(uint8_t* romBuffer, CdlStripOption flag) { - if(flag == CdlStripOption::StripUnused) { - for(uint32_t i = 0; i < _prgSize; i++) { - if(_cdlData[i] == 0) { - romBuffer[i] = 0; - } - } - } else if(flag == CdlStripOption::StripUsed) { - for(uint32_t i = 0; i < _prgSize; i++) { - if(_cdlData[i] != 0) { + if (flag == CdlStripOption::StripUnused) + { + for (uint32_t i = 0; i < _prgSize; i++) + { + if (_cdlData[i] == 0) + { romBuffer[i] = 0; } } } -} \ No newline at end of file + else if (flag == CdlStripOption::StripUsed) + { + for (uint32_t i = 0; i < _prgSize; i++) + { + if (_cdlData[i] != 0) + { + romBuffer[i] = 0; + } + } + } +} diff --git a/Core/CodeDataLogger.h b/Core/CodeDataLogger.h index b680c78..7eb90bc 100644 --- a/Core/CodeDataLogger.h +++ b/Core/CodeDataLogger.h @@ -10,7 +10,7 @@ private: uint32_t _prgSize = 0; uint32_t _codeSize = 0; uint32_t _dataSize = 0; - + void CalculateStats(); public: @@ -34,10 +34,10 @@ public: uint8_t GetCpuFlags(uint32_t absoluteAddr); CpuType GetCpuType(uint32_t absoluteAddr); - void SetCdlData(uint8_t *cdlData, uint32_t length); - void GetCdlData(uint32_t offset, uint32_t length, uint8_t *cdlData); + void SetCdlData(uint8_t* cdlData, uint32_t length); + void GetCdlData(uint32_t offset, uint32_t length, uint8_t* cdlData); uint8_t GetFlags(uint32_t addr); void MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags); void StripData(uint8_t* romBuffer, CdlStripOption flag); -}; \ No newline at end of file +}; diff --git a/Core/Console.cpp b/Core/Console.cpp index 5941e51..68bb04b 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -82,7 +82,7 @@ void Console::Release() _videoDecoder->StopThread(); _videoRenderer->StopThread(); - + _videoDecoder.reset(); _videoRenderer.reset(); _debugHud.reset(); @@ -97,13 +97,18 @@ void Console::Release() void Console::RunFrame() { _frameRunning = true; - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { Gameboy* gameboy = _cart->GetGameboy(); - while(_frameRunning) { + while (_frameRunning) + { gameboy->Exec(); } - } else { - while(_frameRunning) { + } + else + { + while (_frameRunning) + { _cpu->Exec(); } } @@ -111,10 +116,11 @@ void Console::RunFrame() void Console::Run() { - if(!_cpu) { + if (!_cpu) + { return; } - + auto emulationLock = _emulationLock.AcquireSafe(); auto lock = _runLock.AcquireSafe(); @@ -134,14 +140,20 @@ void Console::Run() _frameLimiter.reset(new FrameLimiter(_frameDelay)); _lastFrameTimer.Reset(); - while(!_stopFlag) { - bool useRunAhead = _settings->GetEmulationConfig().RunAheadFrames > 0 && !_debugger && !_rewindManager->IsRewinding() && _settings->GetEmulationSpeed() > 0 && _settings->GetEmulationSpeed() <= 100; - if(useRunAhead) { + while (!_stopFlag) + { + bool useRunAhead = _settings->GetEmulationConfig().RunAheadFrames > 0 && !_debugger && !_rewindManager-> + IsRewinding() && _settings->GetEmulationSpeed() > 0 && _settings->GetEmulationSpeed() <= 100; + if (useRunAhead) + { RunFrameWithRunAhead(); - } else { + } + else + { RunFrame(); - if (_historyViewer) { + if (_historyViewer) + { _historyViewer->ProcessEndOfFrame(); } _rewindManager->ProcessEndOfFrame(); @@ -150,16 +162,19 @@ void Console::Run() WaitForLock(); - if(_pauseOnNextFrame) { + if (_pauseOnNextFrame) + { _pauseOnNextFrame = false; _paused = true; } - if(_paused && !_stopFlag && !_debugger) { + if (_paused && !_stopFlag && !_debugger) + { WaitForPauseEnd(); - } + } - if(_memoryManager->GetMasterClock() == 0) { + if (_memoryManager->GetMasterClock() == 0) + { //After a reset or power cycle, run the PPU/etc ahead of the CPU (simulates delay CPU takes to get out of reset) _memoryManager->IncMasterClockStartup(); } @@ -174,10 +189,13 @@ void Console::Run() bool Console::ProcessSystemActions() { - if(_controlManager->GetSystemActionManager()->IsResetPressed()) { + if (_controlManager->GetSystemActionManager()->IsResetPressed()) + { Reset(); return true; - } else if(_controlManager->GetSystemActionManager()->IsPowerCyclePressed()) { + } + else if (_controlManager->GetSystemActionManager()->IsPowerCyclePressed()) + { PowerCycle(); return true; } @@ -194,7 +212,8 @@ void Console::RunFrameWithRunAhead() RunFrame(); Serialize(runAheadState, 0); - while(frameCount > 1) { + while (frameCount > 1) + { //Run extra frames if the requested run ahead frame count is higher than 1 frameCount--; RunFrame(); @@ -204,9 +223,10 @@ void Console::RunFrameWithRunAhead() //Run one frame normally (with audio/video output) RunFrame(); _rewindManager->ProcessEndOfFrame(); - + bool wasReset = ProcessSystemActions(); - if(!wasReset) { + if (!wasReset) + { //Load the state we saved earlier _isRunAheadFrame = true; Deserialize(runAheadState, SaveStateManager::FileFormatVersion, false); @@ -218,27 +238,33 @@ void Console::ProcessEndOfFrame() { #ifndef LIBRETRO _cart->RunCoprocessors(); - if(_cart->GetCoprocessor()) { + if (_cart->GetCoprocessor()) + { _cart->GetCoprocessor()->ProcessEndOfFrame(); } - if(!_isRunAheadFrame) { + if (!_isRunAheadFrame) + { _frameLimiter->ProcessFrame(); - while(_frameLimiter->WaitForNextFrame()) { - if(_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0) { + while (_frameLimiter->WaitForNextFrame()) + { + if (_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0) + { //Need to process another event, stop sleeping break; } } double newFrameDelay = GetFrameDelay(); - if(newFrameDelay != _frameDelay) { + if (newFrameDelay != _frameDelay) + { _frameDelay = newFrameDelay; _frameLimiter->SetDelay(_frameDelay); } PreferencesConfig cfg = _settings->GetPreferences(); - if(cfg.ShowDebugInfo) { + if (cfg.ShowDebugInfo) + { double lastFrameTime = _lastFrameTimer.GetElapsedMS(); _lastFrameTimer.Reset(); _stats->DisplayStats(this, lastFrameTime); @@ -264,7 +290,8 @@ void Console::RunSingleFrame() RunFrame(); _cart->RunCoprocessors(); - if(_cart->GetCoprocessor()) { + if (_cart->GetCoprocessor()) + { _cart->GetCoprocessor()->ProcessEndOfFrame(); } @@ -278,24 +305,28 @@ void Console::Stop(bool sendNotification) _notificationManager->SendNotification(ConsoleNotificationType::BeforeGameUnload); shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); debugger->Run(); } _emulationLock.WaitForRelease(); - if(_emuThread) { + if (_emuThread) + { _emuThread->join(); _emuThread.release(); } - if(_cart && !_settings->GetPreferences().DisableGameSelectionScreen) { + if (_cart && !_settings->GetPreferences().DisableGameSelectionScreen) + { RomInfo romInfo = _cart->GetRomInfo(); _saveStateManager->SaveRecentGame(romInfo.RomFile.GetFileName(), romInfo.RomFile, romInfo.PatchFile); } - if(sendNotification) { + if (sendNotification) + { _notificationManager->SendNotification(ConsoleNotificationType::BeforeEmulationStop); } @@ -321,7 +352,8 @@ void Console::Stop(bool sendNotification) _soundMixer->StopAudio(true); - if(sendNotification) { + if (sendNotification) + { _notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped); } } @@ -347,28 +379,34 @@ void Console::Reset() _notificationManager->SendNotification(ConsoleNotificationType::GameReset); ProcessEvent(EventType::Reset); - if(_cart->GetSpcData()) { + if (_cart->GetSpcData()) + { _spc->LoadSpcFile(_cart->GetSpcData()); _spcHud.reset(new SpcHud(this, _cart->GetSpcData())); - } else { + } + else + { _spcHud.reset(); } - if(debugger) { + if (debugger) + { //Debugger was suspended in SystemActionManager::Reset(), resume debugger here debugger->SuspendDebugger(true); } - _runLock.Release(); + _runLock.Release(); _lockCounter--; } void Console::ReloadRom(bool forPowerCycle) { shared_ptr cart = _cart; - if(cart) { + if (cart) + { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->Run(); } @@ -386,27 +424,32 @@ void Console::PowerCycle() bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, bool forPowerCycle) { - if(_cart) { + if (_cart) + { //Make sure the battery is saved to disk before we load another game (or reload the same game) _cart->SaveBattery(); } bool result = false; - EmulationConfig orgConfig = _settings->GetEmulationConfig(); //backup emulation config (can be temporarily overriden to control the power on RAM state) + EmulationConfig orgConfig = _settings->GetEmulationConfig(); + //backup emulation config (can be temporarily overriden to control the power on RAM state) shared_ptr cart = forPowerCycle ? _cart : BaseCartridge::CreateCartridge(this, romFile, patchFile); - if(cart) { + if (cart) + { bool debuggerActive = _debugger != nullptr; - if(stopRom) { + if (stopRom) + { KeyManager::UpdateDevices(); Stop(false); } _cheatManager->ClearCheats(false); - + _cart = cart; - + auto lock = _debuggerLock.AcquireSafe(); - if(_debugger) { + if (_debugger) + { //Reset debugger if it was running before _debugger->Release(); _debugger.reset(); @@ -425,10 +468,13 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _msu1.reset(Msu1::Init(romFile, _spc.get())); - if(_cart->GetSpcData()) { + if (_cart->GetSpcData()) + { _spc->LoadSpcFile(_cart->GetSpcData()); _spcHud.reset(new SpcHud(this, _cart->GetSpcData())); - } else { + } + else + { _spcHud.reset(); } @@ -436,16 +482,20 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _memoryManager->Initialize(this); _internalRegisters->Initialize(this); - if(_cart->GetCoprocessor() == nullptr && _cart->GetGameboy()) { + if (_cart->GetCoprocessor() == nullptr && _cart->GetGameboy()) + { _cart->GetGameboy()->PowerOn(); _consoleType = _cart->GetGameboy()->IsCgb() ? ConsoleType::GameboyColor : ConsoleType::Gameboy; _settings->SetFlag(EmulationFlags::GameboyMode); - } else { + } + else + { _consoleType = ConsoleType::Snes; _settings->ClearFlag(EmulationFlags::GameboyMode); } - if(debuggerActive) { + if (debuggerActive) + { GetDebugger(); } @@ -456,26 +506,31 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _notificationManager->RegisterNotificationListener(_rewindManager); _controlManager->UpdateControlDevices(); - + UpdateRegion(); _notificationManager->SendNotification(ConsoleNotificationType::GameLoaded, (void*)forPowerCycle); _paused = false; - if(!forPowerCycle) { + if (!forPowerCycle) + { string modelName = _region == ConsoleRegion::Pal ? "PAL" : "NTSC"; string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")"; - MessageManager::DisplayMessage(messageTitle, FolderUtilities::GetFilename(GetRomInfo().RomFile.GetFileName(), false)); + MessageManager::DisplayMessage(messageTitle, + FolderUtilities::GetFilename(GetRomInfo().RomFile.GetFileName(), false)); } - if(stopRom) { - #ifndef LIBRETRO + if (stopRom) + { +#ifndef LIBRETRO _emuThread.reset(new thread(&Console::Run, this)); - #endif +#endif } result = true; - } else { + } + else + { MessageManager::DisplayMessage("Error", "CouldNotLoadFile", romFile.GetFileName()); } @@ -486,18 +541,24 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, RomInfo Console::GetRomInfo() { shared_ptr cart = _cart; - if(cart) { + if (cart) + { return cart->GetRomInfo(); - } else { + } + else + { return {}; } } uint64_t Console::GetMasterClock() { - if(_settings->CheckFlag(EmulationFlags::GameboyMode) && _cart->GetGameboy()) { + if (_settings->CheckFlag(EmulationFlags::GameboyMode) && _cart->GetGameboy()) + { return _cart->GetGameboy()->GetCycleCount(); - } else { + } + else + { return _memoryManager->GetMasterClock(); } } @@ -519,12 +580,16 @@ ConsoleType Console::GetConsoleType() void Console::UpdateRegion() { - switch(_settings->GetEmulationConfig().Region) { - case ConsoleRegion::Auto: _region = _cart->GetRegion(); break; + switch (_settings->GetEmulationConfig().Region) + { + case ConsoleRegion::Auto: _region = _cart->GetRegion(); + break; - default: - case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc; break; - case ConsoleRegion::Pal: _region = ConsoleRegion::Pal; break; + default: + case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc; + break; + case ConsoleRegion::Pal: _region = ConsoleRegion::Pal; + break; } _masterClockRate = _region == ConsoleRegion::Pal ? 21281370 : 21477270; @@ -532,12 +597,18 @@ void Console::UpdateRegion() double Console::GetFps() { - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { return 59.72750056960583; - } else { - if(_region == ConsoleRegion::Ntsc) { + } + else + { + if (_region == ConsoleRegion::Ntsc) + { return _settings->GetVideoConfig().IntegerFpsMode ? 60.0 : 60.0988118623484; - } else { + } + else + { return _settings->GetVideoConfig().IntegerFpsMode ? 50.0 : 50.00697796826829; } } @@ -547,17 +618,28 @@ double Console::GetFrameDelay() { uint32_t emulationSpeed = _settings->GetEmulationSpeed(); double frameDelay; - if(emulationSpeed == 0) { + if (emulationSpeed == 0) + { frameDelay = 0; - } else { + } + else + { UpdateRegion(); - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { frameDelay = 16.74270629882813; - } else { - switch(_region) { - default: - case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 16.6666666666666666667 : 16.63926405550947; break; - case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146; break; + } + else + { + switch (_region) + { + default: + case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode + ? 16.6666666666666666667 + : 16.63926405550947; + break; + case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146; + break; } } frameDelay /= (emulationSpeed / 100.0); @@ -587,13 +669,19 @@ void Console::CopyRewindData(shared_ptr sourceConsole) void Console::PauseOnNextFrame() { shared_ptr debugger = _debugger; - if(debugger) { - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + if (debugger) + { + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { debugger->Step(CpuType::Gameboy, 144, StepType::SpecificScanline); - } else { + } + else + { debugger->Step(CpuType::Cpu, 240, StepType::SpecificScanline); } - } else { + } + else + { _pauseOnNextFrame = true; _paused = false; } @@ -602,13 +690,19 @@ void Console::PauseOnNextFrame() void Console::Pause() { shared_ptr debugger = _debugger; - if(debugger) { - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + if (debugger) + { + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { debugger->Step(CpuType::Gameboy, 1, StepType::Step); - } else { + } + else + { debugger->Step(CpuType::Cpu, 1, StepType::Step); } - } else { + } + else + { _paused = true; } } @@ -616,9 +710,12 @@ void Console::Pause() void Console::Resume() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->Run(); - } else { + } + else + { _paused = false; } } @@ -626,9 +723,12 @@ void Console::Resume() bool Console::IsPaused() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { return debugger->IsExecutionStopped(); - } else { + } + else + { return _paused; } } @@ -643,14 +743,16 @@ void Console::WaitForPauseEnd() PlatformUtilities::EnableScreensaver(); PlatformUtilities::RestoreTimerResolution(); - while(_paused && !_stopFlag && !_debugger) { + while (_paused && !_stopFlag && !_debugger) + { //Sleep until emulation is resumed std::this_thread::sleep_for(std::chrono::duration(30)); } PlatformUtilities::DisableScreensaver(); _runLock.Acquire(); - if(!_stopFlag) { + if (!_stopFlag) + { _notificationManager->SendNotification(ConsoleNotificationType::GameResumed); } } @@ -663,7 +765,8 @@ ConsoleLock Console::AcquireLock() void Console::Lock() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); } @@ -674,7 +777,8 @@ void Console::Lock() void Console::Unlock() { shared_ptr debugger = _debugger; - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(true); } @@ -689,18 +793,24 @@ bool Console::IsThreadPaused() void Console::WaitForLock() { - if(_lockCounter > 0) { + if (_lockCounter > 0) + { //Need to temporarely pause the emu (to save/load a state, etc.) _runLock.Release(); _threadPaused = true; //Spin wait until we are allowed to start again - while(_lockCounter > 0) {} + while (_lockCounter > 0) + { + } shared_ptr debugger = _debugger; - if(debugger) { - while(debugger->HasBreakRequest()) {} + if (debugger) + { + while (debugger->HasBreakRequest()) + { + } } _threadPaused = false; @@ -709,12 +819,13 @@ void Console::WaitForLock() } } -void Console::Serialize(ostream &out, int compressionLevel) +void Console::Serialize(ostream& out, int compressionLevel) { Serializer serializer(SaveStateManager::FileFormatVersion); bool isGameboyMode = _settings->CheckFlag(EmulationFlags::GameboyMode); - if(!isGameboyMode) { + if (!isGameboyMode) + { serializer.Stream(_cpu.get()); serializer.Stream(_memoryManager.get()); serializer.Stream(_ppu.get()); @@ -723,22 +834,26 @@ void Console::Serialize(ostream &out, int compressionLevel) serializer.Stream(_cart.get()); serializer.Stream(_controlManager.get()); serializer.Stream(_spc.get()); - if(_msu1) { + if (_msu1) + { serializer.Stream(_msu1.get()); } - } else { + } + else + { serializer.Stream(_cart.get()); serializer.Stream(_controlManager.get()); } serializer.Save(out, compressionLevel); } -void Console::Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed) +void Console::Deserialize(istream& in, uint32_t fileFormatVersion, bool compressed) { Serializer serializer(in, fileFormatVersion, compressed); bool isGameboyMode = _settings->CheckFlag(EmulationFlags::GameboyMode); - if(!isGameboyMode) { + if (!isGameboyMode) + { serializer.Stream(_cpu.get()); serializer.Stream(_memoryManager.get()); serializer.Stream(_ppu.get()); @@ -747,10 +862,13 @@ void Console::Deserialize(istream &in, uint32_t fileFormatVersion, bool compress serializer.Stream(_cart.get()); serializer.Stream(_controlManager.get()); serializer.Stream(_spc.get()); - if(_msu1) { + if (_msu1) + { serializer.Stream(_msu1.get()); } - } else { + } + else + { serializer.Stream(_cart.get()); serializer.Stream(_controlManager.get()); } @@ -860,11 +978,13 @@ shared_ptr Console::GetMsu1() shared_ptr Console::GetDebugger(bool autoStart) { shared_ptr debugger = _debugger; - if(!debugger && autoStart) { + if (!debugger && autoStart) + { //Lock to make sure we don't try to start debuggers in 2 separate threads at once auto lock = _debuggerLock.AcquireSafe(); debugger = _debugger; - if(!debugger) { + if (!debugger) + { debugger.reset(new Debugger(shared_from_this())); _debugger = debugger; } @@ -908,37 +1028,44 @@ bool Console::IsRunAheadFrame() uint32_t Console::GetFrameCount() { shared_ptr cart = _cart; - if(_settings->CheckFlag(EmulationFlags::GameboyMode) && cart->GetGameboy()) { + if (_settings->CheckFlag(EmulationFlags::GameboyMode) && cart->GetGameboy()) + { GbPpu* ppu = cart->GetGameboy()->GetPpu(); return ppu ? ppu->GetFrameCount() : 0; - } else { + } + else + { shared_ptr ppu = _ppu; return ppu ? ppu->GetFrameCount() : 0; } } -template +template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessInterrupt(originalPc, currentPc, forNmi); } } void Console::ProcessEvent(EventType type) { - if(type == EventType::EndFrame && _spcHud) { + if (type == EventType::EndFrame && _spcHud) + { _spcHud->Draw(GetFrameCount()); } - if(_debugger) { + if (_debugger) + { _debugger->ProcessEvent(type); } } void Console::BreakImmediately(BreakSource source) { - if(_debugger) { + if (_debugger) + { _debugger->BreakImmediately(source); } } diff --git a/Core/Console.h b/Core/Console.h index acfd904..a2d5d2b 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -53,7 +53,7 @@ private: shared_ptr _internalRegisters; shared_ptr _controlManager; shared_ptr _dmaController; - + shared_ptr _msu1; shared_ptr _debugger; @@ -73,7 +73,7 @@ private: shared_ptr _spcHud; thread::id _emulationThreadId; - + atomic _lockCounter; SimpleLock _runLock; SimpleLock _emulationLock; @@ -124,7 +124,7 @@ public: void PowerCycle(); void PauseOnNextFrame(); - + void Pause(); void Resume(); bool IsPaused(); @@ -141,8 +141,8 @@ public: void Unlock(); bool IsThreadPaused(); - void Serialize(ostream &out, int compressionLevel = 1); - void Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed = true); + void Serialize(ostream& out, int compressionLevel = 1); + void Deserialize(istream& in, uint32_t fileFormatVersion, bool compressed = true); shared_ptr GetSoundMixer(); shared_ptr GetVideoRenderer(); @@ -172,72 +172,84 @@ public: bool IsDebugging(); thread::id GetEmulationThreadId(); - + bool IsRunning(); bool IsRunAheadFrame(); - uint32_t GetFrameCount(); + uint32_t GetFrameCount(); double GetFps(); void CopyRewindData(shared_ptr sourceConsole); - template __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) + template + __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessMemoryRead(addr, value, opType); } } - template __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) + template + __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessMemoryWrite(addr, value, opType); } } __forceinline void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessPpuRead(addr, value, memoryType); } } __forceinline void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessPpuWrite(addr, value, memoryType); } } __forceinline void ProcessWorkRamRead(uint32_t addr, uint8_t value) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessWorkRamRead(addr, value); } } __forceinline void ProcessWorkRamWrite(uint32_t addr, uint8_t value) { - if(_debugger) { + if (_debugger) + { _debugger->ProcessWorkRamWrite(addr, value); } } - - template __forceinline void ProcessPpuCycle() + + template + __forceinline void ProcessPpuCycle() { - if(_debugger) { + if (_debugger) + { _debugger->ProcessPpuCycle(); } } __forceinline void DebugLog(string log) { - if(_debugger) { + if (_debugger) + { _debugger->Log(log); } } - template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); + template + void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessEvent(EventType type); void BreakImmediately(BreakSource source); }; diff --git a/Core/ConsoleLock.cpp b/Core/ConsoleLock.cpp index 783fc31..800be1d 100644 --- a/Core/ConsoleLock.cpp +++ b/Core/ConsoleLock.cpp @@ -3,7 +3,7 @@ #include "Console.h" #include "Debugger.h" -ConsoleLock::ConsoleLock(Console *console) +ConsoleLock::ConsoleLock(Console* console) { _console = console; _console->Lock(); diff --git a/Core/ConsoleLock.h b/Core/ConsoleLock.h index fd79c3d..94dedb4 100644 --- a/Core/ConsoleLock.h +++ b/Core/ConsoleLock.h @@ -7,9 +7,9 @@ class Debugger; class ConsoleLock { private: - Console *_console = nullptr; + Console* _console = nullptr; public: - ConsoleLock(Console *console); + ConsoleLock(Console* console); ~ConsoleLock(); -}; \ No newline at end of file +}; diff --git a/Core/ControlDeviceState.h b/Core/ControlDeviceState.h index bcc392e..7c17098 100644 --- a/Core/ControlDeviceState.h +++ b/Core/ControlDeviceState.h @@ -7,7 +7,7 @@ struct ControlDeviceState { vector State; - bool operator!=(ControlDeviceState &other) + bool operator!=(ControlDeviceState& other) { return State.size() != other.State.size() || memcmp(State.data(), other.State.data(), State.size()) != 0; } @@ -17,4 +17,4 @@ struct ControllerData { ControllerType Type; ControlDeviceState State; -}; \ No newline at end of file +}; diff --git a/Core/ControlManager.cpp b/Core/ControlManager.cpp index 8aa15b0..9e3d9b8 100644 --- a/Core/ControlManager.cpp +++ b/Core/ControlManager.cpp @@ -37,7 +37,7 @@ void ControlManager::RegisterInputProvider(IInputProvider* provider) void ControlManager::UnregisterInputProvider(IInputProvider* provider) { auto lock = _deviceLock.AcquireSafe(); - vector &vec = _inputProviders; + vector& vec = _inputProviders; vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end()); } @@ -50,7 +50,7 @@ void ControlManager::RegisterInputRecorder(IInputRecorder* provider) void ControlManager::UnregisterInputRecorder(IInputRecorder* provider) { auto lock = _deviceLock.AcquireSafe(); - vector &vec = _inputRecorders; + vector& vec = _inputRecorders; vec.erase(std::remove(vec.begin(), vec.end(), provider), vec.end()); } @@ -59,12 +59,16 @@ vector ControlManager::GetPortStates() auto lock = _deviceLock.AcquireSafe(); vector states; - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { shared_ptr device = GetControlDevice(i); - if(device) { - states.push_back({ device->GetControllerType(), device->GetRawState() }); - } else { - states.push_back({ ControllerType::None, ControlDeviceState()}); + if (device) + { + states.push_back({device->GetControllerType(), device->GetRawState()}); + } + else + { + states.push_back({ControllerType::None, ControlDeviceState()}); } } return states; @@ -79,8 +83,13 @@ shared_ptr ControlManager::GetControlDevice(uint8_t port) { auto lock = _deviceLock.AcquireSafe(); - auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(), [port](const shared_ptr control) { return control->GetPort() == port; }); - if(result != _controlDevices.end()) { + auto result = std::find_if(_controlDevices.begin(), _controlDevices.end(), + [port](const shared_ptr control) + { + return control->GetPort() == port; + }); + if (result != _controlDevices.end()) + { return *result; } return nullptr; @@ -101,35 +110,46 @@ ControllerType ControlManager::GetControllerType(uint8_t port) return _console->GetSettings()->GetInputConfig().Controllers[port].Type; } -shared_ptr ControlManager::CreateControllerDevice(ControllerType type, uint8_t port, Console* console) +shared_ptr ControlManager::CreateControllerDevice(ControllerType type, uint8_t port, + Console* console) { shared_ptr device; - + InputConfig cfg = console->GetSettings()->GetInputConfig(); - switch(type) { - case ControllerType::None: break; - case ControllerType::SnesController: device.reset(new SnesController(console, port, cfg.Controllers[port].Keys)); break; - case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port)); break; - case ControllerType::SuperScope: device.reset(new SuperScope(console, port, cfg.Controllers[port].Keys)); break; - case ControllerType::Multitap: device.reset(new Multitap(console, port, cfg.Controllers[port].Keys, cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, cfg.Controllers[4].Keys)); break; + switch (type) + { + case ControllerType::None: break; + case ControllerType::SnesController: device.reset(new SnesController(console, port, cfg.Controllers[port].Keys)); + break; + case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port)); + break; + case ControllerType::SuperScope: device.reset(new SuperScope(console, port, cfg.Controllers[port].Keys)); + break; + case ControllerType::Multitap: device.reset(new Multitap(console, port, cfg.Controllers[port].Keys, + cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, + cfg.Controllers[4].Keys)); + break; } - + return device; } void ControlManager::UpdateControlDevices() { uint32_t version = _console->GetSettings()->GetInputConfigVersion(); - if(_inputConfigVersion != version) { + if (_inputConfigVersion != version) + { _inputConfigVersion = version; auto lock = _deviceLock.AcquireSafe(); _controlDevices.clear(); RegisterControlDevice(_systemActionManager); - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { shared_ptr device = CreateControllerDevice(GetControllerType(i), i, _console); - if(device) { + if (device) + { RegisterControlDevice(device); } } @@ -143,13 +163,16 @@ void ControlManager::UpdateInputState() auto lock = _deviceLock.AcquireSafe(); //string log = "F: " + std::to_string(_console->GetPpu()->GetFrameCount()) + " C:" + std::to_string(_pollCounter) + " "; - for(shared_ptr &device : _controlDevices) { + for (shared_ptr& device : _controlDevices) + { device->ClearState(); device->SetStateFromInput(); - for(size_t i = 0; i < _inputProviders.size(); i++) { + for (size_t i = 0; i < _inputProviders.size(); i++) + { IInputProvider* provider = _inputProviders[i]; - if(provider->SetInput(device.get())) { + if (provider->SetInput(device.get())) + { break; } } @@ -159,12 +182,15 @@ void ControlManager::UpdateInputState() } shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->ProcessEvent(EventType::InputPolled); } - if(!_console->IsRunAheadFrame()) { - for(IInputRecorder* recorder : _inputRecorders) { + if (!_console->IsRunAheadFrame()) + { + for (IInputRecorder* recorder : _inputRecorders) + { recorder->RecordInput(_controlDevices); } } @@ -187,7 +213,8 @@ void ControlManager::SetPollCounter(uint32_t value) uint8_t ControlManager::Read(uint16_t addr) { uint8_t value = _console->GetMemoryManager()->GetOpenBus() & (addr == 0x4016 ? 0xFC : 0xE0); - for(shared_ptr &device : _controlDevices) { + for (shared_ptr& device : _controlDevices) + { value |= device->ReadRam(addr); } @@ -196,21 +223,25 @@ uint8_t ControlManager::Read(uint16_t addr) void ControlManager::Write(uint16_t addr, uint8_t value) { - for(shared_ptr &device : _controlDevices) { + for (shared_ptr& device : _controlDevices) + { device->WriteRam(addr, value); } } -void ControlManager::Serialize(Serializer &s) +void ControlManager::Serialize(Serializer& s) { InputConfig cfg = _console->GetSettings()->GetInputConfig(); - s.Stream(cfg.Controllers[0].Type, cfg.Controllers[1].Type, cfg.Controllers[2].Type, cfg.Controllers[3].Type, cfg.Controllers[4].Type); - if(!s.IsSaving()) { + s.Stream(cfg.Controllers[0].Type, cfg.Controllers[1].Type, cfg.Controllers[2].Type, cfg.Controllers[3].Type, + cfg.Controllers[4].Type); + if (!s.IsSaving()) + { _console->GetSettings()->SetInputConfig(cfg); UpdateControlDevices(); } - for(shared_ptr &device : _controlDevices) { + for (shared_ptr& device : _controlDevices) + { s.Stream(device.get()); } } diff --git a/Core/ControlManager.h b/Core/ControlManager.h index 7ee212f..675abfe 100644 --- a/Core/ControlManager.h +++ b/Core/ControlManager.h @@ -19,7 +19,7 @@ class ControlManager : public ISerializable private: vector _inputRecorders; vector _inputProviders; - + uint32_t _pollCounter; uint32_t _inputConfigVersion; @@ -54,11 +54,11 @@ public: SystemActionManager* GetSystemActionManager(); shared_ptr GetControlDevice(uint8_t port); vector> GetControlDevices(); - + static shared_ptr CreateControllerDevice(ControllerType type, uint8_t port, Console* console); uint8_t Read(uint16_t addr); void Write(uint16_t addr, uint8_t value); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; diff --git a/Core/Cpu.Instructions.h b/Core/Cpu.Instructions.h index ba14506..302831b 100644 --- a/Core/Cpu.Instructions.h +++ b/Core/Cpu.Instructions.h @@ -4,28 +4,36 @@ Add/substract operations void Cpu::Add8(uint8_t value) { uint32_t result; - if(CheckFlag(ProcFlags::Decimal)) { + if (CheckFlag(ProcFlags::Decimal)) + { result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry); - if(result > 0x09) result += 0x06; + if (result > 0x09) result += 0x06; result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F); - } else { + } + else + { result = (_state.A & 0xFF) + value + (_state.PS & ProcFlags::Carry); } - if(~(_state.A ^ value) & (_state.A ^ result) & 0x80) { + if (~(_state.A ^ value) & (_state.A ^ result) & 0x80) + { SetFlags(ProcFlags::Overflow); - } else { + } + else + { ClearFlags(ProcFlags::Overflow); } - if(CheckFlag(ProcFlags::Decimal) && result > 0x9F) { + if (CheckFlag(ProcFlags::Decimal) && result > 0x9F) + { result += 0x60; } ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero); SetZeroNegativeFlags((uint8_t)result); - if(result > 0xFF) { + if (result > 0xFF) + { SetFlags(ProcFlags::Carry); } @@ -35,35 +43,43 @@ void Cpu::Add8(uint8_t value) void Cpu::Add16(uint16_t value) { uint32_t result; - if(CheckFlag(ProcFlags::Decimal)) { + if (CheckFlag(ProcFlags::Decimal)) + { result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry); - if(result > 0x09) result += 0x06; + if (result > 0x09) result += 0x06; result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F); - if(result > 0x9F) result += 0x60; + if (result > 0x9F) result += 0x60; result = (_state.A & 0xF00) + (value & 0xF00) + (result > 0xFF ? 0x100 : 0) + (result & 0xFF); - if(result > 0x9FF) result += 0x600; + if (result > 0x9FF) result += 0x600; result = (_state.A & 0xF000) + (value & 0xF000) + (result > 0xFFF ? 0x1000 : 0) + (result & 0xFFF); - } else { + } + else + { result = _state.A + value + (_state.PS & ProcFlags::Carry); } - if(~(_state.A ^ value) & (_state.A ^ result) & 0x8000) { + if (~(_state.A ^ value) & (_state.A ^ result) & 0x8000) + { SetFlags(ProcFlags::Overflow); - } else { + } + else + { ClearFlags(ProcFlags::Overflow); } - if(CheckFlag(ProcFlags::Decimal) && result > 0x9FFF) { + if (CheckFlag(ProcFlags::Decimal) && result > 0x9FFF) + { result += 0x6000; } ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero); SetZeroNegativeFlags((uint16_t)result); - if(result > 0xFFFF) { + if (result > 0xFFFF) + { SetFlags(ProcFlags::Carry); } @@ -72,9 +88,12 @@ void Cpu::Add16(uint16_t value) void Cpu::ADC() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { Add8(GetByteValue()); - } else { + } + else + { Add16(GetWordValue()); } } @@ -82,28 +101,36 @@ void Cpu::ADC() void Cpu::Sub8(uint8_t value) { int32_t result; - if(CheckFlag(ProcFlags::Decimal)) { + if (CheckFlag(ProcFlags::Decimal)) + { result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry); - if(result <= 0x0F) result -= 0x06; + if (result <= 0x0F) result -= 0x06; result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F); - } else { + } + else + { result = (_state.A & 0xFF) + value + (_state.PS & ProcFlags::Carry); } - if(~(_state.A ^ value) & (_state.A ^ result) & 0x80) { + if (~(_state.A ^ value) & (_state.A ^ result) & 0x80) + { SetFlags(ProcFlags::Overflow); - } else { + } + else + { ClearFlags(ProcFlags::Overflow); } - if(CheckFlag(ProcFlags::Decimal) && result <= 0xFF) { + if (CheckFlag(ProcFlags::Decimal) && result <= 0xFF) + { result -= 0x60; } ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero); SetZeroNegativeFlags((uint8_t)result); - if(result > 0xFF) { + if (result > 0xFF) + { SetFlags(ProcFlags::Carry); } @@ -113,35 +140,43 @@ void Cpu::Sub8(uint8_t value) void Cpu::Sub16(uint16_t value) { int32_t result; - if(CheckFlag(ProcFlags::Decimal)) { + if (CheckFlag(ProcFlags::Decimal)) + { result = (_state.A & 0x0F) + (value & 0x0F) + (_state.PS & ProcFlags::Carry); - if(result <= 0x0F) result -= 0x06; + if (result <= 0x0F) result -= 0x06; result = (_state.A & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F); - if(result <= 0xFF) result -= 0x60; + if (result <= 0xFF) result -= 0x60; result = (_state.A & 0xF00) + (value & 0xF00) + (result > 0xFF ? 0x100 : 0) + (result & 0xFF); - if(result <= 0xFFF) result -= 0x600; + if (result <= 0xFFF) result -= 0x600; result = (_state.A & 0xF000) + (value & 0xF000) + (result > 0xFFF ? 0x1000 : 0) + (result & 0xFFF); - } else { + } + else + { result = _state.A + value + (_state.PS & ProcFlags::Carry); } - if(~(_state.A ^ value) & (_state.A ^ result) & 0x8000) { + if (~(_state.A ^ value) & (_state.A ^ result) & 0x8000) + { SetFlags(ProcFlags::Overflow); - } else { + } + else + { ClearFlags(ProcFlags::Overflow); } - if(CheckFlag(ProcFlags::Decimal) && result <= 0xFFFF) { + if (CheckFlag(ProcFlags::Decimal) && result <= 0xFFFF) + { result -= 0x6000; } ClearFlags(ProcFlags::Carry | ProcFlags::Negative | ProcFlags::Zero); SetZeroNegativeFlags((uint16_t)result); - if(result > 0xFFFF) { + if (result > 0xFFFF) + { SetFlags(ProcFlags::Carry); } @@ -150,9 +185,12 @@ void Cpu::Sub16(uint16_t value) void Cpu::SBC() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { Sub8(~GetByteValue()); - } else { + } + else + { Sub16(~GetWordValue()); } } @@ -213,10 +251,12 @@ void Cpu::BVS() void Cpu::BranchRelative(bool branch) { - if(branch) { + if (branch) + { int8_t offset = _operand; Idle(); - if(_state.EmulationMode && ((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00)) { + if (_state.EmulationMode && ((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00)) + { //Extra cycle in emulation mode if crossing a page Idle(); } @@ -273,7 +313,8 @@ void Cpu::SEP() { Idle(); SetFlags((uint8_t)_operand); - if(CheckFlag(ProcFlags::IndexMode8)) { + if (CheckFlag(ProcFlags::IndexMode8)) + { //Truncate X/Y when 8-bit indexes are enabled _state.Y &= 0xFF; _state.X &= 0xFF; @@ -323,19 +364,22 @@ void Cpu::INC_Acc() SetRegister(_state.A, _state.A + 1, CheckFlag(ProcFlags::MemoryMode8)); } -void Cpu::IncDecReg(uint16_t ®, int8_t offset) +void Cpu::IncDecReg(uint16_t& reg, int8_t offset) { SetRegister(reg, reg + offset, CheckFlag(ProcFlags::IndexMode8)); } void Cpu::IncDec(int8_t offset) { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue() + offset; SetZeroNegativeFlags(value); Idle(); Write(_operand, value); - } else { + } + else + { uint16_t value = GetWordValue() + offset; SetZeroNegativeFlags(value); Idle(); @@ -348,20 +392,29 @@ Compare instructions *********************/ void Cpu::Compare(uint16_t reg, bool eightBitMode) { - if(eightBitMode) { + if (eightBitMode) + { uint8_t value = GetByteValue(); - if((uint8_t)reg >= value) { + if ((uint8_t)reg >= value) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } uint8_t result = (uint8_t)reg - value; SetZeroNegativeFlags(result); - } else { + } + else + { uint16_t value = GetWordValue(); - if(reg >= value) { + if (reg >= value) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } @@ -423,10 +476,13 @@ void Cpu::RTI() Idle(); Idle(); - if(_state.EmulationMode) { + if (_state.EmulationMode) + { SetPS(PopByte()); _state.PC = PopWord(); - } else { + } + else + { SetPS(PopByte()); _state.PC = PopWord(); _state.K = PopByte(); @@ -461,13 +517,15 @@ Interrupts ***********/ void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt) { - if(forHardwareInterrupt) { + if (forHardwareInterrupt) + { //IRQ/NMI waste 2 cycles here. BRK/COP do not (because they do those 2 cycles while loading the OP code + signature byte) ReadCode(_state.PC); Idle(); } - if(_state.EmulationMode) { + if (_state.EmulationMode) + { PushWord(_state.PC); PushByte(_state.PS | 0x20); @@ -476,7 +534,9 @@ void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt) _state.K = 0; _state.PC = ReadVector(vector); - } else { + } + else + { PushByte(_state.K); PushWord(_state.PC); PushByte(_state.PS); @@ -504,27 +564,36 @@ Bitwise operations *******************/ void Cpu::AND() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { SetRegister(_state.A, _state.A & GetByteValue(), true); - } else { + } + else + { SetRegister(_state.A, _state.A & GetWordValue(), false); } } void Cpu::EOR() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { SetRegister(_state.A, _state.A ^ GetByteValue(), true); - } else { + } + else + { SetRegister(_state.A, _state.A ^ GetWordValue(), false); } } void Cpu::ORA() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { SetRegister(_state.A, _state.A | GetByteValue(), true); - } else { + } + else + { SetRegister(_state.A, _state.A | GetWordValue(), false); } } @@ -532,48 +601,64 @@ void Cpu::ORA() /**************** Shift operations *****************/ -template T Cpu::ShiftLeft(T value) +template +T Cpu::ShiftLeft(T value) { T result = value << 1; - if(value & (1 << (sizeof(T) * 8 - 1))) { + if (value & (1 << (sizeof(T) * 8 - 1))) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } SetZeroNegativeFlags(result); return result; } -template T Cpu::RollLeft(T value) +template +T Cpu::RollLeft(T value) { T result = value << 1 | (_state.PS & ProcFlags::Carry); - if(value & (1 << (sizeof(T) * 8 - 1))) { + if (value & (1 << (sizeof(T) * 8 - 1))) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } SetZeroNegativeFlags(result); return result; } -template T Cpu::ShiftRight(T value) +template +T Cpu::ShiftRight(T value) { T result = value >> 1; - if(value & 0x01) { + if (value & 0x01) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } SetZeroNegativeFlags(result); return result; } -template T Cpu::RollRight(T value) +template +T Cpu::RollRight(T value) { T result = value >> 1 | ((_state.PS & 0x01) << (sizeof(T) * 8 - 1)); - if(value & 0x01) { + if (value & 0x01) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } SetZeroNegativeFlags(result); @@ -582,20 +667,26 @@ template T Cpu::RollRight(T value) void Cpu::ASL_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | (ShiftLeft((uint8_t)_state.A)); - } else { + } + else + { _state.A = ShiftLeft(_state.A); } } void Cpu::ASL() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, ShiftLeft(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, ShiftLeft(value)); @@ -604,20 +695,26 @@ void Cpu::ASL() void Cpu::LSR_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | ShiftRight((uint8_t)_state.A); - } else { + } + else + { _state.A = ShiftRight(_state.A); } } void Cpu::LSR() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, ShiftRight(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, ShiftRight(value)); @@ -626,20 +723,26 @@ void Cpu::LSR() void Cpu::ROL_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | RollLeft((uint8_t)_state.A); - } else { + } + else + { _state.A = RollLeft(_state.A); } } void Cpu::ROL() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, RollLeft(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, RollLeft(value)); @@ -648,20 +751,26 @@ void Cpu::ROL() void Cpu::ROR_Acc() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { _state.A = (_state.A & 0xFF00) | RollRight((uint8_t)_state.A); - } else { + } + else + { _state.A = RollRight(_state.A); } } void Cpu::ROR() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); Idle(); Write(_operand, RollRight(value)); - } else { + } + else + { uint16_t value = GetWordValue(); Idle(); WriteWord(_operand, RollRight(value)); @@ -685,14 +794,16 @@ void Cpu::MVN() _state.X++; _state.Y++; - if(CheckFlag(ProcFlags::IndexMode8)) { + if (CheckFlag(ProcFlags::IndexMode8)) + { _state.X &= 0xFF; _state.Y &= 0xFF; } _state.A--; - if(_state.A != 0xFFFF) { + if (_state.A != 0xFFFF) + { //Operation isn't done, set the PC back to the start of the instruction _state.PC -= 3; } @@ -712,14 +823,16 @@ void Cpu::MVP() _state.X--; _state.Y--; - if(CheckFlag(ProcFlags::IndexMode8)) { + if (CheckFlag(ProcFlags::IndexMode8)) + { _state.X &= 0xFF; _state.Y &= 0xFF; } _state.A--; - - if(_state.A != 0xFFFF) { + + if (_state.A != 0xFFFF) + { //Operation isn't done, set the PC back to the start of the instruction _state.PC -= 3; } @@ -793,9 +906,12 @@ void Cpu::PLP() //"For PLP, (all of) the flags are pulled from the stack. Note that when the e flag is 1, the m and x flag are forced to 1, so after the PLP, both flags will still be 1 no matter what value is pulled from the stack." Idle(); Idle(); - if(_state.EmulationMode) { + if (_state.EmulationMode) + { SetPS(PopByte() | ProcFlags::MemoryMode8 | ProcFlags::IndexMode8); - } else { + } + else + { SetPS(PopByte()); } } @@ -844,19 +960,25 @@ void Cpu::PLY() void Cpu::PushRegister(uint16_t reg, bool eightBitMode) { //"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value." - if(eightBitMode) { + if (eightBitMode) + { PushByte((uint8_t)reg); - } else { + } + else + { PushWord(reg); } } -void Cpu::PullRegister(uint16_t ®, bool eightBitMode) +void Cpu::PullRegister(uint16_t& reg, bool eightBitMode) { //"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value." - if(eightBitMode) { + if (eightBitMode) + { SetRegister(reg, PopByte(), true); - } else { + } + else + { SetRegister(reg, PopWord(), false); } } @@ -864,20 +986,26 @@ void Cpu::PullRegister(uint16_t ®, bool eightBitMode) /********************* Store/load operations **********************/ -void Cpu::LoadRegister(uint16_t ®, bool eightBitMode) +void Cpu::LoadRegister(uint16_t& reg, bool eightBitMode) { - if(eightBitMode) { + if (eightBitMode) + { SetRegister(reg, GetByteValue(), true); - } else { + } + else + { SetRegister(reg, GetWordValue(), false); } } void Cpu::StoreRegister(uint16_t val, bool eightBitMode) { - if(eightBitMode) { + if (eightBitMode) + { Write(_operand, (uint8_t)val); - } else { + } + else + { WriteWord(_operand, val); } } @@ -927,26 +1055,36 @@ void Cpu::STZ() /******************* Bit test operations ********************/ -template void Cpu::TestBits(T value, bool alterZeroFlagOnly) +template +void Cpu::TestBits(T value, bool alterZeroFlagOnly) { - if(alterZeroFlagOnly) { + if (alterZeroFlagOnly) + { //"Immediate addressing only affects the z flag (with the result of the bitwise And), but does not affect the n and v flags." - if(((T)_state.A & value) == 0) { + if (((T)_state.A & value) == 0) + { SetFlags(ProcFlags::Zero); - } else { + } + else + { ClearFlags(ProcFlags::Zero); } - } else { + } + else + { ClearFlags(ProcFlags::Zero | ProcFlags::Overflow | ProcFlags::Negative); - if(((T)_state.A & value) == 0) { + if (((T)_state.A & value) == 0) + { SetFlags(ProcFlags::Zero); } - if(value & (1 << (sizeof(T) * 8 - 2))) { + if (value & (1 << (sizeof(T) * 8 - 2))) + { SetFlags(ProcFlags::Overflow); } - if(value & (1 << (sizeof(T) * 8 - 1))) { + if (value & (1 << (sizeof(T) * 8 - 1))) + { SetFlags(ProcFlags::Negative); } } @@ -954,16 +1092,20 @@ template void Cpu::TestBits(T value, bool alterZeroFlagOnly) void Cpu::BIT() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { TestBits(GetByteValue(), _immediateMode); - } else { + } + else + { TestBits(GetWordValue(), _immediateMode); } } void Cpu::TRB() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); TestBits(value, true); @@ -971,7 +1113,9 @@ void Cpu::TRB() Idle(); Write(_operand, value); - } else { + } + else + { uint16_t value = GetWordValue(); TestBits(value, true); @@ -984,7 +1128,8 @@ void Cpu::TRB() void Cpu::TSB() { - if(CheckFlag(ProcFlags::MemoryMode8)) { + if (CheckFlag(ProcFlags::MemoryMode8)) + { uint8_t value = GetByteValue(); TestBits(value, true); @@ -992,7 +1137,9 @@ void Cpu::TSB() Idle(); Write(_operand, value); - } else { + } + else + { uint16_t value = GetWordValue(); TestBits(value, true); @@ -1076,14 +1223,18 @@ void Cpu::XBA() void Cpu::XCE() { bool carry = CheckFlag(ProcFlags::Carry); - if(_state.EmulationMode) { + if (_state.EmulationMode) + { SetFlags(ProcFlags::Carry); - } else { + } + else + { ClearFlags(ProcFlags::Carry); } _state.EmulationMode = carry; - if(_state.EmulationMode) { + if (_state.EmulationMode) + { SetPS(_state.PS | ProcFlags::IndexMode8 | ProcFlags::MemoryMode8); _state.SP = 0x100 | (_state.SP & 0xFF); } @@ -1129,7 +1280,8 @@ void Cpu::AddrMode_AbsIdxX(bool isWrite) { uint32_t baseAddr = GetDataAddress(ReadOperandWord()); _operand = (baseAddr + _state.X) & 0xFFFFFF; - if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) { + if (isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) + { Idle(); } } @@ -1138,7 +1290,8 @@ void Cpu::AddrMode_AbsIdxY(bool isWrite) { uint32_t baseAddr = GetDataAddress(ReadOperandWord()); _operand = (baseAddr + _state.Y) & 0xFFFFFF; - if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) { + if (isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) + { Idle(); } } @@ -1192,7 +1345,8 @@ void Cpu::AddrMode_BlkMov() uint8_t Cpu::ReadDirectOperandByte() { uint8_t value = ReadOperandByte(); - if(_state.D & 0xFF) { + if (_state.D & 0xFF) + { //Add 1 cycle for direct register low (DL) not equal 0 Idle(); } @@ -1232,8 +1386,9 @@ void Cpu::AddrMode_DirIndIdxY(bool isWrite) { uint32_t baseAddr = GetDataAddress(GetDirectAddressIndirectWord(ReadDirectOperandByte())); _operand = (baseAddr + _state.Y) & 0xFFFFFF; - - if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) { + + if (isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) + { Idle(); } } @@ -1268,7 +1423,7 @@ void Cpu::AddrMode_ImmX() void Cpu::AddrMode_ImmM() { - _immediateMode = true; + _immediateMode = true; _operand = CheckFlag(ProcFlags::MemoryMode8) ? ReadOperandByte() : ReadOperandWord(); } diff --git a/Core/Cpu.Shared.h b/Core/Cpu.Shared.h index 309da55..e3a8190 100644 --- a/Core/Cpu.Shared.h +++ b/Core/Cpu.Shared.h @@ -39,263 +39,761 @@ void Cpu::Reset() void Cpu::RunOp() { - switch(GetOpCode()) { - case 0x00: AddrMode_Imm8(); BRK(); break; - case 0x01: AddrMode_DirIdxIndX(); ORA(); break; - case 0x02: AddrMode_Imm8(); COP(); break; - case 0x03: AddrMode_StkRel(); ORA(); break; - case 0x04: AddrMode_Dir(); TSB(); break; - case 0x05: AddrMode_Dir(); ORA(); break; - case 0x06: AddrMode_Dir(); ASL(); break; - case 0x07: AddrMode_DirIndLng(); ORA(); break; - case 0x08: PHP(); break; - case 0x09: AddrMode_ImmM(); ORA(); break; - case 0x0A: AddrMode_Acc(); ASL_Acc(); break; - case 0x0B: PHD(); break; - case 0x0C: AddrMode_Abs(); TSB(); break; - case 0x0D: AddrMode_Abs(); ORA(); break; - case 0x0E: AddrMode_Abs(); ASL(); break; - case 0x0F: AddrMode_AbsLng(); ORA(); break; - case 0x10: AddrMode_Rel(); BPL(); break; - case 0x11: AddrMode_DirIndIdxY(false); ORA(); break; - case 0x12: AddrMode_DirInd(); ORA(); break; - case 0x13: AddrMode_StkRelIndIdxY(); ORA(); break; - case 0x14: AddrMode_Dir(); TRB(); break; - case 0x15: AddrMode_DirIdxX(); ORA(); break; - case 0x16: AddrMode_DirIdxX(); ASL(); break; - case 0x17: AddrMode_DirIndLngIdxY(); ORA(); break; - case 0x18: AddrMode_Imp(); CLC(); break; - case 0x19: AddrMode_AbsIdxY(false); ORA(); break; - case 0x1A: AddrMode_Acc(); INC_Acc(); break; - case 0x1B: AddrMode_Imp(); TCS(); break; - case 0x1C: AddrMode_Abs(); TRB(); break; - case 0x1D: AddrMode_AbsIdxX(false); ORA(); break; - case 0x1E: AddrMode_AbsIdxX(true); ASL(); break; - case 0x1F: AddrMode_AbsLngIdxX(); ORA(); break; - case 0x20: AddrMode_AbsJmp(); Idle(); JSR(); break; - case 0x21: AddrMode_DirIdxIndX(); AND(); break; - case 0x22: AddrMode_AbsLngJmp(); JSL(); break; - case 0x23: AddrMode_StkRel(); AND(); break; - case 0x24: AddrMode_Dir(); BIT(); break; - case 0x25: AddrMode_Dir(); AND(); break; - case 0x26: AddrMode_Dir(); ROL(); break; - case 0x27: AddrMode_DirIndLng(); AND(); break; - case 0x28: PLP(); break; - case 0x29: AddrMode_ImmM(); AND(); break; - case 0x2A: AddrMode_Acc(); ROL_Acc(); break; - case 0x2B: PLD(); break; - case 0x2C: AddrMode_Abs(); BIT(); break; - case 0x2D: AddrMode_Abs(); AND(); break; - case 0x2E: AddrMode_Abs(); ROL(); break; - case 0x2F: AddrMode_AbsLng(); AND(); break; - case 0x30: AddrMode_Rel(); BMI(); break; - case 0x31: AddrMode_DirIndIdxY(false); AND(); break; - case 0x32: AddrMode_DirInd(); AND(); break; - case 0x33: AddrMode_StkRelIndIdxY(); AND(); break; - case 0x34: AddrMode_DirIdxX(); BIT(); break; - case 0x35: AddrMode_DirIdxX(); AND(); break; - case 0x36: AddrMode_DirIdxX(); ROL(); break; - case 0x37: AddrMode_DirIndLngIdxY(); AND(); break; - case 0x38: AddrMode_Imp(); SEC(); break; - case 0x39: AddrMode_AbsIdxY(false); AND(); break; - case 0x3A: AddrMode_Acc(); DEC_Acc(); break; - case 0x3B: AddrMode_Imp(); TSC(); break; - case 0x3C: AddrMode_AbsIdxX(false); BIT(); break; - case 0x3D: AddrMode_AbsIdxX(false); AND(); break; - case 0x3E: AddrMode_AbsIdxX(true); ROL(); break; - case 0x3F: AddrMode_AbsLngIdxX(); AND(); break; - case 0x40: RTI(); break; - case 0x41: AddrMode_DirIdxIndX(); EOR(); break; - case 0x42: AddrMode_Imm8(); WDM(); break; - case 0x43: AddrMode_StkRel(); EOR(); break; - case 0x44: AddrMode_BlkMov(); MVP(); break; - case 0x45: AddrMode_Dir(); EOR(); break; - case 0x46: AddrMode_Dir(); LSR(); break; - case 0x47: AddrMode_DirIndLng(); EOR(); break; - case 0x48: PHA(); break; - case 0x49: AddrMode_ImmM(); EOR(); break; - case 0x4A: AddrMode_Acc(); LSR_Acc(); break; - case 0x4B: PHK(); break; - case 0x4C: AddrMode_AbsJmp(); JMP(); break; - case 0x4D: AddrMode_Abs(); EOR(); break; - case 0x4E: AddrMode_Abs(); LSR(); break; - case 0x4F: AddrMode_AbsLng(); EOR(); break; - case 0x50: AddrMode_Rel(); BVC(); break; - case 0x51: AddrMode_DirIndIdxY(false); EOR(); break; - case 0x52: AddrMode_DirInd(); EOR(); break; - case 0x53: AddrMode_StkRelIndIdxY(); EOR(); break; - case 0x54: AddrMode_BlkMov(); MVN(); break; - case 0x55: AddrMode_DirIdxX(); EOR(); break; - case 0x56: AddrMode_DirIdxX(); LSR(); break; - case 0x57: AddrMode_DirIndLngIdxY(); EOR(); break; - case 0x58: AddrMode_Imp(); CLI(); break; - case 0x59: AddrMode_AbsIdxY(false); EOR(); break; - case 0x5A: PHY(); break; - case 0x5B: AddrMode_Imp(); TCD(); break; - case 0x5C: AddrMode_AbsLngJmp(); JML(); break; - case 0x5D: AddrMode_AbsIdxX(false); EOR(); break; - case 0x5E: AddrMode_AbsIdxX(true); LSR(); break; - case 0x5F: AddrMode_AbsLngIdxX(); EOR(); break; - case 0x60: RTS(); break; - case 0x61: AddrMode_DirIdxIndX(); ADC(); break; - case 0x62: AddrMode_RelLng(); PER(); break; - case 0x63: AddrMode_StkRel(); ADC(); break; - case 0x64: AddrMode_Dir(); STZ(); break; - case 0x65: AddrMode_Dir(); ADC(); break; - case 0x66: AddrMode_Dir(); ROR(); break; - case 0x67: AddrMode_DirIndLng(); ADC(); break; - case 0x68: PLA(); break; - case 0x69: AddrMode_ImmM(); ADC(); break; - case 0x6A: AddrMode_Acc(); ROR_Acc(); break; - case 0x6B: RTL(); break; - case 0x6C: AddrMode_AbsInd(); JMP(); break; - case 0x6D: AddrMode_Abs(); ADC(); break; - case 0x6E: AddrMode_Abs(); ROR(); break; - case 0x6F: AddrMode_AbsLng(); ADC(); break; - case 0x70: AddrMode_Rel(); BVS(); break; - case 0x71: AddrMode_DirIndIdxY(false); ADC(); break; - case 0x72: AddrMode_DirInd(); ADC(); break; - case 0x73: AddrMode_StkRelIndIdxY(); ADC(); break; - case 0x74: AddrMode_DirIdxX(); STZ(); break; - case 0x75: AddrMode_DirIdxX(); ADC(); break; - case 0x76: AddrMode_DirIdxX(); ROR(); break; - case 0x77: AddrMode_DirIndLngIdxY(); ADC(); break; - case 0x78: AddrMode_Imp(); SEI(); break; - case 0x79: AddrMode_AbsIdxY(false); ADC(); break; - case 0x7A: PLY(); break; - case 0x7B: AddrMode_Imp(); TDC(); break; - case 0x7C: AddrMode_AbsIdxXInd(); JMP(); break; - case 0x7D: AddrMode_AbsIdxX(false); ADC(); break; - case 0x7E: AddrMode_AbsIdxX(true); ROR(); break; - case 0x7F: AddrMode_AbsLngIdxX(); ADC(); break; - case 0x80: AddrMode_Rel(); BRA(); break; - case 0x81: AddrMode_DirIdxIndX(); STA(); break; - case 0x82: AddrMode_RelLng(); BRL(); break; - case 0x83: AddrMode_StkRel(); STA(); break; - case 0x84: AddrMode_Dir(); STY(); break; - case 0x85: AddrMode_Dir(); STA(); break; - case 0x86: AddrMode_Dir(); STX(); break; - case 0x87: AddrMode_DirIndLng(); STA(); break; - case 0x88: AddrMode_Imp(); DEY(); break; - case 0x89: AddrMode_ImmM(); BIT(); break; - case 0x8A: AddrMode_Imp(); TXA(); break; - case 0x8B: PHB(); break; - case 0x8C: AddrMode_Abs(); STY(); break; - case 0x8D: AddrMode_Abs(); STA(); break; - case 0x8E: AddrMode_Abs(); STX(); break; - case 0x8F: AddrMode_AbsLng(); STA(); break; - case 0x90: AddrMode_Rel(); BCC(); break; - case 0x91: AddrMode_DirIndIdxY(true); STA(); break; - case 0x92: AddrMode_DirInd(); STA(); break; - case 0x93: AddrMode_StkRelIndIdxY(); STA(); break; - case 0x94: AddrMode_DirIdxX(); STY(); break; - case 0x95: AddrMode_DirIdxX(); STA(); break; - case 0x96: AddrMode_DirIdxY(); STX(); break; - case 0x97: AddrMode_DirIndLngIdxY(); STA(); break; - case 0x98: AddrMode_Imp(); TYA(); break; - case 0x99: AddrMode_AbsIdxY(true); STA(); break; - case 0x9A: AddrMode_Imp(); TXS(); break; - case 0x9B: AddrMode_Imp(); TXY(); break; - case 0x9C: AddrMode_Abs(); STZ(); break; - case 0x9D: AddrMode_AbsIdxX(true); STA(); break; - case 0x9E: AddrMode_AbsIdxX(true); STZ(); break; - case 0x9F: AddrMode_AbsLngIdxX(); STA(); break; - case 0xA0: AddrMode_ImmX(); LDY(); break; - case 0xA1: AddrMode_DirIdxIndX(); LDA(); break; - case 0xA2: AddrMode_ImmX(); LDX(); break; - case 0xA3: AddrMode_StkRel(); LDA(); break; - case 0xA4: AddrMode_Dir(); LDY(); break; - case 0xA5: AddrMode_Dir(); LDA(); break; - case 0xA6: AddrMode_Dir(); LDX(); break; - case 0xA7: AddrMode_DirIndLng(); LDA(); break; - case 0xA8: AddrMode_Imp(); TAY(); break; - case 0xA9: AddrMode_ImmM(); LDA(); break; - case 0xAA: AddrMode_Imp(); TAX(); break; - case 0xAB: PLB(); break; - case 0xAC: AddrMode_Abs(); LDY(); break; - case 0xAD: AddrMode_Abs(); LDA(); break; - case 0xAE: AddrMode_Abs(); LDX(); break; - case 0xAF: AddrMode_AbsLng(); LDA(); break; - case 0xB0: AddrMode_Rel(); BCS(); break; - case 0xB1: AddrMode_DirIndIdxY(false); LDA(); break; - case 0xB2: AddrMode_DirInd(); LDA(); break; - case 0xB3: AddrMode_StkRelIndIdxY(); LDA(); break; - case 0xB4: AddrMode_DirIdxX(); LDY(); break; - case 0xB5: AddrMode_DirIdxX(); LDA(); break; - case 0xB6: AddrMode_DirIdxY(); LDX(); break; - case 0xB7: AddrMode_DirIndLngIdxY(); LDA(); break; - case 0xB8: AddrMode_Imp(); CLV(); break; - case 0xB9: AddrMode_AbsIdxY(false); LDA(); break; - case 0xBA: AddrMode_Imp(); TSX(); break; - case 0xBB: AddrMode_Imp(); TYX(); break; - case 0xBC: AddrMode_AbsIdxX(false); LDY(); break; - case 0xBD: AddrMode_AbsIdxX(false); LDA(); break; - case 0xBE: AddrMode_AbsIdxY(false); LDX(); break; - case 0xBF: AddrMode_AbsLngIdxX(); LDA(); break; - case 0xC0: AddrMode_ImmX(); CPY(); break; - case 0xC1: AddrMode_DirIdxIndX(); CMP(); break; - case 0xC2: AddrMode_Imm8(); REP(); break; - case 0xC3: AddrMode_StkRel(); CMP(); break; - case 0xC4: AddrMode_Dir(); CPY(); break; - case 0xC5: AddrMode_Dir(); CMP(); break; - case 0xC6: AddrMode_Dir(); DEC(); break; - case 0xC7: AddrMode_DirIndLng(); CMP(); break; - case 0xC8: AddrMode_Imp(); INY(); break; - case 0xC9: AddrMode_ImmM(); CMP(); break; - case 0xCA: AddrMode_Imp(); DEX(); break; - case 0xCB: AddrMode_Imp(); WAI(); break; - case 0xCC: AddrMode_Abs(); CPY(); break; - case 0xCD: AddrMode_Abs(); CMP(); break; - case 0xCE: AddrMode_Abs(); DEC(); break; - case 0xCF: AddrMode_AbsLng(); CMP(); break; - case 0xD0: AddrMode_Rel(); BNE(); break; - case 0xD1: AddrMode_DirIndIdxY(false); CMP(); break; - case 0xD2: AddrMode_DirInd(); CMP(); break; - case 0xD3: AddrMode_StkRelIndIdxY(); CMP(); break; - case 0xD4: AddrMode_Dir(); PEI(); break; - case 0xD5: AddrMode_DirIdxX(); CMP(); break; - case 0xD6: AddrMode_DirIdxX(); DEC(); break; - case 0xD7: AddrMode_DirIndLngIdxY(); CMP(); break; - case 0xD8: AddrMode_Imp(); CLD(); break; - case 0xD9: AddrMode_AbsIdxY(false); CMP(); break; - case 0xDA: PHX(); break; - case 0xDB: AddrMode_Imp(); STP(); break; - case 0xDC: AddrMode_AbsIndLng(); JML(); break; - case 0xDD: AddrMode_AbsIdxX(false); CMP(); break; - case 0xDE: AddrMode_AbsIdxX(true); DEC(); break; - case 0xDF: AddrMode_AbsLngIdxX(); CMP(); break; - case 0xE0: AddrMode_ImmX(); CPX(); break; - case 0xE1: AddrMode_DirIdxIndX(); SBC(); break; - case 0xE2: AddrMode_Imm8(); SEP(); break; - case 0xE3: AddrMode_StkRel(); SBC(); break; - case 0xE4: AddrMode_Dir(); CPX(); break; - case 0xE5: AddrMode_Dir(); SBC(); break; - case 0xE6: AddrMode_Dir(); INC(); break; - case 0xE7: AddrMode_DirIndLng(); SBC(); break; - case 0xE8: AddrMode_Imp(); INX(); break; - case 0xE9: AddrMode_ImmM(); SBC(); break; - case 0xEA: AddrMode_Imp(); NOP(); break; - case 0xEB: AddrMode_Imp(); XBA(); break; - case 0xEC: AddrMode_Abs(); CPX(); break; - case 0xED: AddrMode_Abs(); SBC(); break; - case 0xEE: AddrMode_Abs(); INC(); break; - case 0xEF: AddrMode_AbsLng(); SBC(); break; - case 0xF0: AddrMode_Rel(); BEQ(); break; - case 0xF1: AddrMode_DirIndIdxY(false); SBC(); break; - case 0xF2: AddrMode_DirInd(); SBC(); break; - case 0xF3: AddrMode_StkRelIndIdxY(); SBC(); break; - case 0xF4: AddrMode_Imm16(); PEA(); break; - case 0xF5: AddrMode_DirIdxX(); SBC(); break; - case 0xF6: AddrMode_DirIdxX(); INC(); break; - case 0xF7: AddrMode_DirIndLngIdxY(); SBC(); break; - case 0xF8: AddrMode_Imp(); SED(); break; - case 0xF9: AddrMode_AbsIdxY(false); SBC(); break; - case 0xFA: PLX(); break; - case 0xFB: AddrMode_Imp(); XCE(); break; - case 0xFC: AddrMode_AbsIdxXInd(); JSR(); break; - case 0xFD: AddrMode_AbsIdxX(false); SBC(); break; - case 0xFE: AddrMode_AbsIdxX(true); INC(); break; - case 0xFF: AddrMode_AbsLngIdxX(); SBC(); break; + switch (GetOpCode()) + { + case 0x00: AddrMode_Imm8(); + BRK(); + break; + case 0x01: AddrMode_DirIdxIndX(); + ORA(); + break; + case 0x02: AddrMode_Imm8(); + COP(); + break; + case 0x03: AddrMode_StkRel(); + ORA(); + break; + case 0x04: AddrMode_Dir(); + TSB(); + break; + case 0x05: AddrMode_Dir(); + ORA(); + break; + case 0x06: AddrMode_Dir(); + ASL(); + break; + case 0x07: AddrMode_DirIndLng(); + ORA(); + break; + case 0x08: PHP(); + break; + case 0x09: AddrMode_ImmM(); + ORA(); + break; + case 0x0A: AddrMode_Acc(); + ASL_Acc(); + break; + case 0x0B: PHD(); + break; + case 0x0C: AddrMode_Abs(); + TSB(); + break; + case 0x0D: AddrMode_Abs(); + ORA(); + break; + case 0x0E: AddrMode_Abs(); + ASL(); + break; + case 0x0F: AddrMode_AbsLng(); + ORA(); + break; + case 0x10: AddrMode_Rel(); + BPL(); + break; + case 0x11: AddrMode_DirIndIdxY(false); + ORA(); + break; + case 0x12: AddrMode_DirInd(); + ORA(); + break; + case 0x13: AddrMode_StkRelIndIdxY(); + ORA(); + break; + case 0x14: AddrMode_Dir(); + TRB(); + break; + case 0x15: AddrMode_DirIdxX(); + ORA(); + break; + case 0x16: AddrMode_DirIdxX(); + ASL(); + break; + case 0x17: AddrMode_DirIndLngIdxY(); + ORA(); + break; + case 0x18: AddrMode_Imp(); + CLC(); + break; + case 0x19: AddrMode_AbsIdxY(false); + ORA(); + break; + case 0x1A: AddrMode_Acc(); + INC_Acc(); + break; + case 0x1B: AddrMode_Imp(); + TCS(); + break; + case 0x1C: AddrMode_Abs(); + TRB(); + break; + case 0x1D: AddrMode_AbsIdxX(false); + ORA(); + break; + case 0x1E: AddrMode_AbsIdxX(true); + ASL(); + break; + case 0x1F: AddrMode_AbsLngIdxX(); + ORA(); + break; + case 0x20: AddrMode_AbsJmp(); + Idle(); + JSR(); + break; + case 0x21: AddrMode_DirIdxIndX(); + AND(); + break; + case 0x22: AddrMode_AbsLngJmp(); + JSL(); + break; + case 0x23: AddrMode_StkRel(); + AND(); + break; + case 0x24: AddrMode_Dir(); + BIT(); + break; + case 0x25: AddrMode_Dir(); + AND(); + break; + case 0x26: AddrMode_Dir(); + ROL(); + break; + case 0x27: AddrMode_DirIndLng(); + AND(); + break; + case 0x28: PLP(); + break; + case 0x29: AddrMode_ImmM(); + AND(); + break; + case 0x2A: AddrMode_Acc(); + ROL_Acc(); + break; + case 0x2B: PLD(); + break; + case 0x2C: AddrMode_Abs(); + BIT(); + break; + case 0x2D: AddrMode_Abs(); + AND(); + break; + case 0x2E: AddrMode_Abs(); + ROL(); + break; + case 0x2F: AddrMode_AbsLng(); + AND(); + break; + case 0x30: AddrMode_Rel(); + BMI(); + break; + case 0x31: AddrMode_DirIndIdxY(false); + AND(); + break; + case 0x32: AddrMode_DirInd(); + AND(); + break; + case 0x33: AddrMode_StkRelIndIdxY(); + AND(); + break; + case 0x34: AddrMode_DirIdxX(); + BIT(); + break; + case 0x35: AddrMode_DirIdxX(); + AND(); + break; + case 0x36: AddrMode_DirIdxX(); + ROL(); + break; + case 0x37: AddrMode_DirIndLngIdxY(); + AND(); + break; + case 0x38: AddrMode_Imp(); + SEC(); + break; + case 0x39: AddrMode_AbsIdxY(false); + AND(); + break; + case 0x3A: AddrMode_Acc(); + DEC_Acc(); + break; + case 0x3B: AddrMode_Imp(); + TSC(); + break; + case 0x3C: AddrMode_AbsIdxX(false); + BIT(); + break; + case 0x3D: AddrMode_AbsIdxX(false); + AND(); + break; + case 0x3E: AddrMode_AbsIdxX(true); + ROL(); + break; + case 0x3F: AddrMode_AbsLngIdxX(); + AND(); + break; + case 0x40: RTI(); + break; + case 0x41: AddrMode_DirIdxIndX(); + EOR(); + break; + case 0x42: AddrMode_Imm8(); + WDM(); + break; + case 0x43: AddrMode_StkRel(); + EOR(); + break; + case 0x44: AddrMode_BlkMov(); + MVP(); + break; + case 0x45: AddrMode_Dir(); + EOR(); + break; + case 0x46: AddrMode_Dir(); + LSR(); + break; + case 0x47: AddrMode_DirIndLng(); + EOR(); + break; + case 0x48: PHA(); + break; + case 0x49: AddrMode_ImmM(); + EOR(); + break; + case 0x4A: AddrMode_Acc(); + LSR_Acc(); + break; + case 0x4B: PHK(); + break; + case 0x4C: AddrMode_AbsJmp(); + JMP(); + break; + case 0x4D: AddrMode_Abs(); + EOR(); + break; + case 0x4E: AddrMode_Abs(); + LSR(); + break; + case 0x4F: AddrMode_AbsLng(); + EOR(); + break; + case 0x50: AddrMode_Rel(); + BVC(); + break; + case 0x51: AddrMode_DirIndIdxY(false); + EOR(); + break; + case 0x52: AddrMode_DirInd(); + EOR(); + break; + case 0x53: AddrMode_StkRelIndIdxY(); + EOR(); + break; + case 0x54: AddrMode_BlkMov(); + MVN(); + break; + case 0x55: AddrMode_DirIdxX(); + EOR(); + break; + case 0x56: AddrMode_DirIdxX(); + LSR(); + break; + case 0x57: AddrMode_DirIndLngIdxY(); + EOR(); + break; + case 0x58: AddrMode_Imp(); + CLI(); + break; + case 0x59: AddrMode_AbsIdxY(false); + EOR(); + break; + case 0x5A: PHY(); + break; + case 0x5B: AddrMode_Imp(); + TCD(); + break; + case 0x5C: AddrMode_AbsLngJmp(); + JML(); + break; + case 0x5D: AddrMode_AbsIdxX(false); + EOR(); + break; + case 0x5E: AddrMode_AbsIdxX(true); + LSR(); + break; + case 0x5F: AddrMode_AbsLngIdxX(); + EOR(); + break; + case 0x60: RTS(); + break; + case 0x61: AddrMode_DirIdxIndX(); + ADC(); + break; + case 0x62: AddrMode_RelLng(); + PER(); + break; + case 0x63: AddrMode_StkRel(); + ADC(); + break; + case 0x64: AddrMode_Dir(); + STZ(); + break; + case 0x65: AddrMode_Dir(); + ADC(); + break; + case 0x66: AddrMode_Dir(); + ROR(); + break; + case 0x67: AddrMode_DirIndLng(); + ADC(); + break; + case 0x68: PLA(); + break; + case 0x69: AddrMode_ImmM(); + ADC(); + break; + case 0x6A: AddrMode_Acc(); + ROR_Acc(); + break; + case 0x6B: RTL(); + break; + case 0x6C: AddrMode_AbsInd(); + JMP(); + break; + case 0x6D: AddrMode_Abs(); + ADC(); + break; + case 0x6E: AddrMode_Abs(); + ROR(); + break; + case 0x6F: AddrMode_AbsLng(); + ADC(); + break; + case 0x70: AddrMode_Rel(); + BVS(); + break; + case 0x71: AddrMode_DirIndIdxY(false); + ADC(); + break; + case 0x72: AddrMode_DirInd(); + ADC(); + break; + case 0x73: AddrMode_StkRelIndIdxY(); + ADC(); + break; + case 0x74: AddrMode_DirIdxX(); + STZ(); + break; + case 0x75: AddrMode_DirIdxX(); + ADC(); + break; + case 0x76: AddrMode_DirIdxX(); + ROR(); + break; + case 0x77: AddrMode_DirIndLngIdxY(); + ADC(); + break; + case 0x78: AddrMode_Imp(); + SEI(); + break; + case 0x79: AddrMode_AbsIdxY(false); + ADC(); + break; + case 0x7A: PLY(); + break; + case 0x7B: AddrMode_Imp(); + TDC(); + break; + case 0x7C: AddrMode_AbsIdxXInd(); + JMP(); + break; + case 0x7D: AddrMode_AbsIdxX(false); + ADC(); + break; + case 0x7E: AddrMode_AbsIdxX(true); + ROR(); + break; + case 0x7F: AddrMode_AbsLngIdxX(); + ADC(); + break; + case 0x80: AddrMode_Rel(); + BRA(); + break; + case 0x81: AddrMode_DirIdxIndX(); + STA(); + break; + case 0x82: AddrMode_RelLng(); + BRL(); + break; + case 0x83: AddrMode_StkRel(); + STA(); + break; + case 0x84: AddrMode_Dir(); + STY(); + break; + case 0x85: AddrMode_Dir(); + STA(); + break; + case 0x86: AddrMode_Dir(); + STX(); + break; + case 0x87: AddrMode_DirIndLng(); + STA(); + break; + case 0x88: AddrMode_Imp(); + DEY(); + break; + case 0x89: AddrMode_ImmM(); + BIT(); + break; + case 0x8A: AddrMode_Imp(); + TXA(); + break; + case 0x8B: PHB(); + break; + case 0x8C: AddrMode_Abs(); + STY(); + break; + case 0x8D: AddrMode_Abs(); + STA(); + break; + case 0x8E: AddrMode_Abs(); + STX(); + break; + case 0x8F: AddrMode_AbsLng(); + STA(); + break; + case 0x90: AddrMode_Rel(); + BCC(); + break; + case 0x91: AddrMode_DirIndIdxY(true); + STA(); + break; + case 0x92: AddrMode_DirInd(); + STA(); + break; + case 0x93: AddrMode_StkRelIndIdxY(); + STA(); + break; + case 0x94: AddrMode_DirIdxX(); + STY(); + break; + case 0x95: AddrMode_DirIdxX(); + STA(); + break; + case 0x96: AddrMode_DirIdxY(); + STX(); + break; + case 0x97: AddrMode_DirIndLngIdxY(); + STA(); + break; + case 0x98: AddrMode_Imp(); + TYA(); + break; + case 0x99: AddrMode_AbsIdxY(true); + STA(); + break; + case 0x9A: AddrMode_Imp(); + TXS(); + break; + case 0x9B: AddrMode_Imp(); + TXY(); + break; + case 0x9C: AddrMode_Abs(); + STZ(); + break; + case 0x9D: AddrMode_AbsIdxX(true); + STA(); + break; + case 0x9E: AddrMode_AbsIdxX(true); + STZ(); + break; + case 0x9F: AddrMode_AbsLngIdxX(); + STA(); + break; + case 0xA0: AddrMode_ImmX(); + LDY(); + break; + case 0xA1: AddrMode_DirIdxIndX(); + LDA(); + break; + case 0xA2: AddrMode_ImmX(); + LDX(); + break; + case 0xA3: AddrMode_StkRel(); + LDA(); + break; + case 0xA4: AddrMode_Dir(); + LDY(); + break; + case 0xA5: AddrMode_Dir(); + LDA(); + break; + case 0xA6: AddrMode_Dir(); + LDX(); + break; + case 0xA7: AddrMode_DirIndLng(); + LDA(); + break; + case 0xA8: AddrMode_Imp(); + TAY(); + break; + case 0xA9: AddrMode_ImmM(); + LDA(); + break; + case 0xAA: AddrMode_Imp(); + TAX(); + break; + case 0xAB: PLB(); + break; + case 0xAC: AddrMode_Abs(); + LDY(); + break; + case 0xAD: AddrMode_Abs(); + LDA(); + break; + case 0xAE: AddrMode_Abs(); + LDX(); + break; + case 0xAF: AddrMode_AbsLng(); + LDA(); + break; + case 0xB0: AddrMode_Rel(); + BCS(); + break; + case 0xB1: AddrMode_DirIndIdxY(false); + LDA(); + break; + case 0xB2: AddrMode_DirInd(); + LDA(); + break; + case 0xB3: AddrMode_StkRelIndIdxY(); + LDA(); + break; + case 0xB4: AddrMode_DirIdxX(); + LDY(); + break; + case 0xB5: AddrMode_DirIdxX(); + LDA(); + break; + case 0xB6: AddrMode_DirIdxY(); + LDX(); + break; + case 0xB7: AddrMode_DirIndLngIdxY(); + LDA(); + break; + case 0xB8: AddrMode_Imp(); + CLV(); + break; + case 0xB9: AddrMode_AbsIdxY(false); + LDA(); + break; + case 0xBA: AddrMode_Imp(); + TSX(); + break; + case 0xBB: AddrMode_Imp(); + TYX(); + break; + case 0xBC: AddrMode_AbsIdxX(false); + LDY(); + break; + case 0xBD: AddrMode_AbsIdxX(false); + LDA(); + break; + case 0xBE: AddrMode_AbsIdxY(false); + LDX(); + break; + case 0xBF: AddrMode_AbsLngIdxX(); + LDA(); + break; + case 0xC0: AddrMode_ImmX(); + CPY(); + break; + case 0xC1: AddrMode_DirIdxIndX(); + CMP(); + break; + case 0xC2: AddrMode_Imm8(); + REP(); + break; + case 0xC3: AddrMode_StkRel(); + CMP(); + break; + case 0xC4: AddrMode_Dir(); + CPY(); + break; + case 0xC5: AddrMode_Dir(); + CMP(); + break; + case 0xC6: AddrMode_Dir(); + DEC(); + break; + case 0xC7: AddrMode_DirIndLng(); + CMP(); + break; + case 0xC8: AddrMode_Imp(); + INY(); + break; + case 0xC9: AddrMode_ImmM(); + CMP(); + break; + case 0xCA: AddrMode_Imp(); + DEX(); + break; + case 0xCB: AddrMode_Imp(); + WAI(); + break; + case 0xCC: AddrMode_Abs(); + CPY(); + break; + case 0xCD: AddrMode_Abs(); + CMP(); + break; + case 0xCE: AddrMode_Abs(); + DEC(); + break; + case 0xCF: AddrMode_AbsLng(); + CMP(); + break; + case 0xD0: AddrMode_Rel(); + BNE(); + break; + case 0xD1: AddrMode_DirIndIdxY(false); + CMP(); + break; + case 0xD2: AddrMode_DirInd(); + CMP(); + break; + case 0xD3: AddrMode_StkRelIndIdxY(); + CMP(); + break; + case 0xD4: AddrMode_Dir(); + PEI(); + break; + case 0xD5: AddrMode_DirIdxX(); + CMP(); + break; + case 0xD6: AddrMode_DirIdxX(); + DEC(); + break; + case 0xD7: AddrMode_DirIndLngIdxY(); + CMP(); + break; + case 0xD8: AddrMode_Imp(); + CLD(); + break; + case 0xD9: AddrMode_AbsIdxY(false); + CMP(); + break; + case 0xDA: PHX(); + break; + case 0xDB: AddrMode_Imp(); + STP(); + break; + case 0xDC: AddrMode_AbsIndLng(); + JML(); + break; + case 0xDD: AddrMode_AbsIdxX(false); + CMP(); + break; + case 0xDE: AddrMode_AbsIdxX(true); + DEC(); + break; + case 0xDF: AddrMode_AbsLngIdxX(); + CMP(); + break; + case 0xE0: AddrMode_ImmX(); + CPX(); + break; + case 0xE1: AddrMode_DirIdxIndX(); + SBC(); + break; + case 0xE2: AddrMode_Imm8(); + SEP(); + break; + case 0xE3: AddrMode_StkRel(); + SBC(); + break; + case 0xE4: AddrMode_Dir(); + CPX(); + break; + case 0xE5: AddrMode_Dir(); + SBC(); + break; + case 0xE6: AddrMode_Dir(); + INC(); + break; + case 0xE7: AddrMode_DirIndLng(); + SBC(); + break; + case 0xE8: AddrMode_Imp(); + INX(); + break; + case 0xE9: AddrMode_ImmM(); + SBC(); + break; + case 0xEA: AddrMode_Imp(); + NOP(); + break; + case 0xEB: AddrMode_Imp(); + XBA(); + break; + case 0xEC: AddrMode_Abs(); + CPX(); + break; + case 0xED: AddrMode_Abs(); + SBC(); + break; + case 0xEE: AddrMode_Abs(); + INC(); + break; + case 0xEF: AddrMode_AbsLng(); + SBC(); + break; + case 0xF0: AddrMode_Rel(); + BEQ(); + break; + case 0xF1: AddrMode_DirIndIdxY(false); + SBC(); + break; + case 0xF2: AddrMode_DirInd(); + SBC(); + break; + case 0xF3: AddrMode_StkRelIndIdxY(); + SBC(); + break; + case 0xF4: AddrMode_Imm16(); + PEA(); + break; + case 0xF5: AddrMode_DirIdxX(); + SBC(); + break; + case 0xF6: AddrMode_DirIdxX(); + INC(); + break; + case 0xF7: AddrMode_DirIndLngIdxY(); + SBC(); + break; + case 0xF8: AddrMode_Imp(); + SED(); + break; + case 0xF9: AddrMode_AbsIdxY(false); + SBC(); + break; + case 0xFA: PLX(); + break; + case 0xFB: AddrMode_Imp(); + XCE(); + break; + case 0xFC: AddrMode_AbsIdxXInd(); + JSR(); + break; + case 0xFD: AddrMode_AbsIdxX(false); + SBC(); + break; + case 0xFE: AddrMode_AbsIdxX(true); + INC(); + break; + case 0xFF: AddrMode_AbsLngIdxX(); + SBC(); + break; } } @@ -319,7 +817,8 @@ void Cpu::DetectNmiSignalEdge() //"This edge detector polls the status of the NMI line during φ2 of each CPU cycle (i.e., during the //second half of each cycle) and raises an internal signal if the input goes from being high during //one cycle to being low during the next" - if(!_state.PrevNmiFlag && _state.NmiFlag) { + if (!_state.PrevNmiFlag && _state.NmiFlag) + { _state.NeedNmi = true; } _state.PrevNmiFlag = _state.NmiFlag; @@ -327,7 +826,8 @@ void Cpu::DetectNmiSignalEdge() void Cpu::UpdateIrqNmiFlags() { - if(!_state.IrqLock) { + if (!_state.IrqLock) + { //"The internal signal goes high during φ1 of the cycle that follows the one where the edge is detected, //and stays high until the NMI has been handled. " _state.PrevNeedNmi = _state.NeedNmi; @@ -343,9 +843,12 @@ void Cpu::SetIrqSource(IrqSource source) bool Cpu::CheckIrqSource(IrqSource source) { - if(_state.IrqSource & (uint8_t)source) { + if (_state.IrqSource & (uint8_t)source) + { return true; - } else { + } + else + { return false; } } @@ -374,9 +877,12 @@ uint8_t Cpu::GetOpCode() void Cpu::IdleOrRead() { - if(_state.PrevIrqSource) { + if (_state.PrevIrqSource) + { ReadCode(_state.PC); - } else { + } + else + { Idle(); } } @@ -443,18 +949,24 @@ void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type) uint8_t Cpu::GetByteValue() { - if(_immediateMode) { + if (_immediateMode) + { return (uint8_t)_operand; - } else { + } + else + { return ReadData(_operand); } } uint16_t Cpu::GetWordValue() { - if(_immediateMode) { + if (_immediateMode) + { return (uint16_t)_operand; - } else { + } + else + { return ReadDataWord(_operand); } } @@ -486,10 +998,13 @@ uint16_t Cpu::PopWord() uint16_t Cpu::GetDirectAddress(uint16_t offset, bool allowEmulationMode) { - if(allowEmulationMode && _state.EmulationMode && (_state.D & 0xFF) == 0) { + if (allowEmulationMode && _state.EmulationMode && (_state.D & 0xFF) == 0) + { //TODO: Check if new instruction or not (PEI) return (uint16_t)((_state.D & 0xFF00) | (offset & 0xFF)); - } else { + } + else + { return (uint16_t)(_state.D + offset); } } @@ -511,9 +1026,12 @@ uint32_t Cpu::GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationM void Cpu::SetSP(uint16_t sp) { - if(_state.EmulationMode) { + if (_state.EmulationMode) + { _state.SP = 0x100 | (sp & 0xFF); - } else { + } + else + { _state.SP = sp; } } @@ -521,25 +1039,29 @@ void Cpu::SetSP(uint16_t sp) void Cpu::SetPS(uint8_t ps) { _state.PS = ps; - if(CheckFlag(ProcFlags::IndexMode8)) { + if (CheckFlag(ProcFlags::IndexMode8)) + { //Truncate X/Y when 8-bit indexes are enabled _state.Y &= 0xFF; _state.X &= 0xFF; } } -void Cpu::SetRegister(uint8_t ®, uint8_t value) +void Cpu::SetRegister(uint8_t& reg, uint8_t value) { SetZeroNegativeFlags(value); reg = value; } -void Cpu::SetRegister(uint16_t ®, uint16_t value, bool eightBitMode) +void Cpu::SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode) { - if(eightBitMode) { + if (eightBitMode) + { SetZeroNegativeFlags((uint8_t)value); reg = (reg & 0xFF00) | (uint8_t)value; - } else { + } + else + { SetZeroNegativeFlags(value); reg = value; } @@ -548,9 +1070,12 @@ void Cpu::SetRegister(uint16_t ®, uint16_t value, bool eightBitMode) void Cpu::SetZeroNegativeFlags(uint16_t value) { ClearFlags(ProcFlags::Zero | ProcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(ProcFlags::Zero); - } else if(value & 0x8000) { + } + else if (value & 0x8000) + { SetFlags(ProcFlags::Negative); } } @@ -558,9 +1083,12 @@ void Cpu::SetZeroNegativeFlags(uint16_t value) void Cpu::SetZeroNegativeFlags(uint8_t value) { ClearFlags(ProcFlags::Zero | ProcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(ProcFlags::Zero); - } else if(value & 0x80) { + } + else if (value & 0x80) + { SetFlags(ProcFlags::Negative); } } @@ -580,7 +1108,7 @@ bool Cpu::CheckFlag(uint8_t flag) return (_state.PS & flag) == flag; } -void Cpu::Serialize(Serializer &s) +void Cpu::Serialize(Serializer& s) { s.Stream( _state.A, _state.CycleCount, _state.D, _state.DBR, _state.EmulationMode, _state.IrqSource, _state.K, diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index 494efb4..b00102f 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -26,24 +26,27 @@ void Cpu::Exec() { _immediateMode = false; - switch(_state.StopState) { - case CpuStopState::Running: RunOp(); break; - case CpuStopState::Stopped: - //STP was executed, CPU no longer executes any code - #ifndef DUMMYCPU + switch (_state.StopState) + { + case CpuStopState::Running: RunOp(); + break; + case CpuStopState::Stopped: + //STP was executed, CPU no longer executes any code +#ifndef DUMMYCPU _memoryManager->IncMasterClock4(); - #endif - return; +#endif + return; - case CpuStopState::WaitingForIrq: - //WAI + case CpuStopState::WaitingForIrq: + //WAI + Idle(); + if (_state.IrqSource || _state.NeedNmi) + { Idle(); - if(_state.IrqSource || _state.NeedNmi) { - Idle(); - Idle(); - _state.StopState = CpuStopState::Running; - } - break; + Idle(); + _state.StopState = CpuStopState::Running; + } + break; } #ifndef DUMMYCPU @@ -120,21 +123,33 @@ void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type) void Cpu::SetReg(CpuRegister reg, uint16_t value) { - switch (reg) { - case CpuRegister::CpuRegA: { _state.A = value; } break; - case CpuRegister::CpuRegX: { _state.X = value; } break; - case CpuRegister::CpuRegY: { _state.Y = value; } break; - case CpuRegister::CpuRegSP: { _state.SP = value; } break; - case CpuRegister::CpuRegD: { _state.D = value; } break; - case CpuRegister::CpuRegPC: { _state.PC = value; } break; - case CpuRegister::CpuRegK: { _state.K = value & 0xFF; } break; - case CpuRegister::CpuRegDBR: { _state.DBR = value & 0xFF; } break; - case CpuRegister::CpuRegPS: { _state.PS = value & 0xFF; } break; - case CpuRegister::CpuFlagNmi: { _state.NmiFlag = value != 0; } break; + switch (reg) + { + case CpuRegister::CpuRegA: { _state.A = value; } + break; + case CpuRegister::CpuRegX: { _state.X = value; } + break; + case CpuRegister::CpuRegY: { _state.Y = value; } + break; + case CpuRegister::CpuRegSP: { _state.SP = value; } + break; + case CpuRegister::CpuRegD: { _state.D = value; } + break; + case CpuRegister::CpuRegPC: { _state.PC = value; } + break; + case CpuRegister::CpuRegK: { _state.K = value & 0xFF; } + break; + case CpuRegister::CpuRegDBR: { _state.DBR = value & 0xFF; } + break; + case CpuRegister::CpuRegPS: { _state.PS = value & 0xFF; } + break; + case CpuRegister::CpuFlagNmi: { _state.NmiFlag = value != 0; } + break; } } -bool Cpu::GetCpuProcFlag(ProcFlags::ProcFlags flag) { +bool Cpu::GetCpuProcFlag(ProcFlags::ProcFlags flag) +{ return _state.PS & static_cast(flag); } diff --git a/Core/Cpu.h b/Core/Cpu.h index 962a93f..8c38c8a 100644 --- a/Core/Cpu.h +++ b/Core/Cpu.h @@ -29,11 +29,11 @@ private: static constexpr uint32_t LegacyIrqVector = 0xFFFE; static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4; - typedef void(Cpu::*Func)(); - - MemoryManager *_memoryManager = nullptr; - DmaController *_dmaController = nullptr; - Console *_console = nullptr; + typedef void (Cpu::*Func)(); + + MemoryManager* _memoryManager = nullptr; + DmaController* _dmaController = nullptr; + Console* _console = nullptr; bool _immediateMode = false; @@ -47,9 +47,9 @@ private: uint16_t GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode = true); uint32_t GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode = true); - + uint8_t GetOpCode(); - + uint16_t GetResetVector(); void UpdateIrqNmiFlags(); @@ -59,7 +59,7 @@ private: void IdleOrRead(); void IdleEndJump(); void IdleTakeBranch(); - + uint8_t ReadOperandByte(); uint16_t ReadOperandWord(); uint32_t ReadOperandLong(); @@ -71,9 +71,9 @@ private: void SetSP(uint16_t sp); void SetPS(uint8_t ps); - void SetRegister(uint8_t ®, uint8_t value); - void SetRegister(uint16_t ®, uint16_t value, bool eightBitMode); - + void SetRegister(uint8_t& reg, uint8_t value); + void SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode); + void SetZeroNegativeFlags(uint16_t value); void SetZeroNegativeFlags(uint8_t value); @@ -109,7 +109,7 @@ private: void Sub8(uint8_t value); void Sub16(uint16_t value); void SBC(); - + //Branch instructions void BCC(); void BCS(); @@ -122,7 +122,7 @@ private: void BVC(); void BVS(); void BranchRelative(bool branch); - + //Set/clear flag instructions void CLC(); void CLD(); @@ -146,7 +146,7 @@ private: void DEC_Acc(); void INC_Acc(); - void IncDecReg(uint16_t & reg, int8_t offset); + void IncDecReg(uint16_t& reg, int8_t offset); void IncDec(int8_t offset); //Compare instructions @@ -174,10 +174,14 @@ private: void EOR(); void ORA(); - template T ShiftLeft(T value); - template T RollLeft(T value); - template T ShiftRight(T value); - template T RollRight(T value); + template + T ShiftLeft(T value); + template + T RollLeft(T value); + template + T ShiftRight(T value); + template + T RollRight(T value); //Shift operations void ASL_Acc(); @@ -213,10 +217,10 @@ private: void PLY(); void PushRegister(uint16_t reg, bool eightBitMode); - void PullRegister(uint16_t ®, bool eightBitMode); + void PullRegister(uint16_t& reg, bool eightBitMode); //Store/load instructions - void LoadRegister(uint16_t ®, bool eightBitMode); + void LoadRegister(uint16_t& reg, bool eightBitMode); void StoreRegister(uint16_t val, bool eightBitMode); void LDA(); @@ -227,9 +231,10 @@ private: void STX(); void STY(); void STZ(); - + //Test bits - template void TestBits(T value, bool alterZeroFlagOnly); + template + void TestBits(T value, bool alterZeroFlagOnly); void BIT(); void TRB(); @@ -282,7 +287,7 @@ private: void AddrMode_BlkMov(); uint8_t ReadDirectOperandByte(); - + //Direct: d void AddrMode_Dir(); //Direct Indexed: d,x @@ -291,7 +296,7 @@ private: void AddrMode_DirIdxY(); //Direct Indirect: (d) void AddrMode_DirInd(); - + //Direct Indexed Indirect: (d,x) void AddrMode_DirIdxIndX(); //Direct Indirect Indexed: (d),y @@ -313,12 +318,12 @@ private: void AddrMode_StkRel(); void AddrMode_StkRelIndIdxY(); - + void RunOp(); public: #ifndef DUMMYCPU - Cpu(Console *console); + Cpu(Console* console); #else DummyCpu(Console* console, CpuType type); #endif @@ -334,7 +339,7 @@ public: bool GetCpuProcFlag(ProcFlags::ProcFlags flag); uint64_t GetCycleCount(); - template + template void IncreaseCycleCount(); void SetNmiFlag(bool nmiFlag); @@ -345,7 +350,7 @@ public: void ClearIrqSource(IrqSource source); // Inherited via ISerializable - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(CpuRegister reg, uint16_t value); void SetCpuProcFlag(ProcFlags::ProcFlags flag, bool set); @@ -377,10 +382,10 @@ public: void SetReg(CpuRegister reg, uint16_t value); -template +template void Cpu::IncreaseCycleCount() { _state.CycleCount += count; } -#endif \ No newline at end of file +#endif diff --git a/Core/CpuBwRamHandler.h b/Core/CpuBwRamHandler.h index 9e12f8c..72d1f04 100644 --- a/Core/CpuBwRamHandler.h +++ b/Core/CpuBwRamHandler.h @@ -10,7 +10,7 @@ class CpuBwRamHandler : public IMemoryHandler { private: - IMemoryHandler * _handler; + IMemoryHandler* _handler; Sa1State* _state; Sa1* _sa1; @@ -24,9 +24,12 @@ public: uint8_t Read(uint32_t addr) override { - if(_state->CharConvDmaActive) { + if (_state->CharConvDmaActive) + { return _sa1->ReadCharConvertType1(addr); - } else { + } + else + { return _handler->Read(addr); } } @@ -36,7 +39,7 @@ public: return Read(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { _handler->PeekBlock(addr, output); } @@ -50,4 +53,4 @@ public: { return _handler->GetAbsoluteAddress(address); } -}; \ No newline at end of file +}; diff --git a/Core/CpuDebugger.cpp b/Core/CpuDebugger.cpp index 4245259..ef0a3fd 100644 --- a/Core/CpuDebugger.cpp +++ b/Core/CpuDebugger.cpp @@ -36,14 +36,16 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType) _codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get(); _settings = debugger->GetConsole()->GetSettings().get(); _memoryManager = debugger->GetConsole()->GetMemoryManager().get(); - - _eventManager.reset(new EventManager(debugger, _cpu, _debugger->GetConsole()->GetPpu().get(), _memoryManager, _debugger->GetConsole()->GetDmaController().get())); + + _eventManager.reset(new EventManager(debugger, _cpu, _debugger->GetConsole()->GetPpu().get(), _memoryManager, + _debugger->GetConsole()->GetDmaController().get())); _callstackManager.reset(new CallstackManager(debugger)); _breakpointManager.reset(new BreakpointManager(debugger, cpuType, _eventManager.get())); _step.reset(new StepRequest()); _assembler.reset(new Assembler(_debugger->GetLabelManager())); - if(GetState().PC == 0) { + if (GetState().PC == 0) + { //Enable breaking on uninit reads when debugger is opened at power on _enableBreakOnUninitRead = true; } @@ -59,26 +61,34 @@ void CpuDebugger::Reset() void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr); - MemoryOperationInfo operation = { addr, value, type }; + MemoryOperationInfo operation = {addr, value, type}; CpuState state = GetState(); BreakSource breakSource = BreakSource::Unspecified; - if(type == MemoryOperationType::ExecOpCode) { - bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag(_cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled); - if(addressInfo.Address >= 0) { - if(addressInfo.Type == SnesMemoryType::PrgRom) { + if (type == MemoryOperationType::ExecOpCode) + { + bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag( + _cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled); + if (addressInfo.Address >= 0) + { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { uint8_t flags = CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)); - if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) { + if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) + { flags |= CdlFlags::SubEntryPoint; } _codeDataLogger->SetFlags(addressInfo.Address, flags); } - if(needDisassemble) { - _disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8), _cpuType); + if (needDisassemble) + { + _disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8), + _cpuType); } } - if(_traceLogger->IsCpuLogged(_cpuType)) { + if (_traceLogger->IsCpuLogged(_cpuType)) + { _debugger->GetState(_debugState, true); DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType); @@ -86,19 +96,25 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType } uint32_t pc = (state.K << 16) | state.PC; - if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) { + if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) + { //JSR, JSL uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType); uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF); AddressInfo srcAddress = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter); AddressInfo retAddress = GetMemoryMappings().GetAbsoluteAddress(returnPc); - _callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, StackFrameFlags::None); - } else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) { + _callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, + StackFrameFlags::None); + } + else if (_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) + { //RTS, RTL, RTI _callstackManager->Pop(addressInfo, pc); } - if(_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B || _prevOpCode == 0x44 || _prevOpCode == 0x54)) { + if (_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B || + _prevOpCode == 0x44 || _prevOpCode == 0x54)) + { //RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out) _step->StepCount = 0; } @@ -106,47 +122,72 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType _prevOpCode = value; _prevProgramCounter = pc; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } - if(_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled)) { - if(value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled)) + { + if (value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB) + { //Break on BRK/STP/WDM/COP - if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) { + if (value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) + { breakSource = BreakSource::BreakOnBrk; _step->StepCount = 0; - } else if(value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop)) { + } + else if (value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop)) + { breakSource = BreakSource::BreakOnCop; _step->StepCount = 0; - } else if(value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm)) { + } + else if (value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm)) + { breakSource = BreakSource::BreakOnWdm; _step->StepCount = 0; - } else if(value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) { + } + else if (value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) + { breakSource = BreakSource::BreakOnStp; _step->StepCount = 0; } } } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else if(type == MemoryOperationType::ExecOperand) { - if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) { - _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); + } + else if (type == MemoryOperationType::ExecOperand) + { + if (addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) + { + _codeDataLogger->SetFlags(addressInfo.Address, + CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else { - if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) { - _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); + } + else + { + if (addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) + { + _codeDataLogger->SetFlags(addressInfo.Address, + CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); } - if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock())) { + if (_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock())) + { //Memory access was a read on an uninitialized memory address - if(_enableBreakOnUninitRead) { - if(_memoryAccessCounter->GetReadCount(addressInfo) == 1) { + if (_enableBreakOnUninitRead) + { + if (_memoryAccessCounter->GetReadCount(addressInfo) == 1) + { //Only warn the first time - _debugger->Log(string(_cpuType == CpuType::Sa1 ? "[SA1]" : "[CPU]") + " Uninitialized memory read: $" + HexUtilities::ToHex24(addr)); + _debugger->Log( + string(_cpuType == CpuType::Sa1 ? "[SA1]" : "[CPU]") + " Uninitialized memory read: $" + + HexUtilities::ToHex24(addr)); } - if(_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled) && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnUninitRead)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled) && _settings->CheckDebuggerFlag( + DebuggerFlags::BreakOnUninitRead)) + { breakSource = BreakSource::BreakOnUninitMemoryRead; _step->StepCount = 0; } @@ -154,22 +195,27 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType } } - if(IsRegister(addr)) { + if (IsRegister(addr)) + { _eventManager->AddEvent(DebugEventType::Register, operation); } - _debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource); + _debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, + breakSource); } void CpuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr); - MemoryOperationInfo operation = { addr, value, type }; - if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) { + MemoryOperationInfo operation = {addr, value, type}; + if (addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == + SnesMemoryType::SaveRam)) + { _disassembler->InvalidateCache(addressInfo, _cpuType); } - if(IsRegister(addr)) { + if (IsRegister(addr)) + { _eventManager->AddEvent(DebugEventType::Register, operation); } @@ -186,25 +232,39 @@ void CpuDebugger::Run() void CpuDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - if((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && GetState().StopState == CpuStopState::Stopped) { + if ((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && GetState().StopState == + CpuStopState::Stopped) + { //If STP was called, the CPU isn't running anymore - use the PPU to break execution instead (useful for test roms that end with STP) step.PpuStepCount = 1; - } else { - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break; - case StepType::StepOver: - if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode == 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54) { - //JSR, JSL, BRK, COP, MVP, MVN - step.BreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + DisassemblyInfo::GetOpSize(_prevOpCode, 0, _cpuType)) & 0xFFFF); - } else { - //For any other instruction, step over is the same as step into - step.StepCount = 1; - } - break; + } + else + { + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; + case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); + break; + case StepType::StepOver: + if (_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode == + 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54) + { + //JSR, JSL, BRK, COP, MVP, MVN + step.BreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + + DisassemblyInfo::GetOpSize(_prevOpCode, 0, _cpuType)) & 0xFFFF); + } + else + { + //For any other instruction, step over is the same as step into + step.StepCount = 1; + } + break; - case StepType::PpuStep: step.PpuStepCount = stepCount; break; - case StepType::SpecificScanline: step.BreakScanline = stepCount; break; + case StepType::PpuStep: step.PpuStepCount = stepCount; + break; + case StepType::SpecificScanline: step.BreakScanline = stepCount; + break; } } _step.reset(new StepRequest(step)); @@ -215,20 +275,24 @@ void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool AddressInfo src = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter); AddressInfo ret = GetMemoryMappings().GetAbsoluteAddress(originalPc); AddressInfo dest = GetMemoryMappings().GetAbsoluteAddress(currentPc); - _callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq); + _callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc, + forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq); _eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq); } void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) { - if(_step->PpuStepCount > 0) { + if (_step->PpuStepCount > 0) + { _step->PpuStepCount--; - if(_step->PpuStepCount == 0) { + if (_step->PpuStepCount == 0) + { _debugger->SleepUntilResume(BreakSource::PpuStep); } } - if(cycle == 0 && scanline == _step->BreakScanline) { + if (cycle == 0 && scanline == _step->BreakScanline) + { _step->BreakScanline = -1; _debugger->SleepUntilResume(BreakSource::PpuStep); } @@ -236,18 +300,24 @@ void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) MemoryMappings& CpuDebugger::GetMemoryMappings() { - if(_cpuType == CpuType::Cpu) { + if (_cpuType == CpuType::Cpu) + { return *_memoryManager->GetMemoryMappings(); - } else { + } + else + { return *_sa1->GetMemoryMappings(); } } CpuState CpuDebugger::GetState() { - if(_cpuType == CpuType::Cpu) { + if (_cpuType == CpuType::Cpu) + { return _cpu->GetState(); - } else { + } + else + { return _sa1->GetCpuState(); } } @@ -275,4 +345,4 @@ shared_ptr CpuDebugger::GetCallstackManager() BreakpointManager* CpuDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/CpuDebugger.h b/Core/CpuDebugger.h index 9ae83ab..f869051 100644 --- a/Core/CpuDebugger.h +++ b/Core/CpuDebugger.h @@ -62,4 +62,4 @@ public: shared_ptr GetAssembler(); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/CpuDisUtils.cpp b/Core/CpuDisUtils.cpp index b776a29..1ab1c0d 100644 --- a/Core/CpuDisUtils.cpp +++ b/Core/CpuDisUtils.cpp @@ -10,7 +10,8 @@ #include "../Utilities/HexUtilities.h" #include "../Utilities/FastString.h" -void CpuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings) +void CpuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); @@ -23,80 +24,127 @@ void CpuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me uint32_t opSize = info.GetOpSize(); FastString operand(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); - if(opSize > 1) { - if(addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng || opSize == 4) { - AddressInfo address { (int32_t)opAddr, SnesMemoryType::CpuMemory }; + if (opSize > 1) + { + if (addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng || opSize == 4) + { + AddressInfo address{(int32_t)opAddr, SnesMemoryType::CpuMemory}; string label = labelManager ? labelManager->GetLabel(address) : ""; - if(label.size()) { + if (label.size()) + { operand.Write(label, true); - } else { + } + else + { operand.WriteAll('$', HexUtilities::ToHex24(opAddr)); } - } else if(opSize == 2) { + } + else if (opSize == 2) + { operand.WriteAll('$', HexUtilities::ToHex((uint8_t)opAddr)); - } else if(opSize == 3) { + } + else if (opSize == 3) + { operand.WriteAll('$', HexUtilities::ToHex((uint16_t)opAddr)); } } - switch(addrMode) { - case AddrMode::Abs: str.Write(operand); break; - case AddrMode::AbsJmp: str.Write(operand); break; - case AddrMode::AbsIdxXInd: str.WriteAll('(', operand, ",X)"); break; - case AddrMode::AbsIdxX: str.WriteAll(operand, ",X"); break; - case AddrMode::AbsIdxY: str.WriteAll(operand, ",Y"); break; - case AddrMode::AbsInd: str.WriteAll('(', operand, ')'); break; - case AddrMode::AbsIndLng: str.WriteAll('[', operand, ']'); break; - case AddrMode::AbsLngIdxX: str.WriteAll(operand, ",X"); break; - case AddrMode::AbsLng: str.Write(operand); break; - case AddrMode::AbsLngJmp: str.Write(operand); break; - case AddrMode::Acc: break; - case AddrMode::BlkMov: str.WriteAll('$', operand[1], operand[2], ','); str.WriteAll('$', operand[3], operand[4]); break; - case AddrMode::DirIdxIndX: str.WriteAll('(', operand, ",X)"); break; - case AddrMode::DirIdxX: str.WriteAll(operand, ",X"); break; - case AddrMode::DirIdxY: str.WriteAll(operand, ",Y"); break; - case AddrMode::DirIndIdxY: str.WriteAll("(", operand, "),Y"); break; - case AddrMode::DirIndLngIdxY: str.WriteAll("[", operand, "],Y"); break; - case AddrMode::DirIndLng: str.WriteAll("[", operand, "]"); break; - case AddrMode::DirInd: str.WriteAll("(", operand, ")"); break; - case AddrMode::Dir: str.Write(operand); break; + switch (addrMode) + { + case AddrMode::Abs: str.Write(operand); + break; + case AddrMode::AbsJmp: str.Write(operand); + break; + case AddrMode::AbsIdxXInd: str.WriteAll('(', operand, ",X)"); + break; + case AddrMode::AbsIdxX: str.WriteAll(operand, ",X"); + break; + case AddrMode::AbsIdxY: str.WriteAll(operand, ",Y"); + break; + case AddrMode::AbsInd: str.WriteAll('(', operand, ')'); + break; + case AddrMode::AbsIndLng: str.WriteAll('[', operand, ']'); + break; + case AddrMode::AbsLngIdxX: str.WriteAll(operand, ",X"); + break; + case AddrMode::AbsLng: str.Write(operand); + break; + case AddrMode::AbsLngJmp: str.Write(operand); + break; + case AddrMode::Acc: break; + case AddrMode::BlkMov: str.WriteAll('$', operand[1], operand[2], ','); + str.WriteAll('$', operand[3], operand[4]); + break; + case AddrMode::DirIdxIndX: str.WriteAll('(', operand, ",X)"); + break; + case AddrMode::DirIdxX: str.WriteAll(operand, ",X"); + break; + case AddrMode::DirIdxY: str.WriteAll(operand, ",Y"); + break; + case AddrMode::DirIndIdxY: str.WriteAll("(", operand, "),Y"); + break; + case AddrMode::DirIndLngIdxY: str.WriteAll("[", operand, "],Y"); + break; + case AddrMode::DirIndLng: str.WriteAll("[", operand, "]"); + break; + case AddrMode::DirInd: str.WriteAll("(", operand, ")"); + break; + case AddrMode::Dir: str.Write(operand); + break; - case AddrMode::Imm8: case AddrMode::Imm16: case AddrMode::ImmX: case AddrMode::ImmM: - str.WriteAll('#', operand); - break; + case AddrMode::Imm8: + case AddrMode::Imm16: + case AddrMode::ImmX: + case AddrMode::ImmM: + str.WriteAll('#', operand); + break; - case AddrMode::Sig8: str.WriteAll('#', operand); break; //BRK/COP signature - case AddrMode::Imp: break; - case AddrMode::RelLng: str.Write(operand); break; - case AddrMode::Rel: str.Write(operand); break; - case AddrMode::Stk: break; - case AddrMode::StkRel: str.WriteAll(operand, ",S"); break; - case AddrMode::StkRelIndIdxY: str.WriteAll('(', operand, ",S),Y"); break; + case AddrMode::Sig8: str.WriteAll('#', operand); + break; //BRK/COP signature + case AddrMode::Imp: break; + case AddrMode::RelLng: str.Write(operand); + break; + case AddrMode::Rel: str.Write(operand); + break; + case AddrMode::Stk: break; + case AddrMode::StkRel: str.WriteAll(operand, ",S"); + break; + case AddrMode::StkRelIndIdxY: str.WriteAll('(', operand, ",S),Y"); + break; - default: throw std::runtime_error("invalid address mode"); + default: throw std::runtime_error("invalid address mode"); } out += str.ToString(); } -uint32_t CpuDisUtils::GetOperandAddress(DisassemblyInfo &info, uint32_t memoryAddr) +uint32_t CpuDisUtils::GetOperandAddress(DisassemblyInfo& info, uint32_t memoryAddr) { uint32_t opSize = info.GetOpSize(); uint32_t opAddr = 0; uint8_t* byteCode = info.GetByteCode(); - if(opSize == 2) { + if (opSize == 2) + { opAddr = byteCode[1]; - } else if(opSize == 3) { + } + else if (opSize == 3) + { opAddr = byteCode[1] | (byteCode[2] << 8); - } else if(opSize == 4) { + } + else if (opSize == 4) + { opAddr = byteCode[1] | (byteCode[2] << 8) | (byteCode[3] << 16); } AddrMode addrMode = CpuDisUtils::OpMode[byteCode[0]]; - if(addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng) { - if(opSize == 2) { + if (addrMode == AddrMode::Rel || addrMode == AddrMode::RelLng) + { + if (opSize == 2) + { opAddr = (memoryAddr & 0xFF0000) | (((int8_t)opAddr + memoryAddr + 2) & 0xFFFF); - } else { + } + else + { opAddr = (memoryAddr & 0xFF0000) | (((int16_t)opAddr + memoryAddr + 3) & 0xFFFF); } } @@ -104,9 +152,10 @@ uint32_t CpuDisUtils::GetOperandAddress(DisassemblyInfo &info, uint32_t memoryAd return opAddr; } -int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console, CpuState &state, CpuType type) +int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, CpuState& state, CpuType type) { - if(HasEffectiveAddress(CpuDisUtils::OpMode[info.GetOpCode()])) { + if (HasEffectiveAddress(CpuDisUtils::OpMode[info.GetOpCode()])) + { DummyCpu cpu(console, type); state.PS &= ~(ProcFlags::IndexMode8 | ProcFlags::MemoryMode8); state.PS |= info.GetFlags(); @@ -119,41 +168,42 @@ int32_t CpuDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console bool CpuDisUtils::HasEffectiveAddress(AddrMode addrMode) { - switch(addrMode) { - case AddrMode::Acc: - case AddrMode::Imp: - case AddrMode::Stk: - case AddrMode::Sig8: - case AddrMode::Imm8: - case AddrMode::Rel: - case AddrMode::RelLng: - case AddrMode::Imm16: - case AddrMode::BlkMov: - case AddrMode::AbsLngJmp: - case AddrMode::AbsLng: - case AddrMode::ImmX: - case AddrMode::ImmM: - case AddrMode::AbsJmp: - return false; + switch (addrMode) + { + case AddrMode::Acc: + case AddrMode::Imp: + case AddrMode::Stk: + case AddrMode::Sig8: + case AddrMode::Imm8: + case AddrMode::Rel: + case AddrMode::RelLng: + case AddrMode::Imm16: + case AddrMode::BlkMov: + case AddrMode::AbsLngJmp: + case AddrMode::AbsLng: + case AddrMode::ImmX: + case AddrMode::ImmM: + case AddrMode::AbsJmp: + return false; - case AddrMode::DirIdxIndX: - case AddrMode::DirIdxX: - case AddrMode::DirIdxY: - case AddrMode::DirIndIdxY: - case AddrMode::DirIndLngIdxY: - case AddrMode::DirIndLng: - case AddrMode::DirInd: - case AddrMode::Dir: - case AddrMode::StkRel: - case AddrMode::StkRelIndIdxY: - case AddrMode::Abs: - case AddrMode::AbsIdxXInd: - case AddrMode::AbsIdxX: - case AddrMode::AbsIdxY: - case AddrMode::AbsLngIdxX: - case AddrMode::AbsInd: - case AddrMode::AbsIndLng: - return true; + case AddrMode::DirIdxIndX: + case AddrMode::DirIdxX: + case AddrMode::DirIdxY: + case AddrMode::DirIndIdxY: + case AddrMode::DirIndLngIdxY: + case AddrMode::DirIndLng: + case AddrMode::DirInd: + case AddrMode::Dir: + case AddrMode::StkRel: + case AddrMode::StkRelIndIdxY: + case AddrMode::Abs: + case AddrMode::AbsIdxXInd: + case AddrMode::AbsIdxX: + case AddrMode::AbsIdxY: + case AddrMode::AbsLngIdxX: + case AddrMode::AbsInd: + case AddrMode::AbsIndLng: + return true; } throw std::runtime_error("Invalid mode"); @@ -161,9 +211,12 @@ bool CpuDisUtils::HasEffectiveAddress(AddrMode addrMode) uint8_t CpuDisUtils::GetOpSize(AddrMode addrMode, uint8_t flags) { - if(addrMode == AddrMode::ImmX) { + if (addrMode == AddrMode::ImmX) + { return (flags & ProcFlags::IndexMode8) ? 2 : 3; - } else if(addrMode == AddrMode::ImmM) { + } + else if (addrMode == AddrMode::ImmM) + { return (flags & ProcFlags::MemoryMode8) ? 2 : 3; } @@ -199,26 +252,42 @@ string CpuDisUtils::OpName[256] = { "CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", // C "BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", // D "CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", // E - "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F + "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F }; typedef AddrMode M; AddrMode CpuDisUtils::OpMode[256] = { //0 1 2 3 4 5 6 7 8 9 A B C D E F - M::Sig8, M::DirIdxIndX, M::Sig8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 0 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1 - M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 2 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3 - M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 4 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5 - M::Stk, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7 - M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 8 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9 - M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // A - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B - M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // C - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D - M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // E - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Imm16, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F -}; \ No newline at end of file + M::Sig8, M::DirIdxIndX, M::Sig8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, + M::Abs, M::Abs, M::Abs, M::AbsLng, // 0 + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1 + M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, + M::Abs, M::Abs, M::Abs, M::AbsLng, // 2 + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3 + M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, + M::Abs, M::Abs, M::Abs, M::AbsLng, // 4 + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Stk, M::Imp, M::AbsLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5 + M::Stk, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, + M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6 + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7 + M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, + M::Abs, M::Abs, M::Abs, M::AbsLng, // 8 + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9 + M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, + M::Abs, M::Abs, M::Abs, M::AbsLng, // A + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B + M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, + M::Abs, M::Abs, M::Abs, M::AbsLng, // C + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D + M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, + M::Abs, M::Abs, M::Abs, M::AbsLng, // E + M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Imm16, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, + M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F +}; diff --git a/Core/CpuDisUtils.h b/Core/CpuDisUtils.h index a6f2a45..b6beb05 100644 --- a/Core/CpuDisUtils.h +++ b/Core/CpuDisUtils.h @@ -13,7 +13,7 @@ class CpuDisUtils { private: static uint8_t OpSize[0x1F]; - static uint32_t GetOperandAddress(DisassemblyInfo &info, uint32_t memoryAddr); + static uint32_t GetOperandAddress(DisassemblyInfo& info, uint32_t memoryAddr); static uint8_t GetOpSize(AddrMode addrMode, uint8_t flags); static bool HasEffectiveAddress(AddrMode addrMode); @@ -22,9 +22,10 @@ public: static string OpName[256]; static AddrMode OpMode[256]; - static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); static uint8_t GetOpSize(uint8_t opCode, uint8_t flags); - static int32_t GetEffectiveAddress(DisassemblyInfo &info, Console* console, CpuState &state, CpuType type); + static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, CpuState& state, CpuType type); }; enum class AddrMode : uint8_t @@ -35,15 +36,20 @@ enum class AddrMode : uint8_t ImmX, ImmM, Abs, - AbsIdxXInd, //JMP/JSR only + AbsIdxXInd, + //JMP/JSR only AbsIdxX, AbsIdxY, - AbsInd, //JMP only - AbsIndLng, //JML only + AbsInd, + //JMP only + AbsIndLng, + //JML only AbsLngIdxX, AbsLng, - AbsJmp, //JSR/JMP only - AbsLngJmp, //JSL/JMP only + AbsJmp, + //JSR/JMP only + AbsLngJmp, + //JSL/JMP only Acc, BlkMov, DirIdxIndX, @@ -60,4 +66,4 @@ enum class AddrMode : uint8_t Stk, StkRel, StkRelIndIdxY -}; \ No newline at end of file +}; diff --git a/Core/CpuTypes.h b/Core/CpuTypes.h index 61c805b..57549e4 100644 --- a/Core/CpuTypes.h +++ b/Core/CpuTypes.h @@ -15,7 +15,7 @@ struct CpuState uint16_t A; uint16_t X; uint16_t Y; - + /* 16-bit stack pointer */ uint16_t SP; @@ -88,4 +88,3 @@ enum class IrqSource Ppu = 1, Coprocessor = 2 }; - diff --git a/Core/Cx4.Instructions.cpp b/Core/Cx4.Instructions.cpp index d266699..9b08837 100644 --- a/Core/Cx4.Instructions.cpp +++ b/Core/Cx4.Instructions.cpp @@ -4,7 +4,7 @@ #include "Cx4DisUtils.h" #include "../Utilities/HexUtilities.h" -static constexpr int shiftLut[4] = { 0 , 1, 8, 16 }; +static constexpr int shiftLut[4] = {0, 1, 8, 16}; extern const uint32_t _dataRom[1024]; @@ -14,86 +14,151 @@ void Cx4::Exec(uint16_t opCode) uint8_t param1 = (opCode >> 8) & 0x03; uint8_t param2 = opCode & 0xFF; - switch(op) { - case 0x00: NOP(); break; - case 0x04: NOP(); break; //??? - case 0x08: Branch(true, param1, param2); break; - case 0x0C: Branch(_state.Zero, param1, param2); break; + switch (op) + { + case 0x00: NOP(); + break; + case 0x04: NOP(); + break; //??? + case 0x08: Branch(true, param1, param2); + break; + case 0x0C: Branch(_state.Zero, param1, param2); + break; - case 0x10: Branch(_state.Carry, param1, param2); break; - case 0x14: Branch(_state.Negative, param1, param2); break; - case 0x18: Branch(_state.Overflow, param1, param2); break; - case 0x1C: WAIT(); break; + case 0x10: Branch(_state.Carry, param1, param2); + break; + case 0x14: Branch(_state.Negative, param1, param2); + break; + case 0x18: Branch(_state.Overflow, param1, param2); + break; + case 0x1C: WAIT(); + break; - case 0x20: NOP(); break; //??? - case 0x24: Skip(param1, param2); break; - case 0x28: JSR(true, param1, param2); break; - case 0x2C: JSR(_state.Zero, param1, param2); break; + case 0x20: NOP(); + break; //??? + case 0x24: Skip(param1, param2); + break; + case 0x28: JSR(true, param1, param2); + break; + case 0x2C: JSR(_state.Zero, param1, param2); + break; - case 0x30: JSR(_state.Carry, param1, param2); break; - case 0x34: JSR(_state.Negative, param1, param2); break; - case 0x38: JSR(_state.Overflow, param1, param2); break; - case 0x3C: RTS(); break; + case 0x30: JSR(_state.Carry, param1, param2); + break; + case 0x34: JSR(_state.Negative, param1, param2); + break; + case 0x38: JSR(_state.Overflow, param1, param2); + break; + case 0x3C: RTS(); + break; - case 0x40: IncMar(); break; - case 0x44: NOP(); break; //??? - case 0x48: CMPR(param1, param2); break; - case 0x4C: CMPR_Imm(param1, param2); break; + case 0x40: IncMar(); + break; + case 0x44: NOP(); + break; //??? + case 0x48: CMPR(param1, param2); + break; + case 0x4C: CMPR_Imm(param1, param2); + break; - case 0x50: CMP(param1, param2); break; - case 0x54: CMP_Imm(param1, param2); break; - case 0x58: SignExtend(param1); break; - case 0x5C: NOP(); break; //??? + case 0x50: CMP(param1, param2); + break; + case 0x54: CMP_Imm(param1, param2); + break; + case 0x58: SignExtend(param1); + break; + case 0x5C: NOP(); + break; //??? - case 0x60: Load(param1, param2); break; - case 0x64: Load_Imm(param1, param2); break; - case 0x68: ReadRam(param1); break; - case 0x6C: ReadRam_Imm(param1, param2); break; + case 0x60: Load(param1, param2); + break; + case 0x64: Load_Imm(param1, param2); + break; + case 0x68: ReadRam(param1); + break; + case 0x6C: ReadRam_Imm(param1, param2); + break; - case 0x70: ReadRom(); break; - case 0x74: ReadRom_Imm((param1 << 8) | param2); break; - case 0x78: NOP(); break; - case 0x7C: LoadP(param1, param2); break; + case 0x70: ReadRom(); + break; + case 0x74: ReadRom_Imm((param1 << 8) | param2); + break; + case 0x78: NOP(); + break; + case 0x7C: LoadP(param1, param2); + break; - case 0x80: ADD(param1, param2); break; - case 0x84: ADD_Imm(param1, param2); break; - case 0x88: SUBR(param1, param2); break; - case 0x8C: SUBR_Imm(param1, param2); break; + case 0x80: ADD(param1, param2); + break; + case 0x84: ADD_Imm(param1, param2); + break; + case 0x88: SUBR(param1, param2); + break; + case 0x8C: SUBR_Imm(param1, param2); + break; - case 0x90: SUB(param1, param2); break; - case 0x94: SUB_Imm(param1, param2); break; - case 0x98: SMUL(param2); break; - case 0x9C: SMUL_Imm(param2); break; + case 0x90: SUB(param1, param2); + break; + case 0x94: SUB_Imm(param1, param2); + break; + case 0x98: SMUL(param2); + break; + case 0x9C: SMUL_Imm(param2); + break; - case 0xA0: XNOR(param1, param2); break; - case 0xA4: XNOR_Imm(param1, param2); break; - case 0xA8: XOR(param1, param2); break; - case 0xAC: XOR_Imm(param1, param2); break; + case 0xA0: XNOR(param1, param2); + break; + case 0xA4: XNOR_Imm(param1, param2); + break; + case 0xA8: XOR(param1, param2); + break; + case 0xAC: XOR_Imm(param1, param2); + break; - case 0xB0: AND(param1, param2); break; - case 0xB4: AND_Imm(param1, param2); break; - case 0xB8: OR(param1, param2); break; - case 0xBC: OR_Imm(param1, param2); break; + case 0xB0: AND(param1, param2); + break; + case 0xB4: AND_Imm(param1, param2); + break; + case 0xB8: OR(param1, param2); + break; + case 0xBC: OR_Imm(param1, param2); + break; - case 0xC0: SHR(param2); break; - case 0xC4: SHR_Imm(param2); break; - case 0xC8: ASR(param2); break; - case 0xCC: ASR_Imm(param2); break; + case 0xC0: SHR(param2); + break; + case 0xC4: SHR_Imm(param2); + break; + case 0xC8: ASR(param2); + break; + case 0xCC: ASR_Imm(param2); + break; - case 0xD0: ROR(param2); break; - case 0xD4: ROR_Imm(param2); break; - case 0xD8: SHL(param2); break; - case 0xDC: SHL_Imm(param2); break; + case 0xD0: ROR(param2); + break; + case 0xD4: ROR_Imm(param2); + break; + case 0xD8: SHL(param2); + break; + case 0xDC: SHL_Imm(param2); + break; - case 0xE0: Store(param1, param2); break; - case 0xE4: NOP(); break; //??? - case 0xE8: WriteRam(param1); break; - case 0xEC: WriteRam_Imm(param1, param2); break; + case 0xE0: Store(param1, param2); + break; + case 0xE4: NOP(); + break; //??? + case 0xE8: WriteRam(param1); + break; + case 0xEC: WriteRam_Imm(param1, param2); + break; - case 0xF0: Swap(param2 & 0x0F); break; - case 0xF4: NOP(); break; //??? - case 0xF8: NOP(); break; //??? - case 0xFC: Stop(); break; + case 0xF0: Swap(param2 & 0x0F); + break; + case 0xF4: NOP(); + break; //??? + case 0xF8: NOP(); + break; //??? + case 0xFC: Stop(); + break; } Step(1); @@ -101,119 +166,177 @@ void Cx4::Exec(uint16_t opCode) uint32_t Cx4::GetSourceValue(uint8_t src) { - switch(src & 0x7F) { - case 0x00: return _state.A; - case 0x01: return (_state.Mult >> 24) & 0xFFFFFF; - case 0x02: return _state.Mult & 0xFFFFFF; - case 0x03: return _state.MemoryDataReg; - case 0x08: return _state.RomBuffer; - case 0x0C: return (_state.RamBuffer[2] << 16) | (_state.RamBuffer[1] << 8) | _state.RamBuffer[0]; - case 0x13: return _state.MemoryAddressReg; - case 0x1C: return _state.DataPointerReg; - case 0x20: return _state.PC; - case 0x28: return _state.P; + switch (src & 0x7F) + { + case 0x00: return _state.A; + case 0x01: return (_state.Mult >> 24) & 0xFFFFFF; + case 0x02: return _state.Mult & 0xFFFFFF; + case 0x03: return _state.MemoryDataReg; + case 0x08: return _state.RomBuffer; + case 0x0C: return (_state.RamBuffer[2] << 16) | (_state.RamBuffer[1] << 8) | _state.RamBuffer[0]; + case 0x13: return _state.MemoryAddressReg; + case 0x1C: return _state.DataPointerReg; + case 0x20: return _state.PC; + case 0x28: return _state.P; - case 0x2E: - _state.Bus.Enabled = true; - _state.Bus.Reading = true; - _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - return 0; + case 0x2E: + _state.Bus.Enabled = true; + _state.Bus.Reading = true; + _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; + _state.Bus.Address = _state.MemoryAddressReg; + return 0; - case 0x2F: - _state.Bus.Enabled = true; - _state.Bus.Reading = true; - _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - return 0; + case 0x2F: + _state.Bus.Enabled = true; + _state.Bus.Reading = true; + _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; + _state.Bus.Address = _state.MemoryAddressReg; + return 0; - case 0x50: return 0x000000; - case 0x51: return 0xFFFFFF; - case 0x52: return 0x00FF00; - case 0x53: return 0xFF0000; - case 0x54: return 0x00FFFF; - case 0x55: return 0xFFFF00; - case 0x56: return 0x800000; - case 0x57: return 0x7FFFFF; - case 0x58: return 0x008000; - case 0x59: return 0x007FFF; - case 0x5A: return 0xFF7FFF; - case 0x5B: return 0xFFFF7F; - case 0x5C: return 0x010000; - case 0x5D: return 0xFEFFFF; - case 0x5E: return 0x000100; - case 0x5F: return 0x00FEFF; + case 0x50: return 0x000000; + case 0x51: return 0xFFFFFF; + case 0x52: return 0x00FF00; + case 0x53: return 0xFF0000; + case 0x54: return 0x00FFFF; + case 0x55: return 0xFFFF00; + case 0x56: return 0x800000; + case 0x57: return 0x7FFFFF; + case 0x58: return 0x008000; + case 0x59: return 0x007FFF; + case 0x5A: return 0xFF7FFF; + case 0x5B: return 0xFFFF7F; + case 0x5C: return 0x010000; + case 0x5D: return 0xFEFFFF; + case 0x5E: return 0x000100; + case 0x5F: return 0x00FEFF; - case 0x60: case 0x70: return _state.Regs[0]; - case 0x61: case 0x71: return _state.Regs[1]; - case 0x62: case 0x72: return _state.Regs[2]; - case 0x63: case 0x73: return _state.Regs[3]; - case 0x64: case 0x74: return _state.Regs[4]; - case 0x65: case 0x75: return _state.Regs[5]; - case 0x66: case 0x76: return _state.Regs[6]; - case 0x67: case 0x77: return _state.Regs[7]; - case 0x68: case 0x78: return _state.Regs[8]; - case 0x69: case 0x79: return _state.Regs[9]; - case 0x6A: case 0x7A: return _state.Regs[10]; - case 0x6B: case 0x7B: return _state.Regs[11]; - case 0x6C: case 0x7C: return _state.Regs[12]; - case 0x6D: case 0x7D: return _state.Regs[13]; - case 0x6E: case 0x7E: return _state.Regs[14]; - case 0x6F: case 0x7F: return _state.Regs[15]; + case 0x60: + case 0x70: return _state.Regs[0]; + case 0x61: + case 0x71: return _state.Regs[1]; + case 0x62: + case 0x72: return _state.Regs[2]; + case 0x63: + case 0x73: return _state.Regs[3]; + case 0x64: + case 0x74: return _state.Regs[4]; + case 0x65: + case 0x75: return _state.Regs[5]; + case 0x66: + case 0x76: return _state.Regs[6]; + case 0x67: + case 0x77: return _state.Regs[7]; + case 0x68: + case 0x78: return _state.Regs[8]; + case 0x69: + case 0x79: return _state.Regs[9]; + case 0x6A: + case 0x7A: return _state.Regs[10]; + case 0x6B: + case 0x7B: return _state.Regs[11]; + case 0x6C: + case 0x7C: return _state.Regs[12]; + case 0x6D: + case 0x7D: return _state.Regs[13]; + case 0x6E: + case 0x7E: return _state.Regs[14]; + case 0x6F: + case 0x7F: return _state.Regs[15]; } return 0; } -void Cx4::WriteRegister(uint8_t reg, uint32_t value) +void Cx4::WriteRegister(uint8_t reg, uint32_t value) { value &= 0xFFFFFF; - switch(reg & 0x7F) { - case 0x01: _state.Mult = (_state.Mult & 0xFFFFFF) | (value << 24); break; - case 0x02: _state.Mult = (_state.Mult & 0xFFFFFF000000) | value; break; - case 0x03: _state.MemoryDataReg = value; break; - case 0x08: _state.RomBuffer = value; break; - case 0x0C: - _state.RamBuffer[0] = value; - _state.RamBuffer[1] = value >> 8; - _state.RamBuffer[2] = value >> 16; - break; + switch (reg & 0x7F) + { + case 0x01: _state.Mult = (_state.Mult & 0xFFFFFF) | (value << 24); + break; + case 0x02: _state.Mult = (_state.Mult & 0xFFFFFF000000) | value; + break; + case 0x03: _state.MemoryDataReg = value; + break; + case 0x08: _state.RomBuffer = value; + break; + case 0x0C: + _state.RamBuffer[0] = value; + _state.RamBuffer[1] = value >> 8; + _state.RamBuffer[2] = value >> 16; + break; - case 0x13: _state.MemoryAddressReg = value; break; - case 0x1C: _state.DataPointerReg = value; break; - case 0x20: _state.PC = value; break; - case 0x28: _state.P = (value & 0x7FFF); break; - - case 0x2E: - _state.Bus.Enabled = true; - _state.Bus.Writing = true; - _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - break; + case 0x13: _state.MemoryAddressReg = value; + break; + case 0x1C: _state.DataPointerReg = value; + break; + case 0x20: _state.PC = value; + break; + case 0x28: _state.P = (value & 0x7FFF); + break; - case 0x2F: - _state.Bus.Enabled = true; - _state.Bus.Writing = true; - _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; - _state.Bus.Address = _state.MemoryAddressReg; - break; + case 0x2E: + _state.Bus.Enabled = true; + _state.Bus.Writing = true; + _state.Bus.DelayCycles = 1 + _state.RomAccessDelay; + _state.Bus.Address = _state.MemoryAddressReg; + break; - case 0x60: case 0x70: _state.Regs[0] = value; break; - case 0x61: case 0x71: _state.Regs[1] = value; break; - case 0x62: case 0x72: _state.Regs[2] = value; break; - case 0x63: case 0x73: _state.Regs[3] = value; break; - case 0x64: case 0x74: _state.Regs[4] = value; break; - case 0x65: case 0x75: _state.Regs[5] = value; break; - case 0x66: case 0x76: _state.Regs[6] = value; break; - case 0x67: case 0x77: _state.Regs[7] = value; break; - case 0x68: case 0x78: _state.Regs[8] = value; break; - case 0x69: case 0x79: _state.Regs[9] = value; break; - case 0x6A: case 0x7a: _state.Regs[10] = value; break; - case 0x6B: case 0x7b: _state.Regs[11] = value; break; - case 0x6C: case 0x7c: _state.Regs[12] = value; break; - case 0x6D: case 0x7d: _state.Regs[13] = value; break; - case 0x6E: case 0x7e: _state.Regs[14] = value; break; - case 0x6F: case 0x7f: _state.Regs[15] = value; break; + case 0x2F: + _state.Bus.Enabled = true; + _state.Bus.Writing = true; + _state.Bus.DelayCycles = 1 + _state.RamAccessDelay; + _state.Bus.Address = _state.MemoryAddressReg; + break; + + case 0x60: + case 0x70: _state.Regs[0] = value; + break; + case 0x61: + case 0x71: _state.Regs[1] = value; + break; + case 0x62: + case 0x72: _state.Regs[2] = value; + break; + case 0x63: + case 0x73: _state.Regs[3] = value; + break; + case 0x64: + case 0x74: _state.Regs[4] = value; + break; + case 0x65: + case 0x75: _state.Regs[5] = value; + break; + case 0x66: + case 0x76: _state.Regs[6] = value; + break; + case 0x67: + case 0x77: _state.Regs[7] = value; + break; + case 0x68: + case 0x78: _state.Regs[8] = value; + break; + case 0x69: + case 0x79: _state.Regs[9] = value; + break; + case 0x6A: + case 0x7a: _state.Regs[10] = value; + break; + case 0x6B: + case 0x7b: _state.Regs[11] = value; + break; + case 0x6C: + case 0x7c: _state.Regs[12] = value; + break; + case 0x6D: + case 0x7d: _state.Regs[13] = value; + break; + case 0x6E: + case 0x7e: _state.Regs[14] = value; + break; + case 0x6F: + case 0x7f: _state.Regs[15] = value; + break; } } @@ -228,7 +351,8 @@ void Cx4::NOP() void Cx4::WAIT() { - if(_state.Bus.Enabled) { + if (_state.Bus.Enabled) + { Step(_state.Bus.DelayCycles); } } @@ -236,17 +360,24 @@ void Cx4::WAIT() void Cx4::Skip(uint8_t flagToCheck, uint8_t skipIfSet) { bool skip; - switch(flagToCheck) { - default: - case 0: skip = _state.Overflow == (skipIfSet & 0x01); break; - case 1: skip = _state.Carry == (skipIfSet & 0x01); break; - case 2: skip = _state.Zero == (skipIfSet & 0x01); break; - case 3: skip = _state.Negative == (skipIfSet & 0x01); break; + switch (flagToCheck) + { + default: + case 0: skip = _state.Overflow == (skipIfSet & 0x01); + break; + case 1: skip = _state.Carry == (skipIfSet & 0x01); + break; + case 2: skip = _state.Zero == (skipIfSet & 0x01); + break; + case 3: skip = _state.Negative == (skipIfSet & 0x01); + break; } - if(skip) { + if (skip) + { _state.PC++; - if(_state.PC == 0) { + if (_state.PC == 0) + { SwitchCachePage(); } Step(1); @@ -255,8 +386,10 @@ void Cx4::Skip(uint8_t flagToCheck, uint8_t skipIfSet) void Cx4::Branch(bool branch, uint8_t far, uint8_t dest) { - if(branch) { - if(far) { + if (branch) + { + if (far) + { _state.PB = _state.P; } _state.PC = dest; @@ -266,9 +399,11 @@ void Cx4::Branch(bool branch, uint8_t far, uint8_t dest) void Cx4::JSR(bool branch, uint8_t far, uint8_t dest) { - if(branch) { + if (branch) + { PushPC(); - if(far) { + if (far) + { _state.PB = _state.P; } _state.PC = dest; @@ -348,11 +483,14 @@ void Cx4::CMP_Imm(uint8_t shift, uint8_t imm) void Cx4::SignExtend(uint8_t mode) { - if(mode == 1) { + if (mode == 1) + { _state.A = ((uint32_t)(int8_t)_state.A) & 0xFFFFFF; _state.Negative = _state.A & 0x800000; _state.Zero = _state.A == 0; - } else if(mode == 2) { + } + else if (mode == 2) + { _state.A = ((uint32_t)(int16_t)_state.A) & 0xFFFFFF; _state.Negative = _state.A & 0x800000; _state.Zero = _state.A == 0; @@ -361,21 +499,31 @@ void Cx4::SignExtend(uint8_t mode) void Cx4::Load(uint8_t dest, uint8_t src) { - switch(dest) { - case 0: _state.A = GetSourceValue(src); break; - case 1: _state.MemoryDataReg = GetSourceValue(src); break; - case 2: _state.MemoryAddressReg = GetSourceValue(src); break; - case 3: _state.P = GetSourceValue(src) & 0x7FFF; break; + switch (dest) + { + case 0: _state.A = GetSourceValue(src); + break; + case 1: _state.MemoryDataReg = GetSourceValue(src); + break; + case 2: _state.MemoryAddressReg = GetSourceValue(src); + break; + case 3: _state.P = GetSourceValue(src) & 0x7FFF; + break; } } void Cx4::Load_Imm(uint8_t dest, uint8_t imm) { - switch(dest) { - case 0: _state.A = imm; break; - case 1: _state.MemoryDataReg = imm; break; - case 2: _state.MemoryAddressReg = imm; break; - case 3: _state.P = imm; break; + switch (dest) + { + case 0: _state.A = imm; + break; + case 1: _state.MemoryDataReg = imm; + break; + case 2: _state.MemoryAddressReg = imm; + break; + case 3: _state.P = imm; + break; } } @@ -471,7 +619,8 @@ void Cx4::XNOR_Imm(uint8_t shift, uint8_t imm) void Cx4::SHR(uint8_t src) { uint8_t shift = GetSourceValue(src) & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA(_state.A >> shift); } SetZeroNegativeFlags(); @@ -480,7 +629,8 @@ void Cx4::SHR(uint8_t src) void Cx4::SHR_Imm(uint8_t imm) { uint8_t shift = imm & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA(_state.A >> shift); } SetZeroNegativeFlags(); @@ -489,7 +639,8 @@ void Cx4::SHR_Imm(uint8_t imm) void Cx4::ASR(uint8_t src) { uint8_t shift = GetSourceValue(src) & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA((((int32_t)_state.A << 8) >> 8) >> shift); } SetZeroNegativeFlags(); @@ -498,7 +649,8 @@ void Cx4::ASR(uint8_t src) void Cx4::ASR_Imm(uint8_t imm) { uint8_t shift = imm & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA((((int32_t)_state.A << 8) >> 8) >> shift); } SetZeroNegativeFlags(); @@ -507,7 +659,8 @@ void Cx4::ASR_Imm(uint8_t imm) void Cx4::SHL(uint8_t src) { uint8_t shift = GetSourceValue(src) & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA(_state.A << shift); } SetZeroNegativeFlags(); @@ -516,7 +669,8 @@ void Cx4::SHL(uint8_t src) void Cx4::SHL_Imm(uint8_t imm) { uint8_t shift = imm & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA(_state.A << shift); } SetZeroNegativeFlags(); @@ -525,7 +679,8 @@ void Cx4::SHL_Imm(uint8_t imm) void Cx4::ROR(uint8_t src) { uint8_t shift = GetSourceValue(src) & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA((_state.A >> shift) | (_state.A << (24 - shift))); } SetZeroNegativeFlags(); @@ -534,7 +689,8 @@ void Cx4::ROR(uint8_t src) void Cx4::ROR_Imm(uint8_t imm) { uint8_t shift = imm & 0x1F; - if(shift < 24) { + if (shift < 24) + { SetA((_state.A >> shift) | (_state.A << (24 - shift))); } SetZeroNegativeFlags(); @@ -552,12 +708,14 @@ void Cx4::ReadRom_Imm(uint16_t imm) void Cx4::ReadRam(uint8_t byteIndex) { - if(byteIndex >= 3) { + if (byteIndex >= 3) + { return; } uint16_t addr = _state.A & 0xFFF; - if(addr >= 0xC00) { + if (addr >= 0xC00) + { addr -= 0x400; } @@ -566,12 +724,14 @@ void Cx4::ReadRam(uint8_t byteIndex) void Cx4::ReadRam_Imm(uint8_t byteIndex, uint8_t imm) { - if(byteIndex >= 3) { + if (byteIndex >= 3) + { return; } uint16_t addr = (_state.DataPointerReg + imm) & 0xFFF; - if(addr >= 0xC00) { + if (addr >= 0xC00) + { addr -= 0x400; } _state.RamBuffer[byteIndex] = _dataRam[addr]; @@ -579,12 +739,14 @@ void Cx4::ReadRam_Imm(uint8_t byteIndex, uint8_t imm) void Cx4::WriteRam(uint8_t byteIndex) { - if(byteIndex >= 3) { + if (byteIndex >= 3) + { return; } uint16_t addr = _state.A & 0xFFF; - if(addr >= 0xC00) { + if (addr >= 0xC00) + { addr -= 0x400; } @@ -593,12 +755,14 @@ void Cx4::WriteRam(uint8_t byteIndex) void Cx4::WriteRam_Imm(uint8_t byteIndex, uint8_t imm) { - if(byteIndex >= 3) { + if (byteIndex >= 3) + { return; } uint16_t addr = (_state.DataPointerReg + imm) & 0xFFF; - if(addr >= 0xC00) { + if (addr >= 0xC00) + { addr -= 0x400; } _dataRam[addr] = _state.RamBuffer[byteIndex]; @@ -606,10 +770,13 @@ void Cx4::WriteRam_Imm(uint8_t byteIndex, uint8_t imm) void Cx4::LoadP(uint8_t byteIndex, uint8_t imm) { - switch(byteIndex) { - case 0: _state.P = (_state.P & 0x7F00) | imm; break; - case 1: _state.P = (_state.P & 0xFF) | ((imm & 0x7F) << 8); break; - default: break; //nop + switch (byteIndex) + { + case 0: _state.P = (_state.P & 0x7F00) | imm; + break; + case 1: _state.P = (_state.P & 0xFF) | ((imm & 0x7F) << 8); + break; + default: break; //nop } } @@ -622,17 +789,21 @@ void Cx4::Swap(uint8_t reg) void Cx4::Store(uint8_t src, uint8_t dst) { - switch(src) { - case 0: WriteRegister(dst, _state.A); break; - case 1: WriteRegister(dst, _state.MemoryDataReg); break; - default: break; //nop + switch (src) + { + case 0: WriteRegister(dst, _state.A); + break; + case 1: WriteRegister(dst, _state.MemoryDataReg); + break; + default: break; //nop } } void Cx4::Stop() { _state.Stopped = true; - if(!_state.IrqDisabled) { + if (!_state.IrqDisabled) + { _state.IrqFlag = true; _cpu->SetIrqSource(IrqSource::Coprocessor); } @@ -645,68 +816,132 @@ void Cx4::IncMar() //Data ROM that contains precalculated math lookup tables for sines, cosines, division, etc. const uint32_t _dataRom[1024] = { - 0xFFFFFF, 0x800000, 0x400000, 0x2AAAAA, 0x200000, 0x199999, 0x155555, 0x124924, 0x100000, 0x0E38E3, 0x0CCCCC, 0x0BA2E8, 0x0AAAAA, 0x09D89D, 0x092492, 0x088888, - 0x080000, 0x078787, 0x071C71, 0x06BCA1, 0x066666, 0x061861, 0x05D174, 0x0590B2, 0x055555, 0x051EB8, 0x04EC4E, 0x04BDA1, 0x049249, 0x0469EE, 0x044444, 0x042108, - 0x040000, 0x03E0F8, 0x03C3C3, 0x03A83A, 0x038E38, 0x03759F, 0x035E50, 0x034834, 0x033333, 0x031F38, 0x030C30, 0x02FA0B, 0x02E8BA, 0x02D82D, 0x02C859, 0x02B931, - 0x02AAAA, 0x029CBC, 0x028F5C, 0x028282, 0x027627, 0x026A43, 0x025ED0, 0x0253C8, 0x024924, 0x023EE0, 0x0234F7, 0x022B63, 0x022222, 0x02192E, 0x021084, 0x020820, - 0x020000, 0x01F81F, 0x01F07C, 0x01E913, 0x01E1E1, 0x01DAE6, 0x01D41D, 0x01CD85, 0x01C71C, 0x01C0E0, 0x01BACF, 0x01B4E8, 0x01AF28, 0x01A98E, 0x01A41A, 0x019EC8, - 0x019999, 0x01948B, 0x018F9C, 0x018ACB, 0x018618, 0x018181, 0x017D05, 0x0178A4, 0x01745D, 0x01702E, 0x016C16, 0x016816, 0x01642C, 0x016058, 0x015C98, 0x0158ED, - 0x015555, 0x0151D0, 0x014E5E, 0x014AFD, 0x0147AE, 0x01446F, 0x014141, 0x013E22, 0x013B13, 0x013813, 0x013521, 0x01323E, 0x012F68, 0x012C9F, 0x0129E4, 0x012735, - 0x012492, 0x0121FB, 0x011F70, 0x011CF0, 0x011A7B, 0x011811, 0x0115B1, 0x01135C, 0x011111, 0x010ECF, 0x010C97, 0x010A68, 0x010842, 0x010624, 0x010410, 0x010204, - 0x010000, 0x00FE03, 0x00FC0F, 0x00FA23, 0x00F83E, 0x00F660, 0x00F489, 0x00F2B9, 0x00F0F0, 0x00EF2E, 0x00ED73, 0x00EBBD, 0x00EA0E, 0x00E865, 0x00E6C2, 0x00E525, - 0x00E38E, 0x00E1FC, 0x00E070, 0x00DEE9, 0x00DD67, 0x00DBEB, 0x00DA74, 0x00D901, 0x00D794, 0x00D62B, 0x00D4C7, 0x00D368, 0x00D20D, 0x00D0B6, 0x00CF64, 0x00CE16, - 0x00CCCC, 0x00CB87, 0x00CA45, 0x00C907, 0x00C7CE, 0x00C698, 0x00C565, 0x00C437, 0x00C30C, 0x00C1E4, 0x00C0C0, 0x00BFA0, 0x00BE82, 0x00BD69, 0x00BC52, 0x00BB3E, - 0x00BA2E, 0x00B921, 0x00B817, 0x00B70F, 0x00B60B, 0x00B509, 0x00B40B, 0x00B30F, 0x00B216, 0x00B11F, 0x00B02C, 0x00AF3A, 0x00AE4C, 0x00AD60, 0x00AC76, 0x00AB8F, - 0x00AAAA, 0x00A9C8, 0x00A8E8, 0x00A80A, 0x00A72F, 0x00A655, 0x00A57E, 0x00A4A9, 0x00A3D7, 0x00A306, 0x00A237, 0x00A16B, 0x00A0A0, 0x009FD8, 0x009F11, 0x009E4C, - 0x009D89, 0x009CC8, 0x009C09, 0x009B4C, 0x009A90, 0x0099D7, 0x00991F, 0x009868, 0x0097B4, 0x009701, 0x00964F, 0x0095A0, 0x0094F2, 0x009445, 0x00939A, 0x0092F1, - 0x009249, 0x0091A2, 0x0090FD, 0x00905A, 0x008FB8, 0x008F17, 0x008E78, 0x008DDA, 0x008D3D, 0x008CA2, 0x008C08, 0x008B70, 0x008AD8, 0x008A42, 0x0089AE, 0x00891A, - 0x008888, 0x0087F7, 0x008767, 0x0086D9, 0x00864B, 0x0085BF, 0x008534, 0x0084A9, 0x008421, 0x008399, 0x008312, 0x00828C, 0x008208, 0x008184, 0x008102, 0x008080, - 0x000000, 0x100000, 0x16A09E, 0x1BB67A, 0x200000, 0x23C6EF, 0x27311C, 0x2A54FF, 0x2D413C, 0x300000, 0x3298B0, 0x3510E5, 0x376CF5, 0x39B056, 0x3BDDD4, 0x3DF7BD, - 0x400000, 0x41F83D, 0x43E1DB, 0x45BE0C, 0x478DDE, 0x49523A, 0x4B0BF1, 0x4CBBB9, 0x4E6238, 0x500000, 0x519595, 0x532370, 0x54A9FE, 0x5629A2, 0x57A2B7, 0x591590, - 0x5A8279, 0x5BE9BA, 0x5D4B94, 0x5EA843, 0x600000, 0x6152FE, 0x62A170, 0x63EB83, 0x653160, 0x667332, 0x67B11D, 0x68EB44, 0x6A21CA, 0x6B54CD, 0x6C846C, 0x6DB0C2, - 0x6ED9EB, 0x700000, 0x712318, 0x72434A, 0x7360AD, 0x747B54, 0x759354, 0x76A8BF, 0x77BBA8, 0x78CC1F, 0x79DA34, 0x7AE5F9, 0x7BEF7A, 0x7CF6C8, 0x7DFBEF, 0x7EFEFD, - 0x800000, 0x80FF01, 0x81FC0F, 0x82F734, 0x83F07B, 0x84E7EE, 0x85DD98, 0x86D182, 0x87C3B6, 0x88B43D, 0x89A31F, 0x8A9066, 0x8B7C19, 0x8C6641, 0x8D4EE4, 0x8E360B, - 0x8F1BBC, 0x900000, 0x90E2DB, 0x91C456, 0x92A475, 0x938341, 0x9460BD, 0x953CF1, 0x9617E2, 0x96F196, 0x97CA11, 0x98A159, 0x997773, 0x9A4C64, 0x9B2031, 0x9BF2DE, - 0x9CC470, 0x9D94EB, 0x9E6454, 0x9F32AF, 0xA00000, 0xA0CC4A, 0xA19792, 0xA261DC, 0xA32B2A, 0xA3F382, 0xA4BAE6, 0xA5815A, 0xA646E1, 0xA70B7E, 0xA7CF35, 0xA89209, - 0xA953FD, 0xAA1513, 0xAAD550, 0xAB94B4, 0xAC5345, 0xAD1103, 0xADCDF2, 0xAE8A15, 0xAF456E, 0xB00000, 0xB0B9CC, 0xB172D6, 0xB22B20, 0xB2E2AC, 0xB3997C, 0xB44F93, - 0xB504F3, 0xB5B99D, 0xB66D95, 0xB720DC, 0xB7D375, 0xB88560, 0xB936A0, 0xB9E738, 0xBA9728, 0xBB4673, 0xBBF51A, 0xBCA320, 0xBD5086, 0xBDFD4E, 0xBEA979, 0xBF5509, - 0xC00000, 0xC0AA5F, 0xC15428, 0xC1FD5C, 0xC2A5FD, 0xC34E0D, 0xC3F58C, 0xC49C7D, 0xC542E1, 0xC5E8B8, 0xC68E05, 0xC732C9, 0xC7D706, 0xC87ABB, 0xC91DEB, 0xC9C098, - 0xCA62C1, 0xCB0469, 0xCBA591, 0xCC463A, 0xCCE664, 0xCD8612, 0xCE2544, 0xCEC3FC, 0xCF623A, 0xD00000, 0xD09D4E, 0xD13A26, 0xD1D689, 0xD27277, 0xD30DF3, 0xD3A8FC, - 0xD44394, 0xD4DDBC, 0xD57774, 0xD610BE, 0xD6A99B, 0xD7420B, 0xD7DA0F, 0xD871A9, 0xD908D8, 0xD99F9F, 0xDA35FE, 0xDACBF5, 0xDB6185, 0xDBF6B0, 0xDC8B76, 0xDD1FD8, - 0xDDB3D7, 0xDE4773, 0xDEDAAD, 0xDF6D86, 0xE00000, 0xE09219, 0xE123D4, 0xE1B530, 0xE24630, 0xE2D6D2, 0xE36719, 0xE3F704, 0xE48694, 0xE515CB, 0xE5A4A8, 0xE6332D, - 0xE6C15A, 0xE74F2F, 0xE7DCAD, 0xE869D6, 0xE8F6A9, 0xE98326, 0xEA0F50, 0xEA9B26, 0xEB26A8, 0xEBB1D9, 0xEC3CB7, 0xECC743, 0xED517F, 0xEDDB6A, 0xEE6506, 0xEEEE52, - 0xEF7750, 0xF00000, 0xF08861, 0xF11076, 0xF1983E, 0xF21FBA, 0xF2A6EA, 0xF32DCF, 0xF3B469, 0xF43AB9, 0xF4C0C0, 0xF5467D, 0xF5CBF2, 0xF6511E, 0xF6D602, 0xF75A9F, - 0xF7DEF5, 0xF86305, 0xF8E6CE, 0xF96A52, 0xF9ED90, 0xFA708A, 0xFAF33F, 0xFB75B1, 0xFBF7DF, 0xFC79CA, 0xFCFB72, 0xFD7CD8, 0xFDFDFB, 0xFE7EDE, 0xFEFF7F, 0xFF7FDF, - 0x000000, 0x03243A, 0x064855, 0x096C32, 0x0C8FB2, 0x0FB2B7, 0x12D520, 0x15F6D0, 0x1917A6, 0x1C3785, 0x1F564E, 0x2273E1, 0x259020, 0x28AAED, 0x2BC428, 0x2EDBB3, - 0x31F170, 0x350540, 0x381704, 0x3B269F, 0x3E33F2, 0x413EE0, 0x444749, 0x474D10, 0x4A5018, 0x4D5043, 0x504D72, 0x534789, 0x563E69, 0x5931F7, 0x5C2214, 0x5F0EA4, - 0x61F78A, 0x64DCA9, 0x67BDE5, 0x6A9B20, 0x6D7440, 0x704927, 0x7319BA, 0x75E5DD, 0x78AD74, 0x7B7065, 0x7E2E93, 0x80E7E4, 0x839C3C, 0x864B82, 0x88F59A, 0x8B9A6B, - 0x8E39D9, 0x90D3CC, 0x93682A, 0x95F6D9, 0x987FBF, 0x9B02C5, 0x9D7FD1, 0x9FF6CA, 0xA26799, 0xA4D224, 0xA73655, 0xA99414, 0xABEB49, 0xAE3BDD, 0xB085BA, 0xB2C8C9, - 0xB504F3, 0xB73A22, 0xB96841, 0xBB8F3A, 0xBDAEF9, 0xBFC767, 0xC1D870, 0xC3E200, 0xC5E403, 0xC7DE65, 0xC9D112, 0xCBBBF7, 0xCD9F02, 0xCF7A1F, 0xD14D3D, 0xD31848, - 0xD4DB31, 0xD695E4, 0xD84852, 0xD9F269, 0xDB941A, 0xDD2D53, 0xDEBE05, 0xE04621, 0xE1C597, 0xE33C59, 0xE4AA59, 0xE60F87, 0xE76BD7, 0xE8BF3B, 0xEA09A6, 0xEB4B0B, - 0xEC835E, 0xEDB293, 0xEED89D, 0xEFF573, 0xF10908, 0xF21352, 0xF31447, 0xF40BDD, 0xF4FA0A, 0xF5DEC6, 0xF6BA07, 0xF78BC5, 0xF853F7, 0xF91297, 0xF9C79D, 0xFA7301, - 0xFB14BE, 0xFBACCD, 0xFC3B27, 0xFCBFC9, 0xFD3AAB, 0xFDABCB, 0xFE1323, 0xFE70AF, 0xFEC46D, 0xFF0E57, 0xFF4E6D, 0xFF84AB, 0xFFB10F, 0xFFD397, 0xFFEC43, 0xFFFB10, - 0x000000, 0x00A2F9, 0x0145F6, 0x01E8F8, 0x028C01, 0x032F14, 0x03D234, 0x047564, 0x0518A5, 0x05BBFB, 0x065F68, 0x0702EF, 0x07A692, 0x084A54, 0x08EE38, 0x099240, - 0x0A366E, 0x0ADAC7, 0x0B7F4C, 0x0C2401, 0x0CC8E7, 0x0D6E02, 0x0E1355, 0x0EB8E3, 0x0F5EAE, 0x1004B9, 0x10AB08, 0x11519E, 0x11F87D, 0x129FA9, 0x134725, 0x13EEF4, - 0x149719, 0x153F99, 0x15E875, 0x1691B2, 0x173B53, 0x17E55C, 0x188FD1, 0x193AB4, 0x19E60A, 0x1A91D8, 0x1B3E20, 0x1BEAE7, 0x1C9831, 0x1D4602, 0x1DF45F, 0x1EA34C, - 0x1F52CE, 0x2002EA, 0x20B3A3, 0x216500, 0x221705, 0x22C9B8, 0x237D1E, 0x24313C, 0x24E618, 0x259BB9, 0x265224, 0x27095F, 0x27C171, 0x287A61, 0x293436, 0x29EEF6, - 0x2AAAAA, 0x2B6759, 0x2C250A, 0x2CE3C7, 0x2DA398, 0x2E6485, 0x2F2699, 0x2FE9DC, 0x30AE59, 0x31741B, 0x323B2C, 0x330398, 0x33CD6B, 0x3498B1, 0x356578, 0x3633CE, - 0x3703C1, 0x37D560, 0x38A8BB, 0x397DE4, 0x3A54EC, 0x3B2DE6, 0x3C08E6, 0x3CE601, 0x3DC54D, 0x3EA6E3, 0x3F8ADC, 0x407152, 0x415A62, 0x42462C, 0x4334D0, 0x442671, - 0x451B37, 0x46134A, 0x470ED6, 0x480E0C, 0x491120, 0x4A184C, 0x4B23CD, 0x4C33EA, 0x4D48EC, 0x4E6327, 0x4F82F9, 0x50A8C9, 0x51D50A, 0x53083F, 0x5442FC, 0x5585EA, - 0x56D1CC, 0x582782, 0x598815, 0x5AF4BC, 0x5C6EED, 0x5DF86C, 0x5F9369, 0x6142A3, 0x6309A5, 0x64ED1E, 0x66F381, 0x692617, 0x6B9322, 0x6E52A5, 0x71937C, 0x75CEB4, - 0x000000, 0x000324, 0x000648, 0x00096D, 0x000C93, 0x000FBA, 0x0012E2, 0x00160B, 0x001936, 0x001C63, 0x001F93, 0x0022C4, 0x0025F9, 0x002930, 0x002C6B, 0x002FA9, - 0x0032EB, 0x003632, 0x00397C, 0x003CCB, 0x00401F, 0x004379, 0x0046D8, 0x004A3D, 0x004DA8, 0x005119, 0x005492, 0x005811, 0x005B99, 0x005F28, 0x0062C0, 0x006660, - 0x006A09, 0x006DBC, 0x00717A, 0x007541, 0x007914, 0x007CF2, 0x0080DC, 0x0084D2, 0x0088D5, 0x008CE6, 0x009105, 0x009533, 0x009970, 0x009DBE, 0x00A21C, 0x00A68B, - 0x00AB0D, 0x00AFA2, 0x00B44B, 0x00B909, 0x00BDDC, 0x00C2C6, 0x00C7C8, 0x00CCE3, 0x00D218, 0x00D767, 0x00DCD3, 0x00E25D, 0x00E806, 0x00EDCF, 0x00F3BB, 0x00F9CA, - 0x010000, 0x01065C, 0x010CE2, 0x011394, 0x011A73, 0x012183, 0x0128C6, 0x01303E, 0x0137EF, 0x013FDC, 0x014808, 0x015077, 0x01592D, 0x01622D, 0x016B7D, 0x017522, - 0x017F21, 0x018980, 0x019444, 0x019F76, 0x01AB1C, 0x01B73E, 0x01C3E7, 0x01D11F, 0x01DEF1, 0x01ED69, 0x01FC95, 0x020C83, 0x021D44, 0x022EE9, 0x024186, 0x025533, - 0x026A09, 0x028025, 0x0297A7, 0x02B0B5, 0x02CB78, 0x02E823, 0x0306EC, 0x032815, 0x034BEB, 0x0372C6, 0x039D10, 0x03CB47, 0x03FE02, 0x0435F7, 0x047405, 0x04B93F, - 0x0506FF, 0x055EF9, 0x05C35D, 0x063709, 0x06BDCF, 0x075CE6, 0x081B97, 0x09046D, 0x0A2736, 0x0B9CC6, 0x0D8E81, 0x1046E9, 0x145AFF, 0x1B2671, 0x28BC48, 0x517BB5, - 0xFFFFFF, 0xFFFB10, 0xFFEC43, 0xFFD397, 0xFFB10F, 0xFF84AB, 0xFF4E6D, 0xFF0E57, 0xFEC46D, 0xFE70AF, 0xFE1323, 0xFDABCB, 0xFD3AAB, 0xFCBFC9, 0xFC3B27, 0xFBACCD, - 0xFB14BE, 0xFA7301, 0xF9C79D, 0xF91297, 0xF853F7, 0xF78BC5, 0xF6BA07, 0xF5DEC6, 0xF4FA0A, 0xF40BDD, 0xF31447, 0xF21352, 0xF10908, 0xEFF573, 0xEED89D, 0xEDB293, - 0xEC835E, 0xEB4B0B, 0xEA09A6, 0xE8BF3B, 0xE76BD7, 0xE60F87, 0xE4AA59, 0xE33C59, 0xE1C597, 0xE04621, 0xDEBE05, 0xDD2D53, 0xDB941A, 0xD9F269, 0xD84852, 0xD695E4, - 0xD4DB31, 0xD31848, 0xD14D3D, 0xCF7A1F, 0xCD9F02, 0xCBBBF7, 0xC9D112, 0xC7DE65, 0xC5E403, 0xC3E200, 0xC1D870, 0xBFC767, 0xBDAEF9, 0xBB8F3A, 0xB96841, 0xB73A22, - 0xB504F3, 0xB2C8C9, 0xB085BA, 0xAE3BDD, 0xABEB49, 0xA99414, 0xA73655, 0xA4D224, 0xA26799, 0x9FF6CA, 0x9D7FD1, 0x9B02C5, 0x987FBF, 0x95F6D9, 0x93682A, 0x90D3CC, - 0x8E39D9, 0x8B9A6B, 0x88F59A, 0x864B82, 0x839C3C, 0x80E7E4, 0x7E2E93, 0x7B7065, 0x78AD74, 0x75E5DD, 0x7319BA, 0x704927, 0x6D7440, 0x6A9B20, 0x67BDE5, 0x64DCA9, - 0x61F78A, 0x5F0EA4, 0x5C2214, 0x5931F7, 0x563E69, 0x534789, 0x504D72, 0x4D5043, 0x4A5018, 0x474D10, 0x444749, 0x413EE0, 0x3E33F2, 0x3B269F, 0x381704, 0x350540, - 0x31F170, 0x2EDBB3, 0x2BC428, 0x28AAED, 0x259020, 0x2273E1, 0x1F564E, 0x1C3785, 0x1917A6, 0x15F6D0, 0x12D520, 0x0FB2B7, 0x0C8FB2, 0x096C32, 0x064855, 0x03243A + 0xFFFFFF, 0x800000, 0x400000, 0x2AAAAA, 0x200000, 0x199999, 0x155555, 0x124924, 0x100000, 0x0E38E3, 0x0CCCCC, + 0x0BA2E8, 0x0AAAAA, 0x09D89D, 0x092492, 0x088888, + 0x080000, 0x078787, 0x071C71, 0x06BCA1, 0x066666, 0x061861, 0x05D174, 0x0590B2, 0x055555, 0x051EB8, 0x04EC4E, + 0x04BDA1, 0x049249, 0x0469EE, 0x044444, 0x042108, + 0x040000, 0x03E0F8, 0x03C3C3, 0x03A83A, 0x038E38, 0x03759F, 0x035E50, 0x034834, 0x033333, 0x031F38, 0x030C30, + 0x02FA0B, 0x02E8BA, 0x02D82D, 0x02C859, 0x02B931, + 0x02AAAA, 0x029CBC, 0x028F5C, 0x028282, 0x027627, 0x026A43, 0x025ED0, 0x0253C8, 0x024924, 0x023EE0, 0x0234F7, + 0x022B63, 0x022222, 0x02192E, 0x021084, 0x020820, + 0x020000, 0x01F81F, 0x01F07C, 0x01E913, 0x01E1E1, 0x01DAE6, 0x01D41D, 0x01CD85, 0x01C71C, 0x01C0E0, 0x01BACF, + 0x01B4E8, 0x01AF28, 0x01A98E, 0x01A41A, 0x019EC8, + 0x019999, 0x01948B, 0x018F9C, 0x018ACB, 0x018618, 0x018181, 0x017D05, 0x0178A4, 0x01745D, 0x01702E, 0x016C16, + 0x016816, 0x01642C, 0x016058, 0x015C98, 0x0158ED, + 0x015555, 0x0151D0, 0x014E5E, 0x014AFD, 0x0147AE, 0x01446F, 0x014141, 0x013E22, 0x013B13, 0x013813, 0x013521, + 0x01323E, 0x012F68, 0x012C9F, 0x0129E4, 0x012735, + 0x012492, 0x0121FB, 0x011F70, 0x011CF0, 0x011A7B, 0x011811, 0x0115B1, 0x01135C, 0x011111, 0x010ECF, 0x010C97, + 0x010A68, 0x010842, 0x010624, 0x010410, 0x010204, + 0x010000, 0x00FE03, 0x00FC0F, 0x00FA23, 0x00F83E, 0x00F660, 0x00F489, 0x00F2B9, 0x00F0F0, 0x00EF2E, 0x00ED73, + 0x00EBBD, 0x00EA0E, 0x00E865, 0x00E6C2, 0x00E525, + 0x00E38E, 0x00E1FC, 0x00E070, 0x00DEE9, 0x00DD67, 0x00DBEB, 0x00DA74, 0x00D901, 0x00D794, 0x00D62B, 0x00D4C7, + 0x00D368, 0x00D20D, 0x00D0B6, 0x00CF64, 0x00CE16, + 0x00CCCC, 0x00CB87, 0x00CA45, 0x00C907, 0x00C7CE, 0x00C698, 0x00C565, 0x00C437, 0x00C30C, 0x00C1E4, 0x00C0C0, + 0x00BFA0, 0x00BE82, 0x00BD69, 0x00BC52, 0x00BB3E, + 0x00BA2E, 0x00B921, 0x00B817, 0x00B70F, 0x00B60B, 0x00B509, 0x00B40B, 0x00B30F, 0x00B216, 0x00B11F, 0x00B02C, + 0x00AF3A, 0x00AE4C, 0x00AD60, 0x00AC76, 0x00AB8F, + 0x00AAAA, 0x00A9C8, 0x00A8E8, 0x00A80A, 0x00A72F, 0x00A655, 0x00A57E, 0x00A4A9, 0x00A3D7, 0x00A306, 0x00A237, + 0x00A16B, 0x00A0A0, 0x009FD8, 0x009F11, 0x009E4C, + 0x009D89, 0x009CC8, 0x009C09, 0x009B4C, 0x009A90, 0x0099D7, 0x00991F, 0x009868, 0x0097B4, 0x009701, 0x00964F, + 0x0095A0, 0x0094F2, 0x009445, 0x00939A, 0x0092F1, + 0x009249, 0x0091A2, 0x0090FD, 0x00905A, 0x008FB8, 0x008F17, 0x008E78, 0x008DDA, 0x008D3D, 0x008CA2, 0x008C08, + 0x008B70, 0x008AD8, 0x008A42, 0x0089AE, 0x00891A, + 0x008888, 0x0087F7, 0x008767, 0x0086D9, 0x00864B, 0x0085BF, 0x008534, 0x0084A9, 0x008421, 0x008399, 0x008312, + 0x00828C, 0x008208, 0x008184, 0x008102, 0x008080, + 0x000000, 0x100000, 0x16A09E, 0x1BB67A, 0x200000, 0x23C6EF, 0x27311C, 0x2A54FF, 0x2D413C, 0x300000, 0x3298B0, + 0x3510E5, 0x376CF5, 0x39B056, 0x3BDDD4, 0x3DF7BD, + 0x400000, 0x41F83D, 0x43E1DB, 0x45BE0C, 0x478DDE, 0x49523A, 0x4B0BF1, 0x4CBBB9, 0x4E6238, 0x500000, 0x519595, + 0x532370, 0x54A9FE, 0x5629A2, 0x57A2B7, 0x591590, + 0x5A8279, 0x5BE9BA, 0x5D4B94, 0x5EA843, 0x600000, 0x6152FE, 0x62A170, 0x63EB83, 0x653160, 0x667332, 0x67B11D, + 0x68EB44, 0x6A21CA, 0x6B54CD, 0x6C846C, 0x6DB0C2, + 0x6ED9EB, 0x700000, 0x712318, 0x72434A, 0x7360AD, 0x747B54, 0x759354, 0x76A8BF, 0x77BBA8, 0x78CC1F, 0x79DA34, + 0x7AE5F9, 0x7BEF7A, 0x7CF6C8, 0x7DFBEF, 0x7EFEFD, + 0x800000, 0x80FF01, 0x81FC0F, 0x82F734, 0x83F07B, 0x84E7EE, 0x85DD98, 0x86D182, 0x87C3B6, 0x88B43D, 0x89A31F, + 0x8A9066, 0x8B7C19, 0x8C6641, 0x8D4EE4, 0x8E360B, + 0x8F1BBC, 0x900000, 0x90E2DB, 0x91C456, 0x92A475, 0x938341, 0x9460BD, 0x953CF1, 0x9617E2, 0x96F196, 0x97CA11, + 0x98A159, 0x997773, 0x9A4C64, 0x9B2031, 0x9BF2DE, + 0x9CC470, 0x9D94EB, 0x9E6454, 0x9F32AF, 0xA00000, 0xA0CC4A, 0xA19792, 0xA261DC, 0xA32B2A, 0xA3F382, 0xA4BAE6, + 0xA5815A, 0xA646E1, 0xA70B7E, 0xA7CF35, 0xA89209, + 0xA953FD, 0xAA1513, 0xAAD550, 0xAB94B4, 0xAC5345, 0xAD1103, 0xADCDF2, 0xAE8A15, 0xAF456E, 0xB00000, 0xB0B9CC, + 0xB172D6, 0xB22B20, 0xB2E2AC, 0xB3997C, 0xB44F93, + 0xB504F3, 0xB5B99D, 0xB66D95, 0xB720DC, 0xB7D375, 0xB88560, 0xB936A0, 0xB9E738, 0xBA9728, 0xBB4673, 0xBBF51A, + 0xBCA320, 0xBD5086, 0xBDFD4E, 0xBEA979, 0xBF5509, + 0xC00000, 0xC0AA5F, 0xC15428, 0xC1FD5C, 0xC2A5FD, 0xC34E0D, 0xC3F58C, 0xC49C7D, 0xC542E1, 0xC5E8B8, 0xC68E05, + 0xC732C9, 0xC7D706, 0xC87ABB, 0xC91DEB, 0xC9C098, + 0xCA62C1, 0xCB0469, 0xCBA591, 0xCC463A, 0xCCE664, 0xCD8612, 0xCE2544, 0xCEC3FC, 0xCF623A, 0xD00000, 0xD09D4E, + 0xD13A26, 0xD1D689, 0xD27277, 0xD30DF3, 0xD3A8FC, + 0xD44394, 0xD4DDBC, 0xD57774, 0xD610BE, 0xD6A99B, 0xD7420B, 0xD7DA0F, 0xD871A9, 0xD908D8, 0xD99F9F, 0xDA35FE, + 0xDACBF5, 0xDB6185, 0xDBF6B0, 0xDC8B76, 0xDD1FD8, + 0xDDB3D7, 0xDE4773, 0xDEDAAD, 0xDF6D86, 0xE00000, 0xE09219, 0xE123D4, 0xE1B530, 0xE24630, 0xE2D6D2, 0xE36719, + 0xE3F704, 0xE48694, 0xE515CB, 0xE5A4A8, 0xE6332D, + 0xE6C15A, 0xE74F2F, 0xE7DCAD, 0xE869D6, 0xE8F6A9, 0xE98326, 0xEA0F50, 0xEA9B26, 0xEB26A8, 0xEBB1D9, 0xEC3CB7, + 0xECC743, 0xED517F, 0xEDDB6A, 0xEE6506, 0xEEEE52, + 0xEF7750, 0xF00000, 0xF08861, 0xF11076, 0xF1983E, 0xF21FBA, 0xF2A6EA, 0xF32DCF, 0xF3B469, 0xF43AB9, 0xF4C0C0, + 0xF5467D, 0xF5CBF2, 0xF6511E, 0xF6D602, 0xF75A9F, + 0xF7DEF5, 0xF86305, 0xF8E6CE, 0xF96A52, 0xF9ED90, 0xFA708A, 0xFAF33F, 0xFB75B1, 0xFBF7DF, 0xFC79CA, 0xFCFB72, + 0xFD7CD8, 0xFDFDFB, 0xFE7EDE, 0xFEFF7F, 0xFF7FDF, + 0x000000, 0x03243A, 0x064855, 0x096C32, 0x0C8FB2, 0x0FB2B7, 0x12D520, 0x15F6D0, 0x1917A6, 0x1C3785, 0x1F564E, + 0x2273E1, 0x259020, 0x28AAED, 0x2BC428, 0x2EDBB3, + 0x31F170, 0x350540, 0x381704, 0x3B269F, 0x3E33F2, 0x413EE0, 0x444749, 0x474D10, 0x4A5018, 0x4D5043, 0x504D72, + 0x534789, 0x563E69, 0x5931F7, 0x5C2214, 0x5F0EA4, + 0x61F78A, 0x64DCA9, 0x67BDE5, 0x6A9B20, 0x6D7440, 0x704927, 0x7319BA, 0x75E5DD, 0x78AD74, 0x7B7065, 0x7E2E93, + 0x80E7E4, 0x839C3C, 0x864B82, 0x88F59A, 0x8B9A6B, + 0x8E39D9, 0x90D3CC, 0x93682A, 0x95F6D9, 0x987FBF, 0x9B02C5, 0x9D7FD1, 0x9FF6CA, 0xA26799, 0xA4D224, 0xA73655, + 0xA99414, 0xABEB49, 0xAE3BDD, 0xB085BA, 0xB2C8C9, + 0xB504F3, 0xB73A22, 0xB96841, 0xBB8F3A, 0xBDAEF9, 0xBFC767, 0xC1D870, 0xC3E200, 0xC5E403, 0xC7DE65, 0xC9D112, + 0xCBBBF7, 0xCD9F02, 0xCF7A1F, 0xD14D3D, 0xD31848, + 0xD4DB31, 0xD695E4, 0xD84852, 0xD9F269, 0xDB941A, 0xDD2D53, 0xDEBE05, 0xE04621, 0xE1C597, 0xE33C59, 0xE4AA59, + 0xE60F87, 0xE76BD7, 0xE8BF3B, 0xEA09A6, 0xEB4B0B, + 0xEC835E, 0xEDB293, 0xEED89D, 0xEFF573, 0xF10908, 0xF21352, 0xF31447, 0xF40BDD, 0xF4FA0A, 0xF5DEC6, 0xF6BA07, + 0xF78BC5, 0xF853F7, 0xF91297, 0xF9C79D, 0xFA7301, + 0xFB14BE, 0xFBACCD, 0xFC3B27, 0xFCBFC9, 0xFD3AAB, 0xFDABCB, 0xFE1323, 0xFE70AF, 0xFEC46D, 0xFF0E57, 0xFF4E6D, + 0xFF84AB, 0xFFB10F, 0xFFD397, 0xFFEC43, 0xFFFB10, + 0x000000, 0x00A2F9, 0x0145F6, 0x01E8F8, 0x028C01, 0x032F14, 0x03D234, 0x047564, 0x0518A5, 0x05BBFB, 0x065F68, + 0x0702EF, 0x07A692, 0x084A54, 0x08EE38, 0x099240, + 0x0A366E, 0x0ADAC7, 0x0B7F4C, 0x0C2401, 0x0CC8E7, 0x0D6E02, 0x0E1355, 0x0EB8E3, 0x0F5EAE, 0x1004B9, 0x10AB08, + 0x11519E, 0x11F87D, 0x129FA9, 0x134725, 0x13EEF4, + 0x149719, 0x153F99, 0x15E875, 0x1691B2, 0x173B53, 0x17E55C, 0x188FD1, 0x193AB4, 0x19E60A, 0x1A91D8, 0x1B3E20, + 0x1BEAE7, 0x1C9831, 0x1D4602, 0x1DF45F, 0x1EA34C, + 0x1F52CE, 0x2002EA, 0x20B3A3, 0x216500, 0x221705, 0x22C9B8, 0x237D1E, 0x24313C, 0x24E618, 0x259BB9, 0x265224, + 0x27095F, 0x27C171, 0x287A61, 0x293436, 0x29EEF6, + 0x2AAAAA, 0x2B6759, 0x2C250A, 0x2CE3C7, 0x2DA398, 0x2E6485, 0x2F2699, 0x2FE9DC, 0x30AE59, 0x31741B, 0x323B2C, + 0x330398, 0x33CD6B, 0x3498B1, 0x356578, 0x3633CE, + 0x3703C1, 0x37D560, 0x38A8BB, 0x397DE4, 0x3A54EC, 0x3B2DE6, 0x3C08E6, 0x3CE601, 0x3DC54D, 0x3EA6E3, 0x3F8ADC, + 0x407152, 0x415A62, 0x42462C, 0x4334D0, 0x442671, + 0x451B37, 0x46134A, 0x470ED6, 0x480E0C, 0x491120, 0x4A184C, 0x4B23CD, 0x4C33EA, 0x4D48EC, 0x4E6327, 0x4F82F9, + 0x50A8C9, 0x51D50A, 0x53083F, 0x5442FC, 0x5585EA, + 0x56D1CC, 0x582782, 0x598815, 0x5AF4BC, 0x5C6EED, 0x5DF86C, 0x5F9369, 0x6142A3, 0x6309A5, 0x64ED1E, 0x66F381, + 0x692617, 0x6B9322, 0x6E52A5, 0x71937C, 0x75CEB4, + 0x000000, 0x000324, 0x000648, 0x00096D, 0x000C93, 0x000FBA, 0x0012E2, 0x00160B, 0x001936, 0x001C63, 0x001F93, + 0x0022C4, 0x0025F9, 0x002930, 0x002C6B, 0x002FA9, + 0x0032EB, 0x003632, 0x00397C, 0x003CCB, 0x00401F, 0x004379, 0x0046D8, 0x004A3D, 0x004DA8, 0x005119, 0x005492, + 0x005811, 0x005B99, 0x005F28, 0x0062C0, 0x006660, + 0x006A09, 0x006DBC, 0x00717A, 0x007541, 0x007914, 0x007CF2, 0x0080DC, 0x0084D2, 0x0088D5, 0x008CE6, 0x009105, + 0x009533, 0x009970, 0x009DBE, 0x00A21C, 0x00A68B, + 0x00AB0D, 0x00AFA2, 0x00B44B, 0x00B909, 0x00BDDC, 0x00C2C6, 0x00C7C8, 0x00CCE3, 0x00D218, 0x00D767, 0x00DCD3, + 0x00E25D, 0x00E806, 0x00EDCF, 0x00F3BB, 0x00F9CA, + 0x010000, 0x01065C, 0x010CE2, 0x011394, 0x011A73, 0x012183, 0x0128C6, 0x01303E, 0x0137EF, 0x013FDC, 0x014808, + 0x015077, 0x01592D, 0x01622D, 0x016B7D, 0x017522, + 0x017F21, 0x018980, 0x019444, 0x019F76, 0x01AB1C, 0x01B73E, 0x01C3E7, 0x01D11F, 0x01DEF1, 0x01ED69, 0x01FC95, + 0x020C83, 0x021D44, 0x022EE9, 0x024186, 0x025533, + 0x026A09, 0x028025, 0x0297A7, 0x02B0B5, 0x02CB78, 0x02E823, 0x0306EC, 0x032815, 0x034BEB, 0x0372C6, 0x039D10, + 0x03CB47, 0x03FE02, 0x0435F7, 0x047405, 0x04B93F, + 0x0506FF, 0x055EF9, 0x05C35D, 0x063709, 0x06BDCF, 0x075CE6, 0x081B97, 0x09046D, 0x0A2736, 0x0B9CC6, 0x0D8E81, + 0x1046E9, 0x145AFF, 0x1B2671, 0x28BC48, 0x517BB5, + 0xFFFFFF, 0xFFFB10, 0xFFEC43, 0xFFD397, 0xFFB10F, 0xFF84AB, 0xFF4E6D, 0xFF0E57, 0xFEC46D, 0xFE70AF, 0xFE1323, + 0xFDABCB, 0xFD3AAB, 0xFCBFC9, 0xFC3B27, 0xFBACCD, + 0xFB14BE, 0xFA7301, 0xF9C79D, 0xF91297, 0xF853F7, 0xF78BC5, 0xF6BA07, 0xF5DEC6, 0xF4FA0A, 0xF40BDD, 0xF31447, + 0xF21352, 0xF10908, 0xEFF573, 0xEED89D, 0xEDB293, + 0xEC835E, 0xEB4B0B, 0xEA09A6, 0xE8BF3B, 0xE76BD7, 0xE60F87, 0xE4AA59, 0xE33C59, 0xE1C597, 0xE04621, 0xDEBE05, + 0xDD2D53, 0xDB941A, 0xD9F269, 0xD84852, 0xD695E4, + 0xD4DB31, 0xD31848, 0xD14D3D, 0xCF7A1F, 0xCD9F02, 0xCBBBF7, 0xC9D112, 0xC7DE65, 0xC5E403, 0xC3E200, 0xC1D870, + 0xBFC767, 0xBDAEF9, 0xBB8F3A, 0xB96841, 0xB73A22, + 0xB504F3, 0xB2C8C9, 0xB085BA, 0xAE3BDD, 0xABEB49, 0xA99414, 0xA73655, 0xA4D224, 0xA26799, 0x9FF6CA, 0x9D7FD1, + 0x9B02C5, 0x987FBF, 0x95F6D9, 0x93682A, 0x90D3CC, + 0x8E39D9, 0x8B9A6B, 0x88F59A, 0x864B82, 0x839C3C, 0x80E7E4, 0x7E2E93, 0x7B7065, 0x78AD74, 0x75E5DD, 0x7319BA, + 0x704927, 0x6D7440, 0x6A9B20, 0x67BDE5, 0x64DCA9, + 0x61F78A, 0x5F0EA4, 0x5C2214, 0x5931F7, 0x563E69, 0x534789, 0x504D72, 0x4D5043, 0x4A5018, 0x474D10, 0x444749, + 0x413EE0, 0x3E33F2, 0x3B269F, 0x381704, 0x350540, + 0x31F170, 0x2EDBB3, 0x2BC428, 0x28AAED, 0x259020, 0x2273E1, 0x1F564E, 0x1C3785, 0x1917A6, 0x15F6D0, 0x12D520, + 0x0FB2B7, 0x0C8FB2, 0x096C32, 0x064855, 0x03243A }; diff --git a/Core/Cx4.cpp b/Core/Cx4.cpp index bbbb369..0d08ac1 100644 --- a/Core/Cx4.cpp +++ b/Core/Cx4.cpp @@ -19,11 +19,11 @@ Cx4::Cx4(Console* console) : BaseCoprocessor(SnesMemoryType::Register) _memoryType = SnesMemoryType::Register; _memoryManager = console->GetMemoryManager().get(); _cpu = console->GetCpu().get(); - + console->GetSettings()->InitializeRam(_dataRam, Cx4::DataRamSize); - - auto &prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers(); - auto &saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers(); + + auto& prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers(); + auto& saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers(); MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); //PRG ROM @@ -62,36 +62,56 @@ void Cx4::Run() { uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); - while(_state.CycleCount < targetCycle) { - if(_state.Locked) { + while (_state.CycleCount < targetCycle) + { + if (_state.Locked) + { Step(1); - } else if(_state.Suspend.Enabled) { - if(_state.Suspend.Duration == 0) { + } + else if (_state.Suspend.Enabled) + { + if (_state.Suspend.Duration == 0) + { Step(1); - } else { + } + else + { Step(1); _state.Suspend.Duration--; - if(_state.Suspend.Duration == 0) { + if (_state.Suspend.Duration == 0) + { _state.Suspend.Enabled = false; } } - } else if(_state.Cache.Enabled) { + } + else if (_state.Cache.Enabled) + { ProcessCache(targetCycle); - } else if(_state.Dma.Enabled) { + } + else if (_state.Dma.Enabled) + { ProcessDma(targetCycle); - } else if(_state.Stopped) { + } + else if (_state.Stopped) + { Step(targetCycle - _state.CycleCount); - } else if(!ProcessCache(targetCycle)) { - if(!_state.Cache.Enabled) { + } + else if (!ProcessCache(targetCycle)) + { + if (!_state.Cache.Enabled) + { //Cache operation required, but both caches are locked, stop Stop(); } - } else { + } + else + { uint16_t opCode = _prgRam[_state.Cache.Page][_state.PC]; _console->ProcessMemoryRead(0, 0, MemoryOperationType::ExecOpCode); _state.PC++; - - if(_state.PC == 0) { + + if (_state.PC == 0) + { //If execution reached the end of the page, start loading the next page //This must be done BEFORE running the instruction (otherwise a jump/branch to address 0 will trigger this) SwitchCachePage(); @@ -104,19 +124,25 @@ void Cx4::Run() void Cx4::Step(uint64_t cycles) { - if(_state.Bus.Enabled) { - if(_state.Bus.DelayCycles > cycles) { + if (_state.Bus.Enabled) + { + if (_state.Bus.DelayCycles > cycles) + { _state.Bus.DelayCycles -= (uint8_t)cycles; - } else { + } + else + { _state.Bus.Enabled = false; _state.Bus.DelayCycles = 0; - if(_state.Bus.Reading) { + if (_state.Bus.Reading) + { _state.MemoryDataReg = ReadCx4(_state.Bus.Address); _state.Bus.Reading = false; } - if(_state.Bus.Writing) { + if (_state.Bus.Writing) + { WriteCx4(_state.Bus.Address, _state.MemoryDataReg); _state.Bus.Writing = false; } @@ -128,21 +154,24 @@ void Cx4::Step(uint64_t cycles) void Cx4::SwitchCachePage() { - if(_state.Cache.Page == 1) { + if (_state.Cache.Page == 1) + { Stop(); return; } _state.Cache.Page = 1; - if(_state.Cache.Lock[1]) { + if (_state.Cache.Lock[1]) + { Stop(); return; - } + } _state.PB = _state.P; uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); - if(!ProcessCache(targetCycle) && !_state.Cache.Enabled) { + if (!ProcessCache(targetCycle) && !_state.Cache.Enabled) + { Stop(); } } @@ -151,8 +180,10 @@ bool Cx4::ProcessCache(uint64_t targetCycle) { uint32_t address = (_state.Cache.Base + (_state.PB << 9)) & 0xFFFFFF; - if(_state.Cache.Pos == 0) { - if(_state.Cache.Address[_state.Cache.Page] == address) { + if (_state.Cache.Pos == 0) + { + if (_state.Cache.Address[_state.Cache.Page] == address) + { //Current cache page matches the needed address, keep using it _state.Cache.Enabled = false; return true; @@ -161,28 +192,32 @@ bool Cx4::ProcessCache(uint64_t targetCycle) //Check if the other page matches _state.Cache.Page ^= 1; - if(_state.Cache.Address[_state.Cache.Page] == address) { + if (_state.Cache.Address[_state.Cache.Page] == address) + { //The other cache page matches, use it _state.Cache.Enabled = false; return true; } - if(_state.Cache.Lock[_state.Cache.Page]) { + if (_state.Cache.Lock[_state.Cache.Page]) + { //If it's locked, use the other page _state.Cache.Page ^= 1; } - if(_state.Cache.Lock[_state.Cache.Page]) { + if (_state.Cache.Lock[_state.Cache.Page]) + { //The both pages are locked, and the cache is invalid, give up. _state.Cache.Enabled = false; return false; } - + _state.Cache.Enabled = true; } //Populate the cache - while(_state.Cache.Pos < 256) { + while (_state.Cache.Pos < 256) + { uint8_t lsb = ReadCx4(address + (_state.Cache.Pos * 2)); Step(GetAccessDelay(address + (_state.Cache.Pos * 2))); @@ -192,12 +227,14 @@ bool Cx4::ProcessCache(uint64_t targetCycle) _prgRam[_state.Cache.Page][_state.Cache.Pos] = (msb << 8) | lsb; _state.Cache.Pos++; - if(_state.CycleCount > targetCycle) { + if (_state.CycleCount > targetCycle) + { break; } } - if(_state.Cache.Pos >= 256) { + if (_state.Cache.Pos >= 256) + { _state.Cache.Address[_state.Cache.Page] = address; _state.Cache.Pos = 0; _state.Cache.Enabled = false; @@ -210,13 +247,16 @@ bool Cx4::ProcessCache(uint64_t targetCycle) void Cx4::ProcessDma(uint64_t targetCycle) { - while(_state.Dma.Pos < _state.Dma.Length) { + while (_state.Dma.Pos < _state.Dma.Length) + { uint32_t src = (_state.Dma.Source + _state.Dma.Pos) & 0xFFFFFF; uint32_t dest = (_state.Dma.Dest + _state.Dma.Pos) & 0xFFFFFF; - IMemoryHandler *srcHandler = _mappings.GetHandler(src); - IMemoryHandler *destHandler = _mappings.GetHandler(dest); - if(!srcHandler || !destHandler || srcHandler->GetMemoryType() == destHandler->GetMemoryType() || destHandler->GetMemoryType() == SnesMemoryType::PrgRom) { + IMemoryHandler* srcHandler = _mappings.GetHandler(src); + IMemoryHandler* destHandler = _mappings.GetHandler(dest); + if (!srcHandler || !destHandler || srcHandler->GetMemoryType() == destHandler->GetMemoryType() || destHandler-> + GetMemoryType() == SnesMemoryType::PrgRom) + { //Invalid DMA, the chip is locked until it gets restarted by a write to $7F53 _state.Locked = true; _state.Dma.Pos = 0; @@ -231,12 +271,14 @@ void Cx4::ProcessDma(uint64_t targetCycle) WriteCx4(dest, value); _state.Dma.Pos++; - if(_state.CycleCount > targetCycle) { + if (_state.CycleCount > targetCycle) + { break; } } - if(_state.Dma.Pos >= _state.Dma.Length) { + if (_state.Dma.Pos >= _state.Dma.Length) + { _state.Dma.Pos = 0; _state.Dma.Enabled = false; } @@ -245,9 +287,12 @@ void Cx4::ProcessDma(uint64_t targetCycle) uint8_t Cx4::GetAccessDelay(uint32_t addr) { IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler->GetMemoryType() == SnesMemoryType::PrgRom) { + if (handler->GetMemoryType() == SnesMemoryType::PrgRom) + { return 1 + _state.RomAccessDelay; - } else if(handler->GetMemoryType() == SnesMemoryType::SaveRam) { + } + else if (handler->GetMemoryType() == SnesMemoryType::SaveRam) + { return 1 + _state.RamAccessDelay; } @@ -257,7 +302,8 @@ uint8_t Cx4::GetAccessDelay(uint32_t addr) uint8_t Cx4::ReadCx4(uint32_t addr) { IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { + if (handler) + { uint8_t value = handler->Read(addr); _console->ProcessMemoryRead(addr, value, MemoryOperationType::Read); return value; @@ -268,7 +314,8 @@ uint8_t Cx4::ReadCx4(uint32_t addr) void Cx4::WriteCx4(uint32_t addr, uint8_t value) { IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { + if (handler) + { _console->ProcessMemoryWrite(addr, value, MemoryOperationType::Write); handler->Write(addr, value); } @@ -277,42 +324,52 @@ void Cx4::WriteCx4(uint32_t addr, uint8_t value) uint8_t Cx4::Read(uint32_t addr) { addr = 0x7000 | (addr & 0xFFF); - if(addr <= 0x7BFF) { + if (addr <= 0x7BFF) + { return _dataRam[addr & 0xFFF]; - } else if(addr >= 0x7F60 && addr <= 0x7F7F) { + } + else if (addr >= 0x7F60 && addr <= 0x7F7F) + { return _state.Vectors[addr & 0x1F]; - } else if((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF)) { + } + else if ((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF)) + { addr &= 0x3F; - uint32_t ® = _state.Regs[addr / 3]; - switch(addr % 3) { - case 0: return reg; - case 1: return reg >> 8; - case 2: return reg >> 16; + uint32_t& reg = _state.Regs[addr / 3]; + switch (addr % 3) + { + case 0: return reg; + case 1: return reg >> 8; + case 2: return reg >> 16; } - } else if(addr >= 0x7F53 && addr <= 0x7F5F) { - return (uint8_t)_state.Suspend.Enabled | ((uint8_t)_state.IrqFlag << 1) | ((uint8_t)IsRunning() << 6) | ((uint8_t)IsBusy() << 7); + } + else if (addr >= 0x7F53 && addr <= 0x7F5F) + { + return (uint8_t)_state.Suspend.Enabled | ((uint8_t)_state.IrqFlag << 1) | ((uint8_t)IsRunning() << 6) | ((uint8_t) + IsBusy() << 7); } - switch(addr) { - case 0x7F40: return _state.Dma.Source; - case 0x7F41: return _state.Dma.Source >> 8; - case 0x7F42: return _state.Dma.Source >> 16; - case 0x7F43: return (uint8_t)_state.Dma.Length; - case 0x7F44: return _state.Dma.Length >> 8; - case 0x7F45: return _state.Dma.Dest; - case 0x7F46: return _state.Dma.Dest >> 8; - case 0x7F47: return _state.Dma.Dest >> 16; - case 0x7F48: return _state.Cache.Page; - case 0x7F49: return _state.Cache.Base; - case 0x7F4A: return _state.Cache.Base >> 8; - case 0x7F4B: return _state.Cache.Base >> 16; - case 0x7F4C: return (uint8_t)_state.Cache.Lock[0] | ((uint8_t)_state.Cache.Lock[1] << 1); - case 0x7F4D: return (uint8_t)_state.Cache.ProgramBank; - case 0x7F4E: return _state.Cache.ProgramBank >> 8; - case 0x7F4F: return _state.Cache.ProgramCounter; - case 0x7F50: return _state.RamAccessDelay | (_state.RomAccessDelay << 4); - case 0x7F51: return _state.IrqDisabled; - case 0x7F52: return _state.SingleRom; + switch (addr) + { + case 0x7F40: return _state.Dma.Source; + case 0x7F41: return _state.Dma.Source >> 8; + case 0x7F42: return _state.Dma.Source >> 16; + case 0x7F43: return (uint8_t)_state.Dma.Length; + case 0x7F44: return _state.Dma.Length >> 8; + case 0x7F45: return _state.Dma.Dest; + case 0x7F46: return _state.Dma.Dest >> 8; + case 0x7F47: return _state.Dma.Dest >> 16; + case 0x7F48: return _state.Cache.Page; + case 0x7F49: return _state.Cache.Base; + case 0x7F4A: return _state.Cache.Base >> 8; + case 0x7F4B: return _state.Cache.Base >> 16; + case 0x7F4C: return (uint8_t)_state.Cache.Lock[0] | ((uint8_t)_state.Cache.Lock[1] << 1); + case 0x7F4D: return (uint8_t)_state.Cache.ProgramBank; + case 0x7F4E: return _state.Cache.ProgramBank >> 8; + case 0x7F4F: return _state.Cache.ProgramCounter; + case 0x7F50: return _state.RamAccessDelay | (_state.RomAccessDelay << 4); + case 0x7F51: return _state.IrqDisabled; + case 0x7F52: return _state.SingleRom; } return 0; @@ -322,94 +379,125 @@ void Cx4::Write(uint32_t addr, uint8_t value) { addr = 0x7000 | (addr & 0xFFF); - if(addr <= 0x7BFF) { + if (addr <= 0x7BFF) + { _dataRam[addr & 0xFFF] = value; return; - } - - if(addr >= 0x7F60 && addr <= 0x7F7F) { + } + + if (addr >= 0x7F60 && addr <= 0x7F7F) + { _state.Vectors[addr & 0x1F] = value; - } else if((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF)) { + } + else if ((addr >= 0x7F80 && addr <= 0x7FAF) || (addr >= 0x7FC0 && addr <= 0x7FEF)) + { addr &= 0x3F; - uint32_t ® = _state.Regs[addr / 3]; - switch(addr % 3) { - case 0: reg = (reg & 0xFFFF00) | value; break; - case 1: reg = (reg & 0xFF00FF) | (value << 8); break; - case 2: reg = (reg & 0x00FFFF) | (value << 16); break; + uint32_t& reg = _state.Regs[addr / 3]; + switch (addr % 3) + { + case 0: reg = (reg & 0xFFFF00) | value; + break; + case 1: reg = (reg & 0xFF00FF) | (value << 8); + break; + case 2: reg = (reg & 0x00FFFF) | (value << 16); + break; } - } else if(addr >= 0x7F55 && addr <= 0x7F5C) { + } + else if (addr >= 0x7F55 && addr <= 0x7F5C) + { _state.Suspend.Enabled = true; _state.Suspend.Duration = (addr - 0x7F55) * 32; - } else { - switch(addr) { - case 0x7F40: _state.Dma.Source = (_state.Dma.Source & 0xFFFF00) | value; break; - case 0x7F41: _state.Dma.Source = (_state.Dma.Source & 0xFF00FF) | (value << 8); break; - case 0x7F42: _state.Dma.Source = (_state.Dma.Source & 0x00FFFF) | (value << 16); break; - case 0x7F43: _state.Dma.Length = (_state.Dma.Length & 0xFF00) | value; break; - case 0x7F44: _state.Dma.Length = (_state.Dma.Length & 0x00FF) | (value << 8); break; - case 0x7F45: _state.Dma.Dest = (_state.Dma.Dest & 0xFFFF00) | value; break; - case 0x7F46: _state.Dma.Dest = (_state.Dma.Dest & 0xFF00FF) | (value << 8); break; - case 0x7F47: - _state.Dma.Dest = (_state.Dma.Dest & 0x00FFFF) | (value << 16); - if(_state.Stopped) { - _state.Dma.Enabled = true; - } - break; + } + else + { + switch (addr) + { + case 0x7F40: _state.Dma.Source = (_state.Dma.Source & 0xFFFF00) | value; + break; + case 0x7F41: _state.Dma.Source = (_state.Dma.Source & 0xFF00FF) | (value << 8); + break; + case 0x7F42: _state.Dma.Source = (_state.Dma.Source & 0x00FFFF) | (value << 16); + break; + case 0x7F43: _state.Dma.Length = (_state.Dma.Length & 0xFF00) | value; + break; + case 0x7F44: _state.Dma.Length = (_state.Dma.Length & 0x00FF) | (value << 8); + break; + case 0x7F45: _state.Dma.Dest = (_state.Dma.Dest & 0xFFFF00) | value; + break; + case 0x7F46: _state.Dma.Dest = (_state.Dma.Dest & 0xFF00FF) | (value << 8); + break; + case 0x7F47: + _state.Dma.Dest = (_state.Dma.Dest & 0x00FFFF) | (value << 16); + if (_state.Stopped) + { + _state.Dma.Enabled = true; + } + break; - case 0x7F48: - _state.Cache.Page = value & 0x01; - if(_state.Stopped) { - _state.Cache.Enabled = true; - } - break; + case 0x7F48: + _state.Cache.Page = value & 0x01; + if (_state.Stopped) + { + _state.Cache.Enabled = true; + } + break; - case 0x7F49: _state.Cache.Base = (_state.Cache.Base & 0xFFFF00) | value; break; - case 0x7F4A: _state.Cache.Base = (_state.Cache.Base & 0xFF00FF) | (value << 8); break; - case 0x7F4B: _state.Cache.Base = (_state.Cache.Base & 0x00FFFF) | (value << 16); break; + case 0x7F49: _state.Cache.Base = (_state.Cache.Base & 0xFFFF00) | value; + break; + case 0x7F4A: _state.Cache.Base = (_state.Cache.Base & 0xFF00FF) | (value << 8); + break; + case 0x7F4B: _state.Cache.Base = (_state.Cache.Base & 0x00FFFF) | (value << 16); + break; - case 0x7F4C: - _state.Cache.Lock[0] = (value & 0x01) != 0; - _state.Cache.Lock[1] = (value & 0x02) != 0; - break; + case 0x7F4C: + _state.Cache.Lock[0] = (value & 0x01) != 0; + _state.Cache.Lock[1] = (value & 0x02) != 0; + break; - case 0x7F4D: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0xFF00) | value; break; - case 0x7F4E: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0x00FF) | ((value & 0x7F) << 8); break; + case 0x7F4D: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0xFF00) | value; + break; + case 0x7F4E: _state.Cache.ProgramBank = (_state.Cache.ProgramBank & 0x00FF) | ((value & 0x7F) << 8); + break; - case 0x7F4F: - _state.Cache.ProgramCounter = value; - if(_state.Stopped) { - _state.Stopped = false; - _state.PB = _state.Cache.ProgramBank; - _state.PC = _state.Cache.ProgramCounter; - } - break; + case 0x7F4F: + _state.Cache.ProgramCounter = value; + if (_state.Stopped) + { + _state.Stopped = false; + _state.PB = _state.Cache.ProgramBank; + _state.PC = _state.Cache.ProgramCounter; + } + break; - case 0x7F50: - _state.RamAccessDelay = value & 0x07; - _state.RomAccessDelay = (value >> 4) & 0x07; - break; + case 0x7F50: + _state.RamAccessDelay = value & 0x07; + _state.RomAccessDelay = (value >> 4) & 0x07; + break; - case 0x7F51: - _state.IrqDisabled = value & 0x01; - if(_state.IrqDisabled) { - _state.IrqFlag = true; - _cpu->ClearIrqSource(IrqSource::Coprocessor); - } - break; + case 0x7F51: + _state.IrqDisabled = value & 0x01; + if (_state.IrqDisabled) + { + _state.IrqFlag = true; + _cpu->ClearIrqSource(IrqSource::Coprocessor); + } + break; - case 0x7F52: _state.SingleRom = (value & 0x01) != 0; break; + case 0x7F52: _state.SingleRom = (value & 0x01) != 0; + break; - case 0x7F53: - _state.Locked = false; - _state.Stopped = true; - break; + case 0x7F53: + _state.Locked = false; + _state.Stopped = true; + break; - case 0x7F5D: _state.Suspend.Enabled = false; break; + case 0x7F5D: _state.Suspend.Enabled = false; + break; - case 0x7F5E: - //Clear IRQ flag in CX4, but keeps IRQ signal high - _state.IrqFlag = false; - break; + case 0x7F5E: + //Clear IRQ flag in CX4, but keeps IRQ signal high + _state.IrqFlag = false; + break; } } } @@ -424,19 +512,23 @@ bool Cx4::IsBusy() return _state.Cache.Enabled || _state.Dma.Enabled || _state.Bus.DelayCycles > 0; } -void Cx4::Serialize(Serializer &s) +void Cx4::Serialize(Serializer& s) { s.Stream( _state.CycleCount, _state.PB, _state.PC, _state.A, _state.P, _state.SP, _state.Mult, _state.RomBuffer, _state.RamBuffer[0], _state.RamBuffer[1], _state.RamBuffer[2], _state.MemoryDataReg, _state.MemoryAddressReg, - _state.DataPointerReg, _state.Negative, _state.Zero, _state.Carry, _state.Overflow, _state.IrqFlag, _state.Stopped, - _state.Locked, _state.IrqDisabled, _state.SingleRom, _state.RamAccessDelay, _state.RomAccessDelay, _state.Bus.Address, - _state.Bus.DelayCycles, _state.Bus.Enabled, _state.Bus.Reading, _state.Bus.Writing, _state.Dma.Dest, _state.Dma.Enabled, - _state.Dma.Length, _state.Dma.Source, _state.Dma.Pos, _state.Suspend.Duration, _state.Suspend.Enabled, _state.Cache.Enabled, + _state.DataPointerReg, _state.Negative, _state.Zero, _state.Carry, _state.Overflow, _state.IrqFlag, + _state.Stopped, + _state.Locked, _state.IrqDisabled, _state.SingleRom, _state.RamAccessDelay, _state.RomAccessDelay, + _state.Bus.Address, + _state.Bus.DelayCycles, _state.Bus.Enabled, _state.Bus.Reading, _state.Bus.Writing, _state.Dma.Dest, + _state.Dma.Enabled, + _state.Dma.Length, _state.Dma.Source, _state.Dma.Pos, _state.Suspend.Duration, _state.Suspend.Enabled, + _state.Cache.Enabled, _state.Cache.Lock[0], _state.Cache.Lock[1], _state.Cache.Address[0], _state.Cache.Address[1], _state.Cache.Base, _state.Cache.Page, _state.Cache.ProgramBank, _state.Cache.ProgramCounter, _state.Cache.Pos ); - + s.StreamArray(_state.Stack, 8); s.StreamArray(_state.Regs, 16); s.StreamArray(_state.Vectors, 0x20); @@ -457,7 +549,7 @@ void Cx4::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo Cx4::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } MemoryMappings* Cx4::GetMemoryMappings() @@ -484,31 +576,48 @@ void Cx4::SetReg(Cx4Register reg, uint32_t value) { switch (reg) { - case Cx4Register::Cx4Reg0: case Cx4Register::Cx4Reg1: case Cx4Register::Cx4Reg2: case Cx4Register::Cx4Reg3: - case Cx4Register::Cx4Reg4: case Cx4Register::Cx4Reg5: case Cx4Register::Cx4Reg6: case Cx4Register::Cx4Reg7: - case Cx4Register::Cx4Reg8: case Cx4Register::Cx4Reg9: case Cx4Register::Cx4Reg10: case Cx4Register::Cx4Reg11: - case Cx4Register::Cx4Reg12: case Cx4Register::Cx4Reg13: case Cx4Register::Cx4Reg14: case Cx4Register::Cx4Reg15: + case Cx4Register::Cx4Reg0: + case Cx4Register::Cx4Reg1: + case Cx4Register::Cx4Reg2: + case Cx4Register::Cx4Reg3: + case Cx4Register::Cx4Reg4: + case Cx4Register::Cx4Reg5: + case Cx4Register::Cx4Reg6: + case Cx4Register::Cx4Reg7: + case Cx4Register::Cx4Reg8: + case Cx4Register::Cx4Reg9: + case Cx4Register::Cx4Reg10: + case Cx4Register::Cx4Reg11: + case Cx4Register::Cx4Reg12: + case Cx4Register::Cx4Reg13: + case Cx4Register::Cx4Reg14: + case Cx4Register::Cx4Reg15: _state.Regs[(static_cast(reg) - static_cast(Cx4Register::Cx4Reg0)) & 0x0F] = value & 0xFFFFFF; // 24-bit break; case Cx4Register::Cx4RegPB: - { - _state.PB = value & 0xFFFF; - } break; + { + _state.PB = value & 0xFFFF; + } + break; case Cx4Register::Cx4RegPC: - { - _state.PC = value & 0xFF; - } break; + { + _state.PC = value & 0xFF; + } + break; case Cx4Register::Cx4RegA: - { - _state.A = value & 0xFFFFFF; // 24-bit - } break; + { + _state.A = value & 0xFFFFFF; // 24-bit + } + break; case Cx4Register::Cx4RegP: - { - _state.P = value & 0xFFFF; - } break; + { + _state.P = value & 0xFFFF; + } + break; case Cx4Register::Cx4RegSP: - { - _state.SP = value & 0xFF; - } break; + { + _state.SP = value & 0xFF; + } + break; } -} \ No newline at end of file +} diff --git a/Core/Cx4.h b/Core/Cx4.h index d18e50c..889acf9 100644 --- a/Core/Cx4.h +++ b/Core/Cx4.h @@ -13,9 +13,9 @@ class Cx4 : public BaseCoprocessor private: static constexpr int DataRamSize = 0xC00; - Console *_console; - MemoryManager *_memoryManager; - Cpu *_cpu; + Console* _console; + MemoryManager* _memoryManager; + Cpu* _cpu; MemoryMappings _mappings; double _clockRatio; @@ -119,7 +119,7 @@ public: uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; uint8_t Peek(uint32_t addr) override; void PeekBlock(uint32_t addr, uint8_t* output) override; @@ -131,4 +131,4 @@ public: Cx4State GetState(); void SetReg(Cx4Register reg, uint32_t value); -}; \ No newline at end of file +}; diff --git a/Core/Cx4Debugger.cpp b/Core/Cx4Debugger.cpp index 4c0de7d..ed415e4 100644 --- a/Core/Cx4Debugger.cpp +++ b/Core/Cx4Debugger.cpp @@ -42,19 +42,23 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType addr = (state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF; AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { (uint32_t)addr, value, type }; + MemoryOperationInfo operation{(uint32_t)addr, value, type}; - if(type == MemoryOperationType::ExecOpCode) { + if (type == MemoryOperationType::ExecOpCode) + { AddressInfo opCodeHighAddr = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr + 1); - if(addressInfo.Type == SnesMemoryType::PrgRom) { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | CdlFlags::Cx4); _codeDataLogger->SetFlags(addressInfo.Address + 1, CdlFlags::Code | CdlFlags::Cx4); } - if(_traceLogger->IsCpuLogged(CpuType::Cx4) || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) { + if (_traceLogger->IsCpuLogged(CpuType::Cx4) || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) + { _disassembler->BuildCache(addressInfo, 0, CpuType::Cx4); - if(_traceLogger->IsCpuLogged(CpuType::Cx4)) { + if (_traceLogger->IsCpuLogged(CpuType::Cx4)) + { DebugState debugState; _debugger->GetState(debugState, true); @@ -65,14 +69,18 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType _prevProgramCounter = addr; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); _memoryAccessCounter->ProcessMemoryExec(opCodeHighAddr, _memoryManager->GetMasterClock()); - } else { - if(addressInfo.Type == SnesMemoryType::PrgRom) { + } + else + { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Cx4); } _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); @@ -84,7 +92,7 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType void Cx4Debugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { (uint32_t)addr, value, type }; + MemoryOperationInfo operation{(uint32_t)addr, value, type}; _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo); _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock()); } @@ -98,17 +106,19 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; - case StepType::StepOut: - case StepType::StepOver: - step.StepCount = 1; - break; + case StepType::StepOut: + case StepType::StepOver: + step.StepCount = 1; + break; - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -117,4 +127,4 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type) BreakpointManager* Cx4Debugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/Cx4Debugger.h b/Core/Cx4Debugger.h index 653adfa..518943e 100644 --- a/Core/Cx4Debugger.h +++ b/Core/Cx4Debugger.h @@ -40,4 +40,4 @@ public: void Run(); void Step(int32_t stepCount, StepType type); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/Cx4DisUtils.cpp b/Core/Cx4DisUtils.cpp index b69f46b..e299d5e 100644 --- a/Core/Cx4DisUtils.cpp +++ b/Core/Cx4DisUtils.cpp @@ -5,7 +5,8 @@ #include "../Utilities/HexUtilities.h" #include "../Utilities/FastString.h" -void Cx4DisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings *settings) +void Cx4DisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); @@ -13,197 +14,417 @@ void Cx4DisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me uint8_t param1 = info.GetByteCode()[1] & 0x03; uint8_t param2 = info.GetByteCode()[0] & 0xFF; - auto writeSrc = [&str, param2]() -> void { - switch(param2 & 0x7F) { - case 0x00: str.Write("A"); break; - case 0x01: str.Write("MULTH"); break; - case 0x02: str.Write("MULTL"); break; - case 0x03: str.Write("MDR"); break; - case 0x08: str.Write("ROM"); break; - case 0x0C: str.Write("RAM"); break; - case 0x13: str.Write("MAR"); break; - case 0x1C: str.Write("DPR"); break; - case 0x20: str.Write("PC"); break; - case 0x28: str.Write("P"); break; + auto writeSrc = [&str, param2]() -> void + { + switch (param2 & 0x7F) + { + case 0x00: str.Write("A"); + break; + case 0x01: str.Write("MULTH"); + break; + case 0x02: str.Write("MULTL"); + break; + case 0x03: str.Write("MDR"); + break; + case 0x08: str.Write("ROM"); + break; + case 0x0C: str.Write("RAM"); + break; + case 0x13: str.Write("MAR"); + break; + case 0x1C: str.Write("DPR"); + break; + case 0x20: str.Write("PC"); + break; + case 0x28: str.Write("P"); + break; - case 0x2E: str.Write("RDROM"); break; + case 0x2E: str.Write("RDROM"); + break; - case 0x2F: str.Write("RDRAM"); break; + case 0x2F: str.Write("RDRAM"); + break; - case 0x50: str.Write("#$000000"); break; - case 0x51: str.Write("#$FFFFFF"); break; - case 0x52: str.Write("#$00FF00"); break; - case 0x53: str.Write("#$FF0000"); break; - case 0x54: str.Write("#$00FFFF"); break; - case 0x55: str.Write("#$FFFF00"); break; - case 0x56: str.Write("#$800000"); break; - case 0x57: str.Write("#$7FFFFF"); break; - case 0x58: str.Write("#$008000"); break; - case 0x59: str.Write("#$007FFF"); break; - case 0x5A: str.Write("#$FF7FFF"); break; - case 0x5B: str.Write("#$FFFF7F"); break; - case 0x5C: str.Write("#$010000"); break; - case 0x5D: str.Write("#$FEFFFF"); break; - case 0x5E: str.Write("#$000100"); break; - case 0x5F: str.Write("#$00FEFF"); break; + case 0x50: str.Write("#$000000"); + break; + case 0x51: str.Write("#$FFFFFF"); + break; + case 0x52: str.Write("#$00FF00"); + break; + case 0x53: str.Write("#$FF0000"); + break; + case 0x54: str.Write("#$00FFFF"); + break; + case 0x55: str.Write("#$FFFF00"); + break; + case 0x56: str.Write("#$800000"); + break; + case 0x57: str.Write("#$7FFFFF"); + break; + case 0x58: str.Write("#$008000"); + break; + case 0x59: str.Write("#$007FFF"); + break; + case 0x5A: str.Write("#$FF7FFF"); + break; + case 0x5B: str.Write("#$FFFF7F"); + break; + case 0x5C: str.Write("#$010000"); + break; + case 0x5D: str.Write("#$FEFFFF"); + break; + case 0x5E: str.Write("#$000100"); + break; + case 0x5F: str.Write("#$00FEFF"); + break; - case 0x60: case 0x70: str.Write("R0"); break; - case 0x61: case 0x71: str.Write("R1"); break; - case 0x62: case 0x72: str.Write("R2"); break; - case 0x63: case 0x73: str.Write("R3"); break; - case 0x64: case 0x74: str.Write("R4"); break; - case 0x65: case 0x75: str.Write("R5"); break; - case 0x66: case 0x76: str.Write("R6"); break; - case 0x67: case 0x77: str.Write("R7"); break; - case 0x68: case 0x78: str.Write("R8"); break; - case 0x69: case 0x79: str.Write("R9"); break; - case 0x6A: case 0x7A: str.Write("R10"); break; - case 0x6B: case 0x7B: str.Write("R11"); break; - case 0x6C: case 0x7C: str.Write("R12"); break; - case 0x6D: case 0x7D: str.Write("R13"); break; - case 0x6E: case 0x7E: str.Write("R14"); break; - case 0x6F: case 0x7F: str.Write("R15"); break; + case 0x60: + case 0x70: str.Write("R0"); + break; + case 0x61: + case 0x71: str.Write("R1"); + break; + case 0x62: + case 0x72: str.Write("R2"); + break; + case 0x63: + case 0x73: str.Write("R3"); + break; + case 0x64: + case 0x74: str.Write("R4"); + break; + case 0x65: + case 0x75: str.Write("R5"); + break; + case 0x66: + case 0x76: str.Write("R6"); + break; + case 0x67: + case 0x77: str.Write("R7"); + break; + case 0x68: + case 0x78: str.Write("R8"); + break; + case 0x69: + case 0x79: str.Write("R9"); + break; + case 0x6A: + case 0x7A: str.Write("R10"); + break; + case 0x6B: + case 0x7B: str.Write("R11"); + break; + case 0x6C: + case 0x7C: str.Write("R12"); + break; + case 0x6D: + case 0x7D: str.Write("R13"); + break; + case 0x6E: + case 0x7E: str.Write("R14"); + break; + case 0x6F: + case 0x7F: str.Write("R15"); + break; } }; - auto writeDest = [&str, param1]() -> void { - switch(param1) { - case 0: str.Write("A"); break; - case 1: str.Write("MDR"); break; - case 2: str.Write("MAR"); break; - case 3: str.Write("P"); break; + auto writeDest = [&str, param1]() -> void + { + switch (param1) + { + case 0: str.Write("A"); + break; + case 1: str.Write("MDR"); + break; + case 2: str.Write("MAR"); + break; + case 3: str.Write("P"); + break; } }; - auto writeShiftedA = [&str, param1]() -> void { - switch(param1) { - case 0: str.Write("A"); break; - case 1: str.Write("(A << 1)"); break; - case 2: str.Write("(A << 8)"); break; - case 3: str.Write("(A << 16)"); break; + auto writeShiftedA = [&str, param1]() -> void + { + switch (param1) + { + case 0: str.Write("A"); + break; + case 1: str.Write("(A << 1)"); + break; + case 2: str.Write("(A << 8)"); + break; + case 3: str.Write("(A << 16)"); + break; } }; - auto writeBranchTarget = [&str, param1, param2]() -> void { - if(param1) { + auto writeBranchTarget = [&str, param1, param2]() -> void + { + if (param1) + { //Far jump str.Write("P:"); } str.WriteAll('$', HexUtilities::ToHex(param2)); }; - - switch(op) { - case 0x00: str.Write("NOP"); break; - case 0x04: str.Write("???"); break; - case 0x08: str.Write("BRA "); writeBranchTarget(); break; - case 0x0C: str.Write("BEQ "); writeBranchTarget(); break; - case 0x10: str.Write("BCS "); writeBranchTarget(); break; - case 0x14: str.Write("BMI "); writeBranchTarget(); break; - case 0x18: str.Write("BVS "); writeBranchTarget(); break; - case 0x1C: str.Write("WAIT"); break; + switch (op) + { + case 0x00: str.Write("NOP"); + break; + case 0x04: str.Write("???"); + break; + case 0x08: str.Write("BRA "); + writeBranchTarget(); + break; + case 0x0C: str.Write("BEQ "); + writeBranchTarget(); + break; - case 0x20: str.Write("???"); break; - case 0x24: - str.Write("SKIP"); - switch(param1) { - case 0: str.Write('V'); break; - case 1: str.Write('C'); break; - case 2: str.Write('Z'); break; - case 3: str.Write('N'); break; - } - str.Write((param2 & 0x01) ? 'S' : 'C'); + case 0x10: str.Write("BCS "); + writeBranchTarget(); + break; + case 0x14: str.Write("BMI "); + writeBranchTarget(); + break; + case 0x18: str.Write("BVS "); + writeBranchTarget(); + break; + case 0x1C: str.Write("WAIT"); + break; + + case 0x20: str.Write("???"); + break; + case 0x24: + str.Write("SKIP"); + switch (param1) + { + case 0: str.Write('V'); break; - - case 0x28: str.Write("JSR "); writeBranchTarget(); break; - case 0x2C: str.Write("JEQ "); writeBranchTarget(); break; - - case 0x30: str.Write("JCS "); writeBranchTarget(); break; - case 0x34: str.Write("JMI "); writeBranchTarget(); break; - case 0x38: str.Write("JVS "); writeBranchTarget(); break; - case 0x3C: str.Write("RTS"); break; - - case 0x40: str.Write("INC MAR"); break; - case 0x44: str.Write("???"); break; - case 0x48: str.Write("CMPR "); writeSrc(); str.Write(","); writeShiftedA(); break; - case 0x4C: str.WriteAll("CMPR #$", HexUtilities::ToHex(param2)); str.Write(","); writeShiftedA(); break; - - case 0x50: str.Write("CMP "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0x54: str.WriteAll("CMP "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - case 0x58: - if(param1 == 1) { - str.Write("SXB"); - } else if(param1 == 2) { - str.Write("SXW"); - } else { - str.Write("???"); - } + case 1: str.Write('C'); break; - case 0x5C: str.Write("???"); break; - - case 0x60: str.Write("LD "); writeDest(); str.Write(","); writeSrc(); break; - case 0x64: str.Write("LD "); writeDest(); str.WriteAll(", #$", HexUtilities::ToHex(param2)); break; - - case 0x68: str.WriteAll("RDRAM RAM:", '0' + param1, ",A"); break; - case 0x6C: str.WriteAll("RDRAM RAM:", '0' + param1, ",DPR+#$", HexUtilities::ToHex(param2)); break; - - case 0x70: str.Write("RDROM (a)"); break; - case 0x74: str.WriteAll("RDROM (#$", HexUtilities::ToHex((param1 << 8) | param2), ")"); break; - case 0x78: str.Write("???"); break; - - case 0x7C: - if(param1 <= 1) { - str.WriteAll("LD P", param1 ? "H" : "L", ",#$", HexUtilities::ToHex(param2)); - } else { - str.Write("???"); - } + case 2: str.Write('Z'); break; - - case 0x80: str.Write("ADD "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0x84: str.WriteAll("ADD "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - case 0x88: str.Write("SUBR "); writeSrc(); str.Write(","); writeShiftedA(); break; - case 0x8C: str.WriteAll("SUBR #$", HexUtilities::ToHex(param2)); str.Write(","); writeShiftedA(); break; - - case 0x90: str.Write("SUB "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0x94: str.WriteAll("SUB "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - case 0x98: str.Write("SMUL A, "); writeSrc(); break; - case 0x9C: str.WriteAll("SMUL A,#$", HexUtilities::ToHex(param2)); break; - - case 0xA0: str.Write("XNOR "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0xA4: str.WriteAll("XNOR "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - case 0xA8: str.Write("XOR "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0xAC: str.WriteAll("XOR "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - - case 0xB0: str.Write("AND "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0xB4: str.WriteAll("AND "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - case 0xB8: str.Write("OR "); writeShiftedA(); str.Write(","); writeSrc(); break; - case 0xBC: str.WriteAll("OR "); writeShiftedA(); str.WriteAll(",#$", HexUtilities::ToHex(param2)); break; - - case 0xC0: str.Write("SHR A,"); writeSrc(); break; - case 0xC4: str.WriteAll("SHR A,#$", HexUtilities::ToHex(param2 & 0x1F)); break; - case 0xC8: str.Write("ASR A,"); writeSrc(); break; - case 0xCC: str.WriteAll("ASR A,#$", HexUtilities::ToHex(param2 & 0x1F)); break; - - case 0xD0: str.Write("ROR A,"); writeSrc(); break; - case 0xD4: str.WriteAll("ROR A,#$", HexUtilities::ToHex(param2 & 0x1F)); break; - case 0xD8: str.Write("SHL A,"); writeSrc(); break; - case 0xDC: str.WriteAll("SHL A,#$", HexUtilities::ToHex(param2 & 0x1F)); break; - - case 0xE0: - if(param1 <= 1) { - str.Write("ST "); writeSrc(); str.WriteAll(",", param1 ? "MDR" : "A"); - } else { - str.Write("???"); - } + case 3: str.Write('N'); break; - case 0xE4: str.Write("???"); break; - case 0xE8: str.WriteAll("WRRAM A,RAM:", '0' + param1); break; - case 0xEC: str.WriteAll("WRRAM DPR+#$", HexUtilities::ToHex(param2), ",RAM:", '0' + param1); break; + } + str.Write((param2 & 0x01) ? 'S' : 'C'); + break; - case 0xF0: str.WriteAll("SWAP A,R", std::to_string(param2 & 0x0F)); break; - case 0xF4: str.Write("???"); break; - case 0xF8: str.Write("???"); break; - case 0xFC: str.Write("STOP"); break; + case 0x28: str.Write("JSR "); + writeBranchTarget(); + break; + case 0x2C: str.Write("JEQ "); + writeBranchTarget(); + break; + + case 0x30: str.Write("JCS "); + writeBranchTarget(); + break; + case 0x34: str.Write("JMI "); + writeBranchTarget(); + break; + case 0x38: str.Write("JVS "); + writeBranchTarget(); + break; + case 0x3C: str.Write("RTS"); + break; + + case 0x40: str.Write("INC MAR"); + break; + case 0x44: str.Write("???"); + break; + case 0x48: str.Write("CMPR "); + writeSrc(); + str.Write(","); + writeShiftedA(); + break; + case 0x4C: str.WriteAll("CMPR #$", HexUtilities::ToHex(param2)); + str.Write(","); + writeShiftedA(); + break; + + case 0x50: str.Write("CMP "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0x54: str.WriteAll("CMP "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + case 0x58: + if (param1 == 1) + { + str.Write("SXB"); + } + else if (param1 == 2) + { + str.Write("SXW"); + } + else + { + str.Write("???"); + } + break; + case 0x5C: str.Write("???"); + break; + + case 0x60: str.Write("LD "); + writeDest(); + str.Write(","); + writeSrc(); + break; + case 0x64: str.Write("LD "); + writeDest(); + str.WriteAll(", #$", HexUtilities::ToHex(param2)); + break; + + case 0x68: str.WriteAll("RDRAM RAM:", '0' + param1, ",A"); + break; + case 0x6C: str.WriteAll("RDRAM RAM:", '0' + param1, ",DPR+#$", HexUtilities::ToHex(param2)); + break; + + case 0x70: str.Write("RDROM (a)"); + break; + case 0x74: str.WriteAll("RDROM (#$", HexUtilities::ToHex((param1 << 8) | param2), ")"); + break; + case 0x78: str.Write("???"); + break; + + case 0x7C: + if (param1 <= 1) + { + str.WriteAll("LD P", param1 ? "H" : "L", ",#$", HexUtilities::ToHex(param2)); + } + else + { + str.Write("???"); + } + break; + + case 0x80: str.Write("ADD "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0x84: str.WriteAll("ADD "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + case 0x88: str.Write("SUBR "); + writeSrc(); + str.Write(","); + writeShiftedA(); + break; + case 0x8C: str.WriteAll("SUBR #$", HexUtilities::ToHex(param2)); + str.Write(","); + writeShiftedA(); + break; + + case 0x90: str.Write("SUB "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0x94: str.WriteAll("SUB "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + case 0x98: str.Write("SMUL A, "); + writeSrc(); + break; + case 0x9C: str.WriteAll("SMUL A,#$", HexUtilities::ToHex(param2)); + break; + + case 0xA0: str.Write("XNOR "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0xA4: str.WriteAll("XNOR "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + case 0xA8: str.Write("XOR "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0xAC: str.WriteAll("XOR "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + + case 0xB0: str.Write("AND "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0xB4: str.WriteAll("AND "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + case 0xB8: str.Write("OR "); + writeShiftedA(); + str.Write(","); + writeSrc(); + break; + case 0xBC: str.WriteAll("OR "); + writeShiftedA(); + str.WriteAll(",#$", HexUtilities::ToHex(param2)); + break; + + case 0xC0: str.Write("SHR A,"); + writeSrc(); + break; + case 0xC4: str.WriteAll("SHR A,#$", HexUtilities::ToHex(param2 & 0x1F)); + break; + case 0xC8: str.Write("ASR A,"); + writeSrc(); + break; + case 0xCC: str.WriteAll("ASR A,#$", HexUtilities::ToHex(param2 & 0x1F)); + break; + + case 0xD0: str.Write("ROR A,"); + writeSrc(); + break; + case 0xD4: str.WriteAll("ROR A,#$", HexUtilities::ToHex(param2 & 0x1F)); + break; + case 0xD8: str.Write("SHL A,"); + writeSrc(); + break; + case 0xDC: str.WriteAll("SHL A,#$", HexUtilities::ToHex(param2 & 0x1F)); + break; + + case 0xE0: + if (param1 <= 1) + { + str.Write("ST "); + writeSrc(); + str.WriteAll(",", param1 ? "MDR" : "A"); + } + else + { + str.Write("???"); + } + break; + case 0xE4: str.Write("???"); + break; + case 0xE8: str.WriteAll("WRRAM A,RAM:", '0' + param1); + break; + case 0xEC: str.WriteAll("WRRAM DPR+#$", HexUtilities::ToHex(param2), ",RAM:", '0' + param1); + break; + + case 0xF0: str.WriteAll("SWAP A,R", std::to_string(param2 & 0x0F)); + break; + case 0xF4: str.Write("???"); + break; + case 0xF8: str.Write("???"); + break; + case 0xFC: str.Write("STOP"); + break; } out += str.ToString(); diff --git a/Core/Cx4DisUtils.h b/Core/Cx4DisUtils.h index c04b2b7..504d6df 100644 --- a/Core/Cx4DisUtils.h +++ b/Core/Cx4DisUtils.h @@ -8,5 +8,6 @@ class EmuSettings; class Cx4DisUtils { public: - static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); }; diff --git a/Core/Cx4Types.h b/Core/Cx4Types.h index 314888c..6057b73 100644 --- a/Core/Cx4Types.h +++ b/Core/Cx4Types.h @@ -48,7 +48,7 @@ struct Cx4State uint8_t PC; //Accumulator - uint32_t A; + uint32_t A; //Page register uint16_t P; @@ -76,7 +76,7 @@ struct Cx4State bool Stopped; bool Locked; bool IrqDisabled; - + bool SingleRom; uint8_t RomAccessDelay; @@ -87,4 +87,4 @@ struct Cx4State Cx4Cache Cache; Cx4Suspend Suspend; uint8_t Vectors[0x20]; -}; \ No newline at end of file +}; diff --git a/Core/DebugBreakHelper.h b/Core/DebugBreakHelper.h index c7f012c..94bcf26 100644 --- a/Core/DebugBreakHelper.h +++ b/Core/DebugBreakHelper.h @@ -6,7 +6,7 @@ class DebugBreakHelper { private: - Debugger * _debugger; + Debugger* _debugger; bool _needResume = false; bool _isEmulationThread = false; @@ -17,11 +17,15 @@ public: _isEmulationThread = debugger->GetConsole()->GetEmulationThreadId() == std::this_thread::get_id(); - if(!_isEmulationThread) { + if (!_isEmulationThread) + { //Only attempt to break if this is done in a thread other than the main emulation thread debugger->BreakRequest(false); - if(!debugger->IsExecutionStopped()) { - while(!debugger->IsExecutionStopped()) {} + if (!debugger->IsExecutionStopped()) + { + while (!debugger->IsExecutionStopped()) + { + } _needResume = true; } } @@ -29,8 +33,9 @@ public: ~DebugBreakHelper() { - if(!_isEmulationThread) { + if (!_isEmulationThread) + { _debugger->BreakRequest(true); } } -}; \ No newline at end of file +}; diff --git a/Core/DebugHud.cpp b/Core/DebugHud.cpp index 14d1d60..9831277 100644 --- a/Core/DebugHud.cpp +++ b/Core/DebugHud.cpp @@ -27,16 +27,19 @@ void DebugHud::ClearScreen() void DebugHud::Draw(uint32_t* argbBuffer, OverscanDimensions overscan, uint32_t lineWidth, uint32_t frameNumber) { auto lock = _commandLock.AcquireSafe(); - for(unique_ptr &command : _commands) { + for (unique_ptr& command : _commands) + { command->Draw(argbBuffer, overscan, lineWidth, frameNumber); } - _commands.erase(std::remove_if(_commands.begin(), _commands.end(), [](const unique_ptr& c) { return c->Expired(); }), _commands.end()); + _commands.erase(std::remove_if(_commands.begin(), _commands.end(), + [](const unique_ptr& c) { return c->Expired(); }), _commands.end()); } void DebugHud::DrawPixel(int x, int y, int color, int frameCount, int startFrame) { auto lock = _commandLock.AcquireSafe(); - if(_commands.size() < DebugHud::MaxCommandCount) { + if (_commands.size() < DebugHud::MaxCommandCount) + { _commands.push_back(unique_ptr(new DrawPixelCommand(x, y, color, frameCount, startFrame))); } } @@ -44,23 +47,29 @@ void DebugHud::DrawPixel(int x, int y, int color, int frameCount, int startFrame void DebugHud::DrawLine(int x, int y, int x2, int y2, int color, int frameCount, int startFrame) { auto lock = _commandLock.AcquireSafe(); - if(_commands.size() < DebugHud::MaxCommandCount) { - _commands.push_back(unique_ptr(new DrawLineCommand(x, y, x2, y2, color, frameCount, startFrame))); + if (_commands.size() < DebugHud::MaxCommandCount) + { + _commands.push_back( + unique_ptr(new DrawLineCommand(x, y, x2, y2, color, frameCount, startFrame))); } } void DebugHud::DrawRectangle(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame) { auto lock = _commandLock.AcquireSafe(); - if(_commands.size() < DebugHud::MaxCommandCount) { - _commands.push_back(unique_ptr(new DrawRectangleCommand(x, y, width, height, color, fill, frameCount, startFrame))); + if (_commands.size() < DebugHud::MaxCommandCount) + { + _commands.push_back( + unique_ptr( + new DrawRectangleCommand(x, y, width, height, color, fill, frameCount, startFrame))); } } void DebugHud::DrawScreenBuffer(uint32_t* screenBuffer, int startFrame) { auto lock = _commandLock.AcquireSafe(); - if(_commands.size() < DebugHud::MaxCommandCount) { + if (_commands.size() < DebugHud::MaxCommandCount) + { _commands.push_back(unique_ptr(new DrawScreenBufferCommand(screenBuffer, startFrame))); } } @@ -68,7 +77,9 @@ void DebugHud::DrawScreenBuffer(uint32_t* screenBuffer, int startFrame) void DebugHud::DrawString(int x, int y, string text, int color, int backColor, int frameCount, int startFrame) { auto lock = _commandLock.AcquireSafe(); - if(_commands.size() < DebugHud::MaxCommandCount) { - _commands.push_back(unique_ptr(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame))); + if (_commands.size() < DebugHud::MaxCommandCount) + { + _commands.push_back( + unique_ptr(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame))); } } diff --git a/Core/DebugStats.cpp b/Core/DebugStats.cpp index 39b5dfe..f3e4204 100644 --- a/Core/DebugStats.cpp +++ b/Core/DebugStats.cpp @@ -6,7 +6,7 @@ #include "DebugHud.h" #include "IAudioDevice.h" -void DebugStats::DisplayStats(Console *console, double lastFrameTime) +void DebugStats::DisplayStats(Console* console, double lastFrameTime) { AudioStatistics stats = console->GetSoundMixer()->GetStatistics(); AudioConfig audioCfg = console->GetSettings()->GetAudioConfig(); @@ -23,21 +23,29 @@ void DebugStats::DisplayStats(Console *console, double lastFrameTime) hud->DrawString(10, 10, "Audio Stats", 0xFFFFFF, 0xFF000000, 1, startFrame); hud->DrawString(10, 21, "Latency: ", 0xFFFFFF, 0xFF000000, 1, startFrame); - int color = (stats.AverageLatency > 0 && std::abs(stats.AverageLatency - audioCfg.AudioLatency) > 3) ? 0xFF0000 : 0xFFFFFF; + int color = (stats.AverageLatency > 0 && std::abs(stats.AverageLatency - audioCfg.AudioLatency) > 3) + ? 0xFF0000 + : 0xFFFFFF; std::stringstream ss; ss << std::fixed << std::setprecision(2) << stats.AverageLatency << " ms"; hud->DrawString(54, 21, ss.str(), color, 0xFF000000, 1, startFrame); - hud->DrawString(10, 30, "Underruns: " + std::to_string(stats.BufferUnderrunEventCount), 0xFFFFFF, 0xFF000000, 1, startFrame); - hud->DrawString(10, 39, "Buffer Size: " + std::to_string(stats.BufferSize / 1024) + "kb", 0xFFFFFF, 0xFF000000, 1, startFrame); - hud->DrawString(10, 48, "Rate: " + std::to_string((uint32_t)(audioCfg.SampleRate * console->GetSoundMixer()->GetRateAdjustment())) + "Hz", 0xFFFFFF, 0xFF000000, 1, startFrame); + hud->DrawString(10, 30, "Underruns: " + std::to_string(stats.BufferUnderrunEventCount), 0xFFFFFF, 0xFF000000, 1, + startFrame); + hud->DrawString(10, 39, "Buffer Size: " + std::to_string(stats.BufferSize / 1024) + "kb", 0xFFFFFF, 0xFF000000, 1, + startFrame); + hud->DrawString( + 10, 48, + "Rate: " + std::to_string((uint32_t)(audioCfg.SampleRate * console->GetSoundMixer()->GetRateAdjustment())) + "Hz", + 0xFFFFFF, 0xFF000000, 1, startFrame); hud->DrawRectangle(132, 8, 115, 49, 0x40000000, true, 1, startFrame); hud->DrawRectangle(132, 8, 115, 49, 0xFFFFFF, false, 1, startFrame); hud->DrawString(134, 10, "Video Stats", 0xFFFFFF, 0xFF000000, 1, startFrame); double totalDuration = 0; - for(int i = 0; i < 60; i++) { + for (int i = 0; i < 60; i++) + { totalDuration += _frameDurations[i]; } @@ -49,10 +57,13 @@ void DebugStats::DisplayStats(Console *console, double lastFrameTime) ss << "Last Frame: " << std::fixed << std::setprecision(2) << lastFrameTime << " ms"; hud->DrawString(134, 30, ss.str(), 0xFFFFFF, 0xFF000000, 1, startFrame); - if(console->GetFrameCount() > 60) { + if (console->GetFrameCount() > 60) + { _lastFrameMin = std::min(lastFrameTime, _lastFrameMin); _lastFrameMax = std::max(lastFrameTime, _lastFrameMax); - } else { + } + else + { _lastFrameMin = 9999; _lastFrameMax = 0; } diff --git a/Core/DebugStats.h b/Core/DebugStats.h index dbf0706..13e5a75 100644 --- a/Core/DebugStats.h +++ b/Core/DebugStats.h @@ -12,5 +12,5 @@ private: double _lastFrameMax = 0; public: - void DisplayStats(Console *console, double lastFrameTime); -}; \ No newline at end of file + void DisplayStats(Console* console, double lastFrameTime); +}; diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index 68c2c80..888530b 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -241,7 +241,7 @@ enum class BreakSource BreakOnWdm = 5, BreakOnStp = 6, BreakOnUninitMemoryRead = 7, - + GbInvalidOamAccess = 8, GbInvalidVramAccess = 9, GbDisableLcdOutsideVblank = 10, diff --git a/Core/DebugUtilities.h b/Core/DebugUtilities.h index 0220e71..215dd45 100644 --- a/Core/DebugUtilities.h +++ b/Core/DebugUtilities.h @@ -7,14 +7,15 @@ class DebugUtilities public: static SnesMemoryType GetCpuMemoryType(CpuType type) { - switch(type) { - case CpuType::Cpu: return SnesMemoryType::CpuMemory; - case CpuType::Spc: return SnesMemoryType::SpcMemory; - case CpuType::NecDsp: return SnesMemoryType::NecDspMemory; - case CpuType::Sa1: return SnesMemoryType::Sa1Memory; - case CpuType::Gsu: return SnesMemoryType::GsuMemory; - case CpuType::Cx4: return SnesMemoryType::Cx4Memory; - case CpuType::Gameboy: return SnesMemoryType::GameboyMemory; + switch (type) + { + case CpuType::Cpu: return SnesMemoryType::CpuMemory; + case CpuType::Spc: return SnesMemoryType::SpcMemory; + case CpuType::NecDsp: return SnesMemoryType::NecDspMemory; + case CpuType::Sa1: return SnesMemoryType::Sa1Memory; + case CpuType::Gsu: return SnesMemoryType::GsuMemory; + case CpuType::Cx4: return SnesMemoryType::Cx4Memory; + case CpuType::Gameboy: return SnesMemoryType::GameboyMemory; } throw std::runtime_error("Invalid CPU type"); @@ -22,41 +23,42 @@ public: static CpuType ToCpuType(SnesMemoryType type) { - switch(type) { - case SnesMemoryType::SpcMemory: - case SnesMemoryType::SpcRam: - case SnesMemoryType::SpcRom: - return CpuType::Spc; + switch (type) + { + case SnesMemoryType::SpcMemory: + case SnesMemoryType::SpcRam: + case SnesMemoryType::SpcRom: + return CpuType::Spc; - case SnesMemoryType::GsuMemory: - case SnesMemoryType::GsuWorkRam: - return CpuType::Gsu; + case SnesMemoryType::GsuMemory: + case SnesMemoryType::GsuWorkRam: + return CpuType::Gsu; - case SnesMemoryType::Sa1InternalRam: - case SnesMemoryType::Sa1Memory: - return CpuType::Sa1; + case SnesMemoryType::Sa1InternalRam: + case SnesMemoryType::Sa1Memory: + return CpuType::Sa1; - case SnesMemoryType::DspDataRam: - case SnesMemoryType::DspDataRom: - case SnesMemoryType::DspProgramRom: - return CpuType::NecDsp; + case SnesMemoryType::DspDataRam: + case SnesMemoryType::DspDataRom: + case SnesMemoryType::DspProgramRom: + return CpuType::NecDsp; - case SnesMemoryType::Cx4DataRam: - case SnesMemoryType::Cx4Memory: - return CpuType::Cx4; - - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbSpriteRam: - case SnesMemoryType::GameboyMemory: - return CpuType::Gameboy; + case SnesMemoryType::Cx4DataRam: + case SnesMemoryType::Cx4Memory: + return CpuType::Cx4; - default: - return CpuType::Cpu; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbSpriteRam: + case SnesMemoryType::GameboyMemory: + return CpuType::Gameboy; + + default: + return CpuType::Cpu; } throw std::runtime_error("Invalid CPU type"); @@ -69,30 +71,32 @@ public: static bool IsPpuMemory(SnesMemoryType memType) { - switch(memType) { - case SnesMemoryType::VideoRam: - case SnesMemoryType::SpriteRam: - case SnesMemoryType::CGRam: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbSpriteRam: - return true; + switch (memType) + { + case SnesMemoryType::VideoRam: + case SnesMemoryType::SpriteRam: + case SnesMemoryType::CGRam: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbSpriteRam: + return true; - default: - return false; + default: + return false; } } static bool IsRomMemory(SnesMemoryType memType) { - switch(memType) { - case SnesMemoryType::PrgRom: - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::SaveRam: //Include save ram here to avoid uninit memory read warnings on save ram - return true; + switch (memType) + { + case SnesMemoryType::PrgRom: + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::SaveRam: //Include save ram here to avoid uninit memory read warnings on save ram + return true; - default: - return false; + default: + return false; } } @@ -100,4 +104,4 @@ public: { return CpuType::Gameboy; } -}; \ No newline at end of file +}; diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 0d2cf61..db32d2b 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -80,18 +80,26 @@ Debugger::Debugger(shared_ptr console) _ppuTools.reset(new PpuTools(_console.get(), _ppu.get())); _scriptManager.reset(new ScriptManager(this)); - if(_gameboy) { + if (_gameboy) + { _gbDebugger.reset(new GbDebugger(this)); } _cpuDebugger.reset(new CpuDebugger(this, CpuType::Cpu)); _spcDebugger.reset(new SpcDebugger(this)); - if(_cart->GetSa1()) { + if (_cart->GetSa1()) + { _sa1Debugger.reset(new CpuDebugger(this, CpuType::Sa1)); - } else if(_cart->GetGsu()) { + } + else if (_cart->GetGsu()) + { _gsuDebugger.reset(new GsuDebugger(this)); - } else if(_cart->GetDsp()) { + } + else if (_cart->GetDsp()) + { _necDspDebugger.reset(new NecDspDebugger(this)); - } else if(_cart->GetCx4()) { + } + else if (_cart->GetCx4()) + { _cx4Debugger.reset(new Cx4Debugger(this)); } @@ -100,12 +108,16 @@ Debugger::Debugger(shared_ptr console) _suspendRequestCount = 0; CpuType cpuType = _gbDebugger ? CpuType::Gameboy : CpuType::Cpu; - string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); - GetCodeDataLogger(cpuType)->LoadCdlFile(cdlFile, _settings->CheckDebuggerFlag(DebuggerFlags::AutoResetCdl), _cart->GetCrc32()); + string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), + FolderUtilities::GetFilename( + _cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); + GetCodeDataLogger(cpuType)->LoadCdlFile(cdlFile, _settings->CheckDebuggerFlag(DebuggerFlags::AutoResetCdl), + _cart->GetCrc32()); RefreshCodeCache(); - if(_console->IsPaused()) { + if (_console->IsPaused()) + { Step(CpuType::Cpu, 1, StepType::Step); } _executionStopped = false; @@ -119,10 +131,13 @@ Debugger::~Debugger() void Debugger::Release() { CpuType cpuType = _gbDebugger ? CpuType::Gameboy : CpuType::Cpu; - string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); + string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), + FolderUtilities::GetFilename( + _cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); GetCodeDataLogger(cpuType)->SaveCdlFile(cdlFile, _cart->GetCrc32()); - while(_executionStopped) { + while (_executionStopped) + { Run(); } } @@ -132,71 +147,92 @@ void Debugger::Reset() _memoryAccessCounter->ResetCounts(); _cpuDebugger->Reset(); _spcDebugger->Reset(); - if(_sa1Debugger) { + if (_sa1Debugger) + { _sa1Debugger->Reset(); } } -template +template void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) { - switch(type) { - case CpuType::Cpu: _cpuDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Spc: _spcDebugger->ProcessRead(addr, value, opType); break; - case CpuType::NecDsp: _necDspDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Sa1: _sa1Debugger->ProcessRead(addr, value, opType); break; - case CpuType::Gsu: _gsuDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Cx4: _cx4Debugger->ProcessRead(addr, value, opType); break; - case CpuType::Gameboy: _gbDebugger->ProcessRead(addr, value, opType); break; + switch (type) + { + case CpuType::Cpu: _cpuDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::Spc: _spcDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::NecDsp: _necDspDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::Sa1: _sa1Debugger->ProcessRead(addr, value, opType); + break; + case CpuType::Gsu: _gsuDebugger->ProcessRead(addr, value, opType); + break; + case CpuType::Cx4: _cx4Debugger->ProcessRead(addr, value, opType); + break; + case CpuType::Gameboy: _gbDebugger->ProcessRead(addr, value, opType); + break; } - - if(_scriptManager->HasScript()) { + + if (_scriptManager->HasScript()) + { _scriptManager->ProcessMemoryOperation(addr, value, opType, type); } } -template +template void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) { - switch(type) { - case CpuType::Cpu: _cpuDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Spc: _spcDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::NecDsp: _necDspDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Sa1: _sa1Debugger->ProcessWrite(addr, value, opType); break; - case CpuType::Gsu: _gsuDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Cx4: _cx4Debugger->ProcessWrite(addr, value, opType); break; - case CpuType::Gameboy: _gbDebugger->ProcessWrite(addr, value, opType); break; + switch (type) + { + case CpuType::Cpu: _cpuDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Spc: _spcDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::NecDsp: _necDspDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Sa1: _sa1Debugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Gsu: _gsuDebugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Cx4: _cx4Debugger->ProcessWrite(addr, value, opType); + break; + case CpuType::Gameboy: _gbDebugger->ProcessWrite(addr, value, opType); + break; } - - if(_scriptManager->HasScript()) { + + if (_scriptManager->HasScript()) + { _scriptManager->ProcessMemoryOperation(addr, value, opType, type); } } void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value) { - AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::WorkRam }; + AddressInfo addressInfo{(int32_t)addr, SnesMemoryType::WorkRam}; _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); - - MemoryOperationInfo operation { 0x7E0000 | addr, value, MemoryOperationType::Read }; + + MemoryOperationInfo operation{0x7E0000 | addr, value, MemoryOperationType::Read}; ProcessBreakConditions(false, _cpuDebugger->GetBreakpointManager(), operation, addressInfo); } void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value) { - AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::WorkRam }; + AddressInfo addressInfo{(int32_t)addr, SnesMemoryType::WorkRam}; _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock()); - - MemoryOperationInfo operation { 0x7E0000 | addr, value, MemoryOperationType::Write }; + + MemoryOperationInfo operation{0x7E0000 | addr, value, MemoryOperationType::Write}; ProcessBreakConditions(false, _cpuDebugger->GetBreakpointManager(), operation, addressInfo); } void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType) { - AddressInfo addressInfo { addr, memoryType }; - MemoryOperationInfo operation { addr, value, MemoryOperationType::Read }; - - BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy ? _gbDebugger->GetBreakpointManager() : _cpuDebugger->GetBreakpointManager(); + AddressInfo addressInfo{addr, memoryType}; + MemoryOperationInfo operation{addr, value, MemoryOperationType::Read}; + + BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy + ? _gbDebugger->GetBreakpointManager() + : _cpuDebugger->GetBreakpointManager(); ProcessBreakConditions(false, bpManager, operation, addressInfo); _memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock()); @@ -204,113 +240,145 @@ void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memor void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType) { - AddressInfo addressInfo { addr, memoryType }; - MemoryOperationInfo operation { addr, value, MemoryOperationType::Write }; - - BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy ? _gbDebugger->GetBreakpointManager() : _cpuDebugger->GetBreakpointManager(); + AddressInfo addressInfo{addr, memoryType}; + MemoryOperationInfo operation{addr, value, MemoryOperationType::Write}; + + BreakpointManager* bpManager = DebugUtilities::ToCpuType(memoryType) == CpuType::Gameboy + ? _gbDebugger->GetBreakpointManager() + : _cpuDebugger->GetBreakpointManager(); ProcessBreakConditions(false, bpManager, operation, addressInfo); _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _console->GetMasterClock()); } -template +template void Debugger::ProcessPpuCycle() { uint16_t scanline; uint16_t cycle; - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { scanline = _gameboy->GetPpu()->GetScanline(); cycle = _gameboy->GetPpu()->GetCycle(); - } else { + } + else + { scanline = _ppu->GetScanline(); cycle = _memoryManager->GetHClock(); } _ppuTools->UpdateViewers(scanline, cycle, cpuType); - switch(cpuType) { - case CpuType::Cpu: - //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs) - if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { - _spc->Run(); - } else if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) { - _cart->RunCoprocessors(); - } + switch (cpuType) + { + case CpuType::Cpu: + //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs) + if (_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) + { + _spc->Run(); + } + else if (_traceLogger->IsCpuLogged(CpuType::NecDsp)) + { + _cart->RunCoprocessors(); + } - _cpuDebugger->ProcessPpuCycle(scanline, cycle); - break; + _cpuDebugger->ProcessPpuCycle(scanline, cycle); + break; - case CpuType::Gameboy: - _gbDebugger->ProcessPpuCycle(scanline, cycle); - break; + case CpuType::Gameboy: + _gbDebugger->ProcessPpuCycle(scanline, cycle); + break; } - if(_breakRequestCount > 0) { + if (_breakRequestCount > 0) + { SleepUntilResume(BreakSource::Unspecified); } } -void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId) +void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo* operation, int breakpointId) { - if(_suspendRequestCount) { + if (_suspendRequestCount) + { return; } _console->GetSoundMixer()->StopAudio(); _disassembler->Disassemble(CpuType::Cpu); _disassembler->Disassemble(CpuType::Spc); - if(_cart->GetSa1()) { + if (_cart->GetSa1()) + { _disassembler->Disassemble(CpuType::Sa1); - } else if(_cart->GetGsu()) { + } + else if (_cart->GetGsu()) + { _disassembler->Disassemble(CpuType::Gsu); - } else if(_cart->GetDsp()) { + } + else if (_cart->GetDsp()) + { _disassembler->Disassemble(CpuType::NecDsp); - } else if(_cart->GetCx4()) { + } + else if (_cart->GetCx4()) + { _disassembler->Disassemble(CpuType::Cx4); - } else if(_cart->GetGameboy()) { + } + else if (_cart->GetGameboy()) + { _disassembler->RefreshDisassembly(CpuType::Gameboy); } _executionStopped = true; - - if(source != BreakSource::Unspecified || _breakRequestCount == 0) { + + if (source != BreakSource::Unspecified || _breakRequestCount == 0) + { //Only trigger code break event if the pause was caused by user action BreakEvent evt = {}; evt.BreakpointId = breakpointId; evt.Source = source; - if(operation) { + if (operation) + { evt.Operation = *operation; } _waitForBreakResume = true; _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, &evt); } - while((_waitForBreakResume && !_suspendRequestCount) || _breakRequestCount) { + while ((_waitForBreakResume && !_suspendRequestCount) || _breakRequestCount) + { std::this_thread::sleep_for(std::chrono::duration(10)); } _executionStopped = false; } -void Debugger::ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source) +void Debugger::ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo& operation, + AddressInfo& addressInfo, BreakSource source) { - if(needBreak || _breakRequestCount || _waitForBreakResume) { + if (needBreak || _breakRequestCount || _waitForBreakResume) + { SleepUntilResume(source); - } else { + } + else + { int breakpointId = bpManager->CheckBreakpoint(operation, addressInfo); - if(breakpointId >= 0) { + if (breakpointId >= 0) + { SleepUntilResume(BreakSource::Breakpoint, &operation, breakpointId); } } } -template +template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) { - switch(type) { - case CpuType::Cpu: _cpuDebugger->ProcessInterrupt(originalPc, currentPc, forNmi); break; - case CpuType::Sa1: _sa1Debugger->ProcessInterrupt(originalPc, currentPc, forNmi); break; - case CpuType::Gameboy: _gbDebugger->ProcessInterrupt(originalPc, currentPc); break; + switch (type) + { + case CpuType::Cpu: _cpuDebugger->ProcessInterrupt(originalPc, currentPc, forNmi); + break; + case CpuType::Sa1: _sa1Debugger->ProcessInterrupt(originalPc, currentPc, forNmi); + break; + case CpuType::Gameboy: _gbDebugger->ProcessInterrupt(originalPc, currentPc); + break; } ProcessEvent(forNmi ? EventType::Nmi : EventType::Irq); @@ -320,46 +388,54 @@ void Debugger::ProcessEvent(EventType type) { _scriptManager->ProcessEvent(type); - switch(type) { - default: break; + switch (type) + { + default: break; - case EventType::StartFrame: - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)CpuType::Cpu); - GetEventManager(CpuType::Cpu)->ClearFrameEvents(); - break; + case EventType::StartFrame: + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, + (void*)CpuType::Cpu); + GetEventManager(CpuType::Cpu)->ClearFrameEvents(); + break; - case EventType::GbStartFrame: - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { - _scriptManager->ProcessEvent(EventType::StartFrame); - } - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)CpuType::Gameboy); - GetEventManager(CpuType::Gameboy)->ClearFrameEvents(); - break; - - case EventType::GbEndFrame: - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { - _scriptManager->ProcessEvent(EventType::EndFrame); - } - break; + case EventType::GbStartFrame: + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { + _scriptManager->ProcessEvent(EventType::StartFrame); + } + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, + (void*)CpuType::Gameboy); + GetEventManager(CpuType::Gameboy)->ClearFrameEvents(); + break; - case EventType::Reset: - Reset(); - break; + case EventType::GbEndFrame: + if (_settings->CheckFlag(EmulationFlags::GameboyMode)) + { + _scriptManager->ProcessEvent(EventType::EndFrame); + } + break; - case EventType::StateLoaded: - _memoryAccessCounter->ResetCounts(); - break; + case EventType::Reset: + Reset(); + break; + + case EventType::StateLoaded: + _memoryAccessCounter->ResetCounts(); + break; } } -int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache) +int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType& resultType, bool useCache) { - MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read }; + MemoryOperationInfo operationInfo{0, 0, MemoryOperationType::Read}; DebugState state; GetState(state, false); - if(useCache) { + if (useCache) + { return _watchExpEval[(int)cpuType]->Evaluate(expression, state, resultType, operationInfo); - } else { + } + else + { ExpressionEvaluator expEval(this, cpuType); return expEval.Evaluate(expression, state, resultType, operationInfo); } @@ -369,19 +445,24 @@ void Debugger::Run() { _cpuDebugger->Run(); _spcDebugger->Run(); - if(_sa1Debugger) { + if (_sa1Debugger) + { _sa1Debugger->Run(); } - if(_gsuDebugger) { + if (_gsuDebugger) + { _gsuDebugger->Run(); } - if(_necDspDebugger) { + if (_necDspDebugger) + { _necDspDebugger->Run(); } - if(_cx4Debugger) { + if (_cx4Debugger) + { _cx4Debugger->Run(); - } - if(_gbDebugger) { + } + if (_gbDebugger) + { _gbDebugger->Run(); } _waitForBreakResume = false; @@ -391,41 +472,57 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type) { DebugBreakHelper helper(this); StepRequest step; - IDebugger *debugger = nullptr; + IDebugger* debugger = nullptr; - switch(cpuType) { - case CpuType::Cpu: debugger = _cpuDebugger.get(); break; - case CpuType::Spc: debugger = _spcDebugger.get(); break; - case CpuType::NecDsp: debugger = _necDspDebugger.get(); break; - case CpuType::Sa1: debugger = _sa1Debugger.get(); break; - case CpuType::Gsu: debugger = _gsuDebugger.get(); break; - case CpuType::Cx4: debugger = _cx4Debugger.get(); break; - case CpuType::Gameboy: debugger = _gbDebugger.get(); break; + switch (cpuType) + { + case CpuType::Cpu: debugger = _cpuDebugger.get(); + break; + case CpuType::Spc: debugger = _spcDebugger.get(); + break; + case CpuType::NecDsp: debugger = _necDspDebugger.get(); + break; + case CpuType::Sa1: debugger = _sa1Debugger.get(); + break; + case CpuType::Gsu: debugger = _gsuDebugger.get(); + break; + case CpuType::Cx4: debugger = _cx4Debugger.get(); + break; + case CpuType::Gameboy: debugger = _gbDebugger.get(); + break; } - if(debugger) { + if (debugger) + { debugger->Step(stepCount, type); } - if(debugger != _cpuDebugger.get()) { + if (debugger != _cpuDebugger.get()) + { _cpuDebugger->Run(); } - if(debugger != _spcDebugger.get()) { + if (debugger != _spcDebugger.get()) + { _spcDebugger->Run(); } - if(_sa1Debugger && debugger != _sa1Debugger.get()) { + if (_sa1Debugger && debugger != _sa1Debugger.get()) + { _sa1Debugger->Run(); } - if(_gsuDebugger && debugger != _gsuDebugger.get()) { + if (_gsuDebugger && debugger != _gsuDebugger.get()) + { _gsuDebugger->Run(); } - if(_necDspDebugger && debugger != _necDspDebugger.get()) { + if (_necDspDebugger && debugger != _necDspDebugger.get()) + { _necDspDebugger->Run(); } - if(_cx4Debugger && debugger != _cx4Debugger.get()) { + if (_cx4Debugger && debugger != _cx4Debugger.get()) + { _cx4Debugger->Run(); } - if(_gbDebugger && debugger != _gbDebugger.get()) { + if (_gbDebugger && debugger != _gbDebugger.get()) + { _gbDebugger->Run(); } _waitForBreakResume = false; @@ -443,24 +540,33 @@ bool Debugger::HasBreakRequest() void Debugger::BreakRequest(bool release) { - if(release) { + if (release) + { _breakRequestCount--; - } else { + } + else + { _breakRequestCount++; } } void Debugger::SuspendDebugger(bool release) { - if(release) { - if(_suspendRequestCount > 0) { + if (release) + { + if (_suspendRequestCount > 0) + { _suspendRequestCount--; - } else { - #ifdef _DEBUG - //throw std::runtime_error("unexpected debugger suspend::release call"); - #endif } - } else { + else + { +#ifdef _DEBUG + //throw std::runtime_error("unexpected debugger suspend::release call"); +#endif + } + } + else + { _suspendRequestCount++; } } @@ -468,17 +574,25 @@ void Debugger::SuspendDebugger(bool release) void Debugger::BreakImmediately(BreakSource source) { bool gbDebugger = _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled); - if(source == BreakSource::GbDisableLcdOutsideVblank && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnDisableLcdOutsideVblank))) { + if (source == BreakSource::GbDisableLcdOutsideVblank && (!gbDebugger || !_settings->CheckDebuggerFlag( + DebuggerFlags::GbBreakOnDisableLcdOutsideVblank))) + { return; - } else if(source == BreakSource::GbInvalidVramAccess && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidVramAccess))) { + } + else if (source == BreakSource::GbInvalidVramAccess && (!gbDebugger || !_settings->CheckDebuggerFlag( + DebuggerFlags::GbBreakOnInvalidVramAccess))) + { return; - } else if(source == BreakSource::GbInvalidOamAccess && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOamAccess))) { + } + else if (source == BreakSource::GbInvalidOamAccess && (!gbDebugger || !_settings->CheckDebuggerFlag( + DebuggerFlags::GbBreakOnInvalidOamAccess))) + { return; } SleepUntilResume(source); } -void Debugger::GetState(DebugState &state, bool partialPpuState) +void Debugger::GetState(DebugState& state, bool partialPpuState) { state.MasterClock = _console->GetMasterClock(); state.Cpu = _cpu->GetState(); @@ -486,27 +600,34 @@ void Debugger::GetState(DebugState &state, bool partialPpuState) state.Spc = _spc->GetState(); state.Dsp = _spc->GetDspState(); - if(!partialPpuState) { - for(int i = 0; i < 8; i++) { + if (!partialPpuState) + { + for (int i = 0; i < 8; i++) + { state.DmaChannels[i] = _dmaController->GetChannelConfig(i); } state.InternalRegs = _internalRegs->GetState(); state.Alu = _internalRegs->GetAluState(); } - if(_cart->GetDsp()) { + if (_cart->GetDsp()) + { state.NecDsp = _cart->GetDsp()->GetState(); } - if(_cart->GetSa1()) { + if (_cart->GetSa1()) + { state.Sa1 = _cart->GetSa1()->GetState(); } - if(_cart->GetGsu()) { + if (_cart->GetGsu()) + { state.Gsu = _cart->GetGsu()->GetState(); } - if(_cart->GetCx4()) { + if (_cart->GetCx4()) + { state.Cx4 = _cart->GetCx4()->GetState(); } - if(_cart->GetGameboy()) { + if (_cart->GetGameboy()) + { state.Gameboy = _cart->GetGameboy()->GetState(); } } @@ -558,23 +679,39 @@ void Debugger::SetSpcRegister(SpcRegister reg, uint16_t value) AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress) { - if(relAddress.Type == SnesMemoryType::CpuMemory) { - if(_memoryManager->IsRegister(relAddress.Address)) { - return { relAddress.Address & 0xFFFF, SnesMemoryType::Register }; - } else { + if (relAddress.Type == SnesMemoryType::CpuMemory) + { + if (_memoryManager->IsRegister(relAddress.Address)) + { + return {relAddress.Address & 0xFFFF, SnesMemoryType::Register}; + } + else + { return _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); } - } else if(relAddress.Type == SnesMemoryType::SpcMemory) { + } + else if (relAddress.Type == SnesMemoryType::SpcMemory) + { return _spc->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::Sa1Memory) { + } + else if (relAddress.Type == SnesMemoryType::Sa1Memory) + { return _cart->GetSa1()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::GsuMemory) { + } + else if (relAddress.Type == SnesMemoryType::GsuMemory) + { return _cart->GetGsu()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::Cx4Memory) { + } + else if (relAddress.Type == SnesMemoryType::Cx4Memory) + { return _cart->GetCx4()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); - } else if(relAddress.Type == SnesMemoryType::NecDspMemory) { - return { relAddress.Address, SnesMemoryType::DspProgramRom }; - } else if(relAddress.Type == SnesMemoryType::GameboyMemory) { + } + else if (relAddress.Type == SnesMemoryType::NecDspMemory) + { + return {relAddress.Address, SnesMemoryType::DspProgramRom}; + } + else if (relAddress.Type == SnesMemoryType::GameboyMemory) + { return _cart->GetGameboy()->GetAbsoluteAddress(relAddress.Address); } @@ -584,64 +721,80 @@ AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress) AddressInfo Debugger::GetRelativeAddress(AddressInfo absAddress, CpuType cpuType) { MemoryMappings* mappings = nullptr; - switch(cpuType) { - case CpuType::Cpu: mappings = _memoryManager->GetMemoryMappings(); break; - case CpuType::Spc: break; - case CpuType::NecDsp: break; - case CpuType::Sa1: mappings = _cart->GetSa1()->GetMemoryMappings(); break; - case CpuType::Gsu: mappings = _cart->GetGsu()->GetMemoryMappings(); break; - case CpuType::Cx4: mappings = _cart->GetCx4()->GetMemoryMappings(); break; - case CpuType::Gameboy: break; + switch (cpuType) + { + case CpuType::Cpu: mappings = _memoryManager->GetMemoryMappings(); + break; + case CpuType::Spc: break; + case CpuType::NecDsp: break; + case CpuType::Sa1: mappings = _cart->GetSa1()->GetMemoryMappings(); + break; + case CpuType::Gsu: mappings = _cart->GetGsu()->GetMemoryMappings(); + break; + case CpuType::Cx4: mappings = _cart->GetCx4()->GetMemoryMappings(); + break; + case CpuType::Gameboy: break; } - switch(absAddress.Type) { - case SnesMemoryType::PrgRom: - case SnesMemoryType::WorkRam: - case SnesMemoryType::SaveRam: { - if(!mappings) { + switch (absAddress.Type) + { + case SnesMemoryType::PrgRom: + case SnesMemoryType::WorkRam: + case SnesMemoryType::SaveRam: + { + if (!mappings) + { throw std::runtime_error("Unsupported cpu type"); } uint8_t startBank = 0; //Try to find a mirror close to where the PC is - if(cpuType == CpuType::Cpu) { - if(absAddress.Type == SnesMemoryType::WorkRam) { + if (cpuType == CpuType::Cpu) + { + if (absAddress.Type == SnesMemoryType::WorkRam) + { startBank = 0x7E; - } else { + } + else + { startBank = _cpu->GetState().K & 0xC0; } - } else if(cpuType == CpuType::Sa1) { + } + else if (cpuType == CpuType::Sa1) + { startBank = (_cart->GetSa1()->GetCpuState().K & 0xC0); - } else if(cpuType == CpuType::Gsu) { + } + else if (cpuType == CpuType::Gsu) + { startBank = (_cart->GetGsu()->GetState().ProgramBank & 0xC0); } - return { mappings->GetRelativeAddress(absAddress, startBank), DebugUtilities::GetCpuMemoryType(cpuType) }; + return {mappings->GetRelativeAddress(absAddress, startBank), DebugUtilities::GetCpuMemoryType(cpuType)}; } - case SnesMemoryType::SpcRam: - case SnesMemoryType::SpcRom: - return { _spc->GetRelativeAddress(absAddress), SnesMemoryType::SpcMemory }; - - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - return { _cart->GetGameboy()->GetRelativeAddress(absAddress), SnesMemoryType::GameboyMemory }; + case SnesMemoryType::SpcRam: + case SnesMemoryType::SpcRom: + return {_spc->GetRelativeAddress(absAddress), SnesMemoryType::SpcMemory}; - case SnesMemoryType::DspProgramRom: - return { absAddress.Address, SnesMemoryType::NecDspMemory }; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + return {_cart->GetGameboy()->GetRelativeAddress(absAddress), SnesMemoryType::GameboyMemory}; - case SnesMemoryType::Register: - return { absAddress.Address & 0xFFFF, SnesMemoryType::Register }; + case SnesMemoryType::DspProgramRom: + return {absAddress.Address, SnesMemoryType::NecDspMemory}; - default: - return { -1, SnesMemoryType::Register }; + case SnesMemoryType::Register: + return {absAddress.Address & 0xFFFF, SnesMemoryType::Register}; + + default: + return {-1, SnesMemoryType::Register}; } } -void Debugger::SetCdlData(CpuType cpuType, uint8_t *cdlData, uint32_t length) +void Debugger::SetCdlData(CpuType cpuType, uint8_t* cdlData, uint32_t length) { DebugBreakHelper helper(this); GetCodeDataLogger(cpuType)->SetCdlData(cdlData, length); @@ -665,7 +818,8 @@ void Debugger::RefreshCodeCache() void Debugger::RebuildPrgCache(CpuType cpuType) { shared_ptr cdl = GetCodeDataLogger(cpuType); - if(!cdl) { + if (!cdl) + { return; } @@ -673,8 +827,10 @@ void Debugger::RebuildPrgCache(CpuType cpuType) AddressInfo addrInfo; addrInfo.Type = cpuType == CpuType::Gameboy ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom; - for(uint32_t i = 0; i < prgRomSize; i++) { - if(cdl->IsCode(i)) { + for (uint32_t i = 0; i < prgRomSize; i++) + { + if (cdl->IsCode(i)) + { addrInfo.Address = (int32_t)i; i += _disassembler->BuildCache(addrInfo, cdl->GetCpuFlags(i), cdl->GetCpuType(i)) - 1; } @@ -685,14 +841,18 @@ void Debugger::GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memor { CpuType cpuType = DebugUtilities::ToCpuType(memoryType); shared_ptr cdl = GetCodeDataLogger(cpuType); - if(memoryType == SnesMemoryType::PrgRom || memoryType == SnesMemoryType::GbPrgRom) { + if (memoryType == SnesMemoryType::PrgRom || memoryType == SnesMemoryType::GbPrgRom) + { cdl->GetCdlData(offset, length, cdlData); - } else { + } + else + { SnesMemoryType prgType = _gbDebugger ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom; AddressInfo relAddress; relAddress.Type = memoryType; - for(uint32_t i = 0; i < length; i++) { + for (uint32_t i = 0; i < length; i++) + { relAddress.Address = offset + i; AddressInfo info = GetAbsoluteAddress(relAddress); cdlData[i] = info.Type == prgType ? cdl->GetFlags(info.Address) : 0; @@ -704,60 +864,82 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { _cpuDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); _spcDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); - if(_gsuDebugger) { + if (_gsuDebugger) + { _gsuDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_sa1Debugger) { + if (_sa1Debugger) + { _sa1Debugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_necDspDebugger) { + if (_necDspDebugger) + { _necDspDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_cx4Debugger) { + if (_cx4Debugger) + { _cx4Debugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } - if(_gbDebugger) { + if (_gbDebugger) + { _gbDebugger->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } } void Debugger::GetBreakpoints(CpuType cpuType, Breakpoint* breakpoints, int& execs, int& reads, int& writes) { - switch (cpuType) { + switch (cpuType) + { case CpuType::Cpu: return _cpuDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); case CpuType::Spc: return _spcDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); - case CpuType::Gsu: { - if (_gsuDebugger) { - return _gsuDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + case CpuType::Gsu: + { + if (_gsuDebugger) + { + return _gsuDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::Sa1: { - if (_sa1Debugger) { - return _sa1Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::Sa1: + { + if (_sa1Debugger) + { + return _sa1Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::NecDsp: { - if (_necDspDebugger) { - return _necDspDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::NecDsp: + { + if (_necDspDebugger) + { + return _necDspDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::Cx4: { - if (_cx4Debugger) { - return _cx4Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::Cx4: + { + if (_cx4Debugger) + { + return _cx4Debugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; - case CpuType::Gameboy: { - if (_gbDebugger) { - return _gbDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + break; + case CpuType::Gameboy: + { + if (_gbDebugger) + { + return _gbDebugger->GetBreakpointManager()->GetBreakpoints(breakpoints, reads, writes, execs); + } } - } break; + break; } } void Debugger::Log(string message) { auto lock = _logLock.AcquireSafe(); - if(_debuggerLog.size() >= 1000) { + if (_debuggerLog.size() >= 1000) + { _debuggerLog.pop_front(); } _debuggerLog.push_back(message); @@ -767,7 +949,8 @@ string Debugger::GetLog() { auto lock = _logLock.AcquireSafe(); stringstream ss; - for(string& msg : _debuggerLog) { + for (string& msg : _debuggerLog) + { ss << msg << "\n"; } return ss.str(); @@ -780,25 +963,35 @@ void Debugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption str Gameboy* gb = _cart->GetGameboy(); vector rom; - if(gb) { + if (gb) + { uint8_t* prgRom = gb->DebugGetMemory(SnesMemoryType::GbPrgRom); uint32_t prgRomSize = gb->DebugGetMemorySize(SnesMemoryType::GbPrgRom); - rom = vector(prgRom, prgRom+prgRomSize); - } else { + rom = vector(prgRom, prgRom + prgRomSize); + } + else + { rom = vector(_cart->DebugGetPrgRom(), _cart->DebugGetPrgRom() + _cart->DebugGetPrgRomSize()); } - if(saveAsIps) { + if (saveAsIps) + { output = IpsPatcher::CreatePatch(_cart->GetOriginalPrgRom(), rom); - } else { - if(stripOption != CdlStripOption::StripNone) { + } + else + { + if (stripOption != CdlStripOption::StripNone) + { GetCodeDataLogger(gb ? CpuType::Gameboy : CpuType::Cpu)->StripData(rom.data(), stripOption); //Preserve rom header regardless of CDL file contents - if(gb) { + if (gb) + { GameboyHeader header = gb->GetHeader(); memcpy(rom.data() + romInfo.HeaderOffset, &header, sizeof(GameboyHeader)); - } else { + } + else + { memcpy(rom.data() + romInfo.HeaderOffset, &romInfo.Header, sizeof(SnesCartInformation)); } } @@ -806,7 +999,8 @@ void Debugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption str } ofstream file(filename, ios::out | ios::binary); - if(file) { + if (file) + { file.write((char*)output.data(), output.size()); file.close(); } @@ -829,9 +1023,12 @@ shared_ptr Debugger::GetMemoryAccessCounter() shared_ptr Debugger::GetCodeDataLogger(CpuType cpuType) { - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { return _gbDebugger ? _gbDebugger->GetCodeDataLogger() : nullptr; - } else { + } + else + { return _codeDataLogger; } } @@ -848,9 +1045,12 @@ shared_ptr Debugger::GetPpuTools() shared_ptr Debugger::GetEventManager(CpuType cpuType) { - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { return std::dynamic_pointer_cast(_gbDebugger->GetEventManager()); - } else { + } + else + { return std::dynamic_pointer_cast(_cpuDebugger->GetEventManager()); } } @@ -867,16 +1067,17 @@ shared_ptr Debugger::GetScriptManager() shared_ptr Debugger::GetCallstackManager(CpuType cpuType) { - switch(cpuType) { - case CpuType::Cpu: return _cpuDebugger->GetCallstackManager(); - case CpuType::Spc: return _spcDebugger->GetCallstackManager(); - case CpuType::Sa1: return _sa1Debugger->GetCallstackManager(); - case CpuType::Gameboy: return _gbDebugger->GetCallstackManager(); + switch (cpuType) + { + case CpuType::Cpu: return _cpuDebugger->GetCallstackManager(); + case CpuType::Spc: return _spcDebugger->GetCallstackManager(); + case CpuType::Sa1: return _sa1Debugger->GetCallstackManager(); + case CpuType::Gameboy: return _gbDebugger->GetCallstackManager(); - case CpuType::Gsu: - case CpuType::NecDsp: - case CpuType::Cx4: - break; + case CpuType::Gsu: + case CpuType::NecDsp: + case CpuType::Cx4: + break; } throw std::runtime_error("GetCallstackManager() - Unsupported CPU type"); } @@ -888,9 +1089,12 @@ shared_ptr Debugger::GetConsole() shared_ptr Debugger::GetAssembler(CpuType cpuType) { - if(cpuType == CpuType::Gameboy) { + if (cpuType == CpuType::Gameboy) + { return std::dynamic_pointer_cast(_gbDebugger->GetAssembler()); - } else { + } + else + { return std::dynamic_pointer_cast(_cpuDebugger->GetAssembler()); } } diff --git a/Core/Debugger.h b/Core/Debugger.h index 4d6f494..0dcbf0a 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -75,7 +75,7 @@ private: shared_ptr _labelManager; unique_ptr _watchExpEval[(int)DebugUtilities::GetLastCpuType() + 1]; - + SimpleLock _logLock; std::list _debuggerLog; @@ -84,7 +84,7 @@ private: atomic _suspendRequestCount; bool _waitForBreakResume = false; - + void Reset(); public: @@ -92,10 +92,10 @@ public: ~Debugger(); void Release(); - template + template void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); - - template + + template void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); void ProcessWorkRamRead(uint32_t addr, uint8_t value); @@ -104,15 +104,15 @@ public: void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType); void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType); - template + template void ProcessPpuCycle(); - template + template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessEvent(EventType type); - int32_t EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache); + int32_t EvaluateExpression(string expression, CpuType cpuType, EvalResultType& resultType, bool useCache); void Run(); void Step(CpuType cpuType, int32_t stepCount, StepType type); @@ -124,7 +124,8 @@ public: void BreakImmediately(BreakSource source); - void ProcessBreakConditions(bool needBreak, BreakpointManager *bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified); + void ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo& operation, + AddressInfo& addressInfo, BreakSource source = BreakSource::Unspecified); void SleepUntilResume(BreakSource source, MemoryOperationInfo* operation = nullptr, int breakpointId = -1); void GetState(DebugState& state, bool partialPpuState); @@ -143,15 +144,15 @@ public: AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType); void GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memoryType, uint8_t* cdlData); - void SetCdlData(CpuType cpuType, uint8_t * cdlData, uint32_t length); + void SetCdlData(CpuType cpuType, uint8_t* cdlData, uint32_t length); void MarkBytesAs(CpuType cpuType, uint32_t start, uint32_t end, uint8_t flags); - + void RefreshCodeCache(); void RebuildPrgCache(CpuType cpuType); void SetBreakpoints(Breakpoint breakpoints[], uint32_t length); void GetBreakpoints(CpuType cpuType, Breakpoint* breakpoints, int& execs, int& reads, int& writes); - + void Log(string message); string GetLog(); diff --git a/Core/DefaultVideoFilter.cpp b/Core/DefaultVideoFilter.cpp index ad729c5..64b33a2 100644 --- a/Core/DefaultVideoFilter.cpp +++ b/Core/DefaultVideoFilter.cpp @@ -20,14 +20,15 @@ void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturation double hue = hueShift * PI; double sat = saturationShift + 1; - double baseValues[6] = { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; + double baseValues[6] = {0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f}; double s = sin(hue) * sat; double c = cos(hue) * sat; - double *output = _yiqToRgbMatrix; - double *input = baseValues; - for(int n = 0; n < 3; n++) { + double* output = _yiqToRgbMatrix; + double* input = baseValues; + for (int n = 0; n < 3; n++) + { double i = *input++; double q = *input++; *output++ = i * c - q * s; @@ -42,24 +43,29 @@ void DefaultVideoFilter::InitLookupTable() InitConversionMatrix(config.Hue, config.Saturation); double y, i, q; - for(int rgb555 = 0; rgb555 < 0x8000; rgb555++) { + for (int rgb555 = 0; rgb555 < 0x8000; rgb555++) + { uint8_t r = rgb555 & 0x1F; uint8_t g = (rgb555 >> 5) & 0x1F; uint8_t b = (rgb555 >> 10) & 0x1F; - if(_gbcAdjustColors) { + if (_gbcAdjustColors) + { uint8_t r2 = std::min(240, (r * 26 + g * 4 + b * 2) >> 2); uint8_t g2 = std::min(240, (g * 24 + b * 8) >> 2); uint8_t b2 = std::min(240, (r * 6 + g * 4 + b * 22) >> 2); r = r2; g = g2; b = b2; - } else { + } + else + { r = To8Bit(r); g = To8Bit(g); b = To8Bit(b); } - if(config.Hue != 0 || config.Saturation != 0 || config.Brightness != 0 || config.Contrast != 0) { + if (config.Hue != 0 || config.Saturation != 0 || config.Brightness != 0 || config.Contrast != 0) + { double redChannel = r / 255.0; double greenChannel = g / 255.0; double blueChannel = b / 255.0; @@ -74,7 +80,9 @@ void DefaultVideoFilter::InitLookupTable() int g = std::min(255, (int)(greenChannel * 255)); int b = std::min(255, (int)(blueChannel * 255)); _calculatedPalette[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b; - } else { + } + else + { _calculatedPalette[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b; } } @@ -89,11 +97,14 @@ void DefaultVideoFilter::OnBeforeApplyFilter() ConsoleType consoleType = _console->GetConsoleType(); bool adjustColors = gbConfig.GbcAdjustColors && consoleType == ConsoleType::GameboyColor; - if(_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config.Contrast || _videoConfig.Brightness != config.Brightness || _gbcAdjustColors != adjustColors) { + if (_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config + .Contrast || _videoConfig.Brightness != config.Brightness || _gbcAdjustColors != adjustColors) + { _gbcAdjustColors = adjustColors; InitLookupTable(); } - _gbBlendFrames = gbConfig.BlendFrames && (consoleType == ConsoleType::Gameboy || consoleType == ConsoleType::GameboyColor); + _gbBlendFrames = gbConfig.BlendFrames && (consoleType == ConsoleType::Gameboy || consoleType == + ConsoleType::GameboyColor); _videoConfig = config; } @@ -111,63 +122,82 @@ uint32_t DefaultVideoFilter::ToArgb(uint16_t rgb555) return 0xFF000000 | (r << 16) | (g << 8) | b; } -void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer) +void DefaultVideoFilter::ApplyFilter(uint16_t* ppuOutputBuffer) { - uint32_t *out = GetOutputBuffer(); + uint32_t* out = GetOutputBuffer(); FrameInfo frameInfo = GetFrameInfo(); OverscanDimensions overscan = GetOverscan(); - + int overscanMultiplier = _baseFrameInfo.Width == 512 ? 2 : 1; uint32_t width = _baseFrameInfo.Width; uint32_t xOffset = overscan.Left * overscanMultiplier; uint32_t yOffset = overscan.Top * overscanMultiplier * width; uint8_t scanlineIntensity = (uint8_t)((1.0 - _console->GetSettings()->GetVideoConfig().ScanlineIntensity) * 255); - if(scanlineIntensity < 255) { - for(uint32_t i = 0; i < frameInfo.Height; i++) { - if(i & 0x01) { - for(uint32_t j = 0; j < frameInfo.Width; j++) { - *out = ApplyScanlineEffect(GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset), scanlineIntensity); + if (scanlineIntensity < 255) + { + for (uint32_t i = 0; i < frameInfo.Height; i++) + { + if (i & 0x01) + { + for (uint32_t j = 0; j < frameInfo.Width; j++) + { + *out = ApplyScanlineEffect(GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset), + scanlineIntensity); out++; } - } else { - for(uint32_t j = 0; j < frameInfo.Width; j++) { + } + else + { + for (uint32_t j = 0; j < frameInfo.Width; j++) + { *out = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset); out++; } } } - } else { - for(uint32_t i = 0; i < frameInfo.Height; i++) { - for(uint32_t j = 0; j < frameInfo.Width; j++) { - out[i*frameInfo.Width+j] = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset); + } + else + { + for (uint32_t i = 0; i < frameInfo.Height; i++) + { + for (uint32_t j = 0; j < frameInfo.Width; j++) + { + out[i * frameInfo.Width + j] = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset); } } } - if(_baseFrameInfo.Width == 512 && _videoConfig.BlendHighResolutionModes) { + if (_baseFrameInfo.Width == 512 && _videoConfig.BlendHighResolutionModes) + { //Very basic blend effect for high resolution modes - for(uint32_t i = 0; i < frameInfo.Height; i+=2) { - for(uint32_t j = 0; j < frameInfo.Width; j+=2) { - uint32_t &pixel1 = out[i*frameInfo.Width + j]; - uint32_t &pixel2 = out[i*frameInfo.Width + j + 1]; - uint32_t &pixel3 = out[(i+1)*frameInfo.Width + j]; - uint32_t &pixel4 = out[(i+1)*frameInfo.Width + j + 1]; + for (uint32_t i = 0; i < frameInfo.Height; i += 2) + { + for (uint32_t j = 0; j < frameInfo.Width; j += 2) + { + uint32_t& pixel1 = out[i * frameInfo.Width + j]; + uint32_t& pixel2 = out[i * frameInfo.Width + j + 1]; + uint32_t& pixel3 = out[(i + 1) * frameInfo.Width + j]; + uint32_t& pixel4 = out[(i + 1) * frameInfo.Width + j + 1]; pixel1 = pixel2 = pixel3 = pixel4 = BlendPixels(BlendPixels(BlendPixels(pixel1, pixel2), pixel3), pixel4); } } } - if(_gbBlendFrames) { + if (_gbBlendFrames) + { std::copy(ppuOutputBuffer, ppuOutputBuffer + 256 * 240, _prevFrame); } } uint32_t DefaultVideoFilter::GetPixel(uint16_t* ppuFrame, uint32_t offset) { - if(_gbBlendFrames) { + if (_gbBlendFrames) + { return BlendPixels(_calculatedPalette[_prevFrame[offset]], _calculatedPalette[ppuFrame[offset]]); - } else { + } + else + { return _calculatedPalette[ppuFrame[offset]]; } } @@ -177,16 +207,16 @@ uint32_t DefaultVideoFilter::BlendPixels(uint32_t a, uint32_t b) return ((((a) ^ (b)) & 0xfffefefeL) >> 1) + ((a) & (b)); } -void DefaultVideoFilter::RgbToYiq(double r, double g, double b, double &y, double &i, double &q) +void DefaultVideoFilter::RgbToYiq(double r, double g, double b, double& y, double& i, double& q) { y = r * 0.299f + g * 0.587f + b * 0.114f; i = r * 0.596f - g * 0.275f - b * 0.321f; q = r * 0.212f - g * 0.523f + b * 0.311f; } -void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double &r, double &g, double &b) +void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double& r, double& g, double& b) { r = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[0] * i + _yiqToRgbMatrix[1] * q))); g = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[2] * i + _yiqToRgbMatrix[3] * q))); b = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[4] * i + _yiqToRgbMatrix[5] * q))); -} \ No newline at end of file +} diff --git a/Core/DefaultVideoFilter.h b/Core/DefaultVideoFilter.h index 0bae98d..09e4a93 100644 --- a/Core/DefaultVideoFilter.h +++ b/Core/DefaultVideoFilter.h @@ -18,8 +18,8 @@ private: void InitConversionMatrix(double hueShift, double saturationShift); void InitLookupTable(); - void RgbToYiq(double r, double g, double b, double &y, double &i, double &q); - void YiqToRgb(double y, double i, double q, double &r, double &g, double &b); + void RgbToYiq(double r, double g, double b, double& y, double& i, double& q); + void YiqToRgb(double y, double i, double q, double& r, double& g, double& b); __forceinline static uint8_t To8Bit(uint8_t color); __forceinline static uint32_t BlendPixels(uint32_t a, uint32_t b); __forceinline uint32_t GetPixel(uint16_t* ppuFrame, uint32_t offset); @@ -29,7 +29,7 @@ protected: public: DefaultVideoFilter(shared_ptr console); - void ApplyFilter(uint16_t *ppuOutputBuffer); + void ApplyFilter(uint16_t* ppuOutputBuffer); static uint32_t ToArgb(uint16_t rgb555); -}; \ No newline at end of file +}; diff --git a/Core/Disassembler.cpp b/Core/Disassembler.cpp index 6f1e50d..635f278 100644 --- a/Core/Disassembler.cpp +++ b/Core/Disassembler.cpp @@ -46,18 +46,21 @@ Disassembler::Disassembler(shared_ptr console, shared_ptrGetMemoryDumper().get(); _memoryManager = console->GetMemoryManager().get(); - for(int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++) { + for (int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++) + { _disassemblyResult[i] = vector(); _needDisassemble[i] = true; } - for(int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) { + for (int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) + { InitSource((SnesMemoryType)i); } - if(_necDsp) { + if (_necDsp) + { //Build cache for the entire DSP chip (since it only contains instructions) - AddressInfo dspStart = { 0, SnesMemoryType::DspProgramRom }; + AddressInfo dspStart = {0, SnesMemoryType::DspProgramRom}; BuildCache(dspStart, 0, CpuType::NecDsp); } } @@ -67,42 +70,49 @@ void Disassembler::InitSource(SnesMemoryType type) uint8_t* src = _memoryDumper->GetMemoryBuffer(type); uint32_t size = _memoryDumper->GetMemorySize(type); _disassemblyCache[(int)type] = vector(size); - _sources[(int)type] = { src, &_disassemblyCache[(int)type], size }; + _sources[(int)type] = {src, &_disassemblyCache[(int)type], size}; } DisassemblerSource& Disassembler::GetSource(SnesMemoryType type) { - if(_sources[(int)type].Data == nullptr) { + if (_sources[(int)type].Data == nullptr) + { throw std::runtime_error("Disassembler::GetSource() invalid memory type"); } return _sources[(int)type]; } -uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuType type) +uint32_t Disassembler::BuildCache(AddressInfo& addrInfo, uint8_t cpuFlags, CpuType type) { DisassemblerSource& src = GetSource(addrInfo.Type); bool needDisassemble = false; int returnSize = 0; int32_t address = addrInfo.Address; - while(address >= 0 && address < (int32_t)src.Cache->size()) { - DisassemblyInfo &disInfo = (*src.Cache)[address]; - if(!disInfo.IsInitialized() || !disInfo.IsValid(cpuFlags)) { - disInfo.Initialize(src.Data+address, cpuFlags, type); - for(int i = 1; i < disInfo.GetOpSize(); i++) { + while (address >= 0 && address < (int32_t)src.Cache->size()) + { + DisassemblyInfo& disInfo = (*src.Cache)[address]; + if (!disInfo.IsInitialized() || !disInfo.IsValid(cpuFlags)) + { + disInfo.Initialize(src.Data + address, cpuFlags, type); + for (int i = 1; i < disInfo.GetOpSize(); i++) + { //Clear any instructions that start in the middle of this one //(can happen when resizing an instruction after X/M updates) (*src.Cache)[address + i] = DisassemblyInfo(); } needDisassemble = true; returnSize += disInfo.GetOpSize(); - } else { + } + else + { returnSize += disInfo.GetOpSize(); break; } - if(disInfo.IsUnconditionalJump()) { + if (disInfo.IsUnconditionalJump()) + { //Can't assume what follows is code, stop disassembling break; } @@ -111,7 +121,8 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy address += disInfo.GetOpSize(); } - if(needDisassemble) { + if (needDisassemble) + { SetDisassembleFlag(type); } @@ -120,12 +131,15 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy void Disassembler::SetDisassembleFlag(CpuType type) { - if(type == CpuType::Cpu || type == CpuType::Sa1 || type == CpuType::Gsu || type == CpuType::Cx4) { + if (type == CpuType::Cpu || type == CpuType::Sa1 || type == CpuType::Gsu || type == CpuType::Cx4) + { _needDisassemble[(int)CpuType::Cpu] = true; _needDisassemble[(int)CpuType::Sa1] = true; _needDisassemble[(int)CpuType::Gsu] = true; _needDisassemble[(int)CpuType::Cx4] = true; - } else { + } + else + { _needDisassemble[(int)type] = true; } } @@ -146,85 +160,97 @@ void Disassembler::InvalidateCache(AddressInfo addrInfo, CpuType type) DisassemblerSource src = GetSource(addrInfo.Type); bool needDisassemble = false; - if(addrInfo.Address >= 0) { - for(int i = 0; i < 4; i++) { - if(addrInfo.Address >= i) { - if((*src.Cache)[addrInfo.Address - i].IsInitialized()) { + if (addrInfo.Address >= 0) + { + for (int i = 0; i < 4; i++) + { + if (addrInfo.Address >= i) + { + if ((*src.Cache)[addrInfo.Address - i].IsInitialized()) + { (*src.Cache)[addrInfo.Address - i].Reset(); needDisassemble = true; } } } } - - if(needDisassemble) { + + if (needDisassemble) + { SetDisassembleFlag(type); } } void Disassembler::Disassemble(CpuType cpuType) { - if(!_needDisassemble[(int)cpuType]) { + if (!_needDisassemble[(int)cpuType]) + { return; } _needDisassemble[(int)cpuType] = false; - auto lock = _disassemblyLock.AcquireSafe(); - - MemoryMappings *mappings = nullptr; + auto lock = _disassemblyLock.AcquireSafe(); + + MemoryMappings* mappings = nullptr; int32_t maxAddr = 0xFFFFFF; - switch(cpuType) { - case CpuType::Cpu: - mappings = _memoryManager->GetMemoryMappings(); - break; + switch (cpuType) + { + case CpuType::Cpu: + mappings = _memoryManager->GetMemoryMappings(); + break; - case CpuType::Sa1: - if(!_sa1) { - return; - } - mappings = _sa1->GetMemoryMappings(); - break; + case CpuType::Sa1: + if (!_sa1) + { + return; + } + mappings = _sa1->GetMemoryMappings(); + break; - case CpuType::Gsu: - if(!_gsu) { - return; - } - mappings = _gsu->GetMemoryMappings(); - break; + case CpuType::Gsu: + if (!_gsu) + { + return; + } + mappings = _gsu->GetMemoryMappings(); + break; - case CpuType::NecDsp: - if(!_console->GetCartridge()->GetDsp()) { - return; - } - mappings = nullptr; - maxAddr = _necDsp->DebugGetProgramRomSize() - 1; - break; + case CpuType::NecDsp: + if (!_console->GetCartridge()->GetDsp()) + { + return; + } + mappings = nullptr; + maxAddr = _necDsp->DebugGetProgramRomSize() - 1; + break; - case CpuType::Spc: - mappings = nullptr; - maxAddr = 0xFFFF; - break; + case CpuType::Spc: + mappings = nullptr; + maxAddr = 0xFFFF; + break; - case CpuType::Gameboy: - if(!_gameboy) { - return; - } - mappings = nullptr; - maxAddr = 0xFFFF; - break; + case CpuType::Gameboy: + if (!_gameboy) + { + return; + } + mappings = nullptr; + maxAddr = 0xFFFF; + break; - case CpuType::Cx4: - if(!_console->GetCartridge()->GetCx4()) { - return; - } - mappings = _console->GetCartridge()->GetCx4()->GetMemoryMappings(); - break; + case CpuType::Cx4: + if (!_console->GetCartridge()->GetCx4()) + { + return; + } + mappings = _console->GetCartridge()->GetCx4()->GetMemoryMappings(); + break; - default: throw std::runtime_error("Disassemble(): Invalid cpu type"); + default: throw std::runtime_error("Disassemble(): Invalid cpu type"); } - vector &results = _disassemblyResult[(int)cpuType]; + vector& results = _disassemblyResult[(int)cpuType]; results.clear(); bool disUnident = _settings->CheckDebuggerFlag(DebuggerFlags::DisassembleUnidentifiedData); @@ -238,54 +264,73 @@ void Disassembler::Disassemble(CpuType cpuType) AddressInfo addrInfo = {}; AddressInfo prevAddrInfo = {}; int byteCounter = 0; - for(int32_t i = 0; i <= maxAddr; i++) { + for (int32_t i = 0; i <= maxAddr; i++) + { prevAddrInfo = addrInfo; - switch(cpuType) { - case CpuType::Spc: addrInfo = _spc->GetAbsoluteAddress(i); break; - case CpuType::NecDsp: addrInfo = { i, SnesMemoryType::DspProgramRom }; break; - case CpuType::Gameboy: addrInfo = _gameboy->GetAbsoluteAddress(i); break; - default: addrInfo = mappings->GetAbsoluteAddress(i); break; + switch (cpuType) + { + case CpuType::Spc: addrInfo = _spc->GetAbsoluteAddress(i); + break; + case CpuType::NecDsp: addrInfo = {i, SnesMemoryType::DspProgramRom}; + break; + case CpuType::Gameboy: addrInfo = _gameboy->GetAbsoluteAddress(i); + break; + default: addrInfo = mappings->GetAbsoluteAddress(i); + break; } - if(addrInfo.Address < 0) { + if (addrInfo.Address < 0) + { continue; } DisassemblerSource src = GetSource(addrInfo.Type); DisassemblyInfo disassemblyInfo = (*src.Cache)[addrInfo.Address]; - + uint8_t opSize = 0; uint8_t opCode = (src.Data + addrInfo.Address)[0]; bool isCode = addrInfo.Type == SnesMemoryType::PrgRom ? _cdl->IsCode(addrInfo.Address) : false; bool isData = addrInfo.Type == SnesMemoryType::PrgRom ? _cdl->IsData(addrInfo.Address) : false; - if(disassemblyInfo.IsInitialized()) { + if (disassemblyInfo.IsInitialized()) + { opSize = disassemblyInfo.GetOpSize(); - } else if((isData && disData) || (!isData && !isCode && disUnident)) { + } + else if ((isData && disData) || (!isData && !isCode && disUnident)) + { opSize = DisassemblyInfo::GetOpSize(opCode, 0, cpuType); } - if(opSize > 0) { - if(inUnknownBlock || inVerifiedBlock) { - int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | (((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0); + if (opSize > 0) + { + if (inUnknownBlock || inVerifiedBlock) + { + int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | ( + ((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0); results.push_back(DisassemblyResult(prevAddrInfo, i - 1, flags)); inUnknownBlock = false; inVerifiedBlock = false; } byteCounter = 0; - if(addrInfo.Type == SnesMemoryType::PrgRom && _cdl->IsSubEntryPoint(addrInfo.Address)) { - results.push_back(DisassemblyResult(addrInfo, i, LineFlags::SubStart | LineFlags::BlockStart | LineFlags::VerifiedCode)); + if (addrInfo.Type == SnesMemoryType::PrgRom && _cdl->IsSubEntryPoint(addrInfo.Address)) + { + results.push_back(DisassemblyResult(addrInfo, i, + LineFlags::SubStart | LineFlags::BlockStart | LineFlags::VerifiedCode)); } - if(_labelManager->GetLabelAndComment(addrInfo, labelInfo)) { + if (_labelManager->GetLabelAndComment(addrInfo, labelInfo)) + { bool hasMultipleComment = labelInfo.Comment.find_first_of('\n') != string::npos; - if(hasMultipleComment) { + if (hasMultipleComment) + { int16_t lineCount = 0; - for(char c : labelInfo.Comment) { - if(c == '\n') { + for (char c : labelInfo.Comment) + { + if (c == '\n') + { results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Comment, lineCount)); lineCount++; } @@ -293,42 +338,62 @@ void Disassembler::Disassemble(CpuType cpuType) results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Comment, lineCount)); } - if(labelInfo.Label.size()) { + if (labelInfo.Label.size()) + { results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Label)); } - if(!hasMultipleComment && labelInfo.Comment.size()) { + if (!hasMultipleComment && labelInfo.Comment.size()) + { results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Comment)); - } else { + } + else + { results.push_back(DisassemblyResult(addrInfo, i)); } - } else { + } + else + { results.push_back(DisassemblyResult(addrInfo, i)); } //Move to the end of the instruction (but realign disassembly if another valid instruction is found) //This can sometimes happen if the 2nd byte of BRK/COP is reused as the first byte of the next instruction //Also required when disassembling unvalidated data as code (to realign once we find verified code) - for(int j = 1, max = (int)(*src.Cache).size(); j < opSize && addrInfo.Address + j < max; j++) { - if((*src.Cache)[addrInfo.Address + j].IsInitialized()) { + for (int j = 1, max = (int)(*src.Cache).size(); j < opSize && addrInfo.Address + j < max; j++) + { + if ((*src.Cache)[addrInfo.Address + j].IsInitialized()) + { break; } i++; } - if(DisassemblyInfo::IsReturnInstruction(opCode, cpuType)) { + if (DisassemblyInfo::IsReturnInstruction(opCode, cpuType)) + { //End of function results.push_back(DisassemblyResult(-1, LineFlags::VerifiedCode | LineFlags::BlockEnd)); - } - } else { - if(showData || showUnident) { - if((isData && inUnknownBlock) || (!isData && inVerifiedBlock)) { - if(isData && inUnknownBlock) { + } + } + else + { + if (showData || showUnident) + { + if ((isData && inUnknownBlock) || (!isData && inVerifiedBlock)) + { + if (isData && inUnknownBlock) + { //In an unknown block and the next byte is data, end the block - results.push_back(DisassemblyResult(prevAddrInfo, i - 1, LineFlags::BlockEnd | (showUnident ? LineFlags::ShowAsData : 0))); - } else if(!isData && inVerifiedBlock) { + results.push_back(DisassemblyResult(prevAddrInfo, i - 1, + LineFlags::BlockEnd | (showUnident ? LineFlags::ShowAsData : 0))); + } + else if (!isData && inVerifiedBlock) + { //In a verified data block and the next byte is unknown, end the block - results.push_back(DisassemblyResult(prevAddrInfo, i - 1, LineFlags::BlockEnd | LineFlags::VerifiedData | (showData ? LineFlags::ShowAsData : 0))); + results.push_back(DisassemblyResult(prevAddrInfo, i - 1, + LineFlags::BlockEnd | LineFlags::VerifiedData | (showData + ? LineFlags::ShowAsData + : 0))); } inUnknownBlock = false; inVerifiedBlock = false; @@ -336,29 +401,45 @@ void Disassembler::Disassemble(CpuType cpuType) } } - if(byteCounter > 0) { + if (byteCounter > 0) + { //If showing as hex data, add a new data line every 8 bytes byteCounter--; - if(byteCounter == 0) { - results.push_back(DisassemblyResult(addrInfo, i, LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0))); + if (byteCounter == 0) + { + results.push_back(DisassemblyResult(addrInfo, i, + LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0))); byteCounter = 8; } - } else if(!inUnknownBlock && !inVerifiedBlock) { + } + else if (!inUnknownBlock && !inVerifiedBlock) + { //If not in a block, start a new block based on the current byte's type (data vs unidentified) bool showAsData = (isData && showData) || ((!isData && !isCode) && showUnident); - if(isData) { + if (isData) + { inVerifiedBlock = true; - results.push_back(DisassemblyResult(addrInfo, i, LineFlags::BlockStart | LineFlags::VerifiedData | (showAsData ? LineFlags::ShowAsData : 0))); - } else { + results.push_back(DisassemblyResult(addrInfo, i, + LineFlags::BlockStart | LineFlags::VerifiedData | (showAsData + ? LineFlags::ShowAsData + : 0))); + } + else + { inUnknownBlock = true; - results.push_back(DisassemblyResult(addrInfo, i, LineFlags::BlockStart | (showAsData ? LineFlags::ShowAsData : 0))); + results.push_back(DisassemblyResult(addrInfo, i, + LineFlags::BlockStart | (showAsData ? LineFlags::ShowAsData : 0))); } - if(showAsData) { + if (showAsData) + { //If showing data as hex, add the first row of the block - results.push_back(DisassemblyResult(addrInfo, i, LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0))); + results.push_back(DisassemblyResult(addrInfo, i, + LineFlags::ShowAsData | (isData ? LineFlags::VerifiedData : 0))); byteCounter = 8; - } else { + } + else + { //If not showing the data at all, display 1 empty line results.push_back(DisassemblyResult(-1, LineFlags::None | (isData ? LineFlags::VerifiedData : 0))); } @@ -366,16 +447,19 @@ void Disassembler::Disassemble(CpuType cpuType) } } - if(inUnknownBlock || inVerifiedBlock) { - int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | (((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0); + if (inUnknownBlock || inVerifiedBlock) + { + int flags = LineFlags::BlockEnd | (inVerifiedBlock ? LineFlags::VerifiedData : 0) | ( + ((inVerifiedBlock && showData) || (inUnknownBlock && showUnident)) ? LineFlags::ShowAsData : 0); results.push_back(DisassemblyResult(addrInfo, maxAddr, flags)); } } -DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo &info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type) +DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo& info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type) { DisassemblyInfo disassemblyInfo = (*GetSource(info.Type).Cache)[info.Address]; - if(!disassemblyInfo.IsInitialized()) { + if (!disassemblyInfo.IsInitialized()) + { disassemblyInfo.Initialize(cpuAddress, cpuFlags, type, _memoryDumper); } return disassemblyInfo; @@ -400,14 +484,20 @@ uint32_t Disassembler::GetLineIndex(CpuType type, uint32_t cpuAddress) auto lock = _disassemblyLock.AcquireSafe(); vector& source = _disassemblyResult[(int)type]; uint32_t lastAddress = 0; - for(size_t i = 1; i < source.size(); i++) { - if(source[i].CpuAddress < 0 || (source[i].Flags & LineFlags::SubStart) | (source[i].Flags & LineFlags::Label) || ((source[i].Flags & LineFlags::Comment) && source[i].CommentLine >= 0)) { + for (size_t i = 1; i < source.size(); i++) + { + if (source[i].CpuAddress < 0 || (source[i].Flags & LineFlags::SubStart) | (source[i].Flags & LineFlags::Label) || + ((source[i].Flags & LineFlags::Comment) && source[i].CommentLine >= 0)) + { continue; } - if(cpuAddress == (uint32_t)source[i].CpuAddress) { + if (cpuAddress == (uint32_t)source[i].CpuAddress) + { return (uint32_t)i; - } else if(cpuAddress >= lastAddress && cpuAddress < (uint32_t)source[i].CpuAddress) { + } + else if (cpuAddress >= lastAddress && cpuAddress < (uint32_t)source[i].CpuAddress) + { return (uint32_t)i - 1; } @@ -416,53 +506,68 @@ uint32_t Disassembler::GetLineIndex(CpuType type, uint32_t cpuAddress) return 0; } -bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &data) +bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& data) { - auto lock =_disassemblyLock.AcquireSafe(); + auto lock = _disassemblyLock.AcquireSafe(); vector& source = _disassemblyResult[(int)type]; SnesMemoryType memType = DebugUtilities::GetCpuMemoryType(type); int32_t maxAddr = type == CpuType::Spc ? 0xFFFF : 0xFFFFFF; - if(lineIndex < source.size()) { + if (lineIndex < source.size()) + { DisassemblyResult result = source[lineIndex]; data.Address = -1; data.AbsoluteAddress = -1; data.EffectiveAddress = -1; data.Flags = result.Flags; - switch(result.Address.Type) { - default: break; - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; break; + switch (result.Address.Type) + { + default: break; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; + break; - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; break; - - case SnesMemoryType::GbCartRam: - case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break; + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; + break; + + case SnesMemoryType::GbCartRam: + case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; + break; } bool isBlockStartEnd = (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) != 0; - if(!isBlockStartEnd && result.Address.Address >= 0) { - if((data.Flags & LineFlags::ShowAsData)) { + if (!isBlockStartEnd && result.Address.Address >= 0) + { + if ((data.Flags & LineFlags::ShowAsData)) + { FastString str(".db", 3); - int nextAddr = lineIndex < source.size() - 2 ? (source[lineIndex+1].CpuAddress + 1) : (maxAddr + 1); - for(int i = 0; i < 8 && result.CpuAddress+i < nextAddr; i++) { + int nextAddr = lineIndex < source.size() - 2 ? (source[lineIndex + 1].CpuAddress + 1) : (maxAddr + 1); + for (int i = 0; i < 8 && result.CpuAddress + i < nextAddr; i++) + { str.Write(" $", 2); str.Write(HexUtilities::ToHexChar(_memoryDumper->GetMemoryValue(memType, result.CpuAddress + i)), 2); } data.Address = result.CpuAddress; data.AbsoluteAddress = result.Address.Address; memcpy(data.Text, str.ToString(), str.GetSize()); - } else if((data.Flags & LineFlags::Comment) && result.CommentLine >= 0) { - string comment = ";" + StringUtilities::Split(_labelManager->GetComment(result.Address), '\n')[result.CommentLine]; + } + else if ((data.Flags & LineFlags::Comment) && result.CommentLine >= 0) + { + string comment = ";" + StringUtilities::Split(_labelManager->GetComment(result.Address), '\n')[result. + CommentLine]; data.Flags |= LineFlags::VerifiedCode; memcpy(data.Comment, comment.c_str(), std::min((int)comment.size(), 1000)); - } else if(data.Flags & LineFlags::Label) { + } + else if (data.Flags & LineFlags::Label) + { string label = _labelManager->GetLabel(result.Address) + ":"; data.Flags |= LineFlags::VerifiedCode; memcpy(data.Text, label.c_str(), std::min((int)label.size(), 1000)); - } else { + } + else + { DisassemblerSource src = GetSource(result.Address.Type); DisassemblyInfo disInfo = (*src.Cache)[result.Address.Address]; CpuType lineCpuType = disInfo.IsInitialized() ? disInfo.GetCpuType() : type; @@ -470,88 +575,119 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d data.Address = result.CpuAddress; data.AbsoluteAddress = result.Address.Address; - switch(lineCpuType) { - case CpuType::Cpu: - case CpuType::Sa1: { + switch (lineCpuType) + { + case CpuType::Cpu: + case CpuType::Sa1: + { CpuState state = type == CpuType::Sa1 ? _sa1->GetCpuState() : _cpu->GetState(); state.PC = (uint16_t)result.CpuAddress; state.K = (result.CpuAddress >> 16); - if(!disInfo.IsInitialized()) { + if (!disInfo.IsInitialized()) + { disInfo = DisassemblyInfo(src.Data + result.Address.Address, state.PS, lineCpuType); - } else { - data.Flags |= (result.Address.Type != SnesMemoryType::PrgRom || _cdl->IsCode(data.AbsoluteAddress)) ? LineFlags::VerifiedCode : LineFlags::UnexecutedCode; + } + else + { + data.Flags |= (result.Address.Type != SnesMemoryType::PrgRom || _cdl->IsCode(data.AbsoluteAddress)) + ? LineFlags::VerifiedCode + : LineFlags::UnexecutedCode; } data.OpSize = disInfo.GetOpSize(); data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state, lineCpuType); - if(data.EffectiveAddress >= 0) { + if (data.EffectiveAddress >= 0) + { data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _memoryDumper, memType, data.ValueSize); - } else { + } + else + { data.ValueSize = 0; } break; } - - case CpuType::Spc: { + + case CpuType::Spc: + { SpcState state = _spc->GetState(); state.PC = (uint16_t)result.CpuAddress; - if(!disInfo.IsInitialized()) { + if (!disInfo.IsInitialized()) + { disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, CpuType::Spc); - } else { + } + else + { data.Flags |= LineFlags::VerifiedCode; } data.OpSize = disInfo.GetOpSize(); data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state, lineCpuType); - if(data.EffectiveAddress >= 0) { + if (data.EffectiveAddress >= 0) + { data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _memoryDumper, memType, data.ValueSize); data.ValueSize = 1; - } else { + } + else + { data.ValueSize = 0; } break; } - case CpuType::Gsu: { + case CpuType::Gsu: + { GsuState state = _gsu->GetState(); - if(!disInfo.IsInitialized()) { + if (!disInfo.IsInitialized()) + { disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, CpuType::Gsu); - } else { + } + else + { data.Flags |= LineFlags::VerifiedCode; } data.OpSize = disInfo.GetOpSize(); data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state, lineCpuType); - if(data.EffectiveAddress >= 0) { + if (data.EffectiveAddress >= 0) + { data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _memoryDumper, memType, data.ValueSize); data.ValueSize = 2; - } else { + } + else + { data.ValueSize = 0; } break; } - - case CpuType::NecDsp: - case CpuType::Cx4: - if(!disInfo.IsInitialized()) { - disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, type); - } else { - data.Flags |= LineFlags::VerifiedCode; - } - data.OpSize = disInfo.GetOpSize(); - data.EffectiveAddress = -1; - data.ValueSize = 0; - break; + case CpuType::NecDsp: + case CpuType::Cx4: + if (!disInfo.IsInitialized()) + { + disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, type); + } + else + { + data.Flags |= LineFlags::VerifiedCode; + } - case CpuType::Gameboy: { + data.OpSize = disInfo.GetOpSize(); + data.EffectiveAddress = -1; + data.ValueSize = 0; + break; + + case CpuType::Gameboy: + { GbCpuState state = _gameboy->GetCpu()->GetState(); - if(!disInfo.IsInitialized()) { + if (!disInfo.IsInitialized()) + { disInfo = DisassemblyInfo(src.Data + result.Address.Address, 0, CpuType::Gameboy); - } else { + } + else + { data.Flags |= LineFlags::VerifiedCode; } @@ -568,27 +704,38 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d disInfo.GetByteCode(data.ByteCode); - if(data.Flags & LineFlags::Comment) { + if (data.Flags & LineFlags::Comment) + { string comment = ";" + _labelManager->GetComment(result.Address); memcpy(data.Comment, comment.c_str(), std::min((int)comment.size(), 1000)); - } else { + } + else + { data.Comment[0] = 0; } } - } else { - if(data.Flags & LineFlags::SubStart) { + } + else + { + if (data.Flags & LineFlags::SubStart) + { string label = _labelManager->GetLabel(result.Address); - if(label.empty()) { + if (label.empty()) + { label = "sub start"; } memcpy(data.Text, label.c_str(), label.size() + 1); - } else if(data.Flags & LineFlags::BlockStart) { + } + else if (data.Flags & LineFlags::BlockStart) + { string label = (data.Flags & LineFlags::VerifiedData) ? "data" : "unidentified"; memcpy(data.Text, label.c_str(), label.size() + 1); } - if(data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) { - if(!(data.Flags & (LineFlags::ShowAsData | LineFlags::SubStart))) { + if (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) + { + if (!(data.Flags & (LineFlags::ShowAsData | LineFlags::SubStart))) + { //For hidden blocks, give the start/end lines an address data.Address = result.CpuAddress; data.AbsoluteAddress = result.Address.Address; @@ -600,25 +747,31 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d return false; } -int32_t Disassembler::SearchDisassembly(CpuType type, const char *searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards) +int32_t Disassembler::SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, + int32_t endPosition, bool searchBackwards) { auto lock = _disassemblyLock.AcquireSafe(); vector& source = _disassemblyResult[(int)type]; int step = searchBackwards ? -1 : 1; CodeLineData lineData = {}; - for(int i = startPosition; i != endPosition; i += step) { + for (int i = startPosition; i != endPosition; i += step) + { GetLineData(type, i, lineData); string line = lineData.Text; std::transform(line.begin(), line.end(), line.begin(), ::tolower); - if(line.find(searchString) != string::npos) { + if (line.find(searchString) != string::npos) + { return i; } //Continue search from start/end of document - if(!searchBackwards && i == (int)(source.size() - 1)) { + if (!searchBackwards && i == (int)(source.size() - 1)) + { i = 0; - } else if(searchBackwards && i == 0) { + } + else if (searchBackwards && i == 0) + { i = (int32_t)(source.size() - 1); } } diff --git a/Core/Disassembler.h b/Core/Disassembler.h index a84a092..799512b 100644 --- a/Core/Disassembler.h +++ b/Core/Disassembler.h @@ -24,16 +24,16 @@ enum class CpuType : uint8_t; struct DisassemblerSource { - uint8_t *Data; - vector *Cache; + uint8_t* Data; + vector* Cache; uint32_t Size; }; class Disassembler { private: - MemoryManager *_memoryManager; - Console *_console; + MemoryManager* _memoryManager; + Console* _console; Cpu* _cpu; Spc* _spc; Gsu* _gsu; @@ -42,17 +42,17 @@ private: NecDsp* _necDsp; Gameboy* _gameboy; EmuSettings* _settings; - Debugger *_debugger; + Debugger* _debugger; shared_ptr _cdl; shared_ptr _labelManager; - MemoryDumper *_memoryDumper; + MemoryDumper* _memoryDumper; DisassemblerSource _sources[(int)SnesMemoryType::Register] = {}; vector _disassemblyCache[(int)SnesMemoryType::Register]; SimpleLock _disassemblyLock; - vector _disassemblyResult[(int)DebugUtilities::GetLastCpuType()+1]; - bool _needDisassemble[(int)DebugUtilities::GetLastCpuType()+1]; + vector _disassemblyResult[(int)DebugUtilities::GetLastCpuType() + 1]; + bool _needDisassemble[(int)DebugUtilities::GetLastCpuType() + 1]; void InitSource(SnesMemoryType type); DisassemblerSource& GetSource(SnesMemoryType type); @@ -61,16 +61,17 @@ private: public: Disassembler(shared_ptr console, shared_ptr cdl, Debugger* debugger); - uint32_t BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuType type); + uint32_t BuildCache(AddressInfo& addrInfo, uint8_t cpuFlags, CpuType type); void ResetPrgCache(); void InvalidateCache(AddressInfo addrInfo, CpuType type); void Disassemble(CpuType cpuType); - DisassemblyInfo GetDisassemblyInfo(AddressInfo &info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type); + DisassemblyInfo GetDisassemblyInfo(AddressInfo& info, uint32_t cpuAddress, uint8_t cpuFlags, CpuType type); void RefreshDisassembly(CpuType type); uint32_t GetLineCount(CpuType type); uint32_t GetLineIndex(CpuType type, uint32_t cpuAddress); - bool GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &data); - int32_t SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards); -}; \ No newline at end of file + bool GetLineData(CpuType type, uint32_t lineIndex, CodeLineData& data); + int32_t SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition, + bool searchBackwards); +}; diff --git a/Core/DisassemblyInfo.cpp b/Core/DisassemblyInfo.cpp index 839f4f4..86fec52 100644 --- a/Core/DisassemblyInfo.cpp +++ b/Core/DisassemblyInfo.cpp @@ -18,12 +18,12 @@ DisassemblyInfo::DisassemblyInfo() { } -DisassemblyInfo::DisassemblyInfo(uint8_t *opPointer, uint8_t cpuFlags, CpuType type) +DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, uint8_t cpuFlags, CpuType type) { Initialize(opPointer, cpuFlags, type); } -void DisassemblyInfo::Initialize(uint8_t *opPointer, uint8_t cpuFlags, CpuType type) +void DisassemblyInfo::Initialize(uint8_t* opPointer, uint8_t cpuFlags, CpuType type) { _cpuType = type; _flags = cpuFlags; @@ -43,8 +43,9 @@ void DisassemblyInfo::Initialize(uint32_t cpuAddress, uint8_t cpuFlags, CpuType _opSize = GetOpSize(_byteCode[0], _flags, _cpuType); - for(int i = 1; i < _opSize; i++) { - _byteCode[i] = memoryDumper->GetMemoryValue(cpuMemType, cpuAddress+i); + for (int i = 1; i < _opSize; i++) + { + _byteCode[i] = memoryDumper->GetMemoryValue(cpuMemType, cpuAddress + i); } _initialized = true; @@ -65,37 +66,45 @@ void DisassemblyInfo::Reset() _initialized = false; } -void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings) +void DisassemblyInfo::GetDisassembly(string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { - switch(_cpuType) { - case CpuType::Sa1: - case CpuType::Cpu: - CpuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); - break; + switch (_cpuType) + { + case CpuType::Sa1: + case CpuType::Cpu: + CpuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); + break; - case CpuType::Spc: SpcDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break; - case CpuType::NecDsp: NecDspDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break; - case CpuType::Gsu: GsuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break; - case CpuType::Cx4: Cx4DisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break; - case CpuType::Gameboy: GameboyDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); break; + case CpuType::Spc: SpcDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); + break; + case CpuType::NecDsp: NecDspDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); + break; + case CpuType::Gsu: GsuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); + break; + case CpuType::Cx4: Cx4DisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); + break; + case CpuType::Gameboy: GameboyDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager, settings); + break; } } -int32_t DisassemblyInfo::GetEffectiveAddress(Console *console, void *cpuState, CpuType cpuType) +int32_t DisassemblyInfo::GetEffectiveAddress(Console* console, void* cpuState, CpuType cpuType) { - switch(_cpuType) { - case CpuType::Sa1: - case CpuType::Cpu: - return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState, cpuType); + switch (_cpuType) + { + case CpuType::Sa1: + case CpuType::Cpu: + return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState, cpuType); - case CpuType::Spc: return SpcDisUtils::GetEffectiveAddress(*this, console, *(SpcState*)cpuState); - case CpuType::Gsu: return GsuDisUtils::GetEffectiveAddress(*this, console, *(GsuState*)cpuState); + case CpuType::Spc: return SpcDisUtils::GetEffectiveAddress(*this, console, *(SpcState*)cpuState); + case CpuType::Gsu: return GsuDisUtils::GetEffectiveAddress(*this, console, *(GsuState*)cpuState); - case CpuType::Cx4: - case CpuType::NecDsp: - return -1; + case CpuType::Cx4: + case CpuType::NecDsp: + return -1; - case CpuType::Gameboy: return GameboyDisUtils::GetEffectiveAddress(*this, console, *(GbCpuState*)cpuState); + case CpuType::Gameboy: return GameboyDisUtils::GetEffectiveAddress(*this, console, *(GbCpuState*)cpuState); } return -1; } @@ -130,12 +139,14 @@ void DisassemblyInfo::GetByteCode(uint8_t copyBuffer[4]) memcpy(copyBuffer, _byteCode, _opSize); } -void DisassemblyInfo::GetByteCode(string &out) +void DisassemblyInfo::GetByteCode(string& out) { FastString str; - for(int i = 0; i < _opSize; i++) { + for (int i = 0; i < _opSize; i++) + { str.WriteAll('$', HexUtilities::ToHex(_byteCode[i])); - if(i < _opSize - 1) { + if (i < _opSize - 1) + { str.Write(' '); } } @@ -144,27 +155,33 @@ void DisassemblyInfo::GetByteCode(string &out) uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type) { - switch(type) { - case CpuType::Sa1: - case CpuType::Cpu: - return CpuDisUtils::GetOpSize(opCode, flags); + switch (type) + { + case CpuType::Sa1: + case CpuType::Cpu: + return CpuDisUtils::GetOpSize(opCode, flags); - case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode); - - case CpuType::Gsu: - if(opCode >= 0x05 && opCode <= 0x0F) { - return 2; - } else if(opCode >= 0xA0 && opCode <= 0xAF) { - return 2; - } else if(opCode >= 0xF0 && opCode <= 0xFF) { - return 3; - } - return 1; + case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode); - case CpuType::NecDsp: return 3; - case CpuType::Cx4: return 2; - - case CpuType::Gameboy: return GameboyDisUtils::GetOpSize(opCode); + case CpuType::Gsu: + if (opCode >= 0x05 && opCode <= 0x0F) + { + return 2; + } + else if (opCode >= 0xA0 && opCode <= 0xAF) + { + return 2; + } + else if (opCode >= 0xF0 && opCode <= 0xFF) + { + return 3; + } + return 1; + + case CpuType::NecDsp: return 3; + case CpuType::Cx4: return 2; + + case CpuType::Gameboy: return GameboyDisUtils::GetOpSize(opCode); } return 0; } @@ -172,19 +189,20 @@ uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type) //TODO: This is never called, removed? bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type) { - switch(type) { - case CpuType::Sa1: - case CpuType::Cpu: - return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL + switch (type) + { + case CpuType::Sa1: + case CpuType::Cpu: + return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL - case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK - - case CpuType::Gameboy: return GameboyDisUtils::IsJumpToSub(opCode); - - case CpuType::Gsu: - case CpuType::NecDsp: - case CpuType::Cx4: - return false; + case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK + + case CpuType::Gameboy: return GameboyDisUtils::IsJumpToSub(opCode); + + case CpuType::Gsu: + case CpuType::NecDsp: + case CpuType::Cx4: + return false; } return false; } @@ -192,52 +210,62 @@ bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type) bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type) { //RTS/RTI - switch(type) { - case CpuType::Sa1: - case CpuType::Cpu: - return opCode == 0x60 || opCode == 0x6B || opCode == 0x40; + switch (type) + { + case CpuType::Sa1: + case CpuType::Cpu: + return opCode == 0x60 || opCode == 0x6B || opCode == 0x40; - case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F; + case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F; - case CpuType::Gameboy: return GameboyDisUtils::IsReturnInstruction(opCode); + case CpuType::Gameboy: return GameboyDisUtils::IsReturnInstruction(opCode); - case CpuType::Gsu: - case CpuType::NecDsp: - case CpuType::Cx4: - return false; + case CpuType::Gsu: + case CpuType::NecDsp: + case CpuType::Cx4: + return false; } - + return false; } bool DisassemblyInfo::IsUnconditionalJump() { uint8_t opCode = GetOpCode(); - switch(_cpuType) { - case CpuType::Sa1: - case CpuType::Cpu: - if(opCode == 0x00 || opCode == 0x20 || opCode == 0x40 || opCode == 0x60 || opCode == 0x80 || opCode == 0x22 || opCode == 0xFC || opCode == 0x6B || opCode == 0x4C || opCode == 0x5C || opCode == 0x6C || opCode == 0x7C || opCode == 0x02) { - //Jumps, RTI, RTS, BRK, COP, etc., stop disassembling - return true; - } else if(opCode == 0x28) { - //PLP, stop disassembling because the 8-bit/16-bit flags could change - return true; - } - return false; - - case CpuType::Gameboy: - if(opCode == 0x18 || opCode == 0xC3 || opCode == 0xEA || opCode == 0xCD || opCode == 0xC9 || opCode == 0xD9 || opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || opCode == 0xF7 || opCode == 0xFF) { - return true; - } - return false; - - case CpuType::Gsu: - case CpuType::Spc: - case CpuType::Cx4: + switch (_cpuType) + { + case CpuType::Sa1: + case CpuType::Cpu: + if (opCode == 0x00 || opCode == 0x20 || opCode == 0x40 || opCode == 0x60 || opCode == 0x80 || opCode == 0x22 || + opCode == 0xFC || opCode == 0x6B || opCode == 0x4C || opCode == 0x5C || opCode == 0x6C || opCode == 0x7C || + opCode == 0x02) + { + //Jumps, RTI, RTS, BRK, COP, etc., stop disassembling return true; + } + else if (opCode == 0x28) + { + //PLP, stop disassembling because the 8-bit/16-bit flags could change + return true; + } + return false; - case CpuType::NecDsp: - return false; + case CpuType::Gameboy: + if (opCode == 0x18 || opCode == 0xC3 || opCode == 0xEA || opCode == 0xCD || opCode == 0xC9 || opCode == 0xD9 || + opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || + opCode == 0xF7 || opCode == 0xFF) + { + return true; + } + return false; + + case CpuType::Gsu: + case CpuType::Spc: + case CpuType::Cx4: + return true; + + case CpuType::NecDsp: + return false; } return false; @@ -245,13 +273,17 @@ bool DisassemblyInfo::IsUnconditionalJump() void DisassemblyInfo::UpdateCpuFlags(uint8_t& cpuFlags) { - if(_cpuType == CpuType::Cpu || _cpuType == CpuType::Sa1) { + if (_cpuType == CpuType::Cpu || _cpuType == CpuType::Sa1) + { uint8_t opCode = GetOpCode(); - if(opCode == 0xC2) { + if (opCode == 0xC2) + { //REP, update the flags and keep disassembling uint8_t flags = GetByteCode()[1]; cpuFlags &= ~flags; - } else if(opCode == 0xE2) { + } + else if (opCode == 0xE2) + { //SEP, update the flags and keep disassembling uint8_t flags = GetByteCode()[1]; cpuFlags |= flags; @@ -259,12 +291,16 @@ void DisassemblyInfo::UpdateCpuFlags(uint8_t& cpuFlags) } } -uint16_t DisassemblyInfo::GetMemoryValue(uint32_t effectiveAddress, MemoryDumper *memoryDumper, SnesMemoryType memType, uint8_t &valueSize) +uint16_t DisassemblyInfo::GetMemoryValue(uint32_t effectiveAddress, MemoryDumper* memoryDumper, SnesMemoryType memType, + uint8_t& valueSize) { - if((_cpuType == CpuType::Spc || _cpuType == CpuType::Gameboy) || (_flags & ProcFlags::MemoryMode8)) { + if ((_cpuType == CpuType::Spc || _cpuType == CpuType::Gameboy) || (_flags & ProcFlags::MemoryMode8)) + { valueSize = 1; return memoryDumper->GetMemoryValue(memType, effectiveAddress); - } else { + } + else + { valueSize = 2; return memoryDumper->GetMemoryValueWord(memType, effectiveAddress); } diff --git a/Core/DisassemblyInfo.h b/Core/DisassemblyInfo.h index 2ee0cc9..ed5a281 100644 --- a/Core/DisassemblyInfo.h +++ b/Core/DisassemblyInfo.h @@ -20,16 +20,16 @@ private: public: DisassemblyInfo(); - DisassemblyInfo(uint8_t *opPointer, uint8_t cpuFlags, CpuType type); + DisassemblyInfo(uint8_t* opPointer, uint8_t cpuFlags, CpuType type); - void Initialize(uint8_t *opPointer, uint8_t cpuFlags, CpuType type); + void Initialize(uint8_t* opPointer, uint8_t cpuFlags, CpuType type); void Initialize(uint32_t cpuAddress, uint8_t cpuFlags, CpuType type, MemoryDumper* memoryDumper); bool IsInitialized(); bool IsValid(uint8_t cpuFlags); void Reset(); - void GetDisassembly(string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings* settings); - + void GetDisassembly(string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); + CpuType GetCpuType(); uint8_t GetOpCode(); uint8_t GetOpSize(); @@ -37,7 +37,7 @@ public: uint8_t* GetByteCode(); void GetByteCode(uint8_t copyBuffer[4]); - void GetByteCode(string &out); + void GetByteCode(string& out); static uint8_t GetOpSize(uint8_t opCode, uint8_t flags, CpuType type); static bool IsJumpToSub(uint8_t opCode, CpuType type); @@ -46,7 +46,7 @@ public: bool IsUnconditionalJump(); void UpdateCpuFlags(uint8_t& cpuFlags); - int32_t GetEffectiveAddress(Console *console, void *cpuState, CpuType type); - uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryDumper *memoryDumper, SnesMemoryType memType, uint8_t &valueSize); + int32_t GetEffectiveAddress(Console* console, void* cpuState, CpuType type); + uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryDumper* memoryDumper, SnesMemoryType memType, + uint8_t& valueSize); }; - diff --git a/Core/DmaController.cpp b/Core/DmaController.cpp index 3fa9217..0d6104b 100644 --- a/Core/DmaController.cpp +++ b/Core/DmaController.cpp @@ -5,19 +5,21 @@ #include "MessageManager.h" #include "../Utilities/Serializer.h" -static constexpr uint8_t _transferByteCount[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; +static constexpr uint8_t _transferByteCount[8] = {1, 2, 2, 4, 4, 4, 2, 4}; static constexpr uint8_t _transferOffset[8][4] = { - { 0, 0, 0, 0 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 }, - { 0, 1, 2, 3 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 } + {0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0}, {0, 0, 1, 1}, + {0, 1, 2, 3}, {0, 1, 0, 1}, {0, 0, 0, 0}, {0, 0, 1, 1} }; -DmaController::DmaController(MemoryManager *memoryManager) +DmaController::DmaController(MemoryManager* memoryManager) { _memoryManager = memoryManager; Reset(); - for(int j = 0; j < 8; j++) { - for(int i = 0; i <= 0x0A; i++) { + for (int j = 0; j < 8; j++) + { + for (int i = 0; i <= 0x0A; i++) + { Write(0x4300 | i | (j << 4), 0xFF); } } @@ -33,36 +35,47 @@ void DmaController::Reset() _dmaPending = false; _needToProcess = false; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { _channel[i].DmaActive = false; } } void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA) { - if(fromBtoA) { - if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) { + if (fromBtoA) + { + if (addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) + { uint8_t valToWrite = _memoryManager->ReadDma(addressBusB, false); _memoryManager->WriteDma(addressBusA, valToWrite, true); - } else { + } + else + { //$2180->WRAM do cause a write to occur (but no read), but the value written is invalid _memoryManager->IncMasterClock4(); _memoryManager->WriteDma(addressBusA, 0xFF, true); } - } else { - if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) { + } + else + { + if (addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) + { uint8_t valToWrite = _memoryManager->ReadDma(addressBusA, true); _memoryManager->WriteDma(addressBusB, valToWrite, false); - } else { + } + else + { //WRAM->$2180 does not cause a write to occur _memoryManager->IncMasterClock8(); } } } -void DmaController::RunDma(DmaChannelConfig &channel) +void DmaController::RunDma(DmaChannelConfig& channel) { - if(!channel.DmaActive) { + if (!channel.DmaActive) + { return; } @@ -70,10 +83,11 @@ void DmaController::RunDma(DmaChannelConfig &channel) _memoryManager->IncMasterClock8(); ProcessPendingTransfers(); - const uint8_t *transferOffsets = _transferOffset[channel.TransferMode]; + const uint8_t* transferOffsets = _transferOffset[channel.TransferMode]; uint8_t i = 0; - do { + do + { //Manual DMA transfers run to the end of the transfer when started CopyDmaByte( (channel.SrcBank << 16) | channel.SrcAddress, @@ -81,14 +95,16 @@ void DmaController::RunDma(DmaChannelConfig &channel) channel.InvertDirection ); - if(!channel.FixedTransfer) { + if (!channel.FixedTransfer) + { channel.SrcAddress += channel.Decrement ? -1 : 1; } channel.TransferSize--; i++; ProcessPendingTransfers(); - } while(channel.TransferSize > 0 && channel.DmaActive); + } + while (channel.TransferSize > 0 && channel.DmaActive); channel.DmaActive = false; } @@ -97,31 +113,37 @@ bool DmaController::InitHdmaChannels() { _hdmaInitPending = false; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { //Reset internal flags on every frame, whether or not the channels are enabled _channel[i].HdmaFinished = false; - _channel[i].DoTransfer = false; //not resetting this causes graphical glitches in some games (Aladdin, Super Ghouls and Ghosts) + _channel[i].DoTransfer = false; + //not resetting this causes graphical glitches in some games (Aladdin, Super Ghouls and Ghosts) } - if(!_hdmaChannels) { + if (!_hdmaChannels) + { //No channels are enabled, no more processing needs to be done UpdateNeedToProcessFlag(); return false; } bool needSync = !HasActiveDmaChannel(); - if(needSync) { + if (needSync) + { SyncStartDma(); } _memoryManager->IncMasterClock8(); - for(int i = 0; i < 8; i++) { - DmaChannelConfig &ch = _channel[i]; - + for (int i = 0; i < 8; i++) + { + DmaChannelConfig& ch = _channel[i]; + //Set DoTransfer to true for all channels if any HDMA channel is enabled ch.DoTransfer = true; - if(_hdmaChannels & (1 << i)) { + if (_hdmaChannels & (1 << i)) + { //"1. Copy AAddress into Address." ch.HdmaTableAddress = ch.SrcAddress; ch.DmaActive = false; @@ -131,12 +153,14 @@ bool DmaController::InitHdmaChannels() _memoryManager->IncMasterClock4(); ch.HdmaTableAddress++; - if(ch.HdmaLineCounterAndRepeat == 0) { + if (ch.HdmaLineCounterAndRepeat == 0) + { ch.HdmaFinished = true; } //3. Load Indirect Address, if necessary. - if(ch.HdmaIndirectAddressing) { + if (ch.HdmaIndirectAddressing) + { uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); _memoryManager->IncMasterClock4(); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); @@ -146,7 +170,8 @@ bool DmaController::InitHdmaChannels() } } - if(needSync) { + if (needSync) + { SyncEndDma(); } @@ -154,15 +179,17 @@ bool DmaController::InitHdmaChannels() return true; } -void DmaController::RunHdmaTransfer(DmaChannelConfig &channel) +void DmaController::RunHdmaTransfer(DmaChannelConfig& channel) { - const uint8_t *transferOffsets = _transferOffset[channel.TransferMode]; + const uint8_t* transferOffsets = _transferOffset[channel.TransferMode]; uint8_t transferByteCount = _transferByteCount[channel.TransferMode]; channel.DmaActive = false; uint8_t i = 0; - if(channel.HdmaIndirectAddressing) { - do { + if (channel.HdmaIndirectAddressing) + { + do + { CopyDmaByte( (channel.HdmaBank << 16) | channel.TransferSize, 0x2100 | (channel.DestAddress + transferOffsets[i]), @@ -170,9 +197,13 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel) ); channel.TransferSize++; i++; - } while(i < transferByteCount); - } else { - do { + } + while (i < transferByteCount); + } + else + { + do + { CopyDmaByte( (channel.SrcBank << 16) | channel.HdmaTableAddress, 0x2100 | (channel.DestAddress + transferOffsets[i]), @@ -180,7 +211,8 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel) ); channel.HdmaTableAddress++; i++; - } while(i < transferByteCount); + } + while (i < transferByteCount); } } @@ -195,13 +227,16 @@ void DmaController::SyncEndDma() { //"Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause" uint8_t cpuSpeed = _memoryManager->GetCpuSpeed(); - _memoryManager->IncrementMasterClockValue(cpuSpeed - ((_memoryManager->GetMasterClock() - _dmaStartClock) % cpuSpeed)); + _memoryManager->IncrementMasterClockValue( + cpuSpeed - ((_memoryManager->GetMasterClock() - _dmaStartClock) % cpuSpeed)); } bool DmaController::HasActiveDmaChannel() { - for(int i = 0; i < 8; i++) { - if(_channel[i].DmaActive) { + for (int i = 0; i < 8; i++) + { + if (_channel[i].DmaActive) + { return true; } } @@ -212,13 +247,15 @@ bool DmaController::ProcessHdmaChannels() { _hdmaPending = false; - if(!_hdmaChannels) { + if (!_hdmaChannels) + { UpdateNeedToProcessFlag(); return false; } bool needSync = !HasActiveDmaChannel(); - if(needSync) { + if (needSync) + { SyncStartDma(); } _memoryManager->IncMasterClock8(); @@ -226,20 +263,24 @@ bool DmaController::ProcessHdmaChannels() uint8_t originalActiveChannel = _activeChannel; //Run all the DMA transfers for each channel first, before fetching data for the next scanline - for(int i = 0; i < 8; i++) { - DmaChannelConfig &ch = _channel[i]; - if((_hdmaChannels & (1 << i)) == 0) { + for (int i = 0; i < 8; i++) + { + DmaChannelConfig& ch = _channel[i]; + if ((_hdmaChannels & (1 << i)) == 0) + { continue; } ch.DmaActive = false; - if(ch.HdmaFinished) { + if (ch.HdmaFinished) + { continue; } - + //1. If DoTransfer is false, skip to step 3. - if(ch.DoTransfer) { + if (ch.DoTransfer) + { //2. For the number of bytes (1, 2, or 4) required for this Transfer Mode... _activeChannel = DmaController::HdmaChannelFlag | i; RunHdmaTransfer(ch); @@ -247,9 +288,11 @@ bool DmaController::ProcessHdmaChannels() } //Update the channel's state & fetch data for the next scanline - for(int i = 0; i < 8; i++) { - DmaChannelConfig &ch = _channel[i]; - if((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished) { + for (int i = 0; i < 8; i++) + { + DmaChannelConfig& ch = _channel[i]; + if ((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished) + { continue; } @@ -265,32 +308,38 @@ bool DmaController::ProcessHdmaChannels() _memoryManager->IncMasterClock4(); //5. If Line Counter is zero... - if((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) { + if ((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) + { ch.HdmaLineCounterAndRepeat = newCounter; ch.HdmaTableAddress++; //"b. If Addressing Mode is Indirect, read two bytes from Address into Indirect Address(and increment Address by two bytes)." - if(ch.HdmaIndirectAddressing) { - if(ch.HdmaLineCounterAndRepeat == 0 && IsLastActiveHdmaChannel(i)) { + if (ch.HdmaIndirectAddressing) + { + if (ch.HdmaLineCounterAndRepeat == 0 && IsLastActiveHdmaChannel(i)) + { //"One oddity: if $43xA is 0 and this is the last active HDMA channel for this scanline, only load one byte for Address, //and use the $00 for the low byte.So Address ends up incremented one less than otherwise expected, and one less CPU Cycle is used." uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); _memoryManager->IncMasterClock4(); ch.TransferSize = (msb << 8); - } else { + } + else + { //"If a new indirect address is required, 16 master cycles are taken to load it." uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); _memoryManager->IncMasterClock4(); - + uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true); _memoryManager->IncMasterClock4(); ch.TransferSize = (msb << 8) | lsb; - } + } } //"c. If $43xA is zero, terminate this HDMA channel for this frame. The bit in $420c is not cleared, though, so it may be automatically restarted next frame." - if(ch.HdmaLineCounterAndRepeat == 0) { + if (ch.HdmaLineCounterAndRepeat == 0) + { ch.HdmaFinished = true; } @@ -299,7 +348,8 @@ bool DmaController::ProcessHdmaChannels() } } - if(needSync) { + if (needSync) + { //If we ran a HDMA transfer, sync SyncEndDma(); } @@ -312,8 +362,10 @@ bool DmaController::ProcessHdmaChannels() bool DmaController::IsLastActiveHdmaChannel(uint8_t channel) { - for(int i = channel + 1; i < 8; i++) { - if((_hdmaChannels & (1 << i)) && !_channel[i].HdmaFinished) { + for (int i = channel + 1; i < 8; i++) + { + if ((_hdmaChannels & (1 << i)) && !_channel[i].HdmaFinished) + { return false; } } @@ -328,7 +380,8 @@ void DmaController::UpdateNeedToProcessFlag() void DmaController::BeginHdmaTransfer() { - if(_hdmaChannels) { + if (_hdmaChannels) + { _hdmaPending = true; UpdateNeedToProcessFlag(); } @@ -342,33 +395,42 @@ void DmaController::BeginHdmaInit() bool DmaController::ProcessPendingTransfers() { - if(!_needToProcess) { + if (!_needToProcess) + { return false; } - if(_dmaStartDelay) { + if (_dmaStartDelay) + { _dmaStartDelay = false; return false; } - if(_hdmaPending) { + if (_hdmaPending) + { return ProcessHdmaChannels(); - } else if(_hdmaInitPending) { + } + else if (_hdmaInitPending) + { return InitHdmaChannels(); - } else if(_dmaPending) { + } + else if (_dmaPending) + { _dmaPending = false; SyncStartDma(); _memoryManager->IncMasterClock8(); ProcessPendingTransfers(); - - for(int i = 0; i < 8; i++) { - if(_channel[i].DmaActive) { + + for (int i = 0; i < 8; i++) + { + if (_channel[i].DmaActive) + { _activeChannel = i; - RunDma(_channel[i]); + RunDma(_channel[i]); } } - + SyncEndDma(); UpdateNeedToProcessFlag(); @@ -380,16 +442,21 @@ bool DmaController::ProcessPendingTransfers() void DmaController::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x420B: { + switch (addr) + { + case 0x420B: + { //MDMAEN - DMA Enable - for(int i = 0; i < 8; i++) { - if(value & (1 << i)) { + for (int i = 0; i < 8; i++) + { + if (value & (1 << i)) + { _channel[i].DmaActive = true; } } - if(value) { + if (value) + { _dmaPending = true; _dmaStartDelay = true; UpdateNeedToProcessFlag(); @@ -397,15 +464,22 @@ void DmaController::Write(uint16_t addr, uint8_t value) break; } - case 0x420C: - //HDMAEN - HDMA Enable - _hdmaChannels = value; - break; + case 0x420C: + //HDMAEN - HDMA Enable + _hdmaChannels = value; + break; - case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370: + case 0x4300: + case 0x4310: + case 0x4320: + case 0x4330: + case 0x4340: + case 0x4350: + case 0x4360: + case 0x4370: { //DMAPx - DMA Control for Channel x - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.InvertDirection = (value & 0x80) != 0; channel.HdmaIndirectAddressing = (value & 0x40) != 0; channel.UnusedFlag = (value & 0x20) != 0; @@ -415,101 +489,192 @@ void DmaController::Write(uint16_t addr, uint8_t value) break; } - case 0x4301: case 0x4311: case 0x4321: case 0x4331: case 0x4341: case 0x4351: case 0x4361: case 0x4371: + case 0x4301: + case 0x4311: + case 0x4321: + case 0x4331: + case 0x4341: + case 0x4351: + case 0x4361: + case 0x4371: { //BBADx - DMA Destination Register for Channel x - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.DestAddress = value; break; } - case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372: + case 0x4302: + case 0x4312: + case 0x4322: + case 0x4332: + case 0x4342: + case 0x4352: + case 0x4362: + case 0x4372: { - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.SrcAddress = (channel.SrcAddress & 0xFF00) | value; break; } - case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373: + case 0x4303: + case 0x4313: + case 0x4323: + case 0x4333: + case 0x4343: + case 0x4353: + case 0x4363: + case 0x4373: { - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.SrcAddress = (channel.SrcAddress & 0xFF) | (value << 8); break; } - case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374: + case 0x4304: + case 0x4314: + case 0x4324: + case 0x4334: + case 0x4344: + case 0x4354: + case 0x4364: + case 0x4374: { - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.SrcBank = value; break; } - case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375: + case 0x4305: + case 0x4315: + case 0x4325: + case 0x4335: + case 0x4345: + case 0x4355: + case 0x4365: + case 0x4375: { //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.TransferSize = (channel.TransferSize & 0xFF00) | value; break; } - case 0x4306: case 0x4316: case 0x4326: case 0x4336: case 0x4346: case 0x4356: case 0x4366: case 0x4376: + case 0x4306: + case 0x4316: + case 0x4326: + case 0x4336: + case 0x4346: + case 0x4356: + case 0x4366: + case 0x4376: { //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.TransferSize = (channel.TransferSize & 0xFF) | (value << 8); break; } - case 0x4307: case 0x4317: case 0x4327: case 0x4337: case 0x4347: case 0x4357: case 0x4367: case 0x4377: + case 0x4307: + case 0x4317: + case 0x4327: + case 0x4337: + case 0x4347: + case 0x4357: + case 0x4367: + case 0x4377: { //DASBx - HDMA Indirect Address bank byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.HdmaBank = value; break; } - case 0x4308: case 0x4318: case 0x4328: case 0x4338: case 0x4348: case 0x4358: case 0x4368: case 0x4378: + case 0x4308: + case 0x4318: + case 0x4328: + case 0x4338: + case 0x4348: + case 0x4358: + case 0x4368: + case 0x4378: { //A2AxL - HDMA Table Address low byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.HdmaTableAddress = (channel.HdmaTableAddress & 0xFF00) | value; break; } - case 0x4309: case 0x4319: case 0x4329: case 0x4339: case 0x4349: case 0x4359: case 0x4369: case 0x4379: + case 0x4309: + case 0x4319: + case 0x4329: + case 0x4339: + case 0x4349: + case 0x4359: + case 0x4369: + case 0x4379: { //A2AxH - HDMA Table Address high byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.HdmaTableAddress = (value << 8) | (channel.HdmaTableAddress & 0xFF); break; } - case 0x430A: case 0x431A: case 0x432A: case 0x433A: case 0x434A: case 0x435A: case 0x436A: case 0x437A: + case 0x430A: + case 0x431A: + case 0x432A: + case 0x433A: + case 0x434A: + case 0x435A: + case 0x436A: + case 0x437A: { //DASBx - HDMA Indirect Address bank byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.HdmaLineCounterAndRepeat = value; break; } - case 0x430B: case 0x431B: case 0x432B: case 0x433B: case 0x434B: case 0x435B: case 0x436B: case 0x437B: - case 0x430F: case 0x431F: case 0x432F: case 0x433F: case 0x434F: case 0x435F: case 0x436F: case 0x437F: + case 0x430B: + case 0x431B: + case 0x432B: + case 0x433B: + case 0x434B: + case 0x435B: + case 0x436B: + case 0x437B: + case 0x430F: + case 0x431F: + case 0x432F: + case 0x433F: + case 0x434F: + case 0x435F: + case 0x436F: + case 0x437F: { //UNUSEDx - HDMA Indirect Address bank byte (x=0-7) DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; channel.UnusedByte = value; } - } } uint8_t DmaController::Read(uint16_t addr) { - switch(addr) { - case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370: + switch (addr) + { + case 0x4300: + case 0x4310: + case 0x4320: + case 0x4330: + case 0x4340: + case 0x4350: + case 0x4360: + case 0x4370: { //DMAPx - DMA Control for Channel x - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return ( (channel.InvertDirection ? 0x80 : 0) | (channel.HdmaIndirectAddressing ? 0x40 : 0) | @@ -520,81 +685,164 @@ uint8_t DmaController::Read(uint16_t addr) ); } - case 0x4301: case 0x4311: case 0x4321: case 0x4331: case 0x4341: case 0x4351: case 0x4361: case 0x4371: + case 0x4301: + case 0x4311: + case 0x4321: + case 0x4331: + case 0x4341: + case 0x4351: + case 0x4361: + case 0x4371: { //BBADx - DMA Destination Register for Channel x - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.DestAddress; } - case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372: + case 0x4302: + case 0x4312: + case 0x4322: + case 0x4332: + case 0x4342: + case 0x4352: + case 0x4362: + case 0x4372: { - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.SrcAddress & 0xFF; } - case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373: + case 0x4303: + case 0x4313: + case 0x4323: + case 0x4333: + case 0x4343: + case 0x4353: + case 0x4363: + case 0x4373: { - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return (channel.SrcAddress >> 8) & 0xFF; } - case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374: + case 0x4304: + case 0x4314: + case 0x4324: + case 0x4334: + case 0x4344: + case 0x4354: + case 0x4364: + case 0x4374: { - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.SrcBank; } - case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375: + case 0x4305: + case 0x4315: + case 0x4325: + case 0x4335: + case 0x4345: + case 0x4355: + case 0x4365: + case 0x4375: { //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.TransferSize & 0xFF; } - case 0x4306: case 0x4316: case 0x4326: case 0x4336: case 0x4346: case 0x4356: case 0x4366: case 0x4376: + case 0x4306: + case 0x4316: + case 0x4326: + case 0x4336: + case 0x4346: + case 0x4356: + case 0x4366: + case 0x4376: { //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return (channel.TransferSize >> 8) & 0xFF; } - case 0x4307: case 0x4317: case 0x4327: case 0x4337: case 0x4347: case 0x4357: case 0x4367: case 0x4377: + case 0x4307: + case 0x4317: + case 0x4327: + case 0x4337: + case 0x4347: + case 0x4357: + case 0x4367: + case 0x4377: { //DASBx - HDMA Indirect Address bank byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.HdmaBank; } - case 0x4308: case 0x4318: case 0x4328: case 0x4338: case 0x4348: case 0x4358: case 0x4368: case 0x4378: + case 0x4308: + case 0x4318: + case 0x4328: + case 0x4338: + case 0x4348: + case 0x4358: + case 0x4368: + case 0x4378: { //A2AxL - HDMA Table Address low byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.HdmaTableAddress & 0xFF; } - case 0x4309: case 0x4319: case 0x4329: case 0x4339: case 0x4349: case 0x4359: case 0x4369: case 0x4379: + case 0x4309: + case 0x4319: + case 0x4329: + case 0x4339: + case 0x4349: + case 0x4359: + case 0x4369: + case 0x4379: { //A2AxH - HDMA Table Address high byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return (channel.HdmaTableAddress >> 8) & 0xFF; } - case 0x430A: case 0x431A: case 0x432A: case 0x433A: case 0x434A: case 0x435A: case 0x436A: case 0x437A: + case 0x430A: + case 0x431A: + case 0x432A: + case 0x433A: + case 0x434A: + case 0x435A: + case 0x436A: + case 0x437A: { //DASBx - HDMA Indirect Address bank byte (x=0-7) - DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.HdmaLineCounterAndRepeat; } - case 0x430B: case 0x431B: case 0x432B: case 0x433B: case 0x434B: case 0x435B: case 0x436B: case 0x437B: - case 0x430F: case 0x431F: case 0x432F: case 0x433F: case 0x434F: case 0x435F: case 0x436F: case 0x437F: + case 0x430B: + case 0x431B: + case 0x432B: + case 0x433B: + case 0x434B: + case 0x435B: + case 0x436B: + case 0x437B: + case 0x430F: + case 0x431F: + case 0x432F: + case 0x433F: + case 0x434F: + case 0x435F: + case 0x436F: + case 0x437F: { //UNUSEDx - HDMA Indirect Address bank byte (x=0-7) DmaChannelConfig& channel = _channel[(addr & 0x70) >> 4]; return channel.UnusedByte; } - } return _memoryManager->GetOpenBus(); } @@ -609,10 +857,11 @@ DmaChannelConfig DmaController::GetChannelConfig(uint8_t channel) return _channel[channel]; } -void DmaController::Serialize(Serializer &s) +void DmaController::Serialize(Serializer& s) { s.Stream(_hdmaPending, _hdmaChannels, _dmaPending, _dmaStartClock, _hdmaInitPending, _dmaStartDelay, _needToProcess); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { s.Stream( _channel[i].Decrement, _channel[i].DestAddress, _channel[i].DoTransfer, _channel[i].FixedTransfer, _channel[i].HdmaBank, _channel[i].HdmaFinished, _channel[i].HdmaIndirectAddressing, diff --git a/Core/DmaController.h b/Core/DmaController.h index 89ee10a..28feae2 100644 --- a/Core/DmaController.h +++ b/Core/DmaController.h @@ -18,17 +18,17 @@ private: uint8_t _hdmaChannels = 0; bool _dmaPending = false; uint64_t _dmaStartClock = 0; - + uint8_t _activeChannel = 0; //Used by debugger's event viewer DmaChannelConfig _channel[8] = {}; - MemoryManager *_memoryManager; - + MemoryManager* _memoryManager; + void CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA); - void RunDma(DmaChannelConfig &channel); - - void RunHdmaTransfer(DmaChannelConfig &channel); + void RunDma(DmaChannelConfig& channel); + + void RunHdmaTransfer(DmaChannelConfig& channel); bool ProcessHdmaChannels(); bool IsLastActiveHdmaChannel(uint8_t channel); bool InitHdmaChannels(); @@ -40,7 +40,7 @@ private: bool HasActiveDmaChannel(); public: - DmaController(MemoryManager *memoryManager); + DmaController(MemoryManager* memoryManager); void Reset(); @@ -55,5 +55,5 @@ public: uint8_t GetActiveChannel(); DmaChannelConfig GetChannelConfig(uint8_t channel); - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/DmaControllerTypes.h b/Core/DmaControllerTypes.h index f673d82..c41648c 100644 --- a/Core/DmaControllerTypes.h +++ b/Core/DmaControllerTypes.h @@ -26,4 +26,4 @@ struct DmaChannelConfig bool UnusedFlag; uint8_t UnusedByte; // 43xB and 43xF -}; \ No newline at end of file +}; diff --git a/Core/DrawCommand.h b/Core/DrawCommand.h index ead95eb..4707672 100644 --- a/Core/DrawCommand.h +++ b/Core/DrawCommand.h @@ -18,34 +18,50 @@ protected: int _yScale; virtual void InternalDraw() = 0; + __forceinline void DrawPixel(uint32_t x, uint32_t y, int color) { - if(x < _overscan.Left || x >= (256 - _overscan.Right) || y < _overscan.Top || y >= (239 - _overscan.Bottom)) { + if (x < _overscan.Left || x >= (256 - _overscan.Right) || y < _overscan.Top || y >= (239 - _overscan.Bottom)) + { //Out of bounds, skip drawing return; } uint32_t alpha = (color & 0xFF000000); - if(alpha > 0) { - if(_yScale == 1) { - if(alpha != 0xFF000000) { - BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)], (uint8_t*)&color); - } else { - _argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)] = color; + if (alpha > 0) + { + if (_yScale == 1) + { + if (alpha != 0xFF000000) + { + BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top) * _lineWidth + (x - _overscan.Left)], + (uint8_t*)&color); } - } else { - int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1)*_xScale) - (int)(x*_xScale); + else + { + _argbBuffer[(y - _overscan.Top) * _lineWidth + (x - _overscan.Left)] = color; + } + } + else + { + int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1) * _xScale) - (int)(x * _xScale); x = (int)(x * (_useIntegerScaling ? _yScale : _xScale)); y = (int)(y * _yScale); int top = (int)(_overscan.Top * _yScale); int left = (int)(_overscan.Left * _xScale); - for(int i = 0; i < _yScale; i++) { - for(int j = 0; j < xPixelCount; j++) { - if(alpha != 0xFF000000) { - BlendColors((uint8_t*)&_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left)+j], (uint8_t*)&color); - } else { - _argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left) +j] = color; + for (int i = 0; i < _yScale; i++) + { + for (int j = 0; j < xPixelCount; j++) + { + if (alpha != 0xFF000000) + { + BlendColors((uint8_t*)&_argbBuffer[(y - top) * _lineWidth + i * _lineWidth + (x - left) + j], + (uint8_t*)&color); + } + else + { + _argbBuffer[(y - top) * _lineWidth + i * _lineWidth + (x - left) + j] = color; } } } @@ -65,7 +81,7 @@ protected: public: DrawCommand(int startFrame, int frameCount, bool useIntegerScaling = false) - { + { _frameCount = frameCount > 0 ? frameCount : -1; _startFrame = startFrame; _useIntegerScaling = useIntegerScaling; @@ -75,9 +91,10 @@ public: { } - void Draw(uint32_t* argbBuffer, OverscanDimensions &overscan, uint32_t lineWidth, uint32_t frameNumber) + void Draw(uint32_t* argbBuffer, OverscanDimensions& overscan, uint32_t lineWidth, uint32_t frameNumber) { - if(_startFrame <= frameNumber) { + if (_startFrame <= frameNumber) + { _argbBuffer = argbBuffer; _overscan = overscan; _lineWidth = lineWidth; diff --git a/Core/DrawLineCommand.h b/Core/DrawLineCommand.h index 28daaf7..7f1e156 100644 --- a/Core/DrawLineCommand.h +++ b/Core/DrawLineCommand.h @@ -16,18 +16,24 @@ protected: int dy = abs(_y2 - y), sy = y < _y2 ? 1 : -1; int err = (dx > dy ? dx : -dy) / 2, e2; - while(true) { + while (true) + { DrawPixel(x, y, _color); - if(x == _x2 && y == _y2) { + if (x == _x2 && y == _y2) + { break; } e2 = err; - if(e2 > -dx) { - err -= dy; x += sx; + if (e2 > -dx) + { + err -= dy; + x += sx; } - if(e2 < dy) { - err += dx; y += sy; + if (e2 < dy) + { + err += dx; + y += sy; } } } diff --git a/Core/DrawRectangleCommand.h b/Core/DrawRectangleCommand.h index 2062626..f96fe36 100644 --- a/Core/DrawRectangleCommand.h +++ b/Core/DrawRectangleCommand.h @@ -11,18 +11,25 @@ private: protected: void InternalDraw() { - if(_fill) { - for(int j = 0; j < _height; j++) { - for(int i = 0; i < _width; i++) { + if (_fill) + { + for (int j = 0; j < _height; j++) + { + for (int i = 0; i < _width; i++) + { DrawPixel(_x + i, _y + j, _color); } } - } else { - for(int i = 0; i < _width; i++) { + } + else + { + for (int i = 0; i < _width; i++) + { DrawPixel(_x + i, _y, _color); DrawPixel(_x + i, _y + _height - 1, _color); } - for(int i = 1; i < _height - 1; i++) { + for (int i = 1; i < _height - 1; i++) + { DrawPixel(_x, _y + i, _color); DrawPixel(_x + _width - 1, _y + i, _color); } @@ -33,11 +40,13 @@ public: DrawRectangleCommand(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame) : DrawCommand(startFrame, frameCount), _x(x), _y(y), _width(width), _height(height), _color(color), _fill(fill) { - if(width < 0) { + if (width < 0) + { _x += width + 1; _width = -width; } - if(height < 0) { + if (height < 0) + { _y += height + 1; _height = -height; } @@ -45,4 +54,4 @@ public: //Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time) _color = (~color & 0xFF000000) | (color & 0xFFFFFF); } -}; \ No newline at end of file +}; diff --git a/Core/DrawScreenBufferCommand.h b/Core/DrawScreenBufferCommand.h index 2cff980..4f58986 100644 --- a/Core/DrawScreenBufferCommand.h +++ b/Core/DrawScreenBufferCommand.h @@ -5,13 +5,15 @@ class DrawScreenBufferCommand : public DrawCommand { private: - uint32_t _screenBuffer[256*240]; + uint32_t _screenBuffer[256 * 240]; protected: void InternalDraw() { - for(int y = 0; y < 240; y++) { - for(int x = 0; x < 256; x++) { + for (int y = 0; y < 240; y++) + { + for (int x = 0; x < 256; x++) + { DrawPixel(x, y, _screenBuffer[(y << 8) + x]); } } diff --git a/Core/DrawStringCommand.h b/Core/DrawStringCommand.h index 6aea0a8..8f9f8e5 100644 --- a/Core/DrawStringCommand.h +++ b/Core/DrawStringCommand.h @@ -11,101 +11,101 @@ private: //Taken from FCEUX's LUA code const int _tabSpace = 4; const uint8_t _font[792] = { - 6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar - 3, 64, 64, 64, 64, 64, 0, 64, - 5, 80, 80, 80, 0, 0, 0, 0, - 6, 80, 80,248, 80,248, 80, 80, - 6, 32,120,160,112, 40,240, 32, - 6, 64,168, 80, 32, 80,168, 16, - 6, 96,144,160, 64,168,144,104, - 3, 64, 64, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar + 3, 64, 64, 64, 64, 64, 0, 64, + 5, 80, 80, 80, 0, 0, 0, 0, + 6, 80, 80, 248, 80, 248, 80, 80, + 6, 32, 120, 160, 112, 40, 240, 32, + 6, 64, 168, 80, 32, 80, 168, 16, + 6, 96, 144, 160, 64, 168, 144, 104, + 3, 64, 64, 0, 0, 0, 0, 0, 4, 32, 64, 64, 64, 64, 64, 32, 4, 64, 32, 32, 32, 32, 32, 64, - 6, 0, 80, 32,248, 32, 80, 0, - 6, 0, 32, 32,248, 32, 32, 0, - 3, 0, 0, 0, 0, 0, 64,128, - 5, 0, 0, 0,240, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 64, + 6, 0, 80, 32, 248, 32, 80, 0, + 6, 0, 32, 32, 248, 32, 32, 0, + 3, 0, 0, 0, 0, 0, 64, 128, + 5, 0, 0, 0, 240, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 64, 5, 16, 16, 32, 32, 32, 64, 64, - 6,112,136,136,136,136,136,112, // 0x30 - 0 + 6, 112, 136, 136, 136, 136, 136, 112, // 0x30 - 0 6, 32, 96, 32, 32, 32, 32, 32, - 6,112,136, 8, 48, 64,128,248, - 6,112,136, 8, 48, 8,136,112, - 6, 16, 48, 80,144,248, 16, 16, - 6,248,128,128,240, 8, 8,240, - 6, 48, 64,128,240,136,136,112, - 6,248, 8, 16, 16, 32, 32, 32, - 6,112,136,136,112,136,136,112, - 6,112,136,136,120, 8, 16, 96, - 3, 0, 0, 64, 0, 0, 64, 0, - 3, 0, 0, 64, 0, 0, 64,128, - 4, 0, 32, 64,128, 64, 32, 0, - 5, 0, 0,240, 0,240, 0, 0, - 4, 0,128, 64, 32, 64,128, 0, - 6,112,136, 8, 16, 32, 0, 32, // 0x3F - ? - 6,112,136,136,184,176,128,112, // 0x40 - @ - 6,112,136,136,248,136,136,136, // 0x41 - A - 6,240,136,136,240,136,136,240, - 6,112,136,128,128,128,136,112, - 6,224,144,136,136,136,144,224, - 6,248,128,128,240,128,128,248, - 6,248,128,128,240,128,128,128, - 6,112,136,128,184,136,136,120, - 6,136,136,136,248,136,136,136, - 4,224, 64, 64, 64, 64, 64,224, - 6, 8, 8, 8, 8, 8,136,112, - 6,136,144,160,192,160,144,136, - 6,128,128,128,128,128,128,248, - 6,136,216,168,168,136,136,136, - 6,136,136,200,168,152,136,136, - 7, 48, 72,132,132,132, 72, 48, - 6,240,136,136,240,128,128,128, - 6,112,136,136,136,168,144,104, - 6,240,136,136,240,144,136,136, - 6,112,136,128,112, 8,136,112, - 6,248, 32, 32, 32, 32, 32, 32, - 6,136,136,136,136,136,136,112, - 6,136,136,136, 80, 80, 32, 32, - 6,136,136,136,136,168,168, 80, - 6,136,136, 80, 32, 80,136,136, - 6,136,136, 80, 32, 32, 32, 32, - 6,248, 8, 16, 32, 64,128,248, - 3,192,128,128,128,128,128,192, + 6, 112, 136, 8, 48, 64, 128, 248, + 6, 112, 136, 8, 48, 8, 136, 112, + 6, 16, 48, 80, 144, 248, 16, 16, + 6, 248, 128, 128, 240, 8, 8, 240, + 6, 48, 64, 128, 240, 136, 136, 112, + 6, 248, 8, 16, 16, 32, 32, 32, + 6, 112, 136, 136, 112, 136, 136, 112, + 6, 112, 136, 136, 120, 8, 16, 96, + 3, 0, 0, 64, 0, 0, 64, 0, + 3, 0, 0, 64, 0, 0, 64, 128, + 4, 0, 32, 64, 128, 64, 32, 0, + 5, 0, 0, 240, 0, 240, 0, 0, + 4, 0, 128, 64, 32, 64, 128, 0, + 6, 112, 136, 8, 16, 32, 0, 32, // 0x3F - ? + 6, 112, 136, 136, 184, 176, 128, 112, // 0x40 - @ + 6, 112, 136, 136, 248, 136, 136, 136, // 0x41 - A + 6, 240, 136, 136, 240, 136, 136, 240, + 6, 112, 136, 128, 128, 128, 136, 112, + 6, 224, 144, 136, 136, 136, 144, 224, + 6, 248, 128, 128, 240, 128, 128, 248, + 6, 248, 128, 128, 240, 128, 128, 128, + 6, 112, 136, 128, 184, 136, 136, 120, + 6, 136, 136, 136, 248, 136, 136, 136, + 4, 224, 64, 64, 64, 64, 64, 224, + 6, 8, 8, 8, 8, 8, 136, 112, + 6, 136, 144, 160, 192, 160, 144, 136, + 6, 128, 128, 128, 128, 128, 128, 248, + 6, 136, 216, 168, 168, 136, 136, 136, + 6, 136, 136, 200, 168, 152, 136, 136, + 7, 48, 72, 132, 132, 132, 72, 48, + 6, 240, 136, 136, 240, 128, 128, 128, + 6, 112, 136, 136, 136, 168, 144, 104, + 6, 240, 136, 136, 240, 144, 136, 136, + 6, 112, 136, 128, 112, 8, 136, 112, + 6, 248, 32, 32, 32, 32, 32, 32, + 6, 136, 136, 136, 136, 136, 136, 112, + 6, 136, 136, 136, 80, 80, 32, 32, + 6, 136, 136, 136, 136, 168, 168, 80, + 6, 136, 136, 80, 32, 80, 136, 136, + 6, 136, 136, 80, 32, 32, 32, 32, + 6, 248, 8, 16, 32, 64, 128, 248, + 3, 192, 128, 128, 128, 128, 128, 192, 5, 64, 64, 32, 32, 32, 16, 16, - 3,192, 64, 64, 64, 64, 64,192, - 4, 64,160, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 0, 0, 0,248, - 3,128, 64, 0, 0, 0, 0, 0, - 5, 0, 0, 96, 16,112,144,112, // 0x61 - a - 5,128,128,224,144,144,144,224, - 5, 0, 0,112,128,128,128,112, - 5, 16, 16,112,144,144,144,112, - 5, 0, 0, 96,144,240,128,112, - 5, 48, 64,224, 64, 64, 64, 64, - 5, 0,112,144,144,112, 16,224, - 5,128,128,224,144,144,144,144, - 2,128, 0,128,128,128,128,128, - 4, 32, 0, 32, 32, 32, 32,192, - 5,128,128,144,160,192,160,144, - 2,128,128,128,128,128,128,128, - 6, 0, 0,208,168,168,168,168, - 5, 0, 0,224,144,144,144,144, - 5, 0, 0, 96,144,144,144, 96, - 5, 0,224,144,144,224,128,128, - 5, 0,112,144,144,112, 16, 16, - 5, 0, 0,176,192,128,128,128, - 5, 0, 0,112,128, 96, 16,224, - 4, 64, 64,224, 64, 64, 64, 32, - 5, 0, 0,144,144,144,144,112, - 5, 0, 0,144,144,144,160,192, - 6, 0, 0,136,136,168,168, 80, - 5, 0, 0,144,144, 96,144,144, - 5, 0,144,144,144,112, 16, 96, - 5, 0, 0,240, 32, 64,128,240, - 4, 32, 64, 64,128, 64, 64, 32, + 3, 192, 64, 64, 64, 64, 64, 192, + 4, 64, 160, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 248, + 3, 128, 64, 0, 0, 0, 0, 0, + 5, 0, 0, 96, 16, 112, 144, 112, // 0x61 - a + 5, 128, 128, 224, 144, 144, 144, 224, + 5, 0, 0, 112, 128, 128, 128, 112, + 5, 16, 16, 112, 144, 144, 144, 112, + 5, 0, 0, 96, 144, 240, 128, 112, + 5, 48, 64, 224, 64, 64, 64, 64, + 5, 0, 112, 144, 144, 112, 16, 224, + 5, 128, 128, 224, 144, 144, 144, 144, + 2, 128, 0, 128, 128, 128, 128, 128, + 4, 32, 0, 32, 32, 32, 32, 192, + 5, 128, 128, 144, 160, 192, 160, 144, + 2, 128, 128, 128, 128, 128, 128, 128, + 6, 0, 0, 208, 168, 168, 168, 168, + 5, 0, 0, 224, 144, 144, 144, 144, + 5, 0, 0, 96, 144, 144, 144, 96, + 5, 0, 224, 144, 144, 224, 128, 128, + 5, 0, 112, 144, 144, 112, 16, 16, + 5, 0, 0, 176, 192, 128, 128, 128, + 5, 0, 0, 112, 128, 96, 16, 224, + 4, 64, 64, 224, 64, 64, 64, 32, + 5, 0, 0, 144, 144, 144, 144, 112, + 5, 0, 0, 144, 144, 144, 160, 192, + 6, 0, 0, 136, 136, 168, 168, 80, + 5, 0, 0, 144, 144, 96, 144, 144, + 5, 0, 144, 144, 144, 112, 16, 96, + 5, 0, 0, 240, 32, 64, 128, 240, + 4, 32, 64, 64, 128, 64, 64, 32, 3, 64, 64, 64, 64, 64, 64, 64, - 4,128, 64, 64, 32, 64, 64,128, - 6, 0,104,176, 0, 0, 0, 0 + 4, 128, 64, 64, 32, 64, 64, 128, + 6, 0, 104, 176, 0, 0, 0, 0 }; int GetCharNumber(char ch) @@ -125,24 +125,35 @@ protected: int startX = (int)(_x * _xScale / _yScale); int x = startX; int y = _y; - for(char c : _text) { - if(c == '\n') { + for (char c : _text) + { + if (c == '\n') + { x = startX; y += 9; - } else if(c == '\t') { + } + else if (c == '\t') + { x += (_tabSpace - (((x - startX) / 8) % _tabSpace)) * 8; - } else { + } + else + { int ch = GetCharNumber(c); int width = GetCharWidth(c); int rowOffset = (c == 'y' || c == 'g' || c == 'p' || c == 'q') ? 1 : 0; - for(int j = 0; j < 8; j++) { - uint8_t rowData = ((j == 7 && rowOffset == 0) || (j == 0 && rowOffset == 1)) ? 0 : _font[ch * 8 + 1 + j - rowOffset]; - for(int i = 0; i < width; i++) { + for (int j = 0; j < 8; j++) + { + uint8_t rowData = ((j == 7 && rowOffset == 0) || (j == 0 && rowOffset == 1)) + ? 0 + : _font[ch * 8 + 1 + j - rowOffset]; + for (int i = 0; i < width; i++) + { int drawFg = (rowData >> (7 - i)) & 0x01; DrawPixel(x + i, y + j, drawFg ? _color : _backColor); } } - for(int i = 0; i < width; i++) { + for (int i = 0; i < width; i++) + { DrawPixel(x + i, y - 1, _backColor); } x += width; diff --git a/Core/DummyCpu.h b/Core/DummyCpu.h index 6cb7d81..3bd27da 100644 --- a/Core/DummyCpu.h +++ b/Core/DummyCpu.h @@ -16,7 +16,9 @@ DummyCpu::DummyCpu(Console* console, CpuType type) { _console = console; - _memoryMappings = type == CpuType::Cpu ? console->GetMemoryManager()->GetMemoryMappings() : console->GetCartridge()->GetSa1()->GetMemoryMappings(); + _memoryMappings = type == CpuType::Cpu + ? console->GetMemoryManager()->GetMemoryMappings() + : console->GetCartridge()->GetSa1()->GetMemoryMappings(); _dmaController = nullptr; _memoryManager = nullptr; } @@ -33,7 +35,7 @@ void DummyCpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type) LogWrite(addr, value); } -void DummyCpu::SetDummyState(CpuState &state) +void DummyCpu::SetDummyState(CpuState& state) { _state = state; _state.StopState = CpuStopState::Running; @@ -65,13 +67,13 @@ void DummyCpu::LogWrite(uint32_t addr, uint8_t value) _writeCounter++; } -void DummyCpu::GetWriteInfo(uint32_t index, uint32_t &addr, uint8_t &value) +void DummyCpu::GetWriteInfo(uint32_t index, uint32_t& addr, uint8_t& value) { addr = _writeAddresses[index]; value = _writeValue[index]; } -void DummyCpu::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value) +void DummyCpu::GetReadInfo(uint32_t index, uint32_t& addr, uint8_t& value) { addr = _readAddresses[index]; value = _readValue[index]; @@ -80,4 +82,4 @@ void DummyCpu::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value) int32_t DummyCpu::GetLastOperand() { return _operand; -} \ No newline at end of file +} diff --git a/Core/DummySpc.h b/Core/DummySpc.h index 5e28dc7..aa74777 100644 --- a/Core/DummySpc.h +++ b/Core/DummySpc.h @@ -12,7 +12,7 @@ #include "Spc.h" -DummySpc::DummySpc(uint8_t *spcRam, SpcState &state) +DummySpc::DummySpc(uint8_t* spcRam, SpcState& state) { _ram = spcRam; @@ -37,9 +37,11 @@ DummySpc::~DummySpc() void DummySpc::Step() { - do { + do + { ProcessCycle(); - } while(_opStep != SpcOpStep::ReadOpCode); + } + while (_opStep != SpcOpStep::ReadOpCode); } uint32_t DummySpc::GetWriteCount() @@ -66,14 +68,14 @@ void DummySpc::LogWrite(uint32_t addr, uint8_t value) _writeCounter++; } -void DummySpc::GetWriteInfo(uint32_t index, uint32_t &addr, uint8_t &value) +void DummySpc::GetWriteInfo(uint32_t index, uint32_t& addr, uint8_t& value) { addr = _writeAddresses[index]; value = _writeValue[index]; } -void DummySpc::GetReadInfo(uint32_t index, uint32_t &addr, uint8_t &value) +void DummySpc::GetReadInfo(uint32_t index, uint32_t& addr, uint8_t& value) { addr = _readAddresses[index]; value = _readValue[index]; -} \ No newline at end of file +} diff --git a/Core/EmuSettings.cpp b/Core/EmuSettings.cpp index b6f8ed8..21022ac 100644 --- a/Core/EmuSettings.cpp +++ b/Core/EmuSettings.cpp @@ -31,15 +31,19 @@ uint32_t EmuSettings::GetVersion() string EmuSettings::GetVersionString() { uint32_t version = GetVersion(); - return std::to_string(version >> 16) + "." + std::to_string((version >> 8) & 0xFF) + "." + std::to_string(version & 0xFF); + return std::to_string(version >> 16) + "." + std::to_string((version >> 8) & 0xFF) + "." + std::to_string( + version & 0xFF); } -void EmuSettings::ProcessString(string & str, const char ** strPointer) +void EmuSettings::ProcessString(string& str, const char** strPointer) { //Make a copy of the string and keep it (the original pointer will not be valid after the call is over) - if(*strPointer) { + if (*strPointer) + { str = *strPointer; - } else { + } + else + { str.clear(); } *strPointer = str.c_str(); @@ -70,14 +74,16 @@ AudioConfig EmuSettings::GetAudioConfig() void EmuSettings::SetInputConfig(InputConfig config) { bool controllersChanged = false; - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { controllersChanged |= _input.Controllers[i].Type != config.Controllers[i].Type; } _input = config; _inputConfigVersion++; - if(controllersChanged) { + if (controllersChanged) + { //Used by net play _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ConfigChanged); } @@ -85,8 +91,10 @@ void EmuSettings::SetInputConfig(InputConfig config) InputConfig EmuSettings::GetInputConfig() { - if(CheckFlag(EmulationFlags::GameboyMode)) { - if(_input.Controllers[0].Type != ControllerType::SnesController) { + if (CheckFlag(EmulationFlags::GameboyMode)) + { + if (_input.Controllers[0].Type != ControllerType::SnesController) + { //Force SNES controller for P1 for gameboy-only mode InputConfig input = _input; input.Controllers[0].Type = ControllerType::SnesController; @@ -103,14 +111,20 @@ uint32_t EmuSettings::GetInputConfigVersion() void EmuSettings::SetEmulationConfig(EmulationConfig config) { - bool prevOverclockEnabled = _emulation.PpuExtraScanlinesAfterNmi > 0 || _emulation.PpuExtraScanlinesBeforeNmi > 0 || _emulation.GsuClockSpeed > 100; - bool overclockEnabled = config.PpuExtraScanlinesAfterNmi > 0 || config.PpuExtraScanlinesBeforeNmi > 0 || config.GsuClockSpeed > 100; + bool prevOverclockEnabled = _emulation.PpuExtraScanlinesAfterNmi > 0 || _emulation.PpuExtraScanlinesBeforeNmi > 0 || + _emulation.GsuClockSpeed > 100; + bool overclockEnabled = config.PpuExtraScanlinesAfterNmi > 0 || config.PpuExtraScanlinesBeforeNmi > 0 || config. + GsuClockSpeed > 100; _emulation = config; - if(prevOverclockEnabled != overclockEnabled) { - if(overclockEnabled) { + if (prevOverclockEnabled != overclockEnabled) + { + if (overclockEnabled) + { MessageManager::DisplayMessage("Overclock", "OverclockEnabled"); - } else { + } + else + { MessageManager::DisplayMessage("Overclock", "OverclockDisabled"); } @@ -177,11 +191,16 @@ void EmuSettings::SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCo { _emulatorKeys[keySetIndex][(uint32_t)shortcut] = keyCombination; - for(int i = 0; i < 3; i++) { - for(std::pair &kvp : _emulatorKeys[i]) { - if(keyCombination.IsSubsetOf(kvp.second)) { + for (int i = 0; i < 3; i++) + { + for (std::pair& kvp : _emulatorKeys[i]) + { + if (keyCombination.IsSubsetOf(kvp.second)) + { _shortcutSupersets[keySetIndex][(uint32_t)shortcut].push_back(kvp.second); - } else if(kvp.second.IsSubsetOf(keyCombination)) { + } + else if (kvp.second.IsSubsetOf(keyCombination)) + { _shortcutSupersets[i][kvp.first].push_back(keyCombination); } } @@ -192,10 +211,14 @@ void EmuSettings::SetShortcutKeys(vector shortcuts) { ClearShortcutKeys(); - for(ShortcutKeyInfo &shortcut : shortcuts) { - if(_emulatorKeys[0][(uint32_t)shortcut.Shortcut].GetKeys().empty()) { + for (ShortcutKeyInfo& shortcut : shortcuts) + { + if (_emulatorKeys[0][(uint32_t)shortcut.Shortcut].GetKeys().empty()) + { SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 0); - } else { + } + else + { SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 1); } } @@ -204,7 +227,8 @@ void EmuSettings::SetShortcutKeys(vector shortcuts) KeyCombination EmuSettings::GetShortcutKey(EmulatorShortcut shortcut, int keySetIndex) { auto result = _emulatorKeys[keySetIndex].find((int)shortcut); - if(result != _emulatorKeys[keySetIndex].end()) { + if (result != _emulatorKeys[keySetIndex].end()) + { return result->second; } return {}; @@ -218,13 +242,16 @@ vector EmuSettings::GetShortcutSupersets(EmulatorShortcut shortc OverscanDimensions EmuSettings::GetOverscan() { OverscanDimensions overscan; - if(CheckFlag(EmulationFlags::GameboyMode)) { + if (CheckFlag(EmulationFlags::GameboyMode)) + { //Force overscan values for gameboy-only mode (not SGB) overscan.Left = 0; overscan.Right = 256 - 160; overscan.Top = 0; overscan.Bottom = 239 - 144; - } else { + } + else + { overscan.Left = _video.OverscanLeft; overscan.Right = _video.OverscanRight; overscan.Top = _video.OverscanTop; @@ -240,50 +267,63 @@ uint32_t EmuSettings::GetRewindBufferSize() uint32_t EmuSettings::GetEmulationSpeed() { - if(CheckFlag(EmulationFlags::MaximumSpeed)) { + if (CheckFlag(EmulationFlags::MaximumSpeed)) + { return 0; - } else if(CheckFlag(EmulationFlags::Turbo)) { + } + else if (CheckFlag(EmulationFlags::Turbo)) + { return _emulation.TurboSpeed; - } else if(CheckFlag(EmulationFlags::Rewind)) { + } + else if (CheckFlag(EmulationFlags::Rewind)) + { return _emulation.RewindSpeed; - } else { + } + else + { return _emulation.EmulationSpeed; } } double EmuSettings::GetAspectRatio(ConsoleRegion region) { - switch(_video.AspectRatio) { - case VideoAspectRatio::NoStretching: return 0.0; - case VideoAspectRatio::Auto: return region == ConsoleRegion::Pal ? (11.0 / 8.0) : (8.0 / 7.0); - case VideoAspectRatio::NTSC: return 8.0 / 7.0; - case VideoAspectRatio::PAL: return 11.0 / 8.0; - case VideoAspectRatio::Standard: return 4.0 / 3.0; - case VideoAspectRatio::Widescreen: return 16.0 / 9.0; - case VideoAspectRatio::Custom: return _video.CustomAspectRatio; + switch (_video.AspectRatio) + { + case VideoAspectRatio::NoStretching: return 0.0; + case VideoAspectRatio::Auto: return region == ConsoleRegion::Pal ? (11.0 / 8.0) : (8.0 / 7.0); + case VideoAspectRatio::NTSC: return 8.0 / 7.0; + case VideoAspectRatio::PAL: return 11.0 / 8.0; + case VideoAspectRatio::Standard: return 4.0 / 3.0; + case VideoAspectRatio::Widescreen: return 16.0 / 9.0; + case VideoAspectRatio::Custom: return _video.CustomAspectRatio; } return 0.0; } void EmuSettings::SetFlag(EmulationFlags flag) { - if((_flags & (int)flag) == 0) { + if ((_flags & (int)flag) == 0) + { _flags |= (int)flag; } } void EmuSettings::SetFlagState(EmulationFlags flag, bool enabled) { - if(enabled) { + if (enabled) + { SetFlag(flag); - } else { + } + else + { ClearFlag(flag); } } void EmuSettings::ClearFlag(EmulationFlags flag) { - if((_flags & (int)flag) != 0) { + if ((_flags & (int)flag) != 0) + { _flags &= ~(int)flag; } } @@ -295,12 +335,17 @@ bool EmuSettings::CheckFlag(EmulationFlags flag) void EmuSettings::SetDebuggerFlag(DebuggerFlags flag, bool enabled) { - if(enabled) { - if((_debuggerFlags & (int)flag) == 0) { + if (enabled) + { + if ((_debuggerFlags & (int)flag) == 0) + { _debuggerFlags |= (int)flag; } - } else { - if((_debuggerFlags & (int)flag) != 0) { + } + else + { + if ((_debuggerFlags & (int)flag) != 0) + { _debuggerFlags &= ~(int)flag; } } @@ -313,16 +358,20 @@ bool EmuSettings::CheckDebuggerFlag(DebuggerFlags flag) void EmuSettings::InitializeRam(void* data, uint32_t length) { - switch(_emulation.RamPowerOnState) { - default: - case RamState::AllZeros: memset(data, 0, length); break; - case RamState::AllOnes: memset(data, 0xFF, length); break; - case RamState::Random: - std::uniform_int_distribution<> dist(0, 255); - for(uint32_t i = 0; i < length; i++) { - ((uint8_t*)data)[i] = dist(_mt); - } - break; + switch (_emulation.RamPowerOnState) + { + default: + case RamState::AllZeros: memset(data, 0, length); + break; + case RamState::AllOnes: memset(data, 0xFF, length); + break; + case RamState::Random: + std::uniform_int_distribution<> dist(0, 255); + for (uint32_t i = 0; i < length; i++) + { + ((uint8_t*)data)[i] = dist(_mt); + } + break; } } @@ -333,8 +382,8 @@ int EmuSettings::GetRandomValue(int maxValue) } bool EmuSettings::GetRandomBool() -{ - return GetRandomValue(1) == 1; +{ + return GetRandomValue(1) == 1; } bool EmuSettings::IsInputEnabled() @@ -344,12 +393,13 @@ bool EmuSettings::IsInputEnabled() double EmuSettings::GetControllerDeadzoneRatio() { - switch(_input.ControllerDeadzoneSize) { - case 0: return 0.5; - case 1: return 0.75; - case 2: return 1; - case 3: return 1.25; - case 4: return 1.5; + switch (_input.ControllerDeadzoneSize) + { + case 0: return 0.5; + case 1: return 0.75; + case 2: return 1; + case 3: return 1.25; + case 4: return 1.5; } return 1; } diff --git a/Core/EmuSettings.h b/Core/EmuSettings.h index c951c6f..e3274d2 100644 --- a/Core/EmuSettings.h +++ b/Core/EmuSettings.h @@ -31,7 +31,7 @@ private: std::unordered_map _emulatorKeys[3]; std::unordered_map> _shortcutSupersets[3]; - void ProcessString(string &str, const char** strPointer); + void ProcessString(string& str, const char** strPointer); void ClearShortcutKeys(); void SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex); @@ -77,11 +77,11 @@ public: void SetDebuggerFlag(DebuggerFlags flag, bool enabled); bool CheckDebuggerFlag(DebuggerFlags flags); - + int GetRandomValue(int maxValue); bool GetRandomBool(); void InitializeRam(void* data, uint32_t length); bool IsInputEnabled(); double GetControllerDeadzoneRatio(); -}; \ No newline at end of file +}; diff --git a/Core/EventManager.cpp b/Core/EventManager.cpp index e2b807e..e216ede 100644 --- a/Core/EventManager.cpp +++ b/Core/EventManager.cpp @@ -10,7 +10,8 @@ #include "DefaultVideoFilter.h" #include "BaseEventManager.h" -EventManager::EventManager(Debugger *debugger, Cpu *cpu, Ppu *ppu, MemoryManager *memoryManager, DmaController *dmaController) +EventManager::EventManager(Debugger* debugger, Cpu* cpu, Ppu* ppu, MemoryManager* memoryManager, + DmaController* dmaController) { _debugger = debugger; _cpu = cpu; @@ -27,7 +28,7 @@ EventManager::~EventManager() delete[] _ppuBuffer; } -void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo &operation, int32_t breakpointId) +void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId) { DebugEventInfo evt = {}; evt.Type = type; @@ -36,10 +37,13 @@ void EventManager::AddEvent(DebugEventType type, MemoryOperationInfo &operation, evt.Cycle = _memoryManager->GetHClock(); evt.BreakpointId = breakpointId; - if(operation.Type == MemoryOperationType::DmaRead || operation.Type == MemoryOperationType::DmaWrite) { + if (operation.Type == MemoryOperationType::DmaRead || operation.Type == MemoryOperationType::DmaWrite) + { evt.DmaChannel = _dmaController->GetActiveChannel(); evt.DmaChannelInfo = _dmaController->GetChannelConfig(evt.DmaChannel & 0x07); - } else { + } + else + { evt.DmaChannel = -1; } @@ -57,14 +61,14 @@ void EventManager::AddEvent(DebugEventType type) evt.Cycle = _memoryManager->GetHClock(); evt.BreakpointId = -1; evt.DmaChannel = -1; - + CpuState state = _cpu->GetState(); evt.ProgramCounter = (state.K << 16) | state.PC; _debugEvents.push_back(evt); } -void EventManager::GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount) +void EventManager::GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount) { auto lock = _lock.AcquireSafe(); uint32_t eventCount = std::min(maxEventCount, (uint32_t)_sentEvents.size()); @@ -72,12 +76,14 @@ void EventManager::GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount maxEventCount = eventCount; } -DebugEventInfo EventManager::GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options) +DebugEventInfo EventManager::GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options) { auto lock = _lock.AcquireSafe(); - for(DebugEventInfo &evt : _sentEvents) { - if(evt.Cycle == cycle && evt.Scanline == scanline) { + for (DebugEventInfo& evt : _sentEvents) + { + if (evt.Cycle == cycle && evt.Scanline == scanline) + { return evt; } } @@ -100,120 +106,191 @@ void EventManager::ClearFrameEvents() _debugEvents.clear(); } -void EventManager::FilterEvents(EventViewerDisplayOptions &options) +void EventManager::FilterEvents(EventViewerDisplayOptions& options) { auto lock = _lock.AcquireSafe(); _sentEvents.clear(); vector events = _snapshot; - if(options.ShowPreviousFrameEvents && _snapshotScanline != 0) { + if (options.ShowPreviousFrameEvents && _snapshotScanline != 0) + { uint32_t key = (_snapshotScanline << 16) + _snapshotCycle; - for(DebugEventInfo &evt : _prevDebugEvents) { + for (DebugEventInfo& evt : _prevDebugEvents) + { uint32_t evtKey = (evt.Scanline << 16) + evt.Cycle; - if(evtKey > key) { + if (evtKey > key) + { events.push_back(evt); } } } - for(DebugEventInfo &evt : events) { - bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite; - bool isDma = evt.Operation.Type == MemoryOperationType::DmaWrite || evt.Operation.Type == MemoryOperationType::DmaRead; + for (DebugEventInfo& evt : events) + { + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == + MemoryOperationType::DmaWrite; + bool isDma = evt.Operation.Type == MemoryOperationType::DmaWrite || evt.Operation.Type == + MemoryOperationType::DmaRead; bool showEvent = false; - switch(evt.Type) { - case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints;break; - case DebugEventType::Irq: showEvent = options.ShowIrq; break; - case DebugEventType::Nmi: showEvent = options.ShowNmi; break; - case DebugEventType::Register: - if(isDma && !options.ShowDmaChannels[evt.DmaChannel & 0x07]) { - showEvent = false; - break; - } - - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg <= 0x213F) { - if(isWrite) { - if(reg >= 0x2101 && reg <= 0x2104) { - showEvent = options.ShowPpuRegisterOamWrites; - } else if(reg >= 0x2105 && reg <= 0x210C) { - showEvent = options.ShowPpuRegisterBgOptionWrites; - } else if(reg >= 0x210D && reg <= 0x2114) { - showEvent = options.ShowPpuRegisterBgScrollWrites; - } else if(reg >= 0x2115 && reg <= 0x2119) { - showEvent = options.ShowPpuRegisterVramWrites; - } else if(reg >= 0x211A && reg <= 0x2120) { - showEvent = options.ShowPpuRegisterMode7Writes; - } else if(reg >= 0x2121 && reg <= 0x2122) { - showEvent = options.ShowPpuRegisterCgramWrites; - } else if(reg >= 0x2123 && reg <= 0x212B) { - showEvent = options.ShowPpuRegisterWindowWrites; - } else { - showEvent = options.ShowPpuRegisterOtherWrites; - } - } else { - showEvent = options.ShowPpuRegisterReads; - } - } else if(reg <= 0x217F) { - showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; - } else if(reg <= 0x2183) { - showEvent = isWrite ? options.ShowWorkRamRegisterWrites : options.ShowWorkRamRegisterReads; - } else if(reg >= 0x4000) { - showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; - } + switch (evt.Type) + { + case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; + break; + case DebugEventType::Irq: showEvent = options.ShowIrq; + break; + case DebugEventType::Nmi: showEvent = options.ShowNmi; + break; + case DebugEventType::Register: + if (isDma && !options.ShowDmaChannels[evt.DmaChannel & 0x07]) + { + showEvent = false; break; + } + + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg <= 0x213F) + { + if (isWrite) + { + if (reg >= 0x2101 && reg <= 0x2104) + { + showEvent = options.ShowPpuRegisterOamWrites; + } + else if (reg >= 0x2105 && reg <= 0x210C) + { + showEvent = options.ShowPpuRegisterBgOptionWrites; + } + else if (reg >= 0x210D && reg <= 0x2114) + { + showEvent = options.ShowPpuRegisterBgScrollWrites; + } + else if (reg >= 0x2115 && reg <= 0x2119) + { + showEvent = options.ShowPpuRegisterVramWrites; + } + else if (reg >= 0x211A && reg <= 0x2120) + { + showEvent = options.ShowPpuRegisterMode7Writes; + } + else if (reg >= 0x2121 && reg <= 0x2122) + { + showEvent = options.ShowPpuRegisterCgramWrites; + } + else if (reg >= 0x2123 && reg <= 0x212B) + { + showEvent = options.ShowPpuRegisterWindowWrites; + } + else + { + showEvent = options.ShowPpuRegisterOtherWrites; + } + } + else + { + showEvent = options.ShowPpuRegisterReads; + } + } + else if (reg <= 0x217F) + { + showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; + } + else if (reg <= 0x2183) + { + showEvent = isWrite ? options.ShowWorkRamRegisterWrites : options.ShowWorkRamRegisterReads; + } + else if (reg >= 0x4000) + { + showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; + } + break; } - if(showEvent) { + if (showEvent) + { _sentEvents.push_back(evt); } } } -void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t *buffer, EventViewerDisplayOptions &options) +void EventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, + EventViewerDisplayOptions& options) { - bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite; + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == + MemoryOperationType::DmaWrite; uint32_t color = 0; - switch(evt.Type) { - case DebugEventType::Breakpoint: color = options.BreakpointColor; break; - case DebugEventType::Irq: color = options.IrqColor; break; - case DebugEventType::Nmi: color = options.NmiColor; break; - case DebugEventType::Register: - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg <= 0x213F) { - if(isWrite) { - if(reg >= 0x2101 && reg <= 0x2104) { - color = options.PpuRegisterWriteOamColor; - } else if(reg >= 0x2105 && reg <= 0x210C) { - color = options.PpuRegisterWriteBgOptionColor; - } else if(reg >= 0x210D && reg <= 0x2114) { - color = options.PpuRegisterWriteBgScrollColor; - } else if(reg >= 0x2115 && reg <= 0x2119) { - color = options.PpuRegisterWriteVramColor; - } else if(reg >= 0x211A && reg <= 0x2120) { - color = options.PpuRegisterWriteMode7Color; - } else if(reg >= 0x2121 && reg <= 0x2122) { - color = options.PpuRegisterWriteCgramColor; - } else if(reg >= 0x2123 && reg <= 0x212B) { - color = options.PpuRegisterWriteWindowColor; - } else { - color = options.PpuRegisterWriteOtherColor; - } - } else { - color = options.PpuRegisterReadColor; + switch (evt.Type) + { + case DebugEventType::Breakpoint: color = options.BreakpointColor; + break; + case DebugEventType::Irq: color = options.IrqColor; + break; + case DebugEventType::Nmi: color = options.NmiColor; + break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg <= 0x213F) + { + if (isWrite) + { + if (reg >= 0x2101 && reg <= 0x2104) + { + color = options.PpuRegisterWriteOamColor; + } + else if (reg >= 0x2105 && reg <= 0x210C) + { + color = options.PpuRegisterWriteBgOptionColor; + } + else if (reg >= 0x210D && reg <= 0x2114) + { + color = options.PpuRegisterWriteBgScrollColor; + } + else if (reg >= 0x2115 && reg <= 0x2119) + { + color = options.PpuRegisterWriteVramColor; + } + else if (reg >= 0x211A && reg <= 0x2120) + { + color = options.PpuRegisterWriteMode7Color; + } + else if (reg >= 0x2121 && reg <= 0x2122) + { + color = options.PpuRegisterWriteCgramColor; + } + else if (reg >= 0x2123 && reg <= 0x212B) + { + color = options.PpuRegisterWriteWindowColor; + } + else + { + color = options.PpuRegisterWriteOtherColor; } - } else if(reg <= 0x217F) { - color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; - } else if(reg <= 0x2183) { - color = isWrite ? options.WorkRamRegisterWriteColor : options.WorkRamRegisterReadColor; - } else if(reg >= 0x4000) { - color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; } - break; + else + { + color = options.PpuRegisterReadColor; + } + } + else if (reg <= 0x217F) + { + color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; + } + else if (reg <= 0x2183) + { + color = isWrite ? options.WorkRamRegisterWriteColor : options.WorkRamRegisterReadColor; + } + else if (reg >= 0x4000) + { + color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; + } + break; } - if(drawBackground){ + if (drawBackground) + { color = 0xFF000000 | ((color >> 1) & 0x7F7F7F); - } else { + } + else + { color |= 0xFF000000; } @@ -224,10 +301,13 @@ void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t uint32_t y = std::min(evt.Scanline * 2, _scanlineCount * 2); uint32_t x = evt.Cycle / 2; - for(int i = iMin; i <= iMax; i++) { - for(int j = jMin; j <= jMax; j++) { + for (int i = iMin; i <= iMax; i++) + { + for (int j = jMin; j <= jMax; j++) + { int32_t pos = (y + i) * EventManager::ScanlineWidth + x + j; - if(pos < 0 || pos >= EventManager::ScanlineWidth * (int)_scanlineCount * 2) { + if (pos < 0 || pos >= EventManager::ScanlineWidth * (int)_scanlineCount * 2) + { continue; } buffer[pos] = color; @@ -247,14 +327,17 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options) _overscanMode = _ppu->GetState().OverscanMode; _useHighResOutput = _ppu->IsHighResOutput(); - if(scanline >= _ppu->GetNmiScanline() || scanline == 0) { - memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256*239)) * sizeof(uint16_t)); - } else { + if (scanline >= _ppu->GetNmiScanline() || scanline == 0) + { + memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), (_useHighResOutput ? (512 * 478) : (256 * 239)) * sizeof(uint16_t)); + } + else + { uint16_t adjustedScanline = scanline + (_overscanMode ? 0 : 7); uint32_t size = _useHighResOutput ? (512 * 478) : (256 * 239); uint32_t offset = _useHighResOutput ? (512 * adjustedScanline * 2) : (256 * adjustedScanline); memcpy(_ppuBuffer, _ppu->GetScreenBuffer(), offset * sizeof(uint16_t)); - memcpy(_ppuBuffer+offset, _ppu->GetPreviousScreenBuffer()+offset, (size - offset) * sizeof(uint16_t)); + memcpy(_ppuBuffer + offset, _ppu->GetPreviousScreenBuffer() + offset, (size - offset) * sizeof(uint16_t)); } _snapshot = _debugEvents; @@ -264,25 +347,29 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options) return _scanlineCount; } -void EventManager::GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options) +void EventManager::GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options) { auto lock = _lock.AcquireSafe(); - if(_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4) { + if (_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4) + { return; } - for(int i = 0; i < EventManager::ScanlineWidth * (int)_scanlineCount * 2; i++) { + for (int i = 0; i < EventManager::ScanlineWidth * (int)_scanlineCount * 2; i++) + { buffer[i] = 0xFF555555; } //Skip the first 7 blank lines in the buffer when overscan mode is off - uint16_t *src = _ppuBuffer + (_overscanMode ? 0 : (_useHighResOutput ? (512 * 14) : (256 * 7))); + uint16_t* src = _ppuBuffer + (_overscanMode ? 0 : (_useHighResOutput ? (512 * 14) : (256 * 7))); - for(uint32_t y = 0, len = _overscanMode ? 239*2 : 224*2; y < len; y++) { - for(uint32_t x = 0; x < 512; x++) { + for (uint32_t y = 0, len = _overscanMode ? 239 * 2 : 224 * 2; y < len; y++) + { + for (uint32_t x = 0; x < 512; x++) + { int srcOffset = _useHighResOutput ? ((y << 9) | x) : (((y >> 1) << 8) | (x >> 1)); - buffer[(y + 2)*EventManager::ScanlineWidth + x + 22*2] = DefaultVideoFilter::ToArgb(src[srcOffset]); + buffer[(y + 2) * EventManager::ScanlineWidth + x + 22 * 2] = DefaultVideoFilter::ToArgb(src[srcOffset]); } } @@ -290,20 +377,24 @@ void EventManager::GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, Event constexpr uint32_t currentScanlineColor = 0xFFFFFF55; int nmiScanline = (_overscanMode ? 240 : 225) * 2 * EventManager::ScanlineWidth; uint32_t scanlineOffset = _snapshotScanline * 2 * EventManager::ScanlineWidth; - for(int i = 0; i < EventManager::ScanlineWidth; i++) { + for (int i = 0; i < EventManager::ScanlineWidth; i++) + { buffer[nmiScanline + i] = nmiColor; buffer[nmiScanline + EventManager::ScanlineWidth + i] = nmiColor; - if(_snapshotScanline != 0) { + if (_snapshotScanline != 0) + { buffer[scanlineOffset + i] = currentScanlineColor; buffer[scanlineOffset + EventManager::ScanlineWidth + i] = currentScanlineColor; } } FilterEvents(options); - for(DebugEventInfo &evt : _sentEvents) { + for (DebugEventInfo& evt : _sentEvents) + { DrawEvent(evt, true, buffer, options); } - for(DebugEventInfo &evt : _sentEvents) { + for (DebugEventInfo& evt : _sentEvents) + { DrawEvent(evt, false, buffer, options); } } diff --git a/Core/EventManager.h b/Core/EventManager.h index 421650d..bc405bd 100644 --- a/Core/EventManager.h +++ b/Core/EventManager.h @@ -19,15 +19,15 @@ class EventManager final : public IEventManager private: static constexpr int ScanlineWidth = 1364 / 2; - Cpu * _cpu; - Ppu *_ppu; + Cpu* _cpu; + Ppu* _ppu; MemoryManager* _memoryManager; - DmaController *_dmaController; - Debugger *_debugger; + DmaController* _dmaController; + Debugger* _debugger; vector _debugEvents; vector _prevDebugEvents; vector _sentEvents; - + vector _snapshot; int16_t _snapshotScanline = -1; uint16_t _snapshotCycle = 0; @@ -36,23 +36,23 @@ private: bool _overscanMode = false; bool _useHighResOutput = false; uint32_t _scanlineCount = 262; - uint16_t *_ppuBuffer = nullptr; + uint16_t* _ppuBuffer = nullptr; - void DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t *buffer, EventViewerDisplayOptions &options); - void FilterEvents(EventViewerDisplayOptions &options); + void DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, EventViewerDisplayOptions& options); + void FilterEvents(EventViewerDisplayOptions& options); public: - EventManager(Debugger *debugger, Cpu *cpu, Ppu *ppu, MemoryManager *memoryManager, DmaController *dmaController); + EventManager(Debugger* debugger, Cpu* cpu, Ppu* ppu, MemoryManager* memoryManager, DmaController* dmaController); ~EventManager(); - void AddEvent(DebugEventType type, MemoryOperationInfo &operation, int32_t breakpointId = -1); + void AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId = -1); void AddEvent(DebugEventType type); - - void GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount); + + void GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount); uint32_t GetEventCount(EventViewerDisplayOptions options); void ClearFrameEvents(); uint32_t TakeEventSnapshot(EventViewerDisplayOptions options); - void GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options); - DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options); + void GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options); + DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options); }; diff --git a/Core/EventType.h b/Core/EventType.h index 153b2c4..b161169 100644 --- a/Core/EventType.h +++ b/Core/EventType.h @@ -14,4 +14,4 @@ enum class EventType GbStartFrame, GbEndFrame, EventTypeSize -}; \ No newline at end of file +}; diff --git a/Core/ExpressionEvaluator.cpp b/Core/ExpressionEvaluator.cpp index 5020d21..c8ba031 100644 --- a/Core/ExpressionEvaluator.cpp +++ b/Core/ExpressionEvaluator.cpp @@ -11,24 +11,38 @@ #include "DebugUtilities.h" #include "../Utilities/HexUtilities.h" -const vector ExpressionEvaluator::_binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } }; -const vector ExpressionEvaluator::_binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } }; -const vector ExpressionEvaluator::_unaryOperators = { { "+", "-", "~", "!" } }; -const vector ExpressionEvaluator::_unaryPrecedence = { { 11, 11, 11, 11 } }; -const std::unordered_set ExpressionEvaluator::_operators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||", "~", "!", "(", ")", "{", "}", "[", "]" } }; +const vector ExpressionEvaluator::_binaryOperators = { + {"*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||"} +}; +const vector ExpressionEvaluator::_binaryPrecedence = {{10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1}}; +const vector ExpressionEvaluator::_unaryOperators = {{"+", "-", "~", "!"}}; +const vector ExpressionEvaluator::_unaryPrecedence = {{11, 11, 11, 11}}; +const std::unordered_set ExpressionEvaluator::_operators = { + { + "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||", "~", "!", "(", + ")", "{", "}", "[", "]" + } +}; -bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOperator) +bool ExpressionEvaluator::IsOperator(string token, int& precedence, bool unaryOperator) { - if(unaryOperator) { - for(size_t i = 0, len = _unaryOperators.size(); i < len; i++) { - if(token.compare(_unaryOperators[i]) == 0) { + if (unaryOperator) + { + for (size_t i = 0, len = _unaryOperators.size(); i < len; i++) + { + if (token.compare(_unaryOperators[i]) == 0) + { precedence = _unaryPrecedence[i]; return true; } } - } else { - for(size_t i = 0, len = _binaryOperators.size(); i < len; i++) { - if(token.compare(_binaryOperators[i]) == 0) { + } + else + { + for (size_t i = 0, len = _binaryOperators.size(); i < len; i++) + { + if (token.compare(_binaryOperators[i]) == 0) + { precedence = _binaryPrecedence[i]; return true; } @@ -39,15 +53,22 @@ bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOp EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator) { - if(unaryOperator) { - for(size_t i = 0, len = _unaryOperators.size(); i < len; i++) { - if(token.compare(_unaryOperators[i]) == 0) { + if (unaryOperator) + { + for (size_t i = 0, len = _unaryOperators.size(); i < len; i++) + { + if (token.compare(_unaryOperators[i]) == 0) + { return (EvalOperators)(EvalOperators::Plus + i); } } - } else { - for(size_t i = 0, len = _binaryOperators.size(); i < len; i++) { - if(token.compare(_binaryOperators[i]) == 0) { + } + else + { + for (size_t i = 0, len = _binaryOperators.size(); i < len; i++) + { + if (token.compare(_binaryOperators[i]) == 0) + { return (EvalOperators)(EvalOperators::Multiplication + i); } } @@ -55,130 +76,209 @@ EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator) return EvalOperators::Addition; } -bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data) +bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t& pos, string& output, ExpressionData& data) { string token; size_t initialPos = pos; size_t len = expression.size(); - do { + do + { char c = std::tolower(expression[pos]); - if((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '@') { + if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '@') + { //Only letters, numbers and underscore are allowed in code labels token += c; pos++; - } else { + } + else + { break; } - } while(pos < len); + } + while (pos < len); int64_t tokenValue = -1; - if(_cpuType == CpuType::Gsu) { + if (_cpuType == CpuType::Gsu) + { tokenValue = ProcessGsuTokens(token); - } else if(_cpuType == CpuType::Gameboy) { + } + else if (_cpuType == CpuType::Gameboy) + { tokenValue = ProcessGameboyTokens(token); - } else if(_cpuType == CpuType::Spc) { + } + else if (_cpuType == CpuType::Spc) + { tokenValue = ProcessCpuSpcTokens(token, true); - } else { // Cpu or Sa1 + } + else + { + // Cpu or Sa1 tokenValue = ProcessCpuSpcTokens(token, false); } - if(tokenValue != -1) { + if (tokenValue != -1) + { output += std::to_string(tokenValue); return true; } int64_t sharedToken = ProcessSharedTokens(token); - if(sharedToken != -1) { + if (sharedToken != -1) + { output += std::to_string(sharedToken); return true; } string originalExpression = expression.substr(initialPos, pos - initialPos); bool validLabel = _labelManager->ContainsLabel(originalExpression); - if(!validLabel) { + if (!validLabel) + { //Check if a multi-byte label exists for this name string label = originalExpression + "+0"; validLabel = _labelManager->ContainsLabel(label); } - if(validLabel) { + if (validLabel) + { data.Labels.push_back(originalExpression); output += std::to_string(EvalValues::FirstLabelIndex + data.Labels.size() - 1); return true; - } else { + } + else + { return false; } } int64_t ExpressionEvaluator::ProcessCpuSpcTokens(string token, bool spc700) { - if(token == "a") { + if (token == "a") + { return EvalValues::RegA; - } else if(token == "x") { + } + else if (token == "x") + { return EvalValues::RegX; - } else if(token == "y") { + } + else if (token == "y") + { return EvalValues::RegY; - } else if(token == "ps") { + } + else if (token == "ps") + { return EvalValues::RegPS; - } else if (token == "pscarry") { + } + else if (token == "pscarry") + { return EvalValues::RegPS_Carry; - } else if (token == "pszero") { + } + else if (token == "pszero") + { return EvalValues::RegPS_Zero; - } else if (token == "psinterrupt") { + } + else if (token == "psinterrupt") + { return EvalValues::RegPS_Interrupt; - } else if (token == "psdecimal") { + } + else if (token == "psdecimal") + { return EvalValues::RegPS_Decimal; - } else if (token == "psoverflow") { + } + else if (token == "psoverflow") + { return EvalValues::RegPS_Overflow; - } else if (token == "psnegative") { + } + else if (token == "psnegative") + { return EvalValues::RegPS_Negative; - } else if (token == "ps8bit" && !spc700) { + } + else if (token == "ps8bit" && !spc700) + { return EvalValues::RegPS_8bit; - } else if (token == "ps8bitindex" && !spc700) { + } + else if (token == "ps8bitindex" && !spc700) + { return EvalValues::RegPS_8bitIndex; - } else if (token == "ps16bit" && !spc700) { + } + else if (token == "ps16bit" && !spc700) + { return EvalValues::RegPS_16bit; - } else if (token == "ps16bitindex" && !spc700) { + } + else if (token == "ps16bitindex" && !spc700) + { return EvalValues::RegPS_16bitIndex; - } else if (token == "pshalfcarry" && spc700) { + } + else if (token == "pshalfcarry" && spc700) + { return EvalValues::RegPS_HalfCarry; - } else if (token == "psbreak" && spc700) { + } + else if (token == "psbreak" && spc700) + { return EvalValues::RegPS_Break; - } else if (token == "psstackzp" && spc700) { + } + else if (token == "psstackzp" && spc700) + { return EvalValues::RegPS_StackZeropage; - } else if(token == "sp") { + } + else if (token == "sp") + { return EvalValues::RegSP; - } else if(token == "pc") { + } + else if (token == "pc") + { return EvalValues::RegPC; - } else if(token == "oppc") { + } + else if (token == "oppc") + { return EvalValues::RegOpPC; - } else if(token == "previousoppc") { + } + else if (token == "previousoppc") + { return EvalValues::PreviousOpPC; - } else if(token == "irq") { + } + else if (token == "irq") + { return EvalValues::Irq; - } else if(token == "nmi") { + } + else if (token == "nmi") + { return EvalValues::Nmi; } return -1; } -int64_t ExpressionEvaluator::ProcessSharedTokens(string token) +int64_t ExpressionEvaluator::ProcessSharedTokens(string token) { - if(token == "frame") { + if (token == "frame") + { return EvalValues::PpuFrameCount; - } else if(token == "cycle") { + } + else if (token == "cycle") + { return EvalValues::PpuCycle; - } else if(token == "scanline") { + } + else if (token == "scanline") + { return EvalValues::PpuScanline; - } else if(token == "value") { + } + else if (token == "value") + { return EvalValues::Value; - } else if(token == "address") { + } + else if (token == "address") + { return EvalValues::Address; - } else if(token == "romaddress") { + } + else if (token == "romaddress") + { return EvalValues::AbsoluteAddress; - } else if(token == "iswrite") { + } + else if (token == "iswrite") + { return EvalValues::IsWrite; - } else if(token == "isread") { + } + else if (token == "isread") + { return EvalValues::IsRead; } return -1; @@ -186,49 +286,92 @@ int64_t ExpressionEvaluator::ProcessSharedTokens(string token) int64_t ExpressionEvaluator::ProcessGsuTokens(string token) { - if(token == "r0") { + if (token == "r0") + { return EvalValues::R0; - } else if(token == "r1") { + } + else if (token == "r1") + { return EvalValues::R1; - } else if(token == "r2") { + } + else if (token == "r2") + { return EvalValues::R2; - } else if(token == "r3") { + } + else if (token == "r3") + { return EvalValues::R3; - } else if(token == "r4") { + } + else if (token == "r4") + { return EvalValues::R4; - } else if(token == "r5") { + } + else if (token == "r5") + { return EvalValues::R5; - } else if(token == "r6") { + } + else if (token == "r6") + { return EvalValues::R6; - } else if(token == "r7") { + } + else if (token == "r7") + { return EvalValues::R7; - } else if(token == "r8") { + } + else if (token == "r8") + { return EvalValues::R8; - } else if(token == "r9") { + } + else if (token == "r9") + { return EvalValues::R9; - } else if(token == "r10") { + } + else if (token == "r10") + { return EvalValues::R10; - } else if(token == "r11") { + } + else if (token == "r11") + { return EvalValues::R11; - } else if(token == "r12") { + } + else if (token == "r12") + { return EvalValues::R12; - } else if(token == "r13") { + } + else if (token == "r13") + { return EvalValues::R13; - } else if(token == "r14") { + } + else if (token == "r14") + { return EvalValues::R14; - } else if(token == "r15") { + } + else if (token == "r15") + { return EvalValues::R15; - } else if(token == "srcreg") { + } + else if (token == "srcreg") + { return EvalValues::SrcReg; - } else if(token == "dstreg") { + } + else if (token == "dstreg") + { return EvalValues::DstReg; - } else if(token == "sfr") { + } + else if (token == "sfr") + { return EvalValues::SFR; - } else if(token == "pbr") { + } + else if (token == "pbr") + { return EvalValues::PBR; - } else if(token == "rombr") { + } + else if (token == "rombr") + { return EvalValues::RomBR; - } else if(token == "rambr") { + } + else if (token == "rambr") + { return EvalValues::RamBR; } return -1; @@ -237,129 +380,190 @@ int64_t ExpressionEvaluator::ProcessGsuTokens(string token) int64_t ExpressionEvaluator::ProcessGameboyTokens(string token) { - if(token == "a") { + if (token == "a") + { return EvalValues::RegA; - } else if(token == "b") { + } + else if (token == "b") + { return EvalValues::RegB; - } else if(token == "c") { + } + else if (token == "c") + { return EvalValues::RegC; - } else if(token == "d") { + } + else if (token == "d") + { return EvalValues::RegD; - } else if(token == "e") { + } + else if (token == "e") + { return EvalValues::RegE; - } else if(token == "f") { + } + else if (token == "f") + { return EvalValues::RegF; - } else if(token == "h") { + } + else if (token == "h") + { return EvalValues::RegH; - } else if(token == "l") { + } + else if (token == "l") + { return EvalValues::RegL; - } else if(token == "af") { + } + else if (token == "af") + { return EvalValues::RegAF; - } else if(token == "bc") { + } + else if (token == "bc") + { return EvalValues::RegBC; - } else if(token == "de") { + } + else if (token == "de") + { return EvalValues::RegDE; - } else if(token == "hl") { + } + else if (token == "hl") + { return EvalValues::RegHL; - } else if(token == "sp") { + } + else if (token == "sp") + { return EvalValues::RegSP; - } else if(token == "pc") { + } + else if (token == "pc") + { return EvalValues::RegPC; } return -1; } -string ExpressionEvaluator::GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success, bool previousTokenIsOp) +string ExpressionEvaluator::GetNextToken(string expression, size_t& pos, ExpressionData& data, bool& success, + bool previousTokenIsOp) { string output; success = true; char c = std::tolower(expression[pos]); - if(c == '$') { + if (c == '$') + { //Hex numbers pos++; - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); - if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) + { output += c; - } else { + } + else + { break; } } - if(output.empty()) { + if (output.empty()) + { //No numbers followed the hex mark, this isn't a valid expression success = false; } output = std::to_string((uint32_t)HexUtilities::FromHex(output)); - } else if(c == '%' && previousTokenIsOp) { + } + else if (c == '%' && previousTokenIsOp) + { //Binary numbers pos++; - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); - if(c == '0' || c == '1') { + if (c == '0' || c == '1') + { output += c; - } else { + } + else + { break; } } - if(output.empty()) { + if (output.empty()) + { //No numbers followed the binary mark, this isn't a valid expression success = false; } uint32_t value = 0; - for(size_t i = 0; i < output.size(); i++) { + for (size_t i = 0; i < output.size(); i++) + { value <<= 1; value |= output[i] == '1' ? 1 : 0; } output = std::to_string(value); - } else if(c >= '0' && c <= '9') { + } + else if (c >= '0' && c <= '9') + { //Regular numbers - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); - if(c >= '0' && c <= '9') { + if (c >= '0' && c <= '9') + { output += c; - } else { + } + else + { break; } } - } else if((c < 'a' || c > 'z') && c != '_' && c != '@') { + } + else if ((c < 'a' || c > 'z') && c != '_' && c != '@') + { //Operators string operatorToken; - for(size_t len = expression.size(); pos < len; pos++) { + for (size_t len = expression.size(); pos < len; pos++) + { c = std::tolower(expression[pos]); operatorToken += c; - if(output.empty() || _operators.find(operatorToken) != _operators.end()) { + if (output.empty() || _operators.find(operatorToken) != _operators.end()) + { //If appending the next char results in a valid operator, append it (or if this is the first character) output += c; - } else { + } + else + { //Reached the end of the operator, return break; } } - } else { + } + else + { //Special tokens and labels success = CheckSpecialTokens(expression, pos, output, data); } return output; } - -bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue) + +bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack& opStack, + std::stack& precedenceStack, vector& outputQueue) { - if(opStack.empty()) { + if (opStack.empty()) + { return false; } - while(opStack.top() != evalOp) { + while (opStack.top() != evalOp) + { outputQueue.push_back(opStack.top()); opStack.pop(); precedenceStack.pop(); - if(opStack.empty()) { + if (opStack.empty()) + { return false; } } - if(evalOp != EvalOperators::Parenthesis) { + if (evalOp != EvalOperators::Parenthesis) + { outputQueue.push_back(opStack.top()); } opStack.pop(); @@ -368,9 +572,9 @@ bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stac return true; } -bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) +bool ExpressionEvaluator::ToRpn(string expression, ExpressionData& data) { - std::stack opStack = std::stack(); + std::stack opStack = std::stack(); std::stack precedenceStack; size_t position = 0; @@ -381,30 +585,36 @@ bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) bool previousTokenIsOp = true; bool operatorExpected = false; bool operatorOrEndTokenExpected = false; - while(true) { + while (true) + { bool success = true; string token = GetNextToken(expression, position, data, success, previousTokenIsOp); - if(!success) { + if (!success) + { return false; } - if(token.empty()) { + if (token.empty()) + { break; } bool requireOperator = operatorExpected; bool requireOperatorOrEndToken = operatorOrEndTokenExpected; bool unaryOperator = previousTokenIsOp; - + operatorExpected = false; operatorOrEndTokenExpected = false; previousTokenIsOp = false; - + int precedence = 0; - if(IsOperator(token, precedence, unaryOperator)) { + if (IsOperator(token, precedence, unaryOperator)) + { EvalOperators op = GetOperator(token, unaryOperator); bool rightAssociative = unaryOperator; - while(!opStack.empty() && ((rightAssociative && precedence < precedenceStack.top()) || (!rightAssociative && precedence <= precedenceStack.top()))) { + while (!opStack.empty() && ((rightAssociative && precedence < precedenceStack.top()) || (!rightAssociative && + precedence <= precedenceStack.top()))) + { //Pop operators from the stack until we find something with higher priority (or empty the stack) data.RpnQueue.push_back(opStack.top()); opStack.pop(); @@ -414,59 +624,85 @@ bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) precedenceStack.push(precedence); previousTokenIsOp = true; - } else if(requireOperator) { + } + else if (requireOperator) + { //We needed an operator, and got something else, this isn't a valid expression (e.g "(3)4" or "[$00]22") return false; - } else if(requireOperatorOrEndToken && token[0] != ')' && token[0] != ']' && token[0] != '}') { + } + else if (requireOperatorOrEndToken && token[0] != ')' && token[0] != ']' && token[0] != '}') + { //We needed an operator or close token - this isn't a valid expression (e.g "%1134") return false; - } else if(token[0] == '(') { + } + else if (token[0] == '(') + { parenthesisCount++; opStack.push(EvalOperators::Parenthesis); precedenceStack.push(0); previousTokenIsOp = true; - } else if(token[0] == ')') { + } + else if (token[0] == ')') + { parenthesisCount--; - if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, data.RpnQueue)) { + if (!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, data.RpnQueue)) + { return false; } operatorOrEndTokenExpected = true; - } else if(token[0] == '[') { + } + else if (token[0] == '[') + { bracketCount++; opStack.push(EvalOperators::Bracket); precedenceStack.push(0); - } else if(token[0] == ']') { + } + else if (token[0] == ']') + { bracketCount--; - if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, data.RpnQueue)) { + if (!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, data.RpnQueue)) + { return false; } operatorOrEndTokenExpected = true; - } else if(token[0] == '{') { + } + else if (token[0] == '{') + { braceCount++; opStack.push(EvalOperators::Braces); precedenceStack.push(0); - } else if(token[0] == '}') { + } + else if (token[0] == '}') + { braceCount--; - if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, data.RpnQueue)){ + if (!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, data.RpnQueue)) + { return false; } operatorOrEndTokenExpected = true; - } else { - if(token[0] < '0' || token[0] > '9') { + } + else + { + if (token[0] < '0' || token[0] > '9') + { return false; - } else { + } + else + { data.RpnQueue.push_back(std::stoll(token)); operatorOrEndTokenExpected = true; } } } - if(braceCount || bracketCount || parenthesisCount) { + if (braceCount || bracketCount || parenthesisCount) + { //Mismatching number of brackets/braces/parenthesis return false; } - while(!opStack.empty()) { + while (!opStack.empty()) + { data.RpnQueue.push_back(opStack.top()); opStack.pop(); } @@ -474,9 +710,11 @@ bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) return true; } -int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo) +int32_t ExpressionEvaluator::Evaluate(ExpressionData& data, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo) { - if(data.RpnQueue.empty()) { + if (data.RpnQueue.empty()) + { resultType = EvalResultType::Invalid; return 0; } @@ -486,188 +724,325 @@ int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, E int64_t left = 0; resultType = EvalResultType::Numeric; - for(size_t i = 0, len = data.RpnQueue.size(); i < len; i++) { + for (size_t i = 0, len = data.RpnQueue.size(); i < len; i++) + { int64_t token = data.RpnQueue[i]; - if(token >= EvalValues::RegA) { + if (token >= EvalValues::RegA) + { //Replace value with a special value - if(token >= EvalValues::FirstLabelIndex) { + if (token >= EvalValues::FirstLabelIndex) + { int64_t labelIndex = token - EvalValues::FirstLabelIndex; - if((size_t)labelIndex < data.Labels.size()) { + if ((size_t)labelIndex < data.Labels.size()) + { token = _labelManager->GetLabelRelativeAddress(data.Labels[(uint32_t)labelIndex], _cpuType); - if(token < -1) { + if (token < -1) + { //Label doesn't exist, try to find a matching multi-byte label string label = data.Labels[(uint32_t)labelIndex] + "+0"; token = _labelManager->GetLabelRelativeAddress(label, _cpuType); } - } else { + } + else + { token = -2; } - if(token < 0) { + if (token < 0) + { //Label is no longer valid resultType = token == -1 ? EvalResultType::OutOfScope : EvalResultType::Invalid; return 0; } - } else { - switch(token) { + } + else + { + switch (token) + { /*case EvalValues::RegOpPC: token = state.Cpu.DebugPC; break;*/ - case EvalValues::PpuFrameCount: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.FrameCount : state.Ppu.FrameCount; break; - case EvalValues::PpuCycle: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.Cycle : state.Ppu.Cycle; break; - case EvalValues::PpuScanline: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.Scanline : state.Ppu.Scanline; break; - case EvalValues::Value: token = operationInfo.Value; break; - case EvalValues::Address: token = operationInfo.Address; break; + case EvalValues::PpuFrameCount: token = _cpuType == CpuType::Gameboy + ? state.Gameboy.Ppu.FrameCount + : state.Ppu.FrameCount; + break; + case EvalValues::PpuCycle: token = _cpuType == CpuType::Gameboy ? state.Gameboy.Ppu.Cycle : state.Ppu.Cycle; + break; + case EvalValues::PpuScanline: token = _cpuType == CpuType::Gameboy + ? state.Gameboy.Ppu.Scanline + : state.Ppu.Scanline; + break; + case EvalValues::Value: token = operationInfo.Value; + break; + case EvalValues::Address: token = operationInfo.Address; + break; //case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(operationInfo.Address); break; - case EvalValues::IsWrite: token = operationInfo.Type == MemoryOperationType::Write || operationInfo.Type == MemoryOperationType::DmaWrite; break; - case EvalValues::IsRead: token = operationInfo.Type != MemoryOperationType::Write && operationInfo.Type != MemoryOperationType::DmaWrite; break; + case EvalValues::IsWrite: token = operationInfo.Type == MemoryOperationType::Write || operationInfo.Type == + MemoryOperationType::DmaWrite; + break; + case EvalValues::IsRead: token = operationInfo.Type != MemoryOperationType::Write && operationInfo.Type != + MemoryOperationType::DmaWrite; + break; //case EvalValues::PreviousOpPC: token = state.CPU.PreviousDebugPC; break; - default: - switch(_cpuType) { - case CpuType::Cpu: - case CpuType::Sa1: - switch(token) { - case EvalValues::RegA: token = state.Cpu.A; break; - case EvalValues::RegX: token = state.Cpu.X; break; - case EvalValues::RegY: token = state.Cpu.Y; break; - case EvalValues::RegSP: token = state.Cpu.SP; break; - case EvalValues::RegPS: token = state.Cpu.PS; break; - case EvalValues::RegPC: token = state.Cpu.PC; break; - case EvalValues::Nmi: token = state.Cpu.NmiFlag; resultType = EvalResultType::Boolean; break; - case EvalValues::Irq: token = state.Cpu.IrqSource != 0; resultType = EvalResultType::Boolean; break; - case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; break; - case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; break; - case EvalValues::RegPS_Interrupt: token = (state.Cpu.PS & 4) != 0; break; - case EvalValues::RegPS_Decimal: token = (state.Cpu.PS & 8) != 0; break; - case EvalValues::RegPS_8bitIndex: token = (state.Cpu.PS & 16) != 0; break; - case EvalValues::RegPS_8bit: token = (state.Cpu.PS & 32) != 0; break; - case EvalValues::RegPS_16bitIndex: token = (state.Cpu.PS & 16) == 0; break; - case EvalValues::RegPS_16bit: token = (state.Cpu.PS & 32) == 0; break; - case EvalValues::RegPS_Overflow: token = (state.Cpu.PS & 64) != 0; break; - case EvalValues::RegPS_Negative: token = (state.Cpu.PS & 128) != 0; break; - } - break; - - case CpuType::Spc: - switch(token) { - case EvalValues::RegA: token = state.Spc.A; break; - case EvalValues::RegX: token = state.Spc.X; break; - case EvalValues::RegY: token = state.Spc.Y; break; - case EvalValues::RegSP: token = state.Spc.SP; break; - case EvalValues::RegPS: token = state.Spc.PS; break; - case EvalValues::RegPC: token = state.Spc.PC; break; - case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; break; - case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; break; - case EvalValues::RegPS_Interrupt: (state.Cpu.PS & 4) != 0; break; - case EvalValues::RegPS_HalfCarry: (state.Cpu.PS & 8) != 0; break; - case EvalValues::RegPS_Break: (state.Cpu.PS & 16) != 0; break; - case EvalValues::RegPS_StackZeropage: (state.Cpu.PS & 32) != 0; break; - case EvalValues::RegPS_Overflow: (state.Cpu.PS & 64) != 0; break; - case EvalValues::RegPS_Negative: (state.Cpu.PS & 128) != 0; break; - } - break; - - case CpuType::Gameboy: - switch(token) { - case EvalValues::RegA: token = state.Gameboy.Cpu.A; break; - case EvalValues::RegB: token = state.Gameboy.Cpu.B; break; - case EvalValues::RegC: token = state.Gameboy.Cpu.C; break; - case EvalValues::RegD: token = state.Gameboy.Cpu.D; break; - case EvalValues::RegE: token = state.Gameboy.Cpu.E; break; - case EvalValues::RegF: token = state.Gameboy.Cpu.Flags; break; - case EvalValues::RegH: token = state.Gameboy.Cpu.H; break; - case EvalValues::RegL: token = state.Gameboy.Cpu.L; break; - case EvalValues::RegAF: token = (state.Gameboy.Cpu.A << 8) | state.Gameboy.Cpu.Flags; break; - case EvalValues::RegBC: token = (state.Gameboy.Cpu.B << 8) | state.Gameboy.Cpu.C; break; - case EvalValues::RegDE: token = (state.Gameboy.Cpu.D << 8) | state.Gameboy.Cpu.E; break; - case EvalValues::RegHL: token = (state.Gameboy.Cpu.H << 8) | state.Gameboy.Cpu.L; break; - case EvalValues::RegSP: token = state.Gameboy.Cpu.SP; break; - case EvalValues::RegPC: token = state.Gameboy.Cpu.PC; break; - } - break; - - case CpuType::Gsu: - switch(token) { - case EvalValues::R0: token = state.Gsu.R[0]; break; - case EvalValues::R1: token = state.Gsu.R[1]; break; - case EvalValues::R2: token = state.Gsu.R[2]; break; - case EvalValues::R3: token = state.Gsu.R[3]; break; - case EvalValues::R4: token = state.Gsu.R[4]; break; - case EvalValues::R5: token = state.Gsu.R[5]; break; - case EvalValues::R6: token = state.Gsu.R[6]; break; - case EvalValues::R7: token = state.Gsu.R[7]; break; - case EvalValues::R8: token = state.Gsu.R[8]; break; - case EvalValues::R9: token = state.Gsu.R[9]; break; - case EvalValues::R10: token = state.Gsu.R[10]; break; - case EvalValues::R11: token = state.Gsu.R[11]; break; - case EvalValues::R12: token = state.Gsu.R[12]; break; - case EvalValues::R13: token = state.Gsu.R[13]; break; - case EvalValues::R14: token = state.Gsu.R[14]; break; - case EvalValues::R15: token = state.Gsu.R[15]; break; - - case EvalValues::SrcReg: token = state.Gsu.SrcReg; break; - case EvalValues::DstReg: token = state.Gsu.DestReg; break; - - case EvalValues::SFR: token = (state.Gsu.SFR.GetFlagsHigh() << 8) | state.Gsu.SFR.GetFlagsLow(); break; - case EvalValues::PBR: token = state.Gsu.ProgramBank; break; - case EvalValues::RomBR: token = state.Gsu.RomBank; break; - case EvalValues::RamBR: token = state.Gsu.RamBank; break; - } - break; - - case CpuType::NecDsp: - case CpuType::Cx4: - throw std::runtime_error("Invalid CPU type"); + default: + switch (_cpuType) + { + case CpuType::Cpu: + case CpuType::Sa1: + switch (token) + { + case EvalValues::RegA: token = state.Cpu.A; + break; + case EvalValues::RegX: token = state.Cpu.X; + break; + case EvalValues::RegY: token = state.Cpu.Y; + break; + case EvalValues::RegSP: token = state.Cpu.SP; + break; + case EvalValues::RegPS: token = state.Cpu.PS; + break; + case EvalValues::RegPC: token = state.Cpu.PC; + break; + case EvalValues::Nmi: token = state.Cpu.NmiFlag; + resultType = EvalResultType::Boolean; + break; + case EvalValues::Irq: token = state.Cpu.IrqSource != 0; + resultType = EvalResultType::Boolean; + break; + case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; + break; + case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; + break; + case EvalValues::RegPS_Interrupt: token = (state.Cpu.PS & 4) != 0; + break; + case EvalValues::RegPS_Decimal: token = (state.Cpu.PS & 8) != 0; + break; + case EvalValues::RegPS_8bitIndex: token = (state.Cpu.PS & 16) != 0; + break; + case EvalValues::RegPS_8bit: token = (state.Cpu.PS & 32) != 0; + break; + case EvalValues::RegPS_16bitIndex: token = (state.Cpu.PS & 16) == 0; + break; + case EvalValues::RegPS_16bit: token = (state.Cpu.PS & 32) == 0; + break; + case EvalValues::RegPS_Overflow: token = (state.Cpu.PS & 64) != 0; + break; + case EvalValues::RegPS_Negative: token = (state.Cpu.PS & 128) != 0; + break; } break; + + case CpuType::Spc: + switch (token) + { + case EvalValues::RegA: token = state.Spc.A; + break; + case EvalValues::RegX: token = state.Spc.X; + break; + case EvalValues::RegY: token = state.Spc.Y; + break; + case EvalValues::RegSP: token = state.Spc.SP; + break; + case EvalValues::RegPS: token = state.Spc.PS; + break; + case EvalValues::RegPC: token = state.Spc.PC; + break; + case EvalValues::RegPS_Carry: token = (state.Cpu.PS & 1) != 0; + break; + case EvalValues::RegPS_Zero: token = (state.Cpu.PS & 2) != 0; + break; + case EvalValues::RegPS_Interrupt: (state.Cpu.PS & 4) != 0; + break; + case EvalValues::RegPS_HalfCarry: (state.Cpu.PS & 8) != 0; + break; + case EvalValues::RegPS_Break: (state.Cpu.PS & 16) != 0; + break; + case EvalValues::RegPS_StackZeropage: (state.Cpu.PS & 32) != 0; + break; + case EvalValues::RegPS_Overflow: (state.Cpu.PS & 64) != 0; + break; + case EvalValues::RegPS_Negative: (state.Cpu.PS & 128) != 0; + break; + } + break; + + case CpuType::Gameboy: + switch (token) + { + case EvalValues::RegA: token = state.Gameboy.Cpu.A; + break; + case EvalValues::RegB: token = state.Gameboy.Cpu.B; + break; + case EvalValues::RegC: token = state.Gameboy.Cpu.C; + break; + case EvalValues::RegD: token = state.Gameboy.Cpu.D; + break; + case EvalValues::RegE: token = state.Gameboy.Cpu.E; + break; + case EvalValues::RegF: token = state.Gameboy.Cpu.Flags; + break; + case EvalValues::RegH: token = state.Gameboy.Cpu.H; + break; + case EvalValues::RegL: token = state.Gameboy.Cpu.L; + break; + case EvalValues::RegAF: token = (state.Gameboy.Cpu.A << 8) | state.Gameboy.Cpu.Flags; + break; + case EvalValues::RegBC: token = (state.Gameboy.Cpu.B << 8) | state.Gameboy.Cpu.C; + break; + case EvalValues::RegDE: token = (state.Gameboy.Cpu.D << 8) | state.Gameboy.Cpu.E; + break; + case EvalValues::RegHL: token = (state.Gameboy.Cpu.H << 8) | state.Gameboy.Cpu.L; + break; + case EvalValues::RegSP: token = state.Gameboy.Cpu.SP; + break; + case EvalValues::RegPC: token = state.Gameboy.Cpu.PC; + break; + } + break; + + case CpuType::Gsu: + switch (token) + { + case EvalValues::R0: token = state.Gsu.R[0]; + break; + case EvalValues::R1: token = state.Gsu.R[1]; + break; + case EvalValues::R2: token = state.Gsu.R[2]; + break; + case EvalValues::R3: token = state.Gsu.R[3]; + break; + case EvalValues::R4: token = state.Gsu.R[4]; + break; + case EvalValues::R5: token = state.Gsu.R[5]; + break; + case EvalValues::R6: token = state.Gsu.R[6]; + break; + case EvalValues::R7: token = state.Gsu.R[7]; + break; + case EvalValues::R8: token = state.Gsu.R[8]; + break; + case EvalValues::R9: token = state.Gsu.R[9]; + break; + case EvalValues::R10: token = state.Gsu.R[10]; + break; + case EvalValues::R11: token = state.Gsu.R[11]; + break; + case EvalValues::R12: token = state.Gsu.R[12]; + break; + case EvalValues::R13: token = state.Gsu.R[13]; + break; + case EvalValues::R14: token = state.Gsu.R[14]; + break; + case EvalValues::R15: token = state.Gsu.R[15]; + break; + + case EvalValues::SrcReg: token = state.Gsu.SrcReg; + break; + case EvalValues::DstReg: token = state.Gsu.DestReg; + break; + + case EvalValues::SFR: token = (state.Gsu.SFR.GetFlagsHigh() << 8) | state.Gsu.SFR.GetFlagsLow(); + break; + case EvalValues::PBR: token = state.Gsu.ProgramBank; + break; + case EvalValues::RomBR: token = state.Gsu.RomBank; + break; + case EvalValues::RamBR: token = state.Gsu.RamBank; + break; + } + break; + + case CpuType::NecDsp: + case CpuType::Cx4: + throw std::runtime_error("Invalid CPU type"); + } + break; } } - } else if(token >= EvalOperators::Multiplication) { + } + else if (token >= EvalOperators::Multiplication) + { right = operandStack[--pos]; - if(pos > 0 && token <= EvalOperators::LogicalOr) { + if (pos > 0 && token <= EvalOperators::LogicalOr) + { //Only do this for binary operators left = operandStack[--pos]; } resultType = EvalResultType::Numeric; - switch(token) { - case EvalOperators::Multiplication: token = left * right; break; - case EvalOperators::Division: - if(right == 0) { - resultType = EvalResultType::DivideBy0; - return 0; - } - token = left / right; break; - case EvalOperators::Modulo: - if(right == 0) { - resultType = EvalResultType::DivideBy0; - return 0; - } - token = left % right; - break; - case EvalOperators::Addition: token = left + right; break; - case EvalOperators::Substration: token = left - right; break; - case EvalOperators::ShiftLeft: token = left << right; break; - case EvalOperators::ShiftRight: token = left >> right; break; - case EvalOperators::SmallerThan: token = left < right; resultType = EvalResultType::Boolean; break; - case EvalOperators::SmallerOrEqual: token = left <= right; resultType = EvalResultType::Boolean; break; - case EvalOperators::GreaterThan: token = left > right; resultType = EvalResultType::Boolean; break; - case EvalOperators::GreaterOrEqual: token = left >= right; resultType = EvalResultType::Boolean; break; - case EvalOperators::Equal: token = left == right; resultType = EvalResultType::Boolean; break; - case EvalOperators::NotEqual: token = left != right; resultType = EvalResultType::Boolean; break; - case EvalOperators::BinaryAnd: token = left & right; break; - case EvalOperators::BinaryXor: token = left ^ right; break; - case EvalOperators::BinaryOr: token = left | right; break; - case EvalOperators::LogicalAnd: token = left && right; resultType = EvalResultType::Boolean; break; - case EvalOperators::LogicalOr: token = left || right; resultType = EvalResultType::Boolean; break; + switch (token) + { + case EvalOperators::Multiplication: token = left * right; + break; + case EvalOperators::Division: + if (right == 0) + { + resultType = EvalResultType::DivideBy0; + return 0; + } + token = left / right; + break; + case EvalOperators::Modulo: + if (right == 0) + { + resultType = EvalResultType::DivideBy0; + return 0; + } + token = left % right; + break; + case EvalOperators::Addition: token = left + right; + break; + case EvalOperators::Substration: token = left - right; + break; + case EvalOperators::ShiftLeft: token = left << right; + break; + case EvalOperators::ShiftRight: token = left >> right; + break; + case EvalOperators::SmallerThan: token = left < right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::SmallerOrEqual: token = left <= right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::GreaterThan: token = left > right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::GreaterOrEqual: token = left >= right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::Equal: token = left == right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::NotEqual: token = left != right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::BinaryAnd: token = left & right; + break; + case EvalOperators::BinaryXor: token = left ^ right; + break; + case EvalOperators::BinaryOr: token = left | right; + break; + case EvalOperators::LogicalAnd: token = left && right; + resultType = EvalResultType::Boolean; + break; + case EvalOperators::LogicalOr: token = left || right; + resultType = EvalResultType::Boolean; + break; //Unary operators - case EvalOperators::Plus: token = right; break; - case EvalOperators::Minus: token = -right; break; - case EvalOperators::BinaryNot: token = ~right; break; - case EvalOperators::LogicalNot: token = !right; break; - case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(_cpuMemory, (uint32_t)right); break; - case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(_cpuMemory, (uint32_t)right); break; - default: throw std::runtime_error("Invalid operator"); + case EvalOperators::Plus: token = right; + break; + case EvalOperators::Minus: token = -right; + break; + case EvalOperators::BinaryNot: token = ~right; + break; + case EvalOperators::LogicalNot: token = !right; + break; + case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(_cpuMemory, (uint32_t)right); + break; + case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord( + _cpuMemory, (uint32_t)right); + break; + default: throw std::runtime_error("Invalid operator"); } } operandStack[pos++] = token; @@ -683,67 +1058,82 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger, CpuType cpuType) _cpuMemory = DebugUtilities::GetCpuMemoryType(cpuType); } -ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool &success) +ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool& success) { ExpressionData* cachedData = PrivateGetRpnList(expression, success); - if(cachedData) { + if (cachedData) + { return *cachedData; - } else { + } + else + { return ExpressionData(); } } ExpressionData* ExpressionEvaluator::PrivateGetRpnList(string expression, bool& success) { - ExpressionData *cachedData = nullptr; + ExpressionData* cachedData = nullptr; { LockHandler lock = _cacheLock.AcquireSafe(); auto result = _cache.find(expression); - if(result != _cache.end()) { + if (result != _cache.end()) + { cachedData = &(result->second); } } - if(cachedData == nullptr) { + if (cachedData == nullptr) + { string fixedExp = expression; fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end()); ExpressionData data; success = ToRpn(fixedExp, data); - if(success) { + if (success) + { LockHandler lock = _cacheLock.AcquireSafe(); _cache[expression] = data; cachedData = &_cache[expression]; } - } else { + } + else + { success = true; } return cachedData; } -int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo, bool& success) +int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo, bool& success) { success = true; - ExpressionData *cachedData = PrivateGetRpnList(expression, success); + ExpressionData* cachedData = PrivateGetRpnList(expression, success); - if(!success) { + if (!success) + { resultType = EvalResultType::Invalid; return 0; } - return Evaluate(*cachedData, state, resultType, operationInfo); + return Evaluate(*cachedData, state, resultType, operationInfo); } -int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo) +int32_t ExpressionEvaluator::Evaluate(string expression, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo) { - try { + try + { bool success; int32_t result = PrivateEvaluate(expression, state, resultType, operationInfo, success); - if(success) { + if (success) + { return result; } - } catch(std::exception&) { + } + catch (std::exception&) + { } resultType = EvalResultType::Invalid; return 0; @@ -751,33 +1141,38 @@ int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, Eval bool ExpressionEvaluator::Validate(string expression) { - try { + try + { DebugState state; EvalResultType type; MemoryOperationInfo operationInfo; bool success; PrivateEvaluate(expression, state, type, operationInfo, success); return success; - } catch(std::exception&) { + } + catch (std::exception&) + { return false; } } #if _DEBUG #include + void ExpressionEvaluator::RunTests() { //Some basic unit tests to run in debug mode - auto test = [=](string expr, EvalResultType expectedType, int expectedResult) { - DebugState state = { 0 }; - MemoryOperationInfo opInfo { 0, 0, MemoryOperationType::Read }; + auto test = [=](string expr, EvalResultType expectedType, int expectedResult) + { + DebugState state = {0}; + MemoryOperationInfo opInfo{0, 0, MemoryOperationType::Read}; EvalResultType type; int32_t result = Evaluate(expr, state, type, opInfo); assert(type == expectedType); assert(result == expectedResult); }; - + test("1 - -1", EvalResultType::Numeric, 2); test("1 - (-1)", EvalResultType::Numeric, 2); test("1 - -(-1)", EvalResultType::Numeric, 0); @@ -808,11 +1203,11 @@ void ExpressionEvaluator::RunTests() test("{$4500}", EvalResultType::Numeric, 0x4545); test("[$4500]", EvalResultType::Numeric, 0x45); - + test("[$45]3", EvalResultType::Invalid, 0); test("($45)3", EvalResultType::Invalid, 0); test("($45]", EvalResultType::Invalid, 0); - + test("%11", EvalResultType::Numeric, 3); test("%011", EvalResultType::Numeric, 3); test("%1011", EvalResultType::Numeric, 11); @@ -829,4 +1224,4 @@ void ExpressionEvaluator::RunTests() test("[$4500+[$4500]]", EvalResultType::Numeric, 0x45); test("-($10+[$4500])", EvalResultType::Numeric, -0x55); } -#endif \ No newline at end of file +#endif diff --git a/Core/ExpressionEvaluator.h b/Core/ExpressionEvaluator.h index 1821cee..9215138 100644 --- a/Core/ExpressionEvaluator.h +++ b/Core/ExpressionEvaluator.h @@ -39,8 +39,10 @@ enum EvalOperators : int64_t LogicalNot = 20000000053, //Used to read ram address - Bracket = 20000000054, //Read byte - Braces = 20000000055, //Read word + Bracket = 20000000054, + //Read byte + Braces = 20000000055, + //Read word //Special value, not used as an operator Parenthesis = 20000000100, @@ -133,7 +135,7 @@ enum class EvalResultType : int32_t class StringHasher { public: - size_t operator()(const std::string& t) const + size_t operator()(const std::string& t) const { //Quick hash for expressions - most are likely to have different lengths, and not expecting dozens of breakpoints, either, so this should be fine. return t.size(); @@ -157,36 +159,40 @@ private: std::unordered_map _cache; SimpleLock _cacheLock; - + int64_t operandStack[1000]; Debugger* _debugger; LabelManager* _labelManager; CpuType _cpuType; SnesMemoryType _cpuMemory; - bool IsOperator(string token, int &precedence, bool unaryOperator); + bool IsOperator(string token, int& precedence, bool unaryOperator); EvalOperators GetOperator(string token, bool unaryOperator); - bool CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data); + bool CheckSpecialTokens(string expression, size_t& pos, string& output, ExpressionData& data); int64_t ProcessCpuSpcTokens(string token, bool spc); int64_t ProcessSharedTokens(string token); int64_t ProcessGsuTokens(string token); int64_t ProcessGameboyTokens(string token); - string GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success, bool previousTokenIsOp); - bool ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue); - bool ToRpn(string expression, ExpressionData &data); - int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo, bool &success); + string GetNextToken(string expression, size_t& pos, ExpressionData& data, bool& success, bool previousTokenIsOp); + bool ProcessSpecialOperator(EvalOperators evalOp, std::stack& opStack, + std::stack& precedenceStack, vector& outputQueue); + bool ToRpn(string expression, ExpressionData& data); + int32_t PrivateEvaluate(string expression, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo, bool& success); ExpressionData* PrivateGetRpnList(string expression, bool& success); public: ExpressionEvaluator(Debugger* debugger, CpuType cpuType); - int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo); - int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo); - ExpressionData GetRpnList(string expression, bool &success); + int32_t Evaluate(ExpressionData& data, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo); + int32_t Evaluate(string expression, DebugState& state, EvalResultType& resultType, + MemoryOperationInfo& operationInfo); + ExpressionData GetRpnList(string expression, bool& success); bool Validate(string expression); #if _DEBUG void RunTests(); #endif -}; \ No newline at end of file +}; diff --git a/Core/FirmwareHelper.h b/Core/FirmwareHelper.h index 43f6371..254c863 100644 --- a/Core/FirmwareHelper.h +++ b/Core/FirmwareHelper.h @@ -14,20 +14,29 @@ struct MissingFirmwareMessage class FirmwareHelper { private: - static bool AttemptLoadDspFirmware(string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector &programRom, vector &dataRom, uint32_t programSize, uint32_t dataSize) + static bool AttemptLoadDspFirmware(string combinedFilename, string splitFilenameProgram, string splitFilenameData, + vector& programRom, vector& dataRom, uint32_t programSize, + uint32_t dataSize) { - VirtualFile combinedFirmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), combinedFilename)); - if(combinedFirmware.GetSize() == programSize + dataSize) { + VirtualFile combinedFirmware( + FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), combinedFilename)); + if (combinedFirmware.GetSize() == programSize + dataSize) + { vector firmwareData; combinedFirmware.ReadFile(firmwareData); programRom.insert(programRom.end(), firmwareData.begin(), firmwareData.begin() + programSize); dataRom.insert(dataRom.end(), firmwareData.begin() + programSize, firmwareData.end()); return true; - } else { - VirtualFile splitFirmwareProg(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameProgram)); - VirtualFile splitFirmwareData(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameData)); + } + else + { + VirtualFile splitFirmwareProg( + FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameProgram)); + VirtualFile splitFirmwareData( + FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), splitFilenameData)); - if(splitFirmwareProg.GetSize() == programSize && splitFirmwareData.GetSize() == dataSize) { + if (splitFirmwareProg.GetSize() == programSize && splitFirmwareData.GetSize() == dataSize) + { splitFirmwareProg.ReadFile(programRom); splitFirmwareData.ReadFile(dataRom); return true; @@ -35,11 +44,12 @@ private: } return false; } - + static bool AttemptLoadBsxFirmware(uint8_t** prgRom, uint32_t& prgSize) { VirtualFile firmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), "BS-X.bin")); - if(firmware.IsValid() && firmware.GetSize() >= 0x8000) { + if (firmware.IsValid() && firmware.GetSize() >= 0x8000) + { *prgRom = new uint8_t[firmware.GetSize()]; prgSize = (uint32_t)firmware.GetSize(); firmware.ReadFile(*prgRom, (uint32_t)firmware.GetSize()); @@ -53,12 +63,14 @@ private: { string path = FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), filename); VirtualFile firmware(path); - if((!firmware.IsValid() || firmware.GetSize() != size) && !altFilename.empty()) { + if ((!firmware.IsValid() || firmware.GetSize() != size) && !altFilename.empty()) + { string altPath = FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), altFilename); firmware = VirtualFile(altPath); } - if(firmware.IsValid() && firmware.GetSize() == size) { + if (firmware.IsValid() && firmware.GetSize() == size) + { *out = new uint8_t[firmware.GetSize()]; firmware.ReadFile(*out, (uint32_t)firmware.GetSize()); return true; @@ -68,13 +80,20 @@ private: } public: - static bool LoadDspFirmware(Console *console, FirmwareType type, string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector &programRom, vector &dataRom, vector &embeddedFirware, uint32_t programSize = 0x1800, uint32_t dataSize = 0x800) + static bool LoadDspFirmware(Console* console, FirmwareType type, string combinedFilename, + string splitFilenameProgram, string splitFilenameData, vector& programRom, + vector& dataRom, vector& embeddedFirware, + uint32_t programSize = 0x1800, uint32_t dataSize = 0x800) { - if(embeddedFirware.size() == programSize + dataSize) { + if (embeddedFirware.size() == programSize + dataSize) + { programRom.insert(programRom.end(), embeddedFirware.begin(), embeddedFirware.begin() + programSize); dataRom.insert(dataRom.end(), embeddedFirware.begin() + programSize, embeddedFirware.end()); return true; - } else if(AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom, programSize, dataSize)) { + } + else if (AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom, + programSize, dataSize)) + { return true; } @@ -85,7 +104,9 @@ public: console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg); //Try again in case the user selected a valid firmware file - if(AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom, programSize, dataSize)) { + if (AttemptLoadDspFirmware(combinedFilename, splitFilenameProgram, splitFilenameData, programRom, dataRom, + programSize, dataSize)) + { return true; } @@ -95,17 +116,19 @@ public: static bool LoadBsxFirmware(Console* console, uint8_t** prgRom, uint32_t& prgSize) { - if(AttemptLoadBsxFirmware(prgRom, prgSize)) { + if (AttemptLoadBsxFirmware(prgRom, prgSize)) + { return true; } MissingFirmwareMessage msg; msg.Filename = "BS-X.bin"; msg.Firmware = FirmwareType::Satellaview; - msg.Size = 1024*1024; + msg.Size = 1024 * 1024; console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg); - - if(AttemptLoadBsxFirmware(prgRom, prgSize)) { + + if (AttemptLoadBsxFirmware(prgRom, prgSize)) + { return true; } @@ -117,7 +140,8 @@ public: { string filename = useSgb2 ? "SGB2.sfc" : "SGB1.sfc"; prgSize = useSgb2 ? 0x80000 : 0x40000; - if(AttemptLoadFirmware(prgRom, filename, prgSize)) { + if (AttemptLoadFirmware(prgRom, filename, prgSize)) + { return true; } @@ -127,7 +151,8 @@ public: msg.Size = prgSize; console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg); - if(AttemptLoadFirmware(prgRom, filename, prgSize)) { + if (AttemptLoadFirmware(prgRom, filename, prgSize)) + { return true; } @@ -139,16 +164,26 @@ public: { string filename; string altFilename; - switch(type) { - default: - case FirmwareType::Gameboy: filename = "dmg_boot.bin"; altFilename = "gb_bios.bin"; break; - case FirmwareType::GameboyColor: filename = "cgb_boot.bin"; altFilename = "gbc_bios.bin"; break; - case FirmwareType::Sgb1GameboyCpu: filename = "sgb_boot.bin"; altFilename = "sgb_bios.bin"; break; - case FirmwareType::Sgb2GameboyCpu: filename = "sgb2_boot.bin"; altFilename = "sgb_bios.bin"; break; + switch (type) + { + default: + case FirmwareType::Gameboy: filename = "dmg_boot.bin"; + altFilename = "gb_bios.bin"; + break; + case FirmwareType::GameboyColor: filename = "cgb_boot.bin"; + altFilename = "gbc_bios.bin"; + break; + case FirmwareType::Sgb1GameboyCpu: filename = "sgb_boot.bin"; + altFilename = "sgb_bios.bin"; + break; + case FirmwareType::Sgb2GameboyCpu: filename = "sgb2_boot.bin"; + altFilename = "sgb_bios.bin"; + break; } uint32_t size = type == FirmwareType::GameboyColor ? 2304 : 256; - if(AttemptLoadFirmware(bootRom, filename, size, altFilename)) { + if (AttemptLoadFirmware(bootRom, filename, size, altFilename)) + { return true; } @@ -165,4 +200,4 @@ public: MessageManager::DisplayMessage("Error", "Could not find boot rom: " + filename);*/ return false; } -}; \ No newline at end of file +}; diff --git a/Core/ForceDisconnectMessage.h b/Core/ForceDisconnectMessage.h index 3378c78..8d12575 100644 --- a/Core/ForceDisconnectMessage.h +++ b/Core/ForceDisconnectMessage.h @@ -11,13 +11,15 @@ private: string _disconnectMessage; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_disconnectMessage); } public: - ForceDisconnectMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + ForceDisconnectMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } ForceDisconnectMessage(string message) : NetMessage(MessageType::ForceDisconnect) { @@ -28,4 +30,4 @@ public: { return _disconnectMessage; } -}; \ No newline at end of file +}; diff --git a/Core/FrameLimiter.h b/Core/FrameLimiter.h index a3d04fd..ddf3fa1 100644 --- a/Core/FrameLimiter.h +++ b/Core/FrameLimiter.h @@ -25,7 +25,8 @@ public: void ProcessFrame() { - if(_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300) { + if (_resetRunTimers || (_clockTimer.GetElapsedMS() - _targetTime) > 300) + { //Reset the timers, this can happen in 3 scenarios: //1) Target frame rate changed //2) The console was reset/power cycled or the emulation was paused (with or without the debugger) @@ -41,7 +42,8 @@ public: bool WaitForNextFrame() { - if(_targetTime - _clockTimer.GetElapsedMS() > 50) { + if (_targetTime - _clockTimer.GetElapsedMS() > 50) + { //When sleeping for a long time (e.g <= 25% speed), sleep in small chunks and check to see if we need to stop sleeping between each sleep call _clockTimer.WaitUntil(_clockTimer.GetElapsedMS() + 40); return true; @@ -50,4 +52,4 @@ public: _clockTimer.WaitUntil(_targetTime); return false; } -}; \ No newline at end of file +}; diff --git a/Core/GameClient.cpp b/Core/GameClient.cpp index 759e907..f6ae32c 100644 --- a/Core/GameClient.cpp +++ b/Core/GameClient.cpp @@ -21,7 +21,8 @@ GameClient::GameClient(shared_ptr console) GameClient::~GameClient() { _stop = true; - if(_clientThread) { + if (_clientThread) + { _clientThread->join(); } } @@ -32,13 +33,14 @@ bool GameClient::Connected() return instance ? instance->_connected : false; } -void GameClient::Connect(shared_ptr console, ClientConnectionData &connectionData) +void GameClient::Connect(shared_ptr console, ClientConnectionData& connectionData) { _instance.reset(new GameClient(console)); console->GetNotificationManager()->RegisterNotificationListener(_instance); - + shared_ptr instance = _instance; - if(instance) { + if (instance) + { instance->PrivateConnect(connectionData); instance->_clientThread.reset(new thread(&GameClient::Exec, instance.get())); } @@ -55,15 +57,18 @@ shared_ptr GameClient::GetConnection() return instance ? instance->_connection : nullptr; } -void GameClient::PrivateConnect(ClientConnectionData &connectionData) +void GameClient::PrivateConnect(ClientConnectionData& connectionData) { _stop = false; shared_ptr socket(new Socket()); - if(socket->Connect(connectionData.Host.c_str(), connectionData.Port)) { + if (socket->Connect(connectionData.Host.c_str(), connectionData.Port)) + { _connection.reset(new GameClientConnection(_console, socket, connectionData)); _console->GetNotificationManager()->RegisterNotificationListener(_connection); _connected = true; - } else { + } + else + { MessageManager::DisplayMessage("NetPlay", "CouldNotConnect"); _connected = false; } @@ -71,12 +76,17 @@ void GameClient::PrivateConnect(ClientConnectionData &connectionData) void GameClient::Exec() { - if(_connected) { - while(!_stop) { - if(!_connection->ConnectionError()) { + if (_connected) + { + while (!_stop) + { + if (!_connection->ConnectionError()) + { _connection->ProcessMessages(); _connection->SendInput(); - } else { + } + else + { _connected = false; _connection->Shutdown(); _connection.reset(); @@ -89,10 +99,11 @@ void GameClient::Exec() void GameClient::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded && - std::this_thread::get_id() != _clientThread->get_id() && + if (type == ConsoleNotificationType::GameLoaded && + std::this_thread::get_id() != _clientThread->get_id() && std::this_thread::get_id() != _console->GetEmulationThreadId() - ) { + ) + { //Disconnect if the client tried to manually load a game //A deadlock occurs if this is called from the emulation thread while a network message is being processed GameClient::Disconnect(); @@ -102,7 +113,8 @@ void GameClient::ProcessNotification(ConsoleNotificationType type, void* paramet void GameClient::SelectController(uint8_t port) { shared_ptr connection = GetConnection(); - if(connection) { + if (connection) + { connection->SelectController(port); } } @@ -117,4 +129,4 @@ uint8_t GameClient::GetControllerPort() { shared_ptr connection = GetConnection(); return connection ? connection->GetControllerPort() : GameConnection::SpectatorPort; -} \ No newline at end of file +} diff --git a/Core/GameClient.h b/Core/GameClient.h index 3774af1..8c7b34f 100644 --- a/Core/GameClient.h +++ b/Core/GameClient.h @@ -23,7 +23,7 @@ private: static shared_ptr GetConnection(); - void PrivateConnect(ClientConnectionData &connectionData); + void PrivateConnect(ClientConnectionData& connectionData); void Exec(); public: @@ -31,7 +31,7 @@ public: virtual ~GameClient(); static bool Connected(); - static void Connect(shared_ptr console, ClientConnectionData &connectionData); + static void Connect(shared_ptr console, ClientConnectionData& connectionData); static void Disconnect(); static void SelectController(uint8_t port); @@ -39,4 +39,4 @@ public: static uint8_t GetAvailableControllers(); void ProcessNotification(ConsoleNotificationType type, void* parameter) override; -}; \ No newline at end of file +}; diff --git a/Core/GameClientConnection.cpp b/Core/GameClientConnection.cpp index 8540eab..24887c4 100644 --- a/Core/GameClientConnection.cpp +++ b/Core/GameClientConnection.cpp @@ -17,7 +17,8 @@ #include "NotificationManager.h" #include "RomFinder.h" -GameClientConnection::GameClientConnection(shared_ptr console, shared_ptr socket, ClientConnectionData &connectionData) : GameConnection(console, socket) +GameClientConnection::GameClientConnection(shared_ptr console, shared_ptr socket, + ClientConnectionData& connectionData) : GameConnection(console, socket) { _connectionData = connectionData; _shutdown = false; @@ -34,12 +35,14 @@ GameClientConnection::~GameClientConnection() void GameClientConnection::Shutdown() { - if(!_shutdown) { + if (!_shutdown) + { _shutdown = true; DisableControllers(); shared_ptr controlManager = _console->GetControlManager(); - if(controlManager) { + if (controlManager) + { controlManager->UnregisterInputProvider(this); } @@ -50,7 +53,9 @@ void GameClientConnection::Shutdown() void GameClientConnection::SendHandshake() { - HandShakeMessage message(_connectionData.PlayerName, HandShakeMessage::GetPasswordHash(_connectionData.Password, _serverSalt), _connectionData.Spectator, _console->GetSettings()->GetVersion()); + HandShakeMessage message(_connectionData.PlayerName, + HandShakeMessage::GetPasswordHash(_connectionData.Password, _serverSalt), + _connectionData.Spectator, _console->GetSettings()->GetVersion()); SendNetMessage(message); } @@ -63,7 +68,8 @@ void GameClientConnection::SendControllerSelection(uint8_t port) void GameClientConnection::ClearInputData() { LockHandler lock = _writeLock.AcquireSafe(); - for(int i = 0; i < BaseControlDevice::PortCount; i++) { + for (int i = 0; i < BaseControlDevice::PortCount; i++) + { _inputSize[i] = 0; _inputData[i].clear(); } @@ -73,80 +79,98 @@ void GameClientConnection::ProcessMessage(NetMessage* message) { GameInformationMessage* gameInfo; - switch(message->GetType()) { - case MessageType::ServerInformation: - _serverSalt = ((ServerInformationMessage*)message)->GetHashSalt(); - SendHandshake(); - break; + switch (message->GetType()) + { + case MessageType::ServerInformation: + _serverSalt = ((ServerInformationMessage*)message)->GetHashSalt(); + SendHandshake(); + break; - case MessageType::SaveState: - if(_gameLoaded) { - DisableControllers(); - _console->Lock(); - ClearInputData(); - ((SaveStateMessage*)message)->LoadState(_console); - _enableControllers = true; - InitControlDevice(); - _console->Unlock(); - } - break; - - case MessageType::MovieData: - if(_gameLoaded) { - PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), ((MovieDataMessage*)message)->GetInputState()); - } - break; - - case MessageType::ForceDisconnect: - MessageManager::DisplayMessage("NetPlay", ((ForceDisconnectMessage*)message)->GetMessage()); - break; - - case MessageType::PlayerList: - _playerList = ((PlayerListMessage*)message)->GetPlayerList(); - break; - - case MessageType::GameInformation: + case MessageType::SaveState: + if (_gameLoaded) + { DisableControllers(); _console->Lock(); - gameInfo = (GameInformationMessage*)message; - if(gameInfo->GetPort() != _controllerPort) { - _controllerPort = gameInfo->GetPort(); - - if(_controllerPort == GameConnection::SpectatorPort) { - MessageManager::DisplayMessage("NetPlay", "ConnectedAsSpectator"); - } else { - MessageManager::DisplayMessage("NetPlay", "ConnectedAsPlayer", std::to_string(_controllerPort + 1)); - } - } - ClearInputData(); + ((SaveStateMessage*)message)->LoadState(_console); + _enableControllers = true; + InitControlDevice(); _console->Unlock(); + } + break; - _gameLoaded = AttemptLoadGame(gameInfo->GetRomFilename(), gameInfo->GetSha1Hash()); - if(!_gameLoaded) { - _console->Stop(true); - } else { - _console->GetControlManager()->UnregisterInputProvider(this); - _console->GetControlManager()->RegisterInputProvider(this); - if(gameInfo->IsPaused()) { - _console->Pause(); - } else { - _console->Resume(); - } + case MessageType::MovieData: + if (_gameLoaded) + { + PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), + ((MovieDataMessage*)message)->GetInputState()); + } + break; + + case MessageType::ForceDisconnect: + MessageManager::DisplayMessage("NetPlay", ((ForceDisconnectMessage*)message)->GetMessage()); + break; + + case MessageType::PlayerList: + _playerList = ((PlayerListMessage*)message)->GetPlayerList(); + break; + + case MessageType::GameInformation: + DisableControllers(); + _console->Lock(); + gameInfo = (GameInformationMessage*)message; + if (gameInfo->GetPort() != _controllerPort) + { + _controllerPort = gameInfo->GetPort(); + + if (_controllerPort == GameConnection::SpectatorPort) + { + MessageManager::DisplayMessage("NetPlay", "ConnectedAsSpectator"); } - break; - default: - break; + else + { + MessageManager::DisplayMessage("NetPlay", "ConnectedAsPlayer", std::to_string(_controllerPort + 1)); + } + } + + ClearInputData(); + _console->Unlock(); + + _gameLoaded = AttemptLoadGame(gameInfo->GetRomFilename(), gameInfo->GetSha1Hash()); + if (!_gameLoaded) + { + _console->Stop(true); + } + else + { + _console->GetControlManager()->UnregisterInputProvider(this); + _console->GetControlManager()->RegisterInputProvider(this); + if (gameInfo->IsPaused()) + { + _console->Pause(); + } + else + { + _console->Resume(); + } + } + break; + default: + break; } } bool GameClientConnection::AttemptLoadGame(string filename, string sha1Hash) { - if(filename.size() > 0) { - if(!RomFinder::LoadMatchingRom(_console.get(), filename, sha1Hash)) { + if (filename.size() > 0) + { + if (!RomFinder::LoadMatchingRom(_console.get(), filename, sha1Hash)) + { MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom", filename); return false; - } else { + } + else + { return true; } } @@ -159,7 +183,8 @@ void GameClientConnection::PushControllerState(uint8_t port, ControlDeviceState _inputData[port].push_back(state); _inputSize[port]++; - if(_inputData[port].size() >= _minimumQueueSize) { + if (_inputData[port].size() >= _minimumQueueSize) + { _waitForInput[port].Signal(); } } @@ -169,30 +194,36 @@ void GameClientConnection::DisableControllers() //Used to prevent deadlocks when client is trying to fill its buffer while the host changes the current game/settings/etc. (i.e situations where we need to call Console::Pause()) _enableControllers = false; ClearInputData(); - for(int i = 0; i < BaseControlDevice::PortCount; i++) { + for (int i = 0; i < BaseControlDevice::PortCount; i++) + { _waitForInput[i].Signal(); } } -bool GameClientConnection::SetInput(BaseControlDevice *device) +bool GameClientConnection::SetInput(BaseControlDevice* device) { - if(_enableControllers) { + if (_enableControllers) + { uint8_t port = device->GetPort(); - while(_inputSize[port] == 0) { + while (_inputSize[port] == 0) + { _waitForInput[port].Wait(); - if(port == 0 && _minimumQueueSize < 10) { + if (port == 0 && _minimumQueueSize < 10) + { //Increase buffer size - reduces freezes at the cost of additional lag _minimumQueueSize++; } - if(_shutdown || !_enableControllers) { + if (_shutdown || !_enableControllers) + { return true; } } LockHandler lock = _writeLock.AcquireSafe(); - if(_shutdown || !_enableControllers || _inputSize[port] == 0) { + if (_shutdown || !_enableControllers || _inputSize[port] == 0) + { return true; } @@ -200,10 +231,13 @@ bool GameClientConnection::SetInput(BaseControlDevice *device) _inputData[port].pop_front(); _inputSize[port]--; - if(_inputData[port].size() > _minimumQueueSize) { + if (_inputData[port].size() > _minimumQueueSize) + { //Too much data, catch up _console->GetSettings()->SetFlag(EmulationFlags::MaximumSpeed); - } else { + } + else + { _console->GetSettings()->ClearFlag(EmulationFlags::MaximumSpeed); } @@ -215,33 +249,41 @@ bool GameClientConnection::SetInput(BaseControlDevice *device) void GameClientConnection::InitControlDevice() { //Pretend we are using port 0 (to use player 1's keybindings during netplay) - _newControlDevice = ControlManager::CreateControllerDevice(_console->GetSettings()->GetInputConfig().Controllers[_controllerPort].Type, 0, _console.get()); + _newControlDevice = ControlManager::CreateControllerDevice( + _console->GetSettings()->GetInputConfig().Controllers[_controllerPort].Type, 0, _console.get()); } void GameClientConnection::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::ConfigChanged) { + if (type == ConsoleNotificationType::ConfigChanged) + { InitControlDevice(); - } else if(type == ConsoleNotificationType::GameLoaded) { + } + else if (type == ConsoleNotificationType::GameLoaded) + { _console->GetControlManager()->RegisterInputProvider(this); } } void GameClientConnection::SendInput() { - if(_gameLoaded) { - if(_newControlDevice) { + if (_gameLoaded) + { + if (_newControlDevice) + { _controlDevice = _newControlDevice; _newControlDevice.reset(); } ControlDeviceState inputState; - if(_controlDevice) { + if (_controlDevice) + { _controlDevice->SetStateFromInput(); inputState = _controlDevice->GetRawState(); } - - if(_lastInputSent != inputState) { + + if (_lastInputSent != inputState) + { InputDataMessage message(inputState); SendNetMessage(message); _lastInputSent = inputState; @@ -257,8 +299,10 @@ void GameClientConnection::SelectController(uint8_t port) uint8_t GameClientConnection::GetAvailableControllers() { uint8_t availablePorts = (1 << BaseControlDevice::PortCount) - 1; - for(PlayerInfo &playerInfo : _playerList) { - if(playerInfo.ControllerPort < BaseControlDevice::PortCount) { + for (PlayerInfo& playerInfo : _playerList) + { + if (playerInfo.ControllerPort < BaseControlDevice::PortCount) + { availablePorts &= ~(1 << playerInfo.ControllerPort); } } @@ -268,4 +312,4 @@ uint8_t GameClientConnection::GetAvailableControllers() uint8_t GameClientConnection::GetControllerPort() { return _controllerPort; -} \ No newline at end of file +} diff --git a/Core/GameClientConnection.h b/Core/GameClientConnection.h index e963847..c9d2513 100644 --- a/Core/GameClientConnection.h +++ b/Core/GameClientConnection.h @@ -45,18 +45,18 @@ protected: void ProcessMessage(NetMessage* message) override; public: - GameClientConnection(shared_ptr console, shared_ptr socket, ClientConnectionData &connectionData); + GameClientConnection(shared_ptr console, shared_ptr socket, ClientConnectionData& connectionData); virtual ~GameClientConnection(); void Shutdown(); void ProcessNotification(ConsoleNotificationType type, void* parameter) override; - bool SetInput(BaseControlDevice *device) override; + bool SetInput(BaseControlDevice* device) override; void InitControlDevice(); void SendInput(); void SelectController(uint8_t port); uint8_t GetAvailableControllers(); uint8_t GetControllerPort(); -}; \ No newline at end of file +}; diff --git a/Core/GameConnection.cpp b/Core/GameConnection.cpp index 1bbf10c..32f4d29 100644 --- a/Core/GameConnection.cpp +++ b/Core/GameConnection.cpp @@ -20,17 +20,20 @@ GameConnection::GameConnection(shared_ptr console, shared_ptr s void GameConnection::ReadSocket() { auto lock = _socketLock.AcquireSafe(); - int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, GameConnection::MaxMsgLength - _readPosition, 0); - if(bytesReceived > 0) { + int bytesReceived = _socket->Recv((char*)_readBuffer + _readPosition, GameConnection::MaxMsgLength - _readPosition, + 0); + if (bytesReceived > 0) + { _readPosition += bytesReceived; } } -bool GameConnection::ExtractMessage(void *buffer, uint32_t &messageLength) +bool GameConnection::ExtractMessage(void* buffer, uint32_t& messageLength) { messageLength = _readBuffer[0] | (_readBuffer[1] << 8) | (_readBuffer[2] << 16) | (_readBuffer[3] << 24); - if(messageLength > GameConnection::MaxMsgLength) { + if (messageLength > GameConnection::MaxMsgLength) + { MessageManager::Log("[Netplay] Invalid data received, closing connection."); Disconnect(); return false; @@ -38,8 +41,9 @@ bool GameConnection::ExtractMessage(void *buffer, uint32_t &messageLength) int packetLength = messageLength + sizeof(messageLength); - if(_readPosition >= packetLength) { - memcpy(buffer, _readBuffer+sizeof(messageLength), messageLength); + if (_readPosition >= packetLength) + { + memcpy(buffer, _readBuffer + sizeof(messageLength), messageLength); memmove(_readBuffer, _readBuffer + packetLength, _readPosition - packetLength); _readPosition -= packetLength; return true; @@ -51,26 +55,29 @@ NetMessage* GameConnection::ReadMessage() { ReadSocket(); - if(_readPosition > 4) { + if (_readPosition > 4) + { uint32_t messageLength; - if(ExtractMessage(_messageBuffer, messageLength)) { - switch((MessageType)_messageBuffer[0]) { - case MessageType::HandShake: return new HandShakeMessage(_messageBuffer, messageLength); - case MessageType::SaveState: return new SaveStateMessage(_messageBuffer, messageLength); - case MessageType::InputData: return new InputDataMessage(_messageBuffer, messageLength); - case MessageType::MovieData: return new MovieDataMessage(_messageBuffer, messageLength); - case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength); - case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength); - case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength); - case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength); - case MessageType::ServerInformation: return new ServerInformationMessage(_messageBuffer, messageLength); + if (ExtractMessage(_messageBuffer, messageLength)) + { + switch ((MessageType)_messageBuffer[0]) + { + case MessageType::HandShake: return new HandShakeMessage(_messageBuffer, messageLength); + case MessageType::SaveState: return new SaveStateMessage(_messageBuffer, messageLength); + case MessageType::InputData: return new InputDataMessage(_messageBuffer, messageLength); + case MessageType::MovieData: return new MovieDataMessage(_messageBuffer, messageLength); + case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength); + case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength); + case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength); + case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength); + case MessageType::ServerInformation: return new ServerInformationMessage(_messageBuffer, messageLength); } } } return nullptr; } -void GameConnection::SendNetMessage(NetMessage &message) +void GameConnection::SendNetMessage(NetMessage& message) { auto lock = _socketLock.AcquireSafe(); message.Send(*_socket.get()); @@ -90,10 +97,11 @@ bool GameConnection::ConnectionError() void GameConnection::ProcessMessages() { NetMessage* message; - while((message = ReadMessage()) != nullptr) { + while ((message = ReadMessage()) != nullptr) + { //Loop until all messages have been processed message->Initialize(); ProcessMessage(message); delete message; - } -} \ No newline at end of file + } +} diff --git a/Core/GameConnection.h b/Core/GameConnection.h index 95ec4be..88f76d9 100644 --- a/Core/GameConnection.h +++ b/Core/GameConnection.h @@ -30,7 +30,7 @@ private: void ReadSocket(); - bool ExtractMessage(void *buffer, uint32_t &messageLength); + bool ExtractMessage(void* buffer, uint32_t& messageLength); NetMessage* ReadMessage(); virtual void ProcessMessage(NetMessage* message) = 0; @@ -44,5 +44,5 @@ public: bool ConnectionError(); void ProcessMessages(); - void SendNetMessage(NetMessage &message); -}; \ No newline at end of file + void SendNetMessage(NetMessage& message); +}; diff --git a/Core/GameInformationMessage.h b/Core/GameInformationMessage.h index e3eec0b..10f7a03 100644 --- a/Core/GameInformationMessage.h +++ b/Core/GameInformationMessage.h @@ -13,22 +13,25 @@ private: bool _paused = false; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_romFilename, _sha1Hash, _controllerPort, _paused); } public: - GameInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + GameInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } - GameInformationMessage(string filepath, string sha1Hash, uint8_t port, bool paused) : NetMessage(MessageType::GameInformation) + GameInformationMessage(string filepath, string sha1Hash, uint8_t port, bool paused) : NetMessage( + MessageType::GameInformation) { _romFilename = FolderUtilities::GetFilename(filepath, true); _sha1Hash = sha1Hash; _controllerPort = port; _paused = paused; } - + uint8_t GetPort() { return _controllerPort; @@ -48,4 +51,4 @@ public: { return _paused; } -}; \ No newline at end of file +}; diff --git a/Core/GameServer.cpp b/Core/GameServer.cpp index 50f7cb1..a452ab3 100644 --- a/Core/GameServer.cpp +++ b/Core/GameServer.cpp @@ -32,9 +32,10 @@ GameServer::~GameServer() _serverThread->join(); Stop(); - + shared_ptr controlManager = _console->GetControlManager(); - if(controlManager) { + if (controlManager) + { controlManager->UnregisterInputRecorder(this); controlManager->UnregisterInputProvider(this); } @@ -43,7 +44,8 @@ GameServer::~GameServer() void GameServer::RegisterServerInput() { shared_ptr controlManager = _console->GetControlManager(); - if(controlManager) { + if (controlManager) + { controlManager->RegisterInputRecorder(this); controlManager->RegisterInputProvider(this); } @@ -51,13 +53,17 @@ void GameServer::RegisterServerInput() void GameServer::AcceptConnections() { - while(true) { + while (true) + { shared_ptr socket = _listener->Accept(); - if(!socket->ConnectionError()) { + if (!socket->ConnectionError()) + { auto connection = shared_ptr(new GameServerConnection(_console, socket, _password)); _console->GetNotificationManager()->RegisterNotificationListener(connection); _openConnections.push_back(connection); - } else { + } + else + { break; } } @@ -67,48 +73,63 @@ void GameServer::AcceptConnections() void GameServer::UpdateConnections() { vector> connectionsToRemove; - for(shared_ptr connection : _openConnections) { - if(connection->ConnectionError()) { + for (shared_ptr connection : _openConnections) + { + if (connection->ConnectionError()) + { connectionsToRemove.push_back(connection); - } else { + } + else + { connection->ProcessMessages(); } } - for(shared_ptr gameConnection : connectionsToRemove) { + for (shared_ptr gameConnection : connectionsToRemove) + { _openConnections.remove(gameConnection); } } list> GameServer::GetConnectionList() { - if(GameServer::Started()) { + if (GameServer::Started()) + { return Instance->_openConnections; - } else { + } + else + { return list>(); } } -bool GameServer::SetInput(BaseControlDevice *device) +bool GameServer::SetInput(BaseControlDevice* device) { uint8_t port = device->GetPort(); - if(device->GetControllerType() == ControllerType::Multitap) { + if (device->GetControllerType() == ControllerType::Multitap) + { //Need special handling for the multitap, merge data from P3/4/5 with P1 (or P2, depending which port the multitap is plugged into) GameServerConnection* connection = GameServerConnection::GetNetPlayDevice(port); - if(connection) { + if (connection) + { ((Multitap*)device)->SetControllerState(0, connection->GetState()); } - for(int i = 2; i < 5; i++) { + for (int i = 2; i < 5; i++) + { GameServerConnection* connection = GameServerConnection::GetNetPlayDevice(i); - if(connection) { + if (connection) + { ((Multitap*)device)->SetControllerState(i - 1, connection->GetState()); } } - } else { + } + else + { GameServerConnection* connection = GameServerConnection::GetNetPlayDevice(port); - if(connection) { + if (connection) + { //Device is controlled by a client device->SetRawState(connection->GetState()); return true; @@ -121,9 +142,12 @@ bool GameServer::SetInput(BaseControlDevice *device) void GameServer::RecordInput(vector> devices) { - for(shared_ptr &device : devices) { - for(shared_ptr connection : _openConnections) { - if(!connection->ConnectionError()) { + for (shared_ptr& device : devices) + { + for (shared_ptr connection : _openConnections) + { + if (!connection->ConnectionError()) + { //Send movie stream connection->SendMovieData(device->GetPort(), device->GetRawState()); } @@ -131,9 +155,10 @@ void GameServer::RecordInput(vector> devices) } } -void GameServer::ProcessNotification(ConsoleNotificationType type, void * parameter) +void GameServer::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded) { + if (type == ConsoleNotificationType::GameLoaded) + { //Register the server as an input provider/recorder RegisterServerInput(); } @@ -146,9 +171,10 @@ void GameServer::Exec() _listener->Listen(10); _stop = false; _initialized = true; - MessageManager::DisplayMessage("NetPlay" , "ServerStarted", std::to_string(_port)); + MessageManager::DisplayMessage("NetPlay", "ServerStarted", std::to_string(_port)); - while(!_stop) { + while (!_stop) + { AcceptConnections(); UpdateConnections(); @@ -172,23 +198,28 @@ void GameServer::StartServer(shared_ptr console, uint16_t port, string void GameServer::StopServer() { - if(Instance) { + if (Instance) + { Instance.reset(); } } bool GameServer::Started() { - if(Instance) { + if (Instance) + { return Instance->_initialized; - } else { + } + else + { return false; } } string GameServer::GetHostPlayerName() { - if(GameServer::Started()) { + if (GameServer::Started()) + { return Instance->_hostPlayerName; } return ""; @@ -196,7 +227,8 @@ string GameServer::GetHostPlayerName() uint8_t GameServer::GetHostControllerPort() { - if(GameServer::Started()) { + if (GameServer::Started()) + { return Instance->_hostControllerPort; } return GameConnection::SpectatorPort; @@ -204,9 +236,11 @@ uint8_t GameServer::GetHostControllerPort() void GameServer::SetHostControllerPort(uint8_t port) { - if(GameServer::Started()) { + if (GameServer::Started()) + { Instance->_console->Lock(); - if(port == GameConnection::SpectatorPort || GetAvailableControllers() & (1 << port)) { + if (port == GameConnection::SpectatorPort || GetAvailableControllers() & (1 << port)) + { //Port is available Instance->_hostControllerPort = port; SendPlayerList(); @@ -218,8 +252,10 @@ void GameServer::SetHostControllerPort(uint8_t port) uint8_t GameServer::GetAvailableControllers() { uint8_t availablePorts = (1 << BaseControlDevice::PortCount) - 1; - for(PlayerInfo &playerInfo : GetPlayerList()) { - if(playerInfo.ControllerPort < BaseControlDevice::PortCount) { + for (PlayerInfo& playerInfo : GetPlayerList()) + { + if (playerInfo.ControllerPort < BaseControlDevice::PortCount) + { availablePorts &= ~(1 << playerInfo.ControllerPort); } } @@ -236,7 +272,8 @@ vector GameServer::GetPlayerList() playerInfo.IsHost = true; playerList.push_back(playerInfo); - for(shared_ptr &connection : GetConnectionList()) { + for (shared_ptr& connection : GetConnectionList()) + { playerInfo.Name = connection->GetPlayerName(); playerInfo.ControllerPort = connection->GetControllerPort(); playerInfo.IsHost = false; @@ -250,9 +287,10 @@ void GameServer::SendPlayerList() { vector playerList = GetPlayerList(); - for(shared_ptr &connection : GetConnectionList()) { + for (shared_ptr& connection : GetConnectionList()) + { //Send player list update to all connections PlayerListMessage message(playerList); connection->SendNetMessage(message); } -} \ No newline at end of file +} diff --git a/Core/GameServer.h b/Core/GameServer.h index 475519d..6b2a489 100644 --- a/Core/GameServer.h +++ b/Core/GameServer.h @@ -50,9 +50,9 @@ public: static list> GetConnectionList(); - bool SetInput(BaseControlDevice *device) override; + bool SetInput(BaseControlDevice* device) override; void RecordInput(vector> devices) override; // Inherited via INotificationListener - virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override; -}; \ No newline at end of file + virtual void ProcessNotification(ConsoleNotificationType type, void* parameter) override; +}; diff --git a/Core/GameServerConnection.cpp b/Core/GameServerConnection.cpp index 7ae203e..6bd9fea 100644 --- a/Core/GameServerConnection.cpp +++ b/Core/GameServerConnection.cpp @@ -19,9 +19,10 @@ #include "BaseControlDevice.h" #include "ServerInformationMessage.h" -GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = { }; +GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = {}; -GameServerConnection::GameServerConnection(shared_ptr console, shared_ptr socket, string serverPassword) : GameConnection(console, socket) +GameServerConnection::GameServerConnection(shared_ptr console, shared_ptr socket, + string serverPassword) : GameConnection(console, socket) { //Server-side connection _serverPassword = serverPassword; @@ -31,8 +32,10 @@ GameServerConnection::GameServerConnection(shared_ptr console, shared_p GameServerConnection::~GameServerConnection() { - if(!_playerName.empty()) { - MessageManager::DisplayMessage("NetPlay", _playerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected."); + if (!_playerName.empty()) + { + MessageManager::DisplayMessage( + "NetPlay", _playerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected."); } UnregisterNetPlayDevice(this); @@ -44,7 +47,8 @@ void GameServerConnection::SendServerInformation() std::mt19937 engine(rd()); std::uniform_int_distribution<> dist((int)' ', (int)'~'); string hash(50, ' '); - for(int i = 0; i < 50; i++) { + for (int i = 0; i < 50; i++) + { int random = dist(engine); hash[i] = (char)random; } @@ -59,7 +63,8 @@ void GameServerConnection::SendGameInformation() { _console->Lock(); RomInfo romInfo = _console->GetRomInfo(); - GameInformationMessage gameInfo(romInfo.RomFile.GetFileName(), _console->GetCartridge()->GetSha1Hash(), _controllerPort, _console->IsPaused()); + GameInformationMessage gameInfo(romInfo.RomFile.GetFileName(), _console->GetCartridge()->GetSha1Hash(), + _controllerPort, _console->IsPaused()); SendNetMessage(gameInfo); SaveStateMessage saveState(_console); SendNetMessage(saveState); @@ -68,7 +73,8 @@ void GameServerConnection::SendGameInformation() void GameServerConnection::SendMovieData(uint8_t port, ControlDeviceState state) { - if(_handshakeCompleted) { + if (_handshakeCompleted) + { MovieDataMessage message(state, port); SendNetMessage(message); } @@ -83,7 +89,8 @@ void GameServerConnection::SendForceDisconnectMessage(string disconnectMessage) void GameServerConnection::PushState(ControlDeviceState state) { - if(_inputData.size() == 0 || state != _inputData.back()) { + if (_inputData.size() == 0 || state != _inputData.back()) + { _inputData.clear(); _inputData.push_back(state); } @@ -93,9 +100,11 @@ ControlDeviceState GameServerConnection::GetState() { size_t inputBufferSize = _inputData.size(); ControlDeviceState stateData; - if(inputBufferSize > 0) { + if (inputBufferSize > 0) + { stateData = _inputData.front(); - if(inputBufferSize > 1) { + if (inputBufferSize > 1) + { //Always keep the last one the client sent, it will be used until a new one is received _inputData.pop_front(); } @@ -106,18 +115,23 @@ ControlDeviceState GameServerConnection::GetState() void GameServerConnection::ProcessHandshakeResponse(HandShakeMessage* message) { //Send the game's current state to the client and register the controller - if(message->IsValid(_console->GetSettings()->GetVersion())) { - if(message->CheckPassword(_serverPassword, _connectionHash)) { + if (message->IsValid(_console->GetSettings()->GetVersion())) + { + if (message->CheckPassword(_serverPassword, _connectionHash)) + { _console->Lock(); _controllerPort = message->IsSpectator() ? GameConnection::SpectatorPort : GetFirstFreeControllerPort(); _playerName = message->GetPlayerName(); - string playerPortMessage = _controllerPort == GameConnection::SpectatorPort ? "Spectator" : "Player " + std::to_string(_controllerPort + 1); + string playerPortMessage = _controllerPort == GameConnection::SpectatorPort + ? "Spectator" + : "Player " + std::to_string(_controllerPort + 1); MessageManager::DisplayMessage("NetPlay", _playerName + " (" + playerPortMessage + ") connected."); - if(_console->GetCartridge()) { + if (_console->GetCartridge()) + { SendGameInformation(); } @@ -125,60 +139,77 @@ void GameServerConnection::ProcessHandshakeResponse(HandShakeMessage* message) RegisterNetPlayDevice(this, _controllerPort); GameServer::SendPlayerList(); _console->Unlock(); - } else { + } + else + { SendForceDisconnectMessage("The password you provided did not match - you have been disconnected."); } - } else { - SendForceDisconnectMessage("Server is using a different version of Mesen-S (" + _console->GetSettings()->GetVersionString() + ") - you have been disconnected."); + } + else + { + SendForceDisconnectMessage( + "Server is using a different version of Mesen-S (" + _console->GetSettings()->GetVersionString() + + ") - you have been disconnected."); MessageManager::DisplayMessage("NetPlay", + "NetplayVersionMismatch", message->GetPlayerName()); } } void GameServerConnection::ProcessMessage(NetMessage* message) { - switch(message->GetType()) { - case MessageType::HandShake: - ProcessHandshakeResponse((HandShakeMessage*)message); - break; + switch (message->GetType()) + { + case MessageType::HandShake: + ProcessHandshakeResponse((HandShakeMessage*)message); + break; - case MessageType::InputData: - if(!_handshakeCompleted) { - SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); - return; - } - PushState(((InputDataMessage*)message)->GetInputState()); - break; + case MessageType::InputData: + if (!_handshakeCompleted) + { + SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); + return; + } + PushState(((InputDataMessage*)message)->GetInputState()); + break; - case MessageType::SelectController: - if(!_handshakeCompleted) { - SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); - return; - } - SelectControllerPort(((SelectControllerMessage*)message)->GetPortNumber()); - break; + case MessageType::SelectController: + if (!_handshakeCompleted) + { + SendForceDisconnectMessage("Handshake has not been completed - invalid packet"); + return; + } + SelectControllerPort(((SelectControllerMessage*)message)->GetPortNumber()); + break; - default: - break; + default: + break; } } void GameServerConnection::SelectControllerPort(uint8_t port) { _console->Lock(); - if(port == GameConnection::SpectatorPort) { + if (port == GameConnection::SpectatorPort) + { //Client wants to be a spectator, make sure we are not using any controller UnregisterNetPlayDevice(this); _controllerPort = port; - } else { + } + else + { GameServerConnection* netPlayDevice = GetNetPlayDevice(port); - if(netPlayDevice == this) { + if (netPlayDevice == this) + { //Nothing to do, we're already this player - } else if(netPlayDevice == nullptr) { + } + else if (netPlayDevice == nullptr) + { //This port is free, we can switch UnregisterNetPlayDevice(this); RegisterNetPlayDevice(this, port); _controllerPort = port; - } else { + } + else + { //Another player is using this port, we can't use it } } @@ -189,26 +220,28 @@ void GameServerConnection::SelectControllerPort(uint8_t port) void GameServerConnection::ProcessNotification(ConsoleNotificationType type, void* parameter) { - switch(type) { - case ConsoleNotificationType::GamePaused: - case ConsoleNotificationType::GameLoaded: - case ConsoleNotificationType::GameResumed: - case ConsoleNotificationType::GameReset: - case ConsoleNotificationType::StateLoaded: - case ConsoleNotificationType::CheatsChanged: - case ConsoleNotificationType::ConfigChanged: - SendGameInformation(); - break; + switch (type) + { + case ConsoleNotificationType::GamePaused: + case ConsoleNotificationType::GameLoaded: + case ConsoleNotificationType::GameResumed: + case ConsoleNotificationType::GameReset: + case ConsoleNotificationType::StateLoaded: + case ConsoleNotificationType::CheatsChanged: + case ConsoleNotificationType::ConfigChanged: + SendGameInformation(); + break; - case ConsoleNotificationType::BeforeEmulationStop: { + case ConsoleNotificationType::BeforeEmulationStop: + { //Make clients unload the current game GameInformationMessage gameInfo("", "0000000000000000000000000000000000000000", _controllerPort, true); SendNetMessage(gameInfo); break; } - default: - break; + default: + break; } } @@ -219,9 +252,12 @@ void GameServerConnection::RegisterNetPlayDevice(GameServerConnection* device, u void GameServerConnection::UnregisterNetPlayDevice(GameServerConnection* device) { - if(device != nullptr) { - for(int i = 0; i < BaseControlDevice::PortCount; i++) { - if(GameServerConnection::_netPlayDevices[i] == device) { + if (device != nullptr) + { + for (int i = 0; i < BaseControlDevice::PortCount; i++) + { + if (GameServerConnection::_netPlayDevices[i] == device) + { GameServerConnection::_netPlayDevices[i] = nullptr; break; } @@ -237,8 +273,10 @@ GameServerConnection* GameServerConnection::GetNetPlayDevice(uint8_t port) uint8_t GameServerConnection::GetFirstFreeControllerPort() { uint8_t hostPost = GameServer::GetHostControllerPort(); - for(int i = 0; i < BaseControlDevice::PortCount; i++) { - if(hostPost != i && GameServerConnection::_netPlayDevices[i] == nullptr) { + for (int i = 0; i < BaseControlDevice::PortCount; i++) + { + if (hostPost != i && GameServerConnection::_netPlayDevices[i] == nullptr) + { return i; } } @@ -253,4 +291,4 @@ string GameServerConnection::GetPlayerName() uint8_t GameServerConnection::GetControllerPort() { return _controllerPort; -} \ No newline at end of file +} diff --git a/Core/GameServerConnection.h b/Core/GameServerConnection.h index 008df01..04a577a 100644 --- a/Core/GameServerConnection.h +++ b/Core/GameServerConnection.h @@ -15,7 +15,7 @@ private: list _inputData; string _playerName; - int _controllerPort; + int _controllerPort; string _connectionHash; string _serverPassword; bool _handshakeCompleted = false; @@ -35,7 +35,7 @@ private: protected: void ProcessMessage(NetMessage* message) override; - + public: GameServerConnection(shared_ptr console, shared_ptr socket, string serverPassword); virtual ~GameServerConnection(); diff --git a/Core/Gameboy.cpp b/Core/Gameboy.cpp index 1625d06..d96ee7b 100644 --- a/Core/Gameboy.cpp +++ b/Core/Gameboy.cpp @@ -19,7 +19,7 @@ #include "../Utilities/VirtualFile.h" #include "../Utilities/Serializer.h" -Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile, bool sgbEnabled) +Gameboy* Gameboy::Create(Console* console, VirtualFile& romFile, bool sgbEnabled) { vector romData; romFile.ReadFile(romData); @@ -31,22 +31,30 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile, bool sgbEnabled MessageManager::Log("File: " + romFile.GetFileName()); MessageManager::Log("Game: " + header.GetCartName()); MessageManager::Log("Cart Type: " + std::to_string(header.CartType)); - switch(header.CgbFlag & 0xC0) { - case 0x00: MessageManager::Log("Supports: Game Boy"); break; - case 0x80: MessageManager::Log("Supports: Game Boy Color (compatible with GB)"); break; - case 0xC0: MessageManager::Log("Supports: Game Boy Color only"); break; + switch (header.CgbFlag & 0xC0) + { + case 0x00: MessageManager::Log("Supports: Game Boy"); + break; + case 0x80: MessageManager::Log("Supports: Game Boy Color (compatible with GB)"); + break; + case 0xC0: MessageManager::Log("Supports: Game Boy Color only"); + break; } MessageManager::Log("File size: " + std::to_string(romData.size() / 1024) + " KB"); - if(header.GetCartRamSize() > 0) { - string sizeString = header.GetCartRamSize() > 1024 ? std::to_string(header.GetCartRamSize() / 1024) + " KB" : std::to_string(header.GetCartRamSize()) + " bytes"; + if (header.GetCartRamSize() > 0) + { + string sizeString = header.GetCartRamSize() > 1024 + ? std::to_string(header.GetCartRamSize() / 1024) + " KB" + : std::to_string(header.GetCartRamSize()) + " bytes"; MessageManager::Log("Cart RAM size: " + sizeString + (header.HasBattery() ? " (with battery)" : "")); } MessageManager::Log("-----------------------------"); GbCart* cart = GbCartFactory::CreateCart(header.CartType); - if(cart) { + if (cart) + { Gameboy* gb = new Gameboy(); gb->Init(console, cart, romData, header, sgbEnabled); return gb; @@ -55,7 +63,8 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile, bool sgbEnabled return nullptr; } -void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData, GameboyHeader& header, bool sgbEnabled) +void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData, GameboyHeader& header, + bool sgbEnabled) { _console = console; _cart.reset(cart); @@ -71,15 +80,20 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData shared_ptr settings = console->GetSettings(); GameboyConfig cfg = settings->GetGameboyConfig(); GameboyModel model = cfg.Model; - if(model == GameboyModel::Auto) { - if((header.CgbFlag & 0x80) != 0) { + if (model == GameboyModel::Auto) + { + if ((header.CgbFlag & 0x80) != 0) + { model = GameboyModel::GameboyColor; - } else { + } + else + { model = GameboyModel::SuperGameboy; } } - if(!sgbEnabled && model == GameboyModel::SuperGameboy) { + if (!sgbEnabled && model == GameboyModel::SuperGameboy) + { //SGB bios isn't available, use gameboy color mode instead model = GameboyModel::GameboyColor; } @@ -98,34 +112,42 @@ void Gameboy::Init(Console* console, GbCart* cart, std::vector& romData _bootRomSize = 0; FirmwareType type = FirmwareType::Gameboy; - if(_model == GameboyModel::SuperGameboy) { + if (_model == GameboyModel::SuperGameboy) + { type = cfg.UseSgb2 ? FirmwareType::Sgb2GameboyCpu : FirmwareType::Sgb1GameboyCpu; - } else if(_model == GameboyModel::GameboyColor) { + } + else if (_model == GameboyModel::GameboyColor) + { type = FirmwareType::GameboyColor; } _bootRomSize = cgbMode ? 9 * 256 : 256; - if(!FirmwareHelper::LoadGbBootRom(console, &_bootRom, type)) { - switch(_model) { - default: - case GameboyModel::Gameboy: - _bootRom = new uint8_t[_bootRomSize]; - memcpy(_bootRom, dmgBootRom, _bootRomSize); - break; + if (!FirmwareHelper::LoadGbBootRom(console, &_bootRom, type)) + { + switch (_model) + { + default: + case GameboyModel::Gameboy: + _bootRom = new uint8_t[_bootRomSize]; + memcpy(_bootRom, dmgBootRom, _bootRomSize); + break; - case GameboyModel::GameboyColor: - _bootRom = new uint8_t[_bootRomSize]; - memcpy(_bootRom, cgbBootRom, _bootRomSize); - break; + case GameboyModel::GameboyColor: + _bootRom = new uint8_t[_bootRomSize]; + memcpy(_bootRom, cgbBootRom, _bootRomSize); + break; - case GameboyModel::SuperGameboy: - _bootRom = new uint8_t[_bootRomSize]; - if(cfg.UseSgb2) { - memcpy(_bootRom, sgb2BootRom, _bootRomSize); - } else { - memcpy(_bootRom, sgbBootRom, _bootRomSize); - } - break; + case GameboyModel::SuperGameboy: + _bootRom = new uint8_t[_bootRomSize]; + if (cfg.UseSgb2) + { + memcpy(_bootRom, sgb2BootRom, _bootRomSize); + } + else + { + memcpy(_bootRom, sgbBootRom, _bootRomSize); + } + break; } } @@ -154,7 +176,7 @@ Gameboy::~Gameboy() delete[] _cartRam; delete[] _prgRom; - + delete[] _spriteRam; delete[] _videoRam; @@ -184,21 +206,24 @@ void Gameboy::Exec() void Gameboy::Run(uint64_t runUntilClock) { - while(_memoryManager->GetCycleCount() < runUntilClock) { + while (_memoryManager->GetCycleCount() < runUntilClock) + { _cpu->Exec(); } } void Gameboy::LoadBattery() { - if(_hasBattery) { + if (_hasBattery) + { _console->GetBatteryManager()->LoadBattery(".srm", _cartRam, _cartRamSize); } } void Gameboy::SaveBattery() { - if(_hasBattery) { + if (_hasBattery) + { _console->GetBatteryManager()->SaveBattery(".srm", _cartRam, _cartRamSize); } } @@ -219,29 +244,31 @@ GbState Gameboy::GetState() uint32_t Gameboy::DebugGetMemorySize(SnesMemoryType type) { - switch(type) { - case SnesMemoryType::GbPrgRom: return _prgRomSize; - case SnesMemoryType::GbWorkRam: return _workRamSize; - case SnesMemoryType::GbCartRam: return _cartRamSize; - case SnesMemoryType::GbHighRam: return Gameboy::HighRamSize; - case SnesMemoryType::GbBootRom: return _bootRomSize; - case SnesMemoryType::GbVideoRam: return _videoRamSize; - case SnesMemoryType::GbSpriteRam: return Gameboy::SpriteRamSize; - default: return 0; + switch (type) + { + case SnesMemoryType::GbPrgRom: return _prgRomSize; + case SnesMemoryType::GbWorkRam: return _workRamSize; + case SnesMemoryType::GbCartRam: return _cartRamSize; + case SnesMemoryType::GbHighRam: return Gameboy::HighRamSize; + case SnesMemoryType::GbBootRom: return _bootRomSize; + case SnesMemoryType::GbVideoRam: return _videoRamSize; + case SnesMemoryType::GbSpriteRam: return Gameboy::SpriteRamSize; + default: return 0; } } uint8_t* Gameboy::DebugGetMemory(SnesMemoryType type) { - switch(type) { - case SnesMemoryType::GbPrgRom: return _prgRom; - case SnesMemoryType::GbWorkRam: return _workRam; - case SnesMemoryType::GbCartRam: return _cartRam; - case SnesMemoryType::GbHighRam: return _highRam; - case SnesMemoryType::GbBootRom: return _bootRom; - case SnesMemoryType::GbVideoRam: return _videoRam; - case SnesMemoryType::GbSpriteRam: return _spriteRam; - default: return nullptr; + switch (type) + { + case SnesMemoryType::GbPrgRom: return _prgRom; + case SnesMemoryType::GbWorkRam: return _workRam; + case SnesMemoryType::GbCartRam: return _cartRam; + case SnesMemoryType::GbHighRam: return _highRam; + case SnesMemoryType::GbBootRom: return _bootRom; + case SnesMemoryType::GbVideoRam: return _videoRam; + case SnesMemoryType::GbSpriteRam: return _spriteRam; + default: return nullptr; } } @@ -260,16 +287,17 @@ GbCpu* Gameboy::GetCpu() return _cpu.get(); } -void Gameboy::GetSoundSamples(int16_t* &samples, uint32_t& sampleCount) +void Gameboy::GetSoundSamples(int16_t* & samples, uint32_t& sampleCount) { _apu->GetSoundSamples(samples, sampleCount); } AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr) { - AddressInfo addrInfo = { -1, SnesMemoryType::Register }; + AddressInfo addrInfo = {-1, SnesMemoryType::Register}; - if(addr >= 0xFF80 && addr <= 0xFFFE) { + if (addr >= 0xFF80 && addr <= 0xFFFE) + { addrInfo.Address = addr & 0x7F; addrInfo.Type = SnesMemoryType::GbHighRam; return addrInfo; @@ -277,22 +305,30 @@ AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr) uint8_t* ptr = _memoryManager->GetMappedBlock(addr); - if(!ptr) { + if (!ptr) + { return addrInfo; } ptr += (addr & 0xFF); - if(ptr >= _prgRom && ptr < _prgRom + _prgRomSize) { + if (ptr >= _prgRom && ptr < _prgRom + _prgRomSize) + { addrInfo.Address = (int32_t)(ptr - _prgRom); addrInfo.Type = SnesMemoryType::GbPrgRom; - } else if(ptr >= _workRam && ptr < _workRam + _workRamSize) { + } + else if (ptr >= _workRam && ptr < _workRam + _workRamSize) + { addrInfo.Address = (int32_t)(ptr - _workRam); addrInfo.Type = SnesMemoryType::GbWorkRam; - } else if(ptr >= _cartRam && ptr < _cartRam + _cartRamSize) { + } + else if (ptr >= _cartRam && ptr < _cartRam + _cartRamSize) + { addrInfo.Address = (int32_t)(ptr - _cartRam); addrInfo.Type = SnesMemoryType::GbCartRam; - } else if(ptr >= _bootRom && ptr < _bootRom + _bootRomSize) { + } + else if (ptr >= _bootRom && ptr < _bootRom + _bootRomSize) + { addrInfo.Address = (int32_t)(ptr - _bootRom); addrInfo.Type = SnesMemoryType::GbBootRom; } @@ -301,13 +337,16 @@ AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr) int32_t Gameboy::GetRelativeAddress(AddressInfo& absAddress) { - if(absAddress.Type == SnesMemoryType::GbHighRam) { + if (absAddress.Type == SnesMemoryType::GbHighRam) + { return 0xFF80 | (absAddress.Address & 0x7F); } - for(int32_t i = 0; i < 0x10000; i += 0x100) { + for (int32_t i = 0; i < 0x10000; i += 0x100) + { AddressInfo blockAddr = GetAbsoluteAddress(i); - if(blockAddr.Type == absAddress.Type && (blockAddr.Address & ~0xFF) == (absAddress.Address & ~0xFF)) { + if (blockAddr.Type == absAddress.Type && (blockAddr.Address & ~0xFF) == (absAddress.Address & ~0xFF)) + { return i | (absAddress.Address & 0xFF); } } diff --git a/Core/Gameboy.h b/Core/Gameboy.h index 518a940..4e0aa78 100644 --- a/Core/Gameboy.h +++ b/Core/Gameboy.h @@ -68,13 +68,13 @@ public: void Exec(); void Run(uint64_t runUntilClock); - + void LoadBattery(); void SaveBattery(); GbPpu* GetPpu(); GbCpu* GetCpu(); - void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount); + void GetSoundSamples(int16_t* & samples, uint32_t& sampleCount); GbState GetState(); GameboyHeader GetHeader(); @@ -94,4 +94,4 @@ public: void Serialize(Serializer& s) override; void SetReg(GbRegister reg, uint16_t value); -}; \ No newline at end of file +}; diff --git a/Core/GameboyDisUtils.cpp b/Core/GameboyDisUtils.cpp index 05f01da..eb7805b 100644 --- a/Core/GameboyDisUtils.cpp +++ b/Core/GameboyDisUtils.cpp @@ -8,127 +8,205 @@ #include"../Utilities/HexUtilities.h" constexpr const char* _opTemplate[256] = { - "NOP", "LD BC, e", "LD (BC), A", "INC BC", "INC B", "DEC B", "LD B, d", "RLCA", "LD (a), SP", "ADD HL, BC", "LD A, (BC)", "DEC BC", "INC C", "DEC C", "LD C, d", "RRCA", - "STOP", "LD DE, e", "LD (DE), A", "INC DE", "INC D", "DEC D", "LD D, d", "RLA", "JR r", "ADD HL, DE", "LD A, (DE)", "DEC DE", "INC E", "DEC E", "LD E, d", "RRA", - "JR NZ, r", "LD HL, e", "LD (HL+), A", "INC HL", "INC H", "DEC H", "LD H, d", "DAA", "JR Z, r", "ADD HL, HL", "LD A, (HL+)", "DEC HL", "INC L", "DEC L", "LD L, d", "CPL", - "JR NC, r", "LD SP, e", "LD (HL-), A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL), d", "SCF", "JR C, r", "ADD HL, SP", "LD A, (HL-)", "DEC SP", "INC A", "DEC A", "LD A, d", "CCF", - "LD B, B", "LD B, C", "LD B, D", "LD B, E", "LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", "LD C, B", "LD C, C", "LD C, D", "LD C, E", "LD C, H", "LD C, L", "LD C, (HL)", "LD C, A", - "LD D, B", "LD D, C", "LD D, D", "LD D, E", "LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", "LD E, B", "LD E, C", "LD E, D", "LD E, E", "LD E, H", "LD E, L", "LD E, (HL)", "LD E, A", - "LD H, B", "LD H, C", "LD H, D", "LD H, E", "LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", "LD L, B", "LD L, C", "LD L, D", "LD L, E", "LD L, H", "LD L, L", "LD L, (HL)", "LD L, A", - "LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E","LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A","LD A, B", "LD A, C", "LD A, D", "LD A, E", "LD A, H", "LD A, L", "LD A, (HL)", "LD A, A", - "ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", "ADD A, H", "ADD A, L", "ADD A, (HL)", "ADD A, A", "ADC A, B", "ADC A, C", "ADC A, D", "ADC A, E", "ADC A, H", "ADC A, L", "ADC A, (HL)", "ADC A, A", - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", "SBC A, B", "SBC A, C", "SBC A, D", "SBC A, E", "SBC A, H", "SBC A, L", "SBC A, (HL)", "SBC A, A", - "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", - "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", - "RET NZ", "POP BC", "JP NZ, a", "JP a", "CALL NZ, a", "PUSH BC", "ADD A, d", "RST 00H", "RET Z", "RET", "JP Z, a", "PREFIX", "CALL Z, a","CALL a", "ADC A, d", "RST 08H", - "RET NC", "POP DE", "JP NC, a", "ILL_D3", "CALL NC, a", "PUSH DE", "SUB d", "RST 10H", "RET C", "RETI", "JP C, a", "ILL_DB", "CALL C, a","ILL_DD", "SBC A, d", "RST 18H", - "LDH (c), A", "POP HL", "LD ($FF00+C), A","ILL_E3","ILL_E4", "PUSH HL", "AND d", "RST 20H", "ADD SP, d", "JP HL", "LD (a), A", "ILL_EB", "ILL_EC", "ILL_ED", "XOR d", "RST 28H", - "LDH A, (c)", "POP AF", "LD A, ($FF00+C)","DI", "ILL_F4", "PUSH AF", "OR d", "RST 30H", "LD HL, SP+d", "LD SP, HL", "LD A, (a)", "EI", "ILL_FC", "ILL_FD", "CP d", "RST 38H" + "NOP", "LD BC, e", "LD (BC), A", "INC BC", "INC B", "DEC B", "LD B, d", "RLCA", "LD (a), SP", "ADD HL, BC", + "LD A, (BC)", "DEC BC", "INC C", "DEC C", "LD C, d", "RRCA", + "STOP", "LD DE, e", "LD (DE), A", "INC DE", "INC D", "DEC D", "LD D, d", "RLA", "JR r", "ADD HL, DE", "LD A, (DE)", + "DEC DE", "INC E", "DEC E", "LD E, d", "RRA", + "JR NZ, r", "LD HL, e", "LD (HL+), A", "INC HL", "INC H", "DEC H", "LD H, d", "DAA", "JR Z, r", "ADD HL, HL", + "LD A, (HL+)", "DEC HL", "INC L", "DEC L", "LD L, d", "CPL", + "JR NC, r", "LD SP, e", "LD (HL-), A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL), d", "SCF", "JR C, r", + "ADD HL, SP", "LD A, (HL-)", "DEC SP", "INC A", "DEC A", "LD A, d", "CCF", + "LD B, B", "LD B, C", "LD B, D", "LD B, E", "LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", "LD C, B", "LD C, C", + "LD C, D", "LD C, E", "LD C, H", "LD C, L", "LD C, (HL)", "LD C, A", + "LD D, B", "LD D, C", "LD D, D", "LD D, E", "LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", "LD E, B", "LD E, C", + "LD E, D", "LD E, E", "LD E, H", "LD E, L", "LD E, (HL)", "LD E, A", + "LD H, B", "LD H, C", "LD H, D", "LD H, E", "LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", "LD L, B", "LD L, C", + "LD L, D", "LD L, E", "LD L, H", "LD L, L", "LD L, (HL)", "LD L, A", + "LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E", "LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A", "LD A, B", + "LD A, C", "LD A, D", "LD A, E", "LD A, H", "LD A, L", "LD A, (HL)", "LD A, A", + "ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", "ADD A, H", "ADD A, L", "ADD A, (HL)", "ADD A, A", "ADC A, B", + "ADC A, C", "ADC A, D", "ADC A, E", "ADC A, H", "ADC A, L", "ADC A, (HL)", "ADC A, A", + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", "SBC A, B", "SBC A, C", "SBC A, D", + "SBC A, E", "SBC A, H", "SBC A, L", "SBC A, (HL)", "SBC A, A", + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", "XOR B", "XOR C", "XOR D", "XOR E", + "XOR H", "XOR L", "XOR (HL)", "XOR A", + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", + "CP (HL)", "CP A", + "RET NZ", "POP BC", "JP NZ, a", "JP a", "CALL NZ, a", "PUSH BC", "ADD A, d", "RST 00H", "RET Z", "RET", "JP Z, a", + "PREFIX", "CALL Z, a", "CALL a", "ADC A, d", "RST 08H", + "RET NC", "POP DE", "JP NC, a", "ILL_D3", "CALL NC, a", "PUSH DE", "SUB d", "RST 10H", "RET C", "RETI", "JP C, a", + "ILL_DB", "CALL C, a", "ILL_DD", "SBC A, d", "RST 18H", + "LDH (c), A", "POP HL", "LD ($FF00+C), A", "ILL_E3", "ILL_E4", "PUSH HL", "AND d", "RST 20H", "ADD SP, d", "JP HL", + "LD (a), A", "ILL_EB", "ILL_EC", "ILL_ED", "XOR d", "RST 28H", + "LDH A, (c)", "POP AF", "LD A, ($FF00+C)", "DI", "ILL_F4", "PUSH AF", "OR d", "RST 30H", "LD HL, SP+d", "LD SP, HL", + "LD A, (a)", "EI", "ILL_FC", "ILL_FD", "CP d", "RST 38H" }; constexpr const char* _cbTemplate[256] = { - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", - "SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", - "BIT 0, B", "BIT 0, C", "BIT 0, D", "BIT 0, E", "BIT 0, H", "BIT 0, L", "BIT 0, (HL)", "BIT 0, A", "BIT 1, B", "BIT 1, C", "BIT 1, D", "BIT 1, E", "BIT 1, H", "BIT 1, L", "BIT 1, (HL)", "BIT 1, A", - "BIT 2, B", "BIT 2, C", "BIT 2, D", "BIT 2, E", "BIT 2, H", "BIT 2, L", "BIT 2, (HL)", "BIT 2, A", "BIT 3, B", "BIT 3, C", "BIT 3, D", "BIT 3, E", "BIT 3, H", "BIT 3, L", "BIT 3, (HL)", "BIT 3, A", - "BIT 4, B", "BIT 4, C", "BIT 4, D", "BIT 4, E", "BIT 4, H", "BIT 4, L", "BIT 4, (HL)", "BIT 4, A", "BIT 5, B", "BIT 5, C", "BIT 5, D", "BIT 5, E", "BIT 5, H", "BIT 5, L", "BIT 5, (HL)", "BIT 5, A", - "BIT 6, B", "BIT 6, C", "BIT 6, D", "BIT 6, E", "BIT 6, H", "BIT 6, L", "BIT 6, (HL)", "BIT 6, A", "BIT 7, B", "BIT 7, C", "BIT 7, D", "BIT 7, E", "BIT 7, H", "BIT 7, L", "BIT 7, (HL)", "BIT 7, A", - "RES 0, B", "RES 0, C", "RES 0, D", "RES 0, E", "RES 0, H", "RES 0, L", "RES 0, (HL)", "RES 0, A", "RES 1, B", "RES 1, C", "RES 1, D", "RES 1, E", "RES 1, H", "RES 1, L", "RES 1, (HL)", "RES 1, A", - "RES 2, B", "RES 2, C", "RES 2, D", "RES 2, E", "RES 2, H", "RES 2, L", "RES 2, (HL)", "RES 2, A", "RES 3, B", "RES 3, C", "RES 3, D", "RES 3, E", "RES 3, H", "RES 3, L", "RES 3, (HL)", "RES 3, A", - "RES 4, B", "RES 4, C", "RES 4, D", "RES 4, E", "RES 4, H", "RES 4, L", "RES 4, (HL)", "RES 4, A", "RES 5, B", "RES 5, C", "RES 5, D", "RES 5, E", "RES 5, H", "RES 5, L", "RES 5, (HL)", "RES 5, A", - "RES 6, B", "RES 6, C", "RES 6, D", "RES 6, E", "RES 6, H", "RES 6, L", "RES 6, (HL)", "RES 6, A", "RES 7, B", "RES 7, C", "RES 7, D", "RES 7, E", "RES 7, H", "RES 7, L", "RES 7, (HL)", "RES 7, A", - "SET 0, B", "SET 0, C", "SET 0, D", "SET 0, E", "SET 0, H", "SET 0, L", "SET 0, (HL)", "SET 0, A", "SET 1, B", "SET 1, C", "SET 1, D", "SET 1, E", "SET 1, H", "SET 1, L", "SET 1, (HL)", "SET 1, A", - "SET 2, B", "SET 2, C", "SET 2, D", "SET 2, E", "SET 2, H", "SET 2, L", "SET 2, (HL)", "SET 2, A", "SET 3, B", "SET 3, C", "SET 3, D", "SET 3, E", "SET 3, H", "SET 3, L", "SET 3, (HL)", "SET 3, A", - "SET 4, B", "SET 4, C", "SET 4, D", "SET 4, E", "SET 4, H", "SET 4, L", "SET 4, (HL)", "SET 4, A", "SET 5, B", "SET 5, C", "SET 5, D", "SET 5, E", "SET 5, H", "SET 5, L", "SET 5, (HL)", "SET 5, A", - "SET 6, B", "SET 6, C", "SET 6, D", "SET 6, E", "SET 6, H", "SET 6, L", "SET 6, (HL)", "SET 6, A", "SET 7, B", "SET 7, C", "SET 7, D", "SET 7, E", "SET 7, H", "SET 7, L", "SET 7, (HL)", "SET 7, A", + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", "RRC B", "RRC C", "RRC D", "RRC E", + "RRC H", "RRC L", "RRC (HL)", "RRC A", + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", + "RR (HL)", "RR A", + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", "SRA B", "SRA C", "SRA D", "SRA E", + "SRA H", "SRA L", "SRA (HL)", "SRA A", + "SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", "SRL B", "SRL C", "SRL D", + "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", + "BIT 0, B", "BIT 0, C", "BIT 0, D", "BIT 0, E", "BIT 0, H", "BIT 0, L", "BIT 0, (HL)", "BIT 0, A", "BIT 1, B", + "BIT 1, C", "BIT 1, D", "BIT 1, E", "BIT 1, H", "BIT 1, L", "BIT 1, (HL)", "BIT 1, A", + "BIT 2, B", "BIT 2, C", "BIT 2, D", "BIT 2, E", "BIT 2, H", "BIT 2, L", "BIT 2, (HL)", "BIT 2, A", "BIT 3, B", + "BIT 3, C", "BIT 3, D", "BIT 3, E", "BIT 3, H", "BIT 3, L", "BIT 3, (HL)", "BIT 3, A", + "BIT 4, B", "BIT 4, C", "BIT 4, D", "BIT 4, E", "BIT 4, H", "BIT 4, L", "BIT 4, (HL)", "BIT 4, A", "BIT 5, B", + "BIT 5, C", "BIT 5, D", "BIT 5, E", "BIT 5, H", "BIT 5, L", "BIT 5, (HL)", "BIT 5, A", + "BIT 6, B", "BIT 6, C", "BIT 6, D", "BIT 6, E", "BIT 6, H", "BIT 6, L", "BIT 6, (HL)", "BIT 6, A", "BIT 7, B", + "BIT 7, C", "BIT 7, D", "BIT 7, E", "BIT 7, H", "BIT 7, L", "BIT 7, (HL)", "BIT 7, A", + "RES 0, B", "RES 0, C", "RES 0, D", "RES 0, E", "RES 0, H", "RES 0, L", "RES 0, (HL)", "RES 0, A", "RES 1, B", + "RES 1, C", "RES 1, D", "RES 1, E", "RES 1, H", "RES 1, L", "RES 1, (HL)", "RES 1, A", + "RES 2, B", "RES 2, C", "RES 2, D", "RES 2, E", "RES 2, H", "RES 2, L", "RES 2, (HL)", "RES 2, A", "RES 3, B", + "RES 3, C", "RES 3, D", "RES 3, E", "RES 3, H", "RES 3, L", "RES 3, (HL)", "RES 3, A", + "RES 4, B", "RES 4, C", "RES 4, D", "RES 4, E", "RES 4, H", "RES 4, L", "RES 4, (HL)", "RES 4, A", "RES 5, B", + "RES 5, C", "RES 5, D", "RES 5, E", "RES 5, H", "RES 5, L", "RES 5, (HL)", "RES 5, A", + "RES 6, B", "RES 6, C", "RES 6, D", "RES 6, E", "RES 6, H", "RES 6, L", "RES 6, (HL)", "RES 6, A", "RES 7, B", + "RES 7, C", "RES 7, D", "RES 7, E", "RES 7, H", "RES 7, L", "RES 7, (HL)", "RES 7, A", + "SET 0, B", "SET 0, C", "SET 0, D", "SET 0, E", "SET 0, H", "SET 0, L", "SET 0, (HL)", "SET 0, A", "SET 1, B", + "SET 1, C", "SET 1, D", "SET 1, E", "SET 1, H", "SET 1, L", "SET 1, (HL)", "SET 1, A", + "SET 2, B", "SET 2, C", "SET 2, D", "SET 2, E", "SET 2, H", "SET 2, L", "SET 2, (HL)", "SET 2, A", "SET 3, B", + "SET 3, C", "SET 3, D", "SET 3, E", "SET 3, H", "SET 3, L", "SET 3, (HL)", "SET 3, A", + "SET 4, B", "SET 4, C", "SET 4, D", "SET 4, E", "SET 4, H", "SET 4, L", "SET 4, (HL)", "SET 4, A", "SET 5, B", + "SET 5, C", "SET 5, D", "SET 5, E", "SET 5, H", "SET 5, L", "SET 5, (HL)", "SET 5, A", + "SET 6, B", "SET 6, C", "SET 6, D", "SET 6, E", "SET 6, H", "SET 6, L", "SET 6, (HL)", "SET 6, A", "SET 7, B", + "SET 7, C", "SET 7, D", "SET 7, E", "SET 7, H", "SET 7, L", "SET 7, (HL)", "SET 7, A", }; constexpr const uint8_t _opSize[256] = { - 1,3,1,1,1,1,2,1,3,1,1,1,1,1,2,1, - 1,3,1,1,1,1,2,1,2,1,1,1,1,1,2,1, - 2,3,1,1,1,1,2,1,2,1,1,1,1,1,2,1, - 2,3,1,1,1,1,2,1,2,1,1,1,1,1,2,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,3,3,3,1,2,1,1,1,3,2,3,3,2,1, - 1,1,3,1,3,1,2,1,1,1,3,1,3,1,2,1, - 2,1,1,1,1,1,2,1,2,1,3,1,1,1,2,1, - 2,1,1,1,1,1,2,1,2,1,3,1,1,1,2,1, + 1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1, + 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1, + 1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, 1, + 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, + 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, }; enum class AddrType : uint8_t { None, BC, - DE, + DE, HL, C, Suff }; static constexpr const AddrType _gbEffAddrType[256] = { - AddrType::None,AddrType::None,AddrType::BC, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::BC, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::DE, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::DE, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::HL, AddrType::HL, AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::HL, AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::Suff,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::C,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None, - AddrType::None,AddrType::None,AddrType::C,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None,AddrType::None + AddrType::None, AddrType::None, AddrType::BC, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::BC, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::DE, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::DE, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::HL, AddrType::HL, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::HL, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::HL, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::HL, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::HL, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::Suff, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::C, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::C, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, AddrType::None, + AddrType::None, AddrType::None }; -void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings) +void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, + LabelManager* labelManager, EmuSettings* settings) { FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); - AddressInfo addrInfo { 0, SnesMemoryType::GameboyMemory }; - auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) { + AddressInfo addrInfo{0, SnesMemoryType::GameboyMemory}; + auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) + { addrInfo.Address = addr; - string label = labelManager ? labelManager->GetLabel(addrInfo) :""; - if(label.empty()) { + string label = labelManager ? labelManager->GetLabel(addrInfo) : ""; + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex(addr)); - } else { + } + else + { str.Write(label, true); } }; uint8_t* byteCode = info.GetByteCode(); const char* op = byteCode[0] == 0xCB ? _cbTemplate[byteCode[1]] : _opTemplate[byteCode[0]]; - if(byteCode[0] == 0xCB) { + if (byteCode[0] == 0xCB) + { byteCode++; } int i = 0; - while(op[i]) { - switch(op[i]) { + while (op[i]) + { + switch (op[i]) + { //Relative jumps - case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); break; + case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); + break; //Jump addresses, memory addresses - case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); break; - case 'c': getOperand((uint16_t)(0xFF00 | byteCode[1])); break; + case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); + break; + case 'c': getOperand((uint16_t)(0xFF00 | byteCode[1])); + break; //Immediate values - case 'd': str.WriteAll("$", HexUtilities::ToHex(byteCode[1])); break; - case 'e': str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8)))); break; + case 'd': str.WriteAll("$", HexUtilities::ToHex(byteCode[1])); + break; + case 'e': str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8)))); + break; - default: str.Write(op[i]); break; + default: str.Write(op[i]); + break; } i++; } @@ -138,19 +216,21 @@ void GameboyDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_ int32_t GameboyDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, GbCpuState& state) { - switch(_gbEffAddrType[info.GetOpCode()]) { - default: - case AddrType::None: return -1; + switch (_gbEffAddrType[info.GetOpCode()]) + { + default: + case AddrType::None: return -1; - case AddrType::BC: return (state.B << 8) | state.C; - case AddrType::DE: return (state.D << 8) | state.E; - case AddrType::HL: return (state.H << 8) | state.L; - case AddrType::C: return 0xFF00 + state.C; - case AddrType::Suff: - if((info.GetByteCode()[1] & 0x07) == 0x06) { - return (state.H << 8) | state.L; - } - return -1; + case AddrType::BC: return (state.B << 8) | state.C; + case AddrType::DE: return (state.D << 8) | state.E; + case AddrType::HL: return (state.H << 8) | state.L; + case AddrType::C: return 0xFF00 + state.C; + case AddrType::Suff: + if ((info.GetByteCode()[1] & 0x07) == 0x06) + { + return (state.H << 8) | state.L; + } + return -1; } } @@ -163,8 +243,9 @@ bool GameboyDisUtils::IsJumpToSub(uint8_t opCode) { return ( opCode == 0xC4 || opCode == 0xCC || opCode == 0xD4 || opCode == 0xDC || //CALL conditional - opCode == 0xCD ||//Unconditional CALL - opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || opCode == 0xF7 || opCode == 0xFF //RST unconditional + opCode == 0xCD || //Unconditional CALL + opCode == 0xC7 || opCode == 0xCF || opCode == 0xD7 || opCode == 0xDF || opCode == 0xE7 || opCode == 0xEF || opCode + == 0xF7 || opCode == 0xFF //RST unconditional ); } @@ -179,4 +260,4 @@ bool GameboyDisUtils::IsReturnInstruction(uint8_t opCode) string GameboyDisUtils::GetOpTemplate(uint8_t op, bool prefixed) { return prefixed ? _cbTemplate[op] : _opTemplate[op]; -} \ No newline at end of file +} diff --git a/Core/GameboyDisUtils.h b/Core/GameboyDisUtils.h index eaf670b..0eb5b1d 100644 --- a/Core/GameboyDisUtils.h +++ b/Core/GameboyDisUtils.h @@ -10,7 +10,8 @@ struct GbCpuState; class GameboyDisUtils { public: - static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, GbCpuState& state); static uint8_t GetOpSize(uint8_t opCode); static bool IsJumpToSub(uint8_t opCode); diff --git a/Core/GameboyHeader.h b/Core/GameboyHeader.h index 108eb76..5c0fc46 100644 --- a/Core/GameboyHeader.h +++ b/Core/GameboyHeader.h @@ -20,7 +20,8 @@ struct GameboyHeader uint32_t GetPrgRomSize() { - if(PrgRomSize < 16) { + if (PrgRomSize < 16) + { return 0x8000 << PrgRomSize; } return 0x8000; @@ -28,29 +29,40 @@ struct GameboyHeader uint32_t GetCartRamSize() { - if(CartType == 5 || CartType == 6) { + if (CartType == 5 || CartType == 6) + { //MBC2 has 512x4bits of cart ram return 0x200; } - switch(CartRamSize) { - case 0: return 0; - case 1: return 0x800; - case 2: return 0x2000; - case 3: return 0x8000; - case 4: return 0x20000; - case 5: return 0x10000; + switch (CartRamSize) + { + case 0: return 0; + case 1: return 0x800; + case 2: return 0x2000; + case 3: return 0x8000; + case 4: return 0x20000; + case 5: return 0x10000; } return 0; } bool HasBattery() { - switch(CartType) { - case 0x03: case 0x06: case 0x09: case 0x0D: - case 0x0F: case 0x10: case 0x13: case 0x1B: - case 0x1E: case 0x22: case 0xFF: - return true; + switch (CartType) + { + case 0x03: + case 0x06: + case 0x09: + case 0x0D: + case 0x0F: + case 0x10: + case 0x13: + case 0x1B: + case 0x1E: + case 0x22: + case 0xFF: + return true; } return false; @@ -59,8 +71,10 @@ struct GameboyHeader string GetCartName() { int nameLength = 11; - for(int i = 0; i < 11; i++) { - if(Title[i] == 0) { + for (int i = 0; i < 11; i++) + { + if (Title[i] == 0) + { nameLength = i; break; } @@ -68,9 +82,12 @@ struct GameboyHeader string name = string(Title, nameLength); size_t lastNonSpace = name.find_last_not_of(' '); - if(lastNonSpace != string::npos) { + if (lastNonSpace != string::npos) + { return name.substr(0, lastNonSpace + 1); - } else { + } + else + { return name; } } diff --git a/Core/GbApu.cpp b/Core/GbApu.cpp index 3a77a76..a69e1e7 100644 --- a/Core/GbApu.cpp +++ b/Core/GbApu.cpp @@ -37,10 +37,13 @@ void GbApu::Init(Console* console, Gameboy* gameboy) blip_clear(_leftChannel); blip_clear(_rightChannel); - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { blip_set_rates(_leftChannel, _gameboy->GetSgb()->GetClockRate(), GbApu::SampleRate); blip_set_rates(_rightChannel, _gameboy->GetSgb()->GetClockRate(), GbApu::SampleRate); - } else { + } + else + { blip_set_rates(_leftChannel, GbApu::ApuFrequency, GbApu::SampleRate); blip_set_rates(_rightChannel, GbApu::ApuFrequency, GbApu::SampleRate); } @@ -72,11 +75,18 @@ void GbApu::Run() GameboyConfig cfg = _settings->GetGameboyConfig(); - if(!_state.ApuEnabled) { + if (!_state.ApuEnabled) + { _clockCounter += clocksToRun; - } else { - while(clocksToRun > 0) { - uint32_t minTimer = std::min({ clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer, _noise->GetState().Timer }); + } + else + { + while (clocksToRun > 0) + { + uint32_t minTimer = std::min({ + clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer, + _noise->GetState().Timer + }); clocksToRun -= minTimer; _square1->Exec(minTimer); @@ -89,9 +99,10 @@ void GbApu::Run() (_square2->GetOutput() & _state.EnableLeftSq2) * cfg.Square2Vol / 100 + (_wave->GetOutput() & _state.EnableLeftWave) * cfg.WaveVol / 100 + (_noise->GetOutput() & _state.EnableLeftNoise) * cfg.NoiseVol / 100 - ) * (_state.LeftVolume + 1) * 40; + ) * (_state.LeftVolume + 1) * 40; - if(_prevLeftOutput != leftOutput) { + if (_prevLeftOutput != leftOutput) + { blip_add_delta(_leftChannel, _clockCounter, leftOutput - _prevLeftOutput); _prevLeftOutput = leftOutput; } @@ -101,9 +112,10 @@ void GbApu::Run() (_square2->GetOutput() & _state.EnableRightSq2) * cfg.Square2Vol / 100 + (_wave->GetOutput() & _state.EnableRightWave) * cfg.WaveVol / 100 + (_noise->GetOutput() & _state.EnableRightNoise) * cfg.NoiseVol / 100 - ) * (_state.RightVolume + 1) * 40; + ) * (_state.RightVolume + 1) * 40; - if(_prevRightOutput != rightOutput) { + if (_prevRightOutput != rightOutput) + { blip_add_delta(_rightChannel, _clockCounter, rightOutput - _prevRightOutput); _prevRightOutput = rightOutput; } @@ -112,7 +124,8 @@ void GbApu::Run() } } - if(!_gameboy->IsSgb() && _clockCounter >= 20000) { + if (!_gameboy->IsSgb() && _clockCounter >= 20000) + { blip_end_frame(_leftChannel, _clockCounter); blip_end_frame(_rightChannel, _clockCounter); @@ -123,7 +136,7 @@ void GbApu::Run() } } -void GbApu::GetSoundSamples(int16_t* &samples, uint32_t& sampleCount) +void GbApu::GetSoundSamples(int16_t* & samples, uint32_t& sampleCount) { Run(); blip_end_frame(_leftChannel, _clockCounter); @@ -139,20 +152,25 @@ void GbApu::ClockFrameSequencer() { Run(); - if(!_state.ApuEnabled) { + if (!_state.ApuEnabled) + { return; } - if((_state.FrameSequenceStep & 0x01) == 0) { + if ((_state.FrameSequenceStep & 0x01) == 0) + { _square1->ClockLengthCounter(); _square2->ClockLengthCounter(); _wave->ClockLengthCounter(); _noise->ClockLengthCounter(); - if((_state.FrameSequenceStep & 0x03) == 2) { + if ((_state.FrameSequenceStep & 0x03) == 2) + { _square1->ClockSweepUnit(); } - } else if(_state.FrameSequenceStep == 7) { + } + else if (_state.FrameSequenceStep == 7) + { _square1->ClockEnvelope(); _square2->ClockEnvelope(); _noise->ClockEnvelope(); @@ -174,52 +192,81 @@ uint8_t GbApu::Read(uint16_t addr) uint8_t GbApu::InternalRead(uint16_t addr) { - switch(addr) { - case 0xFF10: case 0xFF11: case 0xFF12: case 0xFF13: case 0xFF14: - return _square1->Read(addr - 0xFF10); - - case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19: - return _square2->Read(addr - 0xFF15); + switch (addr) + { + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + return _square1->Read(addr - 0xFF10); - case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E: - return _wave->Read(addr - 0xFF1A); + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + return _square2->Read(addr - 0xFF15); - case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23: - return _noise->Read(addr - 0xFF1F); + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + return _wave->Read(addr - 0xFF1A); - case 0xFF24: - return ( - (_state.ExtAudioLeftEnabled ? 0x80 : 0) | - (_state.LeftVolume << 4) | - (_state.ExtAudioRightEnabled ? 0x08 : 0) | - _state.RightVolume - ); + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + return _noise->Read(addr - 0xFF1F); - case 0xFF25: - return ( - (_state.EnableLeftNoise ? 0x80 : 0) | - (_state.EnableLeftWave ? 0x40 : 0) | - (_state.EnableLeftSq2 ? 0x20 : 0) | - (_state.EnableLeftSq1 ? 0x10 : 0) | - (_state.EnableRightNoise ? 0x08 : 0) | - (_state.EnableRightWave ? 0x04 : 0) | - (_state.EnableRightSq2 ? 0x02 : 0) | - (_state.EnableRightSq1 ? 0x01 : 0) - ); + case 0xFF24: + return ( + (_state.ExtAudioLeftEnabled ? 0x80 : 0) | + (_state.LeftVolume << 4) | + (_state.ExtAudioRightEnabled ? 0x08 : 0) | + _state.RightVolume + ); - case 0xFF26: - return ( - (_state.ApuEnabled ? 0x80 : 0) | - 0x70 | //open bus - ((_state.ApuEnabled && _noise->Enabled()) ? 0x08 : 0) | - ((_state.ApuEnabled && _wave->Enabled()) ? 0x04 : 0) | - ((_state.ApuEnabled && _square2->Enabled()) ? 0x02 : 0) | - ((_state.ApuEnabled && _square1->Enabled()) ? 0x01 : 0) - ); + case 0xFF25: + return ( + (_state.EnableLeftNoise ? 0x80 : 0) | + (_state.EnableLeftWave ? 0x40 : 0) | + (_state.EnableLeftSq2 ? 0x20 : 0) | + (_state.EnableLeftSq1 ? 0x10 : 0) | + (_state.EnableRightNoise ? 0x08 : 0) | + (_state.EnableRightWave ? 0x04 : 0) | + (_state.EnableRightSq2 ? 0x02 : 0) | + (_state.EnableRightSq1 ? 0x01 : 0) + ); - case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34: case 0xFF35: case 0xFF36: case 0xFF37: - case 0xFF38: case 0xFF39: case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E: case 0xFF3F: - return _wave->ReadRam(addr); + case 0xFF26: + return ( + (_state.ApuEnabled ? 0x80 : 0) | + 0x70 | //open bus + ((_state.ApuEnabled && _noise->Enabled()) ? 0x08 : 0) | + ((_state.ApuEnabled && _wave->Enabled()) ? 0x04 : 0) | + ((_state.ApuEnabled && _square2->Enabled()) ? 0x02 : 0) | + ((_state.ApuEnabled && _square1->Enabled()) ? 0x01 : 0) + ); + + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + return _wave->ReadRam(addr); } //Open bus @@ -230,63 +277,87 @@ void GbApu::Write(uint16_t addr, uint8_t value) { Run(); - if(!_state.ApuEnabled) { - if(addr == 0xFF11 || addr == 0xFF16 || addr == 0xFF20) { + if (!_state.ApuEnabled) + { + if (addr == 0xFF11 || addr == 0xFF16 || addr == 0xFF20) + { //Allow writes to length counter, but not the upper 2 bits (square duty) value &= 0x3F; - } else if(addr < 0xFF26 && addr != 0xFF1B) { + } + else if (addr < 0xFF26 && addr != 0xFF1B) + { //Ignore all writes to these registers when APU is disabled return; } } - switch(addr) { - case 0xFF10: case 0xFF11: case 0xFF12: case 0xFF13: case 0xFF14: - _square1->Write(addr - 0xFF10, value); - break; + switch (addr) + { + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + _square1->Write(addr - 0xFF10, value); + break; - case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19: - _square2->Write(addr - 0xFF15, value); //Same as square1, but without a sweep unit - break; + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + _square2->Write(addr - 0xFF15, value); //Same as square1, but without a sweep unit + break; - case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E: - _wave->Write(addr - 0xFF1A, value); - break; + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + _wave->Write(addr - 0xFF1A, value); + break; - case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23: - _noise->Write(addr - 0xFF1F, value); - break; + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + _noise->Write(addr - 0xFF1F, value); + break; - case 0xFF24: - _state.ExtAudioLeftEnabled = (value & 0x80) != 0; - _state.LeftVolume = (value & 0x70) >> 4; - _state.ExtAudioRightEnabled = (value & 0x08) != 0; - _state.RightVolume = (value & 0x07); - break; + case 0xFF24: + _state.ExtAudioLeftEnabled = (value & 0x80) != 0; + _state.LeftVolume = (value & 0x70) >> 4; + _state.ExtAudioRightEnabled = (value & 0x08) != 0; + _state.RightVolume = (value & 0x07); + break; - case 0xFF25: - _state.EnableLeftNoise = (value & 0x80) ? 0xFF : 0; - _state.EnableLeftWave = (value & 0x40) ? 0xFF : 0; - _state.EnableLeftSq2 = (value & 0x20) ? 0xFF : 0; - _state.EnableLeftSq1 = (value & 0x10) ? 0xFF : 0; + case 0xFF25: + _state.EnableLeftNoise = (value & 0x80) ? 0xFF : 0; + _state.EnableLeftWave = (value & 0x40) ? 0xFF : 0; + _state.EnableLeftSq2 = (value & 0x20) ? 0xFF : 0; + _state.EnableLeftSq1 = (value & 0x10) ? 0xFF : 0; - _state.EnableRightNoise = (value & 0x08) ? 0xFF : 0; - _state.EnableRightWave = (value & 0x04) ? 0xFF : 0; - _state.EnableRightSq2 = (value & 0x02) ? 0xFF : 0; - _state.EnableRightSq1 = (value & 0x01) ? 0xFF : 0; - break; + _state.EnableRightNoise = (value & 0x08) ? 0xFF : 0; + _state.EnableRightWave = (value & 0x04) ? 0xFF : 0; + _state.EnableRightSq2 = (value & 0x02) ? 0xFF : 0; + _state.EnableRightSq1 = (value & 0x01) ? 0xFF : 0; + break; - case 0xFF26: { + case 0xFF26: + { bool apuEnabled = (value & 0x80) != 0; - if(_state.ApuEnabled != apuEnabled) { - if(!apuEnabled) { + if (_state.ApuEnabled != apuEnabled) + { + if (!apuEnabled) + { _square1->Disable(); _square2->Disable(); _wave->Disable(); _noise->Disable(); Write(0xFF24, 0); Write(0xFF25, 0); - } else { + } + else + { //When powered on, the frame sequencer is reset so that the next step will be 0, //the square duty units are reset to the first step of the waveform, and the wave channel's sample buffer is reset to 0. _state.FrameSequenceStep = 0; @@ -295,38 +366,59 @@ void GbApu::Write(uint16_t addr, uint8_t value) } break; } - case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34: case 0xFF35: case 0xFF36: case 0xFF37: - case 0xFF38: case 0xFF39: case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E: case 0xFF3F: - _wave->WriteRam(addr, value); - break; + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + _wave->WriteRam(addr, value); + break; } } uint8_t GbApu::ReadCgbRegister(uint16_t addr) { - switch(addr) { - case 0xFF76: return _square1->GetOutput() | (_square2->GetOutput() << 4); - case 0xFF77: return _noise->GetOutput() | (_wave->GetOutput() << 4); + switch (addr) + { + case 0xFF76: return _square1->GetOutput() | (_square2->GetOutput() << 4); + case 0xFF77: return _noise->GetOutput() | (_wave->GetOutput() << 4); } //Should not be called return 0; } -template -void GbApu::ProcessLengthEnableFlag(uint8_t value, T &length, bool &lengthEnabled, bool &enabled) +template +void GbApu::ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled) { bool newLengthEnabled = (value & 0x40) != 0; - if(newLengthEnabled && !lengthEnabled && (_state.FrameSequenceStep & 0x01) == 1) { + if (newLengthEnabled && !lengthEnabled && (_state.FrameSequenceStep & 0x01) == 1) + { //"Extra length clocking occurs when writing to NRx4 when the frame sequencer's next step is one that doesn't clock //the length counter. In this case, if the length counter was PREVIOUSLY disabled and now enabled and the length counter //is not zero, it is decremented. If this decrement makes it zero and trigger is clear, the channel is disabled." - if(length > 0) { + if (length > 0) + { length--; - if(length == 0) { - if(value & 0x80) { + if (length == 0) + { + if (value & 0x80) + { length = sizeof(T) == 1 ? 0x3F : 0xFF; - } else { + } + else + { enabled = false; } } @@ -351,5 +443,7 @@ void GbApu::Serialize(Serializer& s) s.Stream(_noise.get()); } -template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint8_t& length, bool& lengthEnabled, bool& enabled); -template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint16_t& length, bool& lengthEnabled, bool& enabled); \ No newline at end of file +template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint8_t& length, bool& lengthEnabled, + bool& enabled); +template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint16_t& length, bool& lengthEnabled, + bool& enabled); diff --git a/Core/GbApu.h b/Core/GbApu.h index ca13e6f..3953396 100644 --- a/Core/GbApu.h +++ b/Core/GbApu.h @@ -52,7 +52,7 @@ public: void Run(); - void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount); + void GetSoundSamples(int16_t* & samples, uint32_t& sampleCount); void ClockFrameSequencer(); @@ -62,7 +62,8 @@ public: uint8_t ReadCgbRegister(uint16_t addr); - template void ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled); + template + void ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled); void Serialize(Serializer& s) override; }; diff --git a/Core/GbAssembler.cpp b/Core/GbAssembler.cpp index 0470415..53c9614 100644 --- a/Core/GbAssembler.cpp +++ b/Core/GbAssembler.cpp @@ -20,17 +20,21 @@ GbAssembler::~GbAssembler() void GbAssembler::InitAssembler() { - for(int i = 0; i < 512; i++) { + for (int i = 0; i < 512; i++) + { string op = GameboyDisUtils::GetOpTemplate(i & 0xFF, i >= 256); size_t spaceIndex = op.find(' '); size_t commaIndex = op.find(','); string opName; OpCodeEntry entry = {}; - if(spaceIndex != string::npos) { + if (spaceIndex != string::npos) + { opName = op.substr(0, spaceIndex); entry.ParamCount = commaIndex != string::npos ? 2 : 1; - } else { + } + else + { opName = op; entry.ParamCount = 0; } @@ -38,18 +42,23 @@ void GbAssembler::InitAssembler() entry.OpCode = i < 256 ? i : ((i << 8) | 0xCB); std::transform(opName.begin(), opName.end(), opName.begin(), ::tolower); - if(_opCodes.find(opName) == _opCodes.end()) { + if (_opCodes.find(opName) == _opCodes.end()) + { _opCodes[opName] = vector(); } - if(entry.ParamCount > 0) { + if (entry.ParamCount > 0) + { string operands = op.substr(spaceIndex + 1); operands.erase(std::remove_if(operands.begin(), operands.end(), isspace), operands.end()); - if(entry.ParamCount == 2) { + if (entry.ParamCount == 2) + { vector operandList = StringUtilities::Split(operands, ','); InitParamEntry(entry.Param1, operandList[0]); InitParamEntry(entry.Param2, operandList[1]); - } else if(entry.ParamCount == 1) { + } + else if (entry.ParamCount == 1) + { InitParamEntry(entry.Param1, operands); } } @@ -59,21 +68,36 @@ void GbAssembler::InitAssembler() void GbAssembler::InitParamEntry(ParamEntry& entry, string param) { - if(param == "a") { + if (param == "a") + { entry.Type = ParamType::Short; - } else if(param == "d") { + } + else if (param == "d") + { entry.Type = ParamType::Byte; - } else if(param == "e") { + } + else if (param == "e") + { entry.Type = ParamType::Short; - } else if(param == "r") { + } + else if (param == "r") + { entry.Type = ParamType::RelAddress; - } else if(param == "(a)") { + } + else if (param == "(a)") + { entry.Type = ParamType::Address; - } else if(param == "(c)") { + } + else if (param == "(c)") + { entry.Type = ParamType::HighAddress; - } else if(param == "SP+d") { + } + else if (param == "SP+d") + { entry.Type = ParamType::StackOffset; - } else { + } + else + { std::transform(param.begin(), param.end(), param.begin(), ::tolower); entry.Type = ParamType::Literal; entry.Param = param; @@ -83,111 +107,143 @@ void GbAssembler::InitParamEntry(ParamEntry& entry, string param) bool GbAssembler::IsRegisterName(string op) { - return op == "hl" || op == "af" || op == "bc" || op == "de" || op == "a" || op == "b" || op == "c" || op == "d" || op == "e" || op == "f" || op == "l" || op == "h"; + return op == "hl" || op == "af" || op == "bc" || op == "de" || op == "a" || op == "b" || op == "c" || op == "d" || op + == "e" || op == "f" || op == "l" || op == "h"; } -int GbAssembler::ReadValue(string operand, int min, int max, unordered_map& localLabels, bool firstPass) +int GbAssembler::ReadValue(string operand, int min, int max, unordered_map& localLabels, + bool firstPass) { int value = 0; - switch(operand[0]) { + switch (operand[0]) + { //Hex - case '$': value = HexUtilities::FromHex(operand.substr(1)); break; + case '$': value = HexUtilities::FromHex(operand.substr(1)); + break; - case '%': - //Binary - for(size_t i = 1; i < operand.size(); i++) { - value <<= 1; - value |= operand[i] == '1' ? 1 : 0; + case '%': + //Binary + for (size_t i = 1; i < operand.size(); i++) + { + value <<= 1; + value |= operand[i] == '1' ? 1 : 0; + } + break; + + default: + if (std::regex_match(operand, labelRegex)) + { + if (firstPass) + { + return 0; } - break; - - default: - if(std::regex_match(operand, labelRegex)) { - if(firstPass) { - return 0; - } else if(localLabels.find(operand) != localLabels.end()) { - value = localLabels.find(operand)->second; - } else { - int labelAddress = _labelManager->GetLabelRelativeAddress(operand, CpuType::Gameboy); - if(labelAddress >= 0) { - //Matching label found - value = labelAddress; - } + else if (localLabels.find(operand) != localLabels.end()) + { + value = localLabels.find(operand)->second; + } + else + { + int labelAddress = _labelManager->GetLabelRelativeAddress(operand, CpuType::Gameboy); + if (labelAddress >= 0) + { + //Matching label found + value = labelAddress; } - } else { - //Decimal - for(size_t i = 0; i < operand.size(); i++) { - if(operand[i] != '-' && (operand[i] < '0' || operand[i] > '9')) { - return -1; - } - } - - try { - value = std::stoi(operand); - if(value < 0) { - value = max + value + 1; - } - } catch(std::exception&) { + } + } + else + { + //Decimal + for (size_t i = 0; i < operand.size(); i++) + { + if (operand[i] != '-' && (operand[i] < '0' || operand[i] > '9')) + { return -1; } } - break; + + try + { + value = std::stoi(operand); + if (value < 0) + { + value = max + value + 1; + } + } + catch (std::exception&) + { + return -1; + } + } + break; } - if(value < min || value > max) { + if (value < min || value > max) + { return -1; } return value; } -bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map& localLabels, bool firstPass) +bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, + unordered_map& localLabels, bool firstPass) { - if(entry.Type != ParamType::Literal && IsRegisterName(operand)) { + if (entry.Type != ParamType::Literal && IsRegisterName(operand)) + { return false; } - switch(entry.Type) { - case ParamType::None: return false; + switch (entry.Type) + { + case ParamType::None: return false; - case ParamType::Literal: { + case ParamType::Literal: + { string param = entry.Param; std::transform(param.begin(), param.end(), param.begin(), ::tolower); std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); return operand == param; } - case ParamType::Byte: - return ReadValue(operand, -128, 0xFF, localLabels, firstPass) >= 0; + case ParamType::Byte: + return ReadValue(operand, -128, 0xFF, localLabels, firstPass) >= 0; - case ParamType::Short: - return ReadValue(operand, -32768, 0xFFFF, localLabels, firstPass) >= 0; + case ParamType::Short: + return ReadValue(operand, -32768, 0xFFFF, localLabels, firstPass) >= 0; - case ParamType::Address: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - return ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass) >= 0; - } - return false; + case ParamType::Address: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + return ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass) >= 0; + } + return false; - case ParamType::HighAddress: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - return ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass) >= 0; - } - return false; + case ParamType::HighAddress: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + return ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass) >= 0; + } + return false; - case ParamType::StackOffset: - std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); - if(operand.size() > 3 && operand.substr(0, 3) == "sp+") { - return ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass) >= 0; - } - return false; + case ParamType::StackOffset: + std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); + if (operand.size() > 3 && operand.substr(0, 3) == "sp+") + { + return ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass) >= 0; + } + return false; - case ParamType::RelAddress: { + case ParamType::RelAddress: + { int value = ReadValue(operand, 0, 0xFFFF, localLabels, firstPass); - if(value >= 0) { + if (value >= 0) + { int offset = (value - (address + 2)); return offset >= -128 && offset <= 127; - } else if(firstPass) { + } + else if (firstPass) + { return 0; } return false; @@ -199,9 +255,12 @@ bool GbAssembler::IsMatch(ParamEntry& entry, string operand, uint32_t address, u void GbAssembler::PushOp(uint16_t opCode, vector& output, uint32_t& address) { - if(opCode < 256) { + if (opCode < 256) + { PushByte((uint8_t)opCode, output, address); - } else { + } + else + { PushWord((uint16_t)opCode, output, address); } } @@ -219,40 +278,48 @@ void GbAssembler::PushWord(uint16_t operand, vector& output, uint32_t& address += 2; } -void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, unordered_map& localLabels, bool firstPass) +void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, + unordered_map& localLabels, bool firstPass) { - switch(entry.Type) { - default: - break; + switch (entry.Type) + { + default: + break; - case ParamType::Byte: - PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address); - break; + case ParamType::Byte: + PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address); + break; - case ParamType::Short: - PushWord((uint16_t)ReadValue(operand, -32768, 65535, localLabels, firstPass), output, address); - break; + case ParamType::Short: + PushWord((uint16_t)ReadValue(operand, -32768, 65535, localLabels, firstPass), output, address); + break; - case ParamType::Address: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - PushWord((uint16_t)ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass), output, address); - } - break; + case ParamType::Address: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + PushWord((uint16_t)ReadValue(operand.substr(1, operand.size() - 2), 0, 0xFFFF, localLabels, firstPass), output, + address); + } + break; - case ParamType::HighAddress: - if(operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') { - PushByte((uint8_t)ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass), output, address); - } - break; + case ParamType::HighAddress: + if (operand.size() > 2 && operand[0] == '(' && operand[operand.size() - 1] == ')') + { + PushByte((uint8_t)ReadValue(operand.substr(1, operand.size() - 2), 0xFF00, 0xFFFF, localLabels, firstPass), + output, address); + } + break; - case ParamType::StackOffset: - std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); - if(operand.size() > 3 && operand.substr(0, 3) == "sp+") { - PushByte((uint8_t)ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass), output, address); - } - break; + case ParamType::StackOffset: + std::transform(operand.begin(), operand.end(), operand.begin(), ::tolower); + if (operand.size() > 3 && operand.substr(0, 3) == "sp+") + { + PushByte((uint8_t)ReadValue(operand.substr(3), 0, 0xFF, localLabels, firstPass), output, address); + } + break; - case ParamType::RelAddress: { + case ParamType::RelAddress: + { int value = ReadValue(operand, 0, 0xFFFF, localLabels, firstPass); int offset = (value - (address + 1)); PushByte((uint8_t)offset, output, address); @@ -261,32 +328,42 @@ void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, unordered_map& localLabels) +void GbAssembler::RunPass(vector& output, string code, uint32_t address, int16_t* assembledCode, + bool firstPass, unordered_map& localLabels) { unordered_set currentPassLabels; - for(string line : StringUtilities::Split(code, '\n')) { + for (string line : StringUtilities::Split(code, '\n')) + { //Remove comment size_t commentIndex = line.find(';'); - if(commentIndex != string::npos) { + if (commentIndex != string::npos) + { line = line.substr(0, commentIndex); } //Check if this is a label definition size_t labelDefIndex = line.find(':'); - if(labelDefIndex != string::npos) { + if (labelDefIndex != string::npos) + { std::smatch match; string labelName = line.substr(0, labelDefIndex); - if(std::regex_search(labelName, match, labelRegex)) { + if (std::regex_search(labelName, match, labelRegex)) + { string label = match.str(1); - if(firstPass && currentPassLabels.find(label) != currentPassLabels.end()) { + if (firstPass && currentPassLabels.find(label) != currentPassLabels.end()) + { output.push_back(AssemblerSpecialCodes::LabelRedefinition); continue; - } else { + } + else + { localLabels[label] = address; currentPassLabels.emplace(label); line = line.substr(labelDefIndex + 1); } - } else { + } + else + { output.push_back(AssemblerSpecialCodes::InvalidLabel); continue; } @@ -294,20 +371,25 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address //Trim left spaces size_t startIndex = line.find_first_not_of("\t "); - if(startIndex > 0 && startIndex != string::npos) { + if (startIndex > 0 && startIndex != string::npos) + { line = line.substr(startIndex); } //Check if this is a .db statement - if(line.size() > 3 && line.substr(0, 3) == ".db") { + if (line.size() > 3 && line.substr(0, 3) == ".db") + { line = line.substr(3); - for(string byte : StringUtilities::Split(line, ' ')) { - if(byte.empty()) { + for (string byte : StringUtilities::Split(line, ' ')) + { + if (byte.empty()) + { continue; } int value = ReadValue(byte, -128, 255, localLabels, true); - if(value >= 0) { + if (value >= 0) + { PushByte((uint8_t)value, output, address); } } @@ -318,20 +400,25 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address //Find op code name size_t spaceIndex = line.find(' '); string opName; - if(spaceIndex != string::npos) { + if (spaceIndex != string::npos) + { opName = line.substr(0, spaceIndex); - } else { + } + else + { opName = line; } - if(opName.empty()) { + if (opName.empty()) + { output.push_back(AssemblerSpecialCodes::EndOfLine); continue; } std::transform(opName.begin(), opName.end(), opName.begin(), ::tolower); - if(_opCodes.find(opName) == _opCodes.end()) { + if (_opCodes.find(opName) == _opCodes.end()) + { //No matching opcode found, mark it as invalid output.push_back(AssemblerSpecialCodes::InvalidInstruction); continue; @@ -340,51 +427,69 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address //Find the operands given int paramCount = 0; vector operandList; - if(spaceIndex != string::npos) { + if (spaceIndex != string::npos) + { string operands = line.substr(spaceIndex + 1); operands.erase(std::remove_if(operands.begin(), operands.end(), isspace), operands.end()); - if(!operands.empty()) { + if (!operands.empty()) + { size_t commaIndex = line.find(','); - if(commaIndex != string::npos) { + if (commaIndex != string::npos) + { paramCount = 2; operandList = StringUtilities::Split(operands, ','); bool invalid = operandList.size() > 2; - for(string operand : operandList) { - if(operand.empty()) { + for (string operand : operandList) + { + if (operand.empty()) + { invalid = true; break; } } - if(invalid) { + if (invalid) + { output.push_back(AssemblerSpecialCodes::InvalidOperands); continue; } - } else { + } + else + { paramCount = 1; - operandList = { operands }; + operandList = {operands}; } } } bool matchFound = false; //Find a matching set of opcode + operands - for(OpCodeEntry& entry : _opCodes.find(opName)->second) { - if(entry.ParamCount == paramCount) { - if(paramCount == 0) { + for (OpCodeEntry& entry : _opCodes.find(opName)->second) + { + if (entry.ParamCount == paramCount) + { + if (paramCount == 0) + { PushOp(entry.OpCode, output, address); matchFound = true; break; - } else if(paramCount == 1) { - if(IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass)) { + } + else if (paramCount == 1) + { + if (IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass)) + { PushOp(entry.OpCode, output, address); ProcessOperand(entry.Param1, operandList[0], output, address, localLabels, firstPass); matchFound = true; break; } - } else if(paramCount == 2) { - if(IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass) && IsMatch(entry.Param2, operandList[1], address, localLabels, firstPass)) { + } + else if (paramCount == 2) + { + if (IsMatch(entry.Param1, operandList[0], address, localLabels, firstPass) && IsMatch( + entry.Param2, operandList[1], address, localLabels, firstPass)) + { PushOp(entry.OpCode, output, address); ProcessOperand(entry.Param1, operandList[0], output, address, localLabels, firstPass); ProcessOperand(entry.Param2, operandList[1], output, address, localLabels, firstPass); @@ -395,9 +500,12 @@ void GbAssembler::RunPass(vector& output, string code, uint32_t address } } - if(!matchFound) { + if (!matchFound) + { output.push_back(AssemblerSpecialCodes::InvalidOperands); - } else { + } + else + { output.push_back(AssemblerSpecialCodes::EndOfLine); } } diff --git a/Core/GbAssembler.h b/Core/GbAssembler.h index e18dca3..32be9ea 100644 --- a/Core/GbAssembler.h +++ b/Core/GbAssembler.h @@ -40,17 +40,20 @@ private: bool IsRegisterName(string op); void InitAssembler(); int ReadValue(string operand, int min, int max, unordered_map& localLabels, bool firstPass); - bool IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map& localLabels, bool firstPass); + bool IsMatch(ParamEntry& entry, string operand, uint32_t address, unordered_map& localLabels, + bool firstPass); void PushOp(uint16_t opCode, vector& output, uint32_t& address); void PushByte(uint8_t operand, vector& output, uint32_t& address); void PushWord(uint16_t operand, vector& output, uint32_t& address); - void ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, unordered_map& localLabels, bool firstPass); + void ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, + unordered_map& localLabels, bool firstPass); - void RunPass(vector& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, unordered_map& localLabels); + void RunPass(vector& output, string code, uint32_t address, int16_t* assembledCode, bool firstPass, + unordered_map& localLabels); public: GbAssembler(shared_ptr labelManager); virtual ~GbAssembler(); uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode); -}; \ No newline at end of file +}; diff --git a/Core/GbCart.h b/Core/GbCart.h index d6fe052..e51c592 100644 --- a/Core/GbCart.h +++ b/Core/GbCart.h @@ -12,7 +12,7 @@ protected: Gameboy* _gameboy = nullptr; GbMemoryManager* _memoryManager = nullptr; uint8_t* _cartRam = nullptr; - + void Map(uint16_t start, uint16_t end, GbMemoryType type, uint32_t offset, bool readonly) { _memoryManager->Map(start, end, type, offset, readonly); diff --git a/Core/GbCartFactory.h b/Core/GbCartFactory.h index 0eeeb86..1744446 100644 --- a/Core/GbCartFactory.h +++ b/Core/GbCartFactory.h @@ -11,24 +11,36 @@ class GbCartFactory public: static GbCart* CreateCart(uint8_t cartType) { - switch(cartType) { - case 0: - return new GbCart(); + switch (cartType) + { + case 0: + return new GbCart(); - case 1: case 2: case 3: - return new GbMbc1(); + case 1: + case 2: + case 3: + return new GbMbc1(); - case 5: case 6: - return new GbMbc2(); + case 5: + case 6: + return new GbMbc2(); - case 15: case 16: - return new GbMbc3(true); + case 15: + case 16: + return new GbMbc3(true); - case 17: case 18: case 19: - return new GbMbc3(false); + case 17: + case 18: + case 19: + return new GbMbc3(false); - case 25: case 26: case 27: case 28: case 29: case 30: - return new GbMbc5(); + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + return new GbMbc5(); }; return nullptr; diff --git a/Core/GbCpu.cpp b/Core/GbCpu.cpp index a4b20f9..ad7995f 100644 --- a/Core/GbCpu.cpp +++ b/Core/GbCpu.cpp @@ -10,7 +10,7 @@ void GbCpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana _console = console; _gameboy = gameboy; _memoryManager = memoryManager; - + _state = {}; _state.PC = 0; @@ -34,8 +34,10 @@ bool GbCpu::IsHalted() void GbCpu::Exec() { uint8_t irqVector = _memoryManager->ProcessIrqRequests(); - if(irqVector) { - if(_state.IME) { + if (irqVector) + { + if (_state.IME) + { uint16_t oldPc = _state.PC; IncCycleCount(); IncCycleCount(); @@ -45,20 +47,27 @@ void GbCpu::Exec() PushByte((uint8_t)_state.PC); IncCycleCount(); - - switch(irqVector) { - case 0: - //IRQ request bit is no longer set, jump to $0000 (ie_push test) - _state.PC = 0; - break; - case GbIrqSource::VerticalBlank: _state.PC = 0x40; break; - case GbIrqSource::LcdStat: _state.PC = 0x48; break; - case GbIrqSource::Timer: _state.PC = 0x50; break; - case GbIrqSource::Serial: _state.PC = 0x58; break; - case GbIrqSource::Joypad: _state.PC = 0x60; break; + switch (irqVector) + { + case 0: + //IRQ request bit is no longer set, jump to $0000 (ie_push test) + _state.PC = 0; + break; + + case GbIrqSource::VerticalBlank: _state.PC = 0x40; + break; + case GbIrqSource::LcdStat: _state.PC = 0x48; + break; + case GbIrqSource::Timer: _state.PC = 0x50; + break; + case GbIrqSource::Serial: _state.PC = 0x58; + break; + case GbIrqSource::Joypad: _state.PC = 0x60; + break; } - if(irqVector) { + if (irqVector) + { //Only clear IRQ bit if an IRQ was processed _memoryManager->ClearIrqRequest(irqVector); } @@ -69,12 +78,14 @@ void GbCpu::Exec() _state.Halted = false; } - if(_state.Halted) { + if (_state.Halted) + { IncCycleCount(); return; } - if(_state.EiPending) { + if (_state.EiPending) + { _state.EiPending = false; _state.IME = true; } @@ -84,263 +95,525 @@ void GbCpu::Exec() void GbCpu::ExecOpCode(uint8_t opCode) { - switch(opCode) { - case 0x00: NOP(); break; - case 0x01: LD(_regBC, ReadCodeWord()); break; - case 0x02: LD_Indirect(_regBC, _state.A); break; - case 0x03: INC(_regBC); break; - case 0x04: INC(_state.B); break; - case 0x05: DEC(_state.B); break; - case 0x06: LD(_state.B, ReadCode()); break; - case 0x07: RLCA(); break; - case 0x08: LD_Indirect16(ReadCodeWord(), _state.SP); break; - case 0x09: ADD(_regHL, _regBC); break; - case 0x0A: LD(_state.A, Read(_regBC)); break; - case 0x0B: DEC(_regBC); break; - case 0x0C: INC(_state.C); break; - case 0x0D: DEC(_state.C); break; - case 0x0E: LD(_state.C, ReadCode()); break; - case 0x0F: RRCA(); break; - case 0x10: STOP(); break; - case 0x11: LD(_regDE, ReadCodeWord()); break; - case 0x12: LD_Indirect(_regDE, _state.A); break; - case 0x13: INC(_regDE); break; - case 0x14: INC(_state.D); break; - case 0x15: DEC(_state.D); break; - case 0x16: LD(_state.D, ReadCode()); break; - case 0x17: RLA(); break; - case 0x18: JR(ReadCode()); break; - case 0x19: ADD(_regHL, _regDE); break; - case 0x1A: LD(_state.A, Read(_regDE)); break; - case 0x1B: DEC(_regDE); break; - case 0x1C: INC(_state.E); break; - case 0x1D: DEC(_state.E); break; - case 0x1E: LD(_state.E, ReadCode()); break; - case 0x1F: RRA(); break; - case 0x20: JR((_state.Flags & GbCpuFlags::Zero) == 0, ReadCode()); break; - case 0x21: LD(_regHL, ReadCodeWord()); break; - case 0x22: LD_Indirect(_regHL, _state.A); _regHL.Inc(); break; - case 0x23: INC(_regHL); break; - case 0x24: INC(_state.H); break; - case 0x25: DEC(_state.H); break; - case 0x26: LD(_state.H, ReadCode()); break; - case 0x27: DAA(); break; - case 0x28: JR((_state.Flags & GbCpuFlags::Zero) != 0, ReadCode()); break; - case 0x29: ADD(_regHL, _regHL); break; - case 0x2A: LD(_state.A, Read(_regHL)); _regHL.Inc(); break; - case 0x2B: DEC(_regHL); break; - case 0x2C: INC(_state.L); break; - case 0x2D: DEC(_state.L); break; - case 0x2E: LD(_state.L, ReadCode()); break; - case 0x2F: CPL(); break; - case 0x30: JR((_state.Flags & GbCpuFlags::Carry) == 0, ReadCode()); break; - case 0x31: LD(_state.SP, ReadCodeWord()); break; - case 0x32: LD_Indirect(_regHL, _state.A); _regHL.Dec(); break; - case 0x33: INC_SP(); break; - case 0x34: INC_Indirect(_regHL); break; - case 0x35: DEC_Indirect(_regHL); break; - case 0x36: LD_Indirect(_regHL, ReadCode()); break; - case 0x37: SCF(); break; - case 0x38: JR((_state.Flags & GbCpuFlags::Carry) != 0, ReadCode()); break; - case 0x39: ADD(_regHL, _state.SP); break; - case 0x3A: LD(_state.A, Read(_regHL)); _regHL.Dec(); break; - case 0x3B: DEC_SP(); break; - case 0x3C: INC(_state.A); break; - case 0x3D: DEC(_state.A); break; - case 0x3E: LD(_state.A, ReadCode()); break; - case 0x3F: CCF(); break; - case 0x40: LD(_state.B, _state.B); break; - case 0x41: LD(_state.B, _state.C); break; - case 0x42: LD(_state.B, _state.D); break; - case 0x43: LD(_state.B, _state.E); break; - case 0x44: LD(_state.B, _state.H); break; - case 0x45: LD(_state.B, _state.L); break; - case 0x46: LD(_state.B, Read(_regHL)); break; - case 0x47: LD(_state.B, _state.A); break; - case 0x48: LD(_state.C, _state.B); break; - case 0x49: LD(_state.C, _state.C); break; - case 0x4A: LD(_state.C, _state.D); break; - case 0x4B: LD(_state.C, _state.E); break; - case 0x4C: LD(_state.C, _state.H); break; - case 0x4D: LD(_state.C, _state.L); break; - case 0x4E: LD(_state.C, Read(_regHL)); break; - case 0x4F: LD(_state.C, _state.A); break; - case 0x50: LD(_state.D, _state.B); break; - case 0x51: LD(_state.D, _state.C); break; - case 0x52: LD(_state.D, _state.D); break; - case 0x53: LD(_state.D, _state.E); break; - case 0x54: LD(_state.D, _state.H); break; - case 0x55: LD(_state.D, _state.L); break; - case 0x56: LD(_state.D, Read(_regHL)); break; - case 0x57: LD(_state.D, _state.A); break; - case 0x58: LD(_state.E, _state.B); break; - case 0x59: LD(_state.E, _state.C); break; - case 0x5A: LD(_state.E, _state.D); break; - case 0x5B: LD(_state.E, _state.E); break; - case 0x5C: LD(_state.E, _state.H); break; - case 0x5D: LD(_state.E, _state.L); break; - case 0x5E: LD(_state.E, Read(_regHL)); break; - case 0x5F: LD(_state.E, _state.A); break; - case 0x60: LD(_state.H, _state.B); break; - case 0x61: LD(_state.H, _state.C); break; - case 0x62: LD(_state.H, _state.D); break; - case 0x63: LD(_state.H, _state.E); break; - case 0x64: LD(_state.H, _state.H); break; - case 0x65: LD(_state.H, _state.L); break; - case 0x66: LD(_state.H, Read(_regHL)); break; - case 0x67: LD(_state.H, _state.A); break; - case 0x68: LD(_state.L, _state.B); break; - case 0x69: LD(_state.L, _state.C); break; - case 0x6A: LD(_state.L, _state.D); break; - case 0x6B: LD(_state.L, _state.E); break; - case 0x6C: LD(_state.L, _state.H); break; - case 0x6D: LD(_state.L, _state.L); break; - case 0x6E: LD(_state.L, Read(_regHL)); break; - case 0x6F: LD(_state.L, _state.A); break; - case 0x70: LD_Indirect(_regHL, _state.B); break; - case 0x71: LD_Indirect(_regHL, _state.C); break; - case 0x72: LD_Indirect(_regHL, _state.D); break; - case 0x73: LD_Indirect(_regHL, _state.E); break; - case 0x74: LD_Indirect(_regHL, _state.H); break; - case 0x75: LD_Indirect(_regHL, _state.L); break; - case 0x76: HALT(); break; - case 0x77: LD_Indirect(_regHL, _state.A); break; - case 0x78: LD(_state.A, _state.B); break; - case 0x79: LD(_state.A, _state.C); break; - case 0x7A: LD(_state.A, _state.D); break; - case 0x7B: LD(_state.A, _state.E); break; - case 0x7C: LD(_state.A, _state.H); break; - case 0x7D: LD(_state.A, _state.L); break; - case 0x7E: LD(_state.A, Read(_regHL)); break; - case 0x7F: LD(_state.A, _state.A); break; - case 0x80: ADD(_state.B); break; - case 0x81: ADD(_state.C); break; - case 0x82: ADD(_state.D); break; - case 0x83: ADD(_state.E); break; - case 0x84: ADD(_state.H); break; - case 0x85: ADD(_state.L); break; - case 0x86: ADD(Read(_regHL)); break; - case 0x87: ADD(_state.A); break; - case 0x88: ADC(_state.B); break; - case 0x89: ADC(_state.C); break; - case 0x8A: ADC(_state.D); break; - case 0x8B: ADC(_state.E); break; - case 0x8C: ADC(_state.H); break; - case 0x8D: ADC(_state.L); break; - case 0x8E: ADC(Read(_regHL)); break; - case 0x8F: ADC(_state.A); break; - case 0x90: SUB(_state.B); break; - case 0x91: SUB(_state.C); break; - case 0x92: SUB(_state.D); break; - case 0x93: SUB(_state.E); break; - case 0x94: SUB(_state.H); break; - case 0x95: SUB(_state.L); break; - case 0x96: SUB(Read(_regHL)); break; - case 0x97: SUB(_state.A); break; - case 0x98: SBC(_state.B); break; - case 0x99: SBC(_state.C); break; - case 0x9A: SBC(_state.D); break; - case 0x9B: SBC(_state.E); break; - case 0x9C: SBC(_state.H); break; - case 0x9D: SBC(_state.L); break; - case 0x9E: SBC(Read(_regHL)); break; - case 0x9F: SBC(_state.A); break; - case 0xA0: AND(_state.B); break; - case 0xA1: AND(_state.C); break; - case 0xA2: AND(_state.D); break; - case 0xA3: AND(_state.E); break; - case 0xA4: AND(_state.H); break; - case 0xA5: AND(_state.L); break; - case 0xA6: AND(Read(_regHL)); break; - case 0xA7: AND(_state.A); break; - case 0xA8: XOR(_state.B); break; - case 0xA9: XOR(_state.C); break; - case 0xAA: XOR(_state.D); break; - case 0xAB: XOR(_state.E); break; - case 0xAC: XOR(_state.H); break; - case 0xAD: XOR(_state.L); break; - case 0xAE: XOR(Read(_regHL)); break; - case 0xAF: XOR(_state.A); break; - case 0xB0: OR(_state.B); break; - case 0xB1: OR(_state.C); break; - case 0xB2: OR(_state.D); break; - case 0xB3: OR(_state.E); break; - case 0xB4: OR(_state.H); break; - case 0xB5: OR(_state.L); break; - case 0xB6: OR(Read(_regHL)); break; - case 0xB7: OR(_state.A); break; - case 0xB8: CP(_state.B); break; - case 0xB9: CP(_state.C); break; - case 0xBA: CP(_state.D); break; - case 0xBB: CP(_state.E); break; - case 0xBC: CP(_state.H); break; - case 0xBD: CP(_state.L); break; - case 0xBE: CP(Read(_regHL)); break; - case 0xBF: CP(_state.A); break; - case 0xC0: RET((_state.Flags & GbCpuFlags::Zero) == 0); break; - case 0xC1: POP(_regBC); break; - case 0xC2: JP((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); break; - case 0xC3: JP(ReadCodeWord()); break; - case 0xC4: CALL((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); break; - case 0xC5: PUSH(_regBC); break; - case 0xC6: ADD(ReadCode()); break; - case 0xC7: RST(0x00); break; - case 0xC8: RET((_state.Flags & GbCpuFlags::Zero) != 0); break; - case 0xC9: RET(); break; - case 0xCA: JP((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); break; - case 0xCB: PREFIX(); break; - case 0xCC: CALL((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); break; - case 0xCD: CALL(ReadCodeWord()); break; - case 0xCE: ADC(ReadCode()); break; - case 0xCF: RST(0x08); break; - case 0xD0: RET((_state.Flags & GbCpuFlags::Carry) == 0); break; - case 0xD1: POP(_regDE); break; - case 0xD2: JP((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); break; - case 0xD3: InvalidOp(); break; - case 0xD4: CALL((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); break; - case 0xD5: PUSH(_regDE); break; - case 0xD6: SUB(ReadCode()); break; - case 0xD7: RST(0x10); break; - case 0xD8: RET((_state.Flags & GbCpuFlags::Carry) != 0); break; - case 0xD9: RETI(); break; - case 0xDA: JP((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); break; - case 0xDB: InvalidOp(); break; - case 0xDC: CALL((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); break; - case 0xDD: InvalidOp(); break; - case 0xDE: SBC(ReadCode()); break; - case 0xDF: RST(0x18); break; - case 0xE0: LD_Indirect(0xFF00 | ReadCode(), _state.A); break; - case 0xE1: POP(_regHL); break; - case 0xE2: LD_Indirect(0xFF00 | _state.C, _state.A); break; - case 0xE3: InvalidOp(); break; - case 0xE4: InvalidOp(); break; - case 0xE5: PUSH(_regHL); break; - case 0xE6: AND(ReadCode()); break; - case 0xE7: RST(0x20); break; - case 0xE8: ADD_SP(ReadCode()); break; - case 0xE9: JP_HL(); break; - case 0xEA: LD_Indirect(ReadCodeWord(), _state.A); break; - case 0xEB: InvalidOp(); break; - case 0xEC: InvalidOp(); break; - case 0xED: InvalidOp(); break; - case 0xEE: XOR(ReadCode()); break; - case 0xEF: RST(0x28); break; - case 0xF0: LD(_state.A, Read(0xFF00 | ReadCode())); break; - case 0xF1: POP_AF(); break; - case 0xF2: LD(_state.A, Read(0xFF00 | _state.C)); break; - case 0xF3: DI(); break; - case 0xF4: InvalidOp(); break; - case 0xF5: PUSH(_regAF); break; - case 0xF6: OR(ReadCode()); break; - case 0xF7: RST(0x30); break; - case 0xF8: LD_HL(ReadCode()); break; - case 0xF9: LD(_state.SP, _regHL); IncCycleCount(); break; - case 0xFA: LD(_state.A, Read(ReadCodeWord())); break; - case 0xFB: EI(); break; - case 0xFC: InvalidOp(); break; - case 0xFD: InvalidOp(); break; - case 0xFE: CP(ReadCode()); break; - case 0xFF: RST(0x38); break; + switch (opCode) + { + case 0x00: NOP(); + break; + case 0x01: LD(_regBC, ReadCodeWord()); + break; + case 0x02: LD_Indirect(_regBC, _state.A); + break; + case 0x03: INC(_regBC); + break; + case 0x04: INC(_state.B); + break; + case 0x05: DEC(_state.B); + break; + case 0x06: LD(_state.B, ReadCode()); + break; + case 0x07: RLCA(); + break; + case 0x08: LD_Indirect16(ReadCodeWord(), _state.SP); + break; + case 0x09: ADD(_regHL, _regBC); + break; + case 0x0A: LD(_state.A, Read(_regBC)); + break; + case 0x0B: DEC(_regBC); + break; + case 0x0C: INC(_state.C); + break; + case 0x0D: DEC(_state.C); + break; + case 0x0E: LD(_state.C, ReadCode()); + break; + case 0x0F: RRCA(); + break; + case 0x10: STOP(); + break; + case 0x11: LD(_regDE, ReadCodeWord()); + break; + case 0x12: LD_Indirect(_regDE, _state.A); + break; + case 0x13: INC(_regDE); + break; + case 0x14: INC(_state.D); + break; + case 0x15: DEC(_state.D); + break; + case 0x16: LD(_state.D, ReadCode()); + break; + case 0x17: RLA(); + break; + case 0x18: JR(ReadCode()); + break; + case 0x19: ADD(_regHL, _regDE); + break; + case 0x1A: LD(_state.A, Read(_regDE)); + break; + case 0x1B: DEC(_regDE); + break; + case 0x1C: INC(_state.E); + break; + case 0x1D: DEC(_state.E); + break; + case 0x1E: LD(_state.E, ReadCode()); + break; + case 0x1F: RRA(); + break; + case 0x20: JR((_state.Flags & GbCpuFlags::Zero) == 0, ReadCode()); + break; + case 0x21: LD(_regHL, ReadCodeWord()); + break; + case 0x22: LD_Indirect(_regHL, _state.A); + _regHL.Inc(); + break; + case 0x23: INC(_regHL); + break; + case 0x24: INC(_state.H); + break; + case 0x25: DEC(_state.H); + break; + case 0x26: LD(_state.H, ReadCode()); + break; + case 0x27: DAA(); + break; + case 0x28: JR((_state.Flags & GbCpuFlags::Zero) != 0, ReadCode()); + break; + case 0x29: ADD(_regHL, _regHL); + break; + case 0x2A: LD(_state.A, Read(_regHL)); + _regHL.Inc(); + break; + case 0x2B: DEC(_regHL); + break; + case 0x2C: INC(_state.L); + break; + case 0x2D: DEC(_state.L); + break; + case 0x2E: LD(_state.L, ReadCode()); + break; + case 0x2F: CPL(); + break; + case 0x30: JR((_state.Flags & GbCpuFlags::Carry) == 0, ReadCode()); + break; + case 0x31: LD(_state.SP, ReadCodeWord()); + break; + case 0x32: LD_Indirect(_regHL, _state.A); + _regHL.Dec(); + break; + case 0x33: INC_SP(); + break; + case 0x34: INC_Indirect(_regHL); + break; + case 0x35: DEC_Indirect(_regHL); + break; + case 0x36: LD_Indirect(_regHL, ReadCode()); + break; + case 0x37: SCF(); + break; + case 0x38: JR((_state.Flags & GbCpuFlags::Carry) != 0, ReadCode()); + break; + case 0x39: ADD(_regHL, _state.SP); + break; + case 0x3A: LD(_state.A, Read(_regHL)); + _regHL.Dec(); + break; + case 0x3B: DEC_SP(); + break; + case 0x3C: INC(_state.A); + break; + case 0x3D: DEC(_state.A); + break; + case 0x3E: LD(_state.A, ReadCode()); + break; + case 0x3F: CCF(); + break; + case 0x40: LD(_state.B, _state.B); + break; + case 0x41: LD(_state.B, _state.C); + break; + case 0x42: LD(_state.B, _state.D); + break; + case 0x43: LD(_state.B, _state.E); + break; + case 0x44: LD(_state.B, _state.H); + break; + case 0x45: LD(_state.B, _state.L); + break; + case 0x46: LD(_state.B, Read(_regHL)); + break; + case 0x47: LD(_state.B, _state.A); + break; + case 0x48: LD(_state.C, _state.B); + break; + case 0x49: LD(_state.C, _state.C); + break; + case 0x4A: LD(_state.C, _state.D); + break; + case 0x4B: LD(_state.C, _state.E); + break; + case 0x4C: LD(_state.C, _state.H); + break; + case 0x4D: LD(_state.C, _state.L); + break; + case 0x4E: LD(_state.C, Read(_regHL)); + break; + case 0x4F: LD(_state.C, _state.A); + break; + case 0x50: LD(_state.D, _state.B); + break; + case 0x51: LD(_state.D, _state.C); + break; + case 0x52: LD(_state.D, _state.D); + break; + case 0x53: LD(_state.D, _state.E); + break; + case 0x54: LD(_state.D, _state.H); + break; + case 0x55: LD(_state.D, _state.L); + break; + case 0x56: LD(_state.D, Read(_regHL)); + break; + case 0x57: LD(_state.D, _state.A); + break; + case 0x58: LD(_state.E, _state.B); + break; + case 0x59: LD(_state.E, _state.C); + break; + case 0x5A: LD(_state.E, _state.D); + break; + case 0x5B: LD(_state.E, _state.E); + break; + case 0x5C: LD(_state.E, _state.H); + break; + case 0x5D: LD(_state.E, _state.L); + break; + case 0x5E: LD(_state.E, Read(_regHL)); + break; + case 0x5F: LD(_state.E, _state.A); + break; + case 0x60: LD(_state.H, _state.B); + break; + case 0x61: LD(_state.H, _state.C); + break; + case 0x62: LD(_state.H, _state.D); + break; + case 0x63: LD(_state.H, _state.E); + break; + case 0x64: LD(_state.H, _state.H); + break; + case 0x65: LD(_state.H, _state.L); + break; + case 0x66: LD(_state.H, Read(_regHL)); + break; + case 0x67: LD(_state.H, _state.A); + break; + case 0x68: LD(_state.L, _state.B); + break; + case 0x69: LD(_state.L, _state.C); + break; + case 0x6A: LD(_state.L, _state.D); + break; + case 0x6B: LD(_state.L, _state.E); + break; + case 0x6C: LD(_state.L, _state.H); + break; + case 0x6D: LD(_state.L, _state.L); + break; + case 0x6E: LD(_state.L, Read(_regHL)); + break; + case 0x6F: LD(_state.L, _state.A); + break; + case 0x70: LD_Indirect(_regHL, _state.B); + break; + case 0x71: LD_Indirect(_regHL, _state.C); + break; + case 0x72: LD_Indirect(_regHL, _state.D); + break; + case 0x73: LD_Indirect(_regHL, _state.E); + break; + case 0x74: LD_Indirect(_regHL, _state.H); + break; + case 0x75: LD_Indirect(_regHL, _state.L); + break; + case 0x76: HALT(); + break; + case 0x77: LD_Indirect(_regHL, _state.A); + break; + case 0x78: LD(_state.A, _state.B); + break; + case 0x79: LD(_state.A, _state.C); + break; + case 0x7A: LD(_state.A, _state.D); + break; + case 0x7B: LD(_state.A, _state.E); + break; + case 0x7C: LD(_state.A, _state.H); + break; + case 0x7D: LD(_state.A, _state.L); + break; + case 0x7E: LD(_state.A, Read(_regHL)); + break; + case 0x7F: LD(_state.A, _state.A); + break; + case 0x80: ADD(_state.B); + break; + case 0x81: ADD(_state.C); + break; + case 0x82: ADD(_state.D); + break; + case 0x83: ADD(_state.E); + break; + case 0x84: ADD(_state.H); + break; + case 0x85: ADD(_state.L); + break; + case 0x86: ADD(Read(_regHL)); + break; + case 0x87: ADD(_state.A); + break; + case 0x88: ADC(_state.B); + break; + case 0x89: ADC(_state.C); + break; + case 0x8A: ADC(_state.D); + break; + case 0x8B: ADC(_state.E); + break; + case 0x8C: ADC(_state.H); + break; + case 0x8D: ADC(_state.L); + break; + case 0x8E: ADC(Read(_regHL)); + break; + case 0x8F: ADC(_state.A); + break; + case 0x90: SUB(_state.B); + break; + case 0x91: SUB(_state.C); + break; + case 0x92: SUB(_state.D); + break; + case 0x93: SUB(_state.E); + break; + case 0x94: SUB(_state.H); + break; + case 0x95: SUB(_state.L); + break; + case 0x96: SUB(Read(_regHL)); + break; + case 0x97: SUB(_state.A); + break; + case 0x98: SBC(_state.B); + break; + case 0x99: SBC(_state.C); + break; + case 0x9A: SBC(_state.D); + break; + case 0x9B: SBC(_state.E); + break; + case 0x9C: SBC(_state.H); + break; + case 0x9D: SBC(_state.L); + break; + case 0x9E: SBC(Read(_regHL)); + break; + case 0x9F: SBC(_state.A); + break; + case 0xA0: AND(_state.B); + break; + case 0xA1: AND(_state.C); + break; + case 0xA2: AND(_state.D); + break; + case 0xA3: AND(_state.E); + break; + case 0xA4: AND(_state.H); + break; + case 0xA5: AND(_state.L); + break; + case 0xA6: AND(Read(_regHL)); + break; + case 0xA7: AND(_state.A); + break; + case 0xA8: XOR(_state.B); + break; + case 0xA9: XOR(_state.C); + break; + case 0xAA: XOR(_state.D); + break; + case 0xAB: XOR(_state.E); + break; + case 0xAC: XOR(_state.H); + break; + case 0xAD: XOR(_state.L); + break; + case 0xAE: XOR(Read(_regHL)); + break; + case 0xAF: XOR(_state.A); + break; + case 0xB0: OR(_state.B); + break; + case 0xB1: OR(_state.C); + break; + case 0xB2: OR(_state.D); + break; + case 0xB3: OR(_state.E); + break; + case 0xB4: OR(_state.H); + break; + case 0xB5: OR(_state.L); + break; + case 0xB6: OR(Read(_regHL)); + break; + case 0xB7: OR(_state.A); + break; + case 0xB8: CP(_state.B); + break; + case 0xB9: CP(_state.C); + break; + case 0xBA: CP(_state.D); + break; + case 0xBB: CP(_state.E); + break; + case 0xBC: CP(_state.H); + break; + case 0xBD: CP(_state.L); + break; + case 0xBE: CP(Read(_regHL)); + break; + case 0xBF: CP(_state.A); + break; + case 0xC0: RET((_state.Flags & GbCpuFlags::Zero) == 0); + break; + case 0xC1: POP(_regBC); + break; + case 0xC2: JP((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); + break; + case 0xC3: JP(ReadCodeWord()); + break; + case 0xC4: CALL((_state.Flags & GbCpuFlags::Zero) == 0, ReadCodeWord()); + break; + case 0xC5: PUSH(_regBC); + break; + case 0xC6: ADD(ReadCode()); + break; + case 0xC7: RST(0x00); + break; + case 0xC8: RET((_state.Flags & GbCpuFlags::Zero) != 0); + break; + case 0xC9: RET(); + break; + case 0xCA: JP((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); + break; + case 0xCB: PREFIX(); + break; + case 0xCC: CALL((_state.Flags & GbCpuFlags::Zero) != 0, ReadCodeWord()); + break; + case 0xCD: CALL(ReadCodeWord()); + break; + case 0xCE: ADC(ReadCode()); + break; + case 0xCF: RST(0x08); + break; + case 0xD0: RET((_state.Flags & GbCpuFlags::Carry) == 0); + break; + case 0xD1: POP(_regDE); + break; + case 0xD2: JP((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); + break; + case 0xD3: InvalidOp(); + break; + case 0xD4: CALL((_state.Flags & GbCpuFlags::Carry) == 0, ReadCodeWord()); + break; + case 0xD5: PUSH(_regDE); + break; + case 0xD6: SUB(ReadCode()); + break; + case 0xD7: RST(0x10); + break; + case 0xD8: RET((_state.Flags & GbCpuFlags::Carry) != 0); + break; + case 0xD9: RETI(); + break; + case 0xDA: JP((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); + break; + case 0xDB: InvalidOp(); + break; + case 0xDC: CALL((_state.Flags & GbCpuFlags::Carry) != 0, ReadCodeWord()); + break; + case 0xDD: InvalidOp(); + break; + case 0xDE: SBC(ReadCode()); + break; + case 0xDF: RST(0x18); + break; + case 0xE0: LD_Indirect(0xFF00 | ReadCode(), _state.A); + break; + case 0xE1: POP(_regHL); + break; + case 0xE2: LD_Indirect(0xFF00 | _state.C, _state.A); + break; + case 0xE3: InvalidOp(); + break; + case 0xE4: InvalidOp(); + break; + case 0xE5: PUSH(_regHL); + break; + case 0xE6: AND(ReadCode()); + break; + case 0xE7: RST(0x20); + break; + case 0xE8: ADD_SP(ReadCode()); + break; + case 0xE9: JP_HL(); + break; + case 0xEA: LD_Indirect(ReadCodeWord(), _state.A); + break; + case 0xEB: InvalidOp(); + break; + case 0xEC: InvalidOp(); + break; + case 0xED: InvalidOp(); + break; + case 0xEE: XOR(ReadCode()); + break; + case 0xEF: RST(0x28); + break; + case 0xF0: LD(_state.A, Read(0xFF00 | ReadCode())); + break; + case 0xF1: POP_AF(); + break; + case 0xF2: LD(_state.A, Read(0xFF00 | _state.C)); + break; + case 0xF3: DI(); + break; + case 0xF4: InvalidOp(); + break; + case 0xF5: PUSH(_regAF); + break; + case 0xF6: OR(ReadCode()); + break; + case 0xF7: RST(0x30); + break; + case 0xF8: LD_HL(ReadCode()); + break; + case 0xF9: LD(_state.SP, _regHL); + IncCycleCount(); + break; + case 0xFA: LD(_state.A, Read(ReadCodeWord())); + break; + case 0xFB: EI(); + break; + case 0xFC: InvalidOp(); + break; + case 0xFD: InvalidOp(); + break; + case 0xFE: CP(ReadCode()); + break; + case 0xFF: RST(0x38); + break; } } @@ -412,9 +685,12 @@ void GbCpu::ClearFlag(uint8_t flag) void GbCpu::SetFlagState(uint8_t flag, bool state) { - if(state) { + if (state) + { SetFlag(flag); - } else { + } + else + { ClearFlag(flag); } } @@ -704,7 +980,6 @@ void GbCpu::CP(uint8_t value) void GbCpu::NOP() { - } void GbCpu::InvalidOp() @@ -718,18 +993,24 @@ void GbCpu::InvalidOp() void GbCpu::STOP() { - if(_gameboy->IsCgb() && _memoryManager->GetState().CgbSwitchSpeedRequest) { + if (_gameboy->IsCgb() && _memoryManager->GetState().CgbSwitchSpeedRequest) + { _memoryManager->ToggleSpeed(); - } else { + } + else + { _state.Halted = true; } } void GbCpu::HALT() { - if(_state.IME || _memoryManager->ProcessIrqRequests() == 0) { + if (_state.IME || _memoryManager->ProcessIrqRequests() == 0) + { _state.Halted = true; - } else { + } + else + { //HALT bug, execution continues, but PC isn't incremented for the first byte HalfCycle(); uint8_t opCode = _memoryManager->Read(_state.PC); @@ -928,7 +1209,7 @@ void GbCpu::SWAP_Indirect(uint16_t addr) Write(addr, val); } -template +template void GbCpu::BIT(uint8_t src) { SetFlagState(GbCpuFlags::Zero, (src & (1 << bit)) == 0); @@ -936,13 +1217,13 @@ void GbCpu::BIT(uint8_t src) SetFlag(GbCpuFlags::HalfCarry); } -template +template void GbCpu::RES(uint8_t& dst) { dst &= ~(1 << bit); } -template +template void GbCpu::RES_Indirect(uint16_t addr) { uint8_t val = Read(addr); @@ -950,13 +1231,13 @@ void GbCpu::RES_Indirect(uint16_t addr) Write(addr, val); } -template +template void GbCpu::SET(uint8_t& dst) { dst |= (1 << bit); } -template +template void GbCpu::SET_Indirect(uint16_t addr) { uint8_t val = Read(addr); @@ -967,19 +1248,26 @@ void GbCpu::SET_Indirect(uint16_t addr) // daa 27 4 z-0x decimal adjust akku void GbCpu::DAA() { - if(CheckFlag(GbCpuFlags::AddSub)) { - if(CheckFlag(GbCpuFlags::Carry)) { + if (CheckFlag(GbCpuFlags::AddSub)) + { + if (CheckFlag(GbCpuFlags::Carry)) + { _state.A -= 0x60; } - if(CheckFlag(GbCpuFlags::HalfCarry)) { + if (CheckFlag(GbCpuFlags::HalfCarry)) + { _state.A -= 0x06; } - } else { - if(CheckFlag(GbCpuFlags::Carry) || _state.A > 0x99) { + } + else + { + if (CheckFlag(GbCpuFlags::Carry) || _state.A > 0x99) + { _state.A += 0x60; SetFlag(GbCpuFlags::Carry); } - if(CheckFlag(GbCpuFlags::HalfCarry) || (_state.A & 0x0F) > 0x09) { + if (CheckFlag(GbCpuFlags::HalfCarry) || (_state.A & 0x0F) > 0x09) + { _state.A += 0x6; } } @@ -1004,7 +1292,8 @@ void GbCpu::JP_HL() //jp f,nn xx nn nn 16;12 ---- conditional jump if nz,z,nc,c void GbCpu::JP(bool condition, uint16_t dstAddr) { - if(condition) { + if (condition) + { _state.PC = dstAddr; IncCycleCount(); } @@ -1020,7 +1309,8 @@ void GbCpu::JR(int8_t offset) //jr f,PC+dd xx dd 12;8 ---- conditional relative jump if nz,z,nc,c void GbCpu::JR(bool condition, int8_t offset) { - if(condition) { + if (condition) + { _state.PC += offset; IncCycleCount(); } @@ -1037,7 +1327,8 @@ void GbCpu::CALL(uint16_t dstAddr) //call f,nn xx nn nn 24;12 ---- conditional call if nz,z,nc,c void GbCpu::CALL(bool condition, uint16_t dstAddr) { - if(condition) { + if (condition) + { IncCycleCount(); PushWord(_state.PC); _state.PC = dstAddr; @@ -1055,7 +1346,8 @@ void GbCpu::RET() void GbCpu::RET(bool condition) { IncCycleCount(); - if(condition) { + if (condition) + { _state.PC = PopWord(); IncCycleCount(); } @@ -1121,263 +1413,520 @@ void GbCpu::DI() void GbCpu::PREFIX() { - switch(ReadCode()) { - case 0x00: RLC(_state.B); break; - case 0x01: RLC(_state.C); break; - case 0x02: RLC(_state.D); break; - case 0x03: RLC(_state.E); break; - case 0x04: RLC(_state.H); break; - case 0x05: RLC(_state.L); break; - case 0x06: RLC_Indirect(_regHL); break; - case 0x07: RLC(_state.A); break; - case 0x08: RRC(_state.B); break; - case 0x09: RRC(_state.C); break; - case 0x0A: RRC(_state.D); break; - case 0x0B: RRC(_state.E); break; - case 0x0C: RRC(_state.H); break; - case 0x0D: RRC(_state.L); break; - case 0x0E: RRC_Indirect(_regHL); break; - case 0x0F: RRC(_state.A); break; - case 0x10: RL(_state.B); break; - case 0x11: RL(_state.C); break; - case 0x12: RL(_state.D); break; - case 0x13: RL(_state.E); break; - case 0x14: RL(_state.H); break; - case 0x15: RL(_state.L); break; - case 0x16: RL_Indirect(_regHL); break; - case 0x17: RL(_state.A); break; - case 0x18: RR(_state.B); break; - case 0x19: RR(_state.C); break; - case 0x1A: RR(_state.D); break; - case 0x1B: RR(_state.E); break; - case 0x1C: RR(_state.H); break; - case 0x1D: RR(_state.L); break; - case 0x1E: RR_Indirect(_regHL); break; - case 0x1F: RR(_state.A); break; - case 0x20: SLA(_state.B); break; - case 0x21: SLA(_state.C); break; - case 0x22: SLA(_state.D); break; - case 0x23: SLA(_state.E); break; - case 0x24: SLA(_state.H); break; - case 0x25: SLA(_state.L); break; - case 0x26: SLA_Indirect(_regHL); break; - case 0x27: SLA(_state.A); break; - case 0x28: SRA(_state.B); break; - case 0x29: SRA(_state.C); break; - case 0x2A: SRA(_state.D); break; - case 0x2B: SRA(_state.E); break; - case 0x2C: SRA(_state.H); break; - case 0x2D: SRA(_state.L); break; - case 0x2E: SRA_Indirect(_regHL); break; - case 0x2F: SRA(_state.A); break; - case 0x30: SWAP(_state.B); break; - case 0x31: SWAP(_state.C); break; - case 0x32: SWAP(_state.D); break; - case 0x33: SWAP(_state.E); break; - case 0x34: SWAP(_state.H); break; - case 0x35: SWAP(_state.L); break; - case 0x36: SWAP_Indirect(_regHL); break; - case 0x37: SWAP(_state.A); break; - case 0x38: SRL(_state.B); break; - case 0x39: SRL(_state.C); break; - case 0x3A: SRL(_state.D); break; - case 0x3B: SRL(_state.E); break; - case 0x3C: SRL(_state.H); break; - case 0x3D: SRL(_state.L); break; - case 0x3E: SRL_Indirect(_regHL); break; - case 0x3F: SRL(_state.A); break; - case 0x40: BIT<0>(_state.B); break; - case 0x41: BIT<0>(_state.C); break; - case 0x42: BIT<0>(_state.D); break; - case 0x43: BIT<0>(_state.E); break; - case 0x44: BIT<0>(_state.H); break; - case 0x45: BIT<0>(_state.L); break; - case 0x46: BIT<0>(Read(_regHL)); break; - case 0x47: BIT<0>(_state.A); break; - case 0x48: BIT<1>(_state.B); break; - case 0x49: BIT<1>(_state.C); break; - case 0x4A: BIT<1>(_state.D); break; - case 0x4B: BIT<1>(_state.E); break; - case 0x4C: BIT<1>(_state.H); break; - case 0x4D: BIT<1>(_state.L); break; - case 0x4E: BIT<1>(Read(_regHL)); break; - case 0x4F: BIT<1>(_state.A); break; - case 0x50: BIT<2>(_state.B); break; - case 0x51: BIT<2>(_state.C); break; - case 0x52: BIT<2>(_state.D); break; - case 0x53: BIT<2>(_state.E); break; - case 0x54: BIT<2>(_state.H); break; - case 0x55: BIT<2>(_state.L); break; - case 0x56: BIT<2>(Read(_regHL)); break; - case 0x57: BIT<2>(_state.A); break; - case 0x58: BIT<3>(_state.B); break; - case 0x59: BIT<3>(_state.C); break; - case 0x5A: BIT<3>(_state.D); break; - case 0x5B: BIT<3>(_state.E); break; - case 0x5C: BIT<3>(_state.H); break; - case 0x5D: BIT<3>(_state.L); break; - case 0x5E: BIT<3>(Read(_regHL)); break; - case 0x5F: BIT<3>(_state.A); break; - case 0x60: BIT<4>(_state.B); break; - case 0x61: BIT<4>(_state.C); break; - case 0x62: BIT<4>(_state.D); break; - case 0x63: BIT<4>(_state.E); break; - case 0x64: BIT<4>(_state.H); break; - case 0x65: BIT<4>(_state.L); break; - case 0x66: BIT<4>(Read(_regHL)); break; - case 0x67: BIT<4>(_state.A); break; - case 0x68: BIT<5>(_state.B); break; - case 0x69: BIT<5>(_state.C); break; - case 0x6A: BIT<5>(_state.D); break; - case 0x6B: BIT<5>(_state.E); break; - case 0x6C: BIT<5>(_state.H); break; - case 0x6D: BIT<5>(_state.L); break; - case 0x6E: BIT<5>(Read(_regHL)); break; - case 0x6F: BIT<5>(_state.A); break; - case 0x70: BIT<6>(_state.B); break; - case 0x71: BIT<6>(_state.C); break; - case 0x72: BIT<6>(_state.D); break; - case 0x73: BIT<6>(_state.E); break; - case 0x74: BIT<6>(_state.H); break; - case 0x75: BIT<6>(_state.L); break; - case 0x76: BIT<6>(Read(_regHL)); break; - case 0x77: BIT<6>(_state.A); break; - case 0x78: BIT<7>(_state.B); break; - case 0x79: BIT<7>(_state.C); break; - case 0x7A: BIT<7>(_state.D); break; - case 0x7B: BIT<7>(_state.E); break; - case 0x7C: BIT<7>(_state.H); break; - case 0x7D: BIT<7>(_state.L); break; - case 0x7E: BIT<7>(Read(_regHL)); break; - case 0x7F: BIT<7>(_state.A); break; - case 0x80: RES<0>(_state.B); break; - case 0x81: RES<0>(_state.C); break; - case 0x82: RES<0>(_state.D); break; - case 0x83: RES<0>(_state.E); break; - case 0x84: RES<0>(_state.H); break; - case 0x85: RES<0>(_state.L); break; - case 0x86: RES_Indirect<0>(_regHL); break; - case 0x87: RES<0>(_state.A); break; - case 0x88: RES<1>(_state.B); break; - case 0x89: RES<1>(_state.C); break; - case 0x8A: RES<1>(_state.D); break; - case 0x8B: RES<1>(_state.E); break; - case 0x8C: RES<1>(_state.H); break; - case 0x8D: RES<1>(_state.L); break; - case 0x8E: RES_Indirect<1>(_regHL); break; - case 0x8F: RES<1>(_state.A); break; - case 0x90: RES<2>(_state.B); break; - case 0x91: RES<2>(_state.C); break; - case 0x92: RES<2>(_state.D); break; - case 0x93: RES<2>(_state.E); break; - case 0x94: RES<2>(_state.H); break; - case 0x95: RES<2>(_state.L); break; - case 0x96: RES_Indirect<2>(_regHL); break; - case 0x97: RES<2>(_state.A); break; - case 0x98: RES<3>(_state.B); break; - case 0x99: RES<3>(_state.C); break; - case 0x9A: RES<3>(_state.D); break; - case 0x9B: RES<3>(_state.E); break; - case 0x9C: RES<3>(_state.H); break; - case 0x9D: RES<3>(_state.L); break; - case 0x9E: RES_Indirect<3>(_regHL); break; - case 0x9F: RES<3>(_state.A); break; - case 0xA0: RES<4>(_state.B); break; - case 0xA1: RES<4>(_state.C); break; - case 0xA2: RES<4>(_state.D); break; - case 0xA3: RES<4>(_state.E); break; - case 0xA4: RES<4>(_state.H); break; - case 0xA5: RES<4>(_state.L); break; - case 0xA6: RES_Indirect<4>(_regHL); break; - case 0xA7: RES<4>(_state.A); break; - case 0xA8: RES<5>(_state.B); break; - case 0xA9: RES<5>(_state.C); break; - case 0xAA: RES<5>(_state.D); break; - case 0xAB: RES<5>(_state.E); break; - case 0xAC: RES<5>(_state.H); break; - case 0xAD: RES<5>(_state.L); break; - case 0xAE: RES_Indirect<5>(_regHL); break; - case 0xAF: RES<5>(_state.A); break; - case 0xB0: RES<6>(_state.B); break; - case 0xB1: RES<6>(_state.C); break; - case 0xB2: RES<6>(_state.D); break; - case 0xB3: RES<6>(_state.E); break; - case 0xB4: RES<6>(_state.H); break; - case 0xB5: RES<6>(_state.L); break; - case 0xB6: RES_Indirect<6>(_regHL); break; - case 0xB7: RES<6>(_state.A); break; - case 0xB8: RES<7>(_state.B); break; - case 0xB9: RES<7>(_state.C); break; - case 0xBA: RES<7>(_state.D); break; - case 0xBB: RES<7>(_state.E); break; - case 0xBC: RES<7>(_state.H); break; - case 0xBD: RES<7>(_state.L); break; - case 0xBE: RES_Indirect<7>(_regHL); break; - case 0xBF: RES<7>(_state.A); break; - case 0xC0: SET<0>(_state.B); break; - case 0xC1: SET<0>(_state.C); break; - case 0xC2: SET<0>(_state.D); break; - case 0xC3: SET<0>(_state.E); break; - case 0xC4: SET<0>(_state.H); break; - case 0xC5: SET<0>(_state.L); break; - case 0xC6: SET_Indirect<0>(_regHL); break; - case 0xC7: SET<0>(_state.A); break; - case 0xC8: SET<1>(_state.B); break; - case 0xC9: SET<1>(_state.C); break; - case 0xCA: SET<1>(_state.D); break; - case 0xCB: SET<1>(_state.E); break; - case 0xCC: SET<1>(_state.H); break; - case 0xCD: SET<1>(_state.L); break; - case 0xCE: SET_Indirect<1>(_regHL); break; - case 0xCF: SET<1>(_state.A); break; - case 0xD0: SET<2>(_state.B); break; - case 0xD1: SET<2>(_state.C); break; - case 0xD2: SET<2>(_state.D); break; - case 0xD3: SET<2>(_state.E); break; - case 0xD4: SET<2>(_state.H); break; - case 0xD5: SET<2>(_state.L); break; - case 0xD6: SET_Indirect<2>(_regHL); break; - case 0xD7: SET<2>(_state.A); break; - case 0xD8: SET<3>(_state.B); break; - case 0xD9: SET<3>(_state.C); break; - case 0xDA: SET<3>(_state.D); break; - case 0xDB: SET<3>(_state.E); break; - case 0xDC: SET<3>(_state.H); break; - case 0xDD: SET<3>(_state.L); break; - case 0xDE: SET_Indirect<3>(_regHL); break; - case 0xDF: SET<3>(_state.A); break; - case 0xE0: SET<4>(_state.B); break; - case 0xE1: SET<4>(_state.C); break; - case 0xE2: SET<4>(_state.D); break; - case 0xE3: SET<4>(_state.E); break; - case 0xE4: SET<4>(_state.H); break; - case 0xE5: SET<4>(_state.L); break; - case 0xE6: SET_Indirect<4>(_regHL); break; - case 0xE7: SET<4>(_state.A); break; - case 0xE8: SET<5>(_state.B); break; - case 0xE9: SET<5>(_state.C); break; - case 0xEA: SET<5>(_state.D); break; - case 0xEB: SET<5>(_state.E); break; - case 0xEC: SET<5>(_state.H); break; - case 0xED: SET<5>(_state.L); break; - case 0xEE: SET_Indirect<5>(_regHL); break; - case 0xEF: SET<5>(_state.A); break; - case 0xF0: SET<6>(_state.B); break; - case 0xF1: SET<6>(_state.C); break; - case 0xF2: SET<6>(_state.D); break; - case 0xF3: SET<6>(_state.E); break; - case 0xF4: SET<6>(_state.H); break; - case 0xF5: SET<6>(_state.L); break; - case 0xF6: SET_Indirect<6>(_regHL); break; - case 0xF7: SET<6>(_state.A); break; - case 0xF8: SET<7>(_state.B); break; - case 0xF9: SET<7>(_state.C); break; - case 0xFA: SET<7>(_state.D); break; - case 0xFB: SET<7>(_state.E); break; - case 0xFC: SET<7>(_state.H); break; - case 0xFD: SET<7>(_state.L); break; - case 0xFE: SET_Indirect<7>(_regHL); break; - case 0xFF: SET<7>(_state.A); break; + switch (ReadCode()) + { + case 0x00: RLC(_state.B); + break; + case 0x01: RLC(_state.C); + break; + case 0x02: RLC(_state.D); + break; + case 0x03: RLC(_state.E); + break; + case 0x04: RLC(_state.H); + break; + case 0x05: RLC(_state.L); + break; + case 0x06: RLC_Indirect(_regHL); + break; + case 0x07: RLC(_state.A); + break; + case 0x08: RRC(_state.B); + break; + case 0x09: RRC(_state.C); + break; + case 0x0A: RRC(_state.D); + break; + case 0x0B: RRC(_state.E); + break; + case 0x0C: RRC(_state.H); + break; + case 0x0D: RRC(_state.L); + break; + case 0x0E: RRC_Indirect(_regHL); + break; + case 0x0F: RRC(_state.A); + break; + case 0x10: RL(_state.B); + break; + case 0x11: RL(_state.C); + break; + case 0x12: RL(_state.D); + break; + case 0x13: RL(_state.E); + break; + case 0x14: RL(_state.H); + break; + case 0x15: RL(_state.L); + break; + case 0x16: RL_Indirect(_regHL); + break; + case 0x17: RL(_state.A); + break; + case 0x18: RR(_state.B); + break; + case 0x19: RR(_state.C); + break; + case 0x1A: RR(_state.D); + break; + case 0x1B: RR(_state.E); + break; + case 0x1C: RR(_state.H); + break; + case 0x1D: RR(_state.L); + break; + case 0x1E: RR_Indirect(_regHL); + break; + case 0x1F: RR(_state.A); + break; + case 0x20: SLA(_state.B); + break; + case 0x21: SLA(_state.C); + break; + case 0x22: SLA(_state.D); + break; + case 0x23: SLA(_state.E); + break; + case 0x24: SLA(_state.H); + break; + case 0x25: SLA(_state.L); + break; + case 0x26: SLA_Indirect(_regHL); + break; + case 0x27: SLA(_state.A); + break; + case 0x28: SRA(_state.B); + break; + case 0x29: SRA(_state.C); + break; + case 0x2A: SRA(_state.D); + break; + case 0x2B: SRA(_state.E); + break; + case 0x2C: SRA(_state.H); + break; + case 0x2D: SRA(_state.L); + break; + case 0x2E: SRA_Indirect(_regHL); + break; + case 0x2F: SRA(_state.A); + break; + case 0x30: SWAP(_state.B); + break; + case 0x31: SWAP(_state.C); + break; + case 0x32: SWAP(_state.D); + break; + case 0x33: SWAP(_state.E); + break; + case 0x34: SWAP(_state.H); + break; + case 0x35: SWAP(_state.L); + break; + case 0x36: SWAP_Indirect(_regHL); + break; + case 0x37: SWAP(_state.A); + break; + case 0x38: SRL(_state.B); + break; + case 0x39: SRL(_state.C); + break; + case 0x3A: SRL(_state.D); + break; + case 0x3B: SRL(_state.E); + break; + case 0x3C: SRL(_state.H); + break; + case 0x3D: SRL(_state.L); + break; + case 0x3E: SRL_Indirect(_regHL); + break; + case 0x3F: SRL(_state.A); + break; + case 0x40: BIT<0>(_state.B); + break; + case 0x41: BIT<0>(_state.C); + break; + case 0x42: BIT<0>(_state.D); + break; + case 0x43: BIT<0>(_state.E); + break; + case 0x44: BIT<0>(_state.H); + break; + case 0x45: BIT<0>(_state.L); + break; + case 0x46: BIT<0>(Read(_regHL)); + break; + case 0x47: BIT<0>(_state.A); + break; + case 0x48: BIT<1>(_state.B); + break; + case 0x49: BIT<1>(_state.C); + break; + case 0x4A: BIT<1>(_state.D); + break; + case 0x4B: BIT<1>(_state.E); + break; + case 0x4C: BIT<1>(_state.H); + break; + case 0x4D: BIT<1>(_state.L); + break; + case 0x4E: BIT<1>(Read(_regHL)); + break; + case 0x4F: BIT<1>(_state.A); + break; + case 0x50: BIT<2>(_state.B); + break; + case 0x51: BIT<2>(_state.C); + break; + case 0x52: BIT<2>(_state.D); + break; + case 0x53: BIT<2>(_state.E); + break; + case 0x54: BIT<2>(_state.H); + break; + case 0x55: BIT<2>(_state.L); + break; + case 0x56: BIT<2>(Read(_regHL)); + break; + case 0x57: BIT<2>(_state.A); + break; + case 0x58: BIT<3>(_state.B); + break; + case 0x59: BIT<3>(_state.C); + break; + case 0x5A: BIT<3>(_state.D); + break; + case 0x5B: BIT<3>(_state.E); + break; + case 0x5C: BIT<3>(_state.H); + break; + case 0x5D: BIT<3>(_state.L); + break; + case 0x5E: BIT<3>(Read(_regHL)); + break; + case 0x5F: BIT<3>(_state.A); + break; + case 0x60: BIT<4>(_state.B); + break; + case 0x61: BIT<4>(_state.C); + break; + case 0x62: BIT<4>(_state.D); + break; + case 0x63: BIT<4>(_state.E); + break; + case 0x64: BIT<4>(_state.H); + break; + case 0x65: BIT<4>(_state.L); + break; + case 0x66: BIT<4>(Read(_regHL)); + break; + case 0x67: BIT<4>(_state.A); + break; + case 0x68: BIT<5>(_state.B); + break; + case 0x69: BIT<5>(_state.C); + break; + case 0x6A: BIT<5>(_state.D); + break; + case 0x6B: BIT<5>(_state.E); + break; + case 0x6C: BIT<5>(_state.H); + break; + case 0x6D: BIT<5>(_state.L); + break; + case 0x6E: BIT<5>(Read(_regHL)); + break; + case 0x6F: BIT<5>(_state.A); + break; + case 0x70: BIT<6>(_state.B); + break; + case 0x71: BIT<6>(_state.C); + break; + case 0x72: BIT<6>(_state.D); + break; + case 0x73: BIT<6>(_state.E); + break; + case 0x74: BIT<6>(_state.H); + break; + case 0x75: BIT<6>(_state.L); + break; + case 0x76: BIT<6>(Read(_regHL)); + break; + case 0x77: BIT<6>(_state.A); + break; + case 0x78: BIT<7>(_state.B); + break; + case 0x79: BIT<7>(_state.C); + break; + case 0x7A: BIT<7>(_state.D); + break; + case 0x7B: BIT<7>(_state.E); + break; + case 0x7C: BIT<7>(_state.H); + break; + case 0x7D: BIT<7>(_state.L); + break; + case 0x7E: BIT<7>(Read(_regHL)); + break; + case 0x7F: BIT<7>(_state.A); + break; + case 0x80: RES<0>(_state.B); + break; + case 0x81: RES<0>(_state.C); + break; + case 0x82: RES<0>(_state.D); + break; + case 0x83: RES<0>(_state.E); + break; + case 0x84: RES<0>(_state.H); + break; + case 0x85: RES<0>(_state.L); + break; + case 0x86: RES_Indirect<0>(_regHL); + break; + case 0x87: RES<0>(_state.A); + break; + case 0x88: RES<1>(_state.B); + break; + case 0x89: RES<1>(_state.C); + break; + case 0x8A: RES<1>(_state.D); + break; + case 0x8B: RES<1>(_state.E); + break; + case 0x8C: RES<1>(_state.H); + break; + case 0x8D: RES<1>(_state.L); + break; + case 0x8E: RES_Indirect<1>(_regHL); + break; + case 0x8F: RES<1>(_state.A); + break; + case 0x90: RES<2>(_state.B); + break; + case 0x91: RES<2>(_state.C); + break; + case 0x92: RES<2>(_state.D); + break; + case 0x93: RES<2>(_state.E); + break; + case 0x94: RES<2>(_state.H); + break; + case 0x95: RES<2>(_state.L); + break; + case 0x96: RES_Indirect<2>(_regHL); + break; + case 0x97: RES<2>(_state.A); + break; + case 0x98: RES<3>(_state.B); + break; + case 0x99: RES<3>(_state.C); + break; + case 0x9A: RES<3>(_state.D); + break; + case 0x9B: RES<3>(_state.E); + break; + case 0x9C: RES<3>(_state.H); + break; + case 0x9D: RES<3>(_state.L); + break; + case 0x9E: RES_Indirect<3>(_regHL); + break; + case 0x9F: RES<3>(_state.A); + break; + case 0xA0: RES<4>(_state.B); + break; + case 0xA1: RES<4>(_state.C); + break; + case 0xA2: RES<4>(_state.D); + break; + case 0xA3: RES<4>(_state.E); + break; + case 0xA4: RES<4>(_state.H); + break; + case 0xA5: RES<4>(_state.L); + break; + case 0xA6: RES_Indirect<4>(_regHL); + break; + case 0xA7: RES<4>(_state.A); + break; + case 0xA8: RES<5>(_state.B); + break; + case 0xA9: RES<5>(_state.C); + break; + case 0xAA: RES<5>(_state.D); + break; + case 0xAB: RES<5>(_state.E); + break; + case 0xAC: RES<5>(_state.H); + break; + case 0xAD: RES<5>(_state.L); + break; + case 0xAE: RES_Indirect<5>(_regHL); + break; + case 0xAF: RES<5>(_state.A); + break; + case 0xB0: RES<6>(_state.B); + break; + case 0xB1: RES<6>(_state.C); + break; + case 0xB2: RES<6>(_state.D); + break; + case 0xB3: RES<6>(_state.E); + break; + case 0xB4: RES<6>(_state.H); + break; + case 0xB5: RES<6>(_state.L); + break; + case 0xB6: RES_Indirect<6>(_regHL); + break; + case 0xB7: RES<6>(_state.A); + break; + case 0xB8: RES<7>(_state.B); + break; + case 0xB9: RES<7>(_state.C); + break; + case 0xBA: RES<7>(_state.D); + break; + case 0xBB: RES<7>(_state.E); + break; + case 0xBC: RES<7>(_state.H); + break; + case 0xBD: RES<7>(_state.L); + break; + case 0xBE: RES_Indirect<7>(_regHL); + break; + case 0xBF: RES<7>(_state.A); + break; + case 0xC0: SET<0>(_state.B); + break; + case 0xC1: SET<0>(_state.C); + break; + case 0xC2: SET<0>(_state.D); + break; + case 0xC3: SET<0>(_state.E); + break; + case 0xC4: SET<0>(_state.H); + break; + case 0xC5: SET<0>(_state.L); + break; + case 0xC6: SET_Indirect<0>(_regHL); + break; + case 0xC7: SET<0>(_state.A); + break; + case 0xC8: SET<1>(_state.B); + break; + case 0xC9: SET<1>(_state.C); + break; + case 0xCA: SET<1>(_state.D); + break; + case 0xCB: SET<1>(_state.E); + break; + case 0xCC: SET<1>(_state.H); + break; + case 0xCD: SET<1>(_state.L); + break; + case 0xCE: SET_Indirect<1>(_regHL); + break; + case 0xCF: SET<1>(_state.A); + break; + case 0xD0: SET<2>(_state.B); + break; + case 0xD1: SET<2>(_state.C); + break; + case 0xD2: SET<2>(_state.D); + break; + case 0xD3: SET<2>(_state.E); + break; + case 0xD4: SET<2>(_state.H); + break; + case 0xD5: SET<2>(_state.L); + break; + case 0xD6: SET_Indirect<2>(_regHL); + break; + case 0xD7: SET<2>(_state.A); + break; + case 0xD8: SET<3>(_state.B); + break; + case 0xD9: SET<3>(_state.C); + break; + case 0xDA: SET<3>(_state.D); + break; + case 0xDB: SET<3>(_state.E); + break; + case 0xDC: SET<3>(_state.H); + break; + case 0xDD: SET<3>(_state.L); + break; + case 0xDE: SET_Indirect<3>(_regHL); + break; + case 0xDF: SET<3>(_state.A); + break; + case 0xE0: SET<4>(_state.B); + break; + case 0xE1: SET<4>(_state.C); + break; + case 0xE2: SET<4>(_state.D); + break; + case 0xE3: SET<4>(_state.E); + break; + case 0xE4: SET<4>(_state.H); + break; + case 0xE5: SET<4>(_state.L); + break; + case 0xE6: SET_Indirect<4>(_regHL); + break; + case 0xE7: SET<4>(_state.A); + break; + case 0xE8: SET<5>(_state.B); + break; + case 0xE9: SET<5>(_state.C); + break; + case 0xEA: SET<5>(_state.D); + break; + case 0xEB: SET<5>(_state.E); + break; + case 0xEC: SET<5>(_state.H); + break; + case 0xED: SET<5>(_state.L); + break; + case 0xEE: SET_Indirect<5>(_regHL); + break; + case 0xEF: SET<5>(_state.A); + break; + case 0xF0: SET<6>(_state.B); + break; + case 0xF1: SET<6>(_state.C); + break; + case 0xF2: SET<6>(_state.D); + break; + case 0xF3: SET<6>(_state.E); + break; + case 0xF4: SET<6>(_state.H); + break; + case 0xF5: SET<6>(_state.L); + break; + case 0xF6: SET_Indirect<6>(_regHL); + break; + case 0xF7: SET<6>(_state.A); + break; + case 0xF8: SET<7>(_state.B); + break; + case 0xF9: SET<7>(_state.C); + break; + case 0xFA: SET<7>(_state.D); + break; + case 0xFB: SET<7>(_state.E); + break; + case 0xFC: SET<7>(_state.H); + break; + case 0xFD: SET<7>(_state.L); + break; + case 0xFE: SET_Indirect<7>(_regHL); + break; + case 0xFF: SET<7>(_state.A); + break; } } @@ -1395,44 +1944,54 @@ void GbCpu::SetReg(GbRegister reg, uint16_t value) switch (reg) { case GbRegister::GbRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case GbRegister::GbRegSP: - { - _state.SP = value; - } break; + { + _state.SP = value; + } + break; case GbRegister::GbRegA: - { - _state.A = value & 0xFF; - } break; + { + _state.A = value & 0xFF; + } + break; case GbRegister::GbRegFlags: - { - _state.Flags = value & 0xFF; - } break; + { + _state.Flags = value & 0xFF; + } + break; case GbRegister::GbRegB: - { - _state.B = value & 0xFF; - } break; + { + _state.B = value & 0xFF; + } + break; case GbRegister::GbRegC: - { - _state.C = value & 0xFF; - } break; + { + _state.C = value & 0xFF; + } + break; case GbRegister::GbRegD: - { - _state.D = value & 0xFF; - } break; + { + _state.D = value & 0xFF; + } + break; case GbRegister::GbRegE: - { - _state.E = value & 0xFF; - } break; + { + _state.E = value & 0xFF; + } + break; case GbRegister::GbRegH: - { - _state.H = value & 0xFF; - } break; + { + _state.H = value & 0xFF; + } + break; case GbRegister::GbRegL: - { - _state.L = value & 0xFF; - } break; + { + _state.L = value & 0xFF; + } + break; } } diff --git a/Core/GbCpu.h b/Core/GbCpu.h index 474708c..89537b2 100644 --- a/Core/GbCpu.h +++ b/Core/GbCpu.h @@ -66,7 +66,7 @@ private: void AND(uint8_t value); void OR(uint8_t value); void XOR(uint8_t value); - + void CP(uint8_t value); void NOP(); @@ -98,19 +98,19 @@ private: void SWAP(uint8_t& dst); void SWAP_Indirect(uint16_t addr); - template + template void BIT(uint8_t src); - template + template void RES(uint8_t& dst); - template + template void RES_Indirect(uint16_t addr); - template + template void SET(uint8_t& dst); - template + template void SET_Indirect(uint16_t addr); void DAA(); @@ -127,7 +127,7 @@ private: void RET(bool condition); void RETI(); void RST(uint8_t value); - + void POP(Register16& reg); void PUSH(Register16& reg); void POP_AF(); @@ -148,7 +148,7 @@ public: bool IsHalted(); void Exec(); - + void Serialize(Serializer& s) override; void SetReg(GbRegister reg, uint16_t value); diff --git a/Core/GbDebugger.cpp b/Core/GbDebugger.cpp index 9fc5d56..a063de3 100644 --- a/Core/GbDebugger.cpp +++ b/Core/GbDebugger.cpp @@ -37,7 +37,8 @@ GbDebugger::GbDebugger(Debugger* debugger) _step.reset(new StepRequest()); _assembler.reset(new GbAssembler(debugger->GetLabelManager())); - if(_gameboy->GetState().MemoryManager.ApuCycleCount == 0) { + if (_gameboy->GetState().MemoryManager.ApuCycleCount == 0) + { //Enable breaking on uninit reads when debugger is opened at power on _enableBreakOnUninitRead = true; } @@ -56,21 +57,26 @@ void GbDebugger::Reset() void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; BreakSource breakSource = BreakSource::Unspecified; - if(type == MemoryOperationType::ExecOpCode) { + if (type == MemoryOperationType::ExecOpCode) + { GbCpuState gbState = _gameboy->GetState().Cpu; - if(_traceLogger->IsCpuLogged(CpuType::Gameboy) || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) { - if(addressInfo.Address >= 0) { - if(addressInfo.Type == SnesMemoryType::GbPrgRom) { + if (_traceLogger->IsCpuLogged(CpuType::Gameboy) || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) + { + if (addressInfo.Address >= 0) + { + if (addressInfo.Type == SnesMemoryType::GbPrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code); } _disassembler->BuildCache(addressInfo, 0, CpuType::Gameboy); } - if(_traceLogger->IsCpuLogged(CpuType::Gameboy)) { + if (_traceLogger->IsCpuLogged(CpuType::Gameboy)) + { DebugState debugState; _debugger->GetState(debugState, true); @@ -79,38 +85,58 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t } } - if(GameboyDisUtils::IsJumpToSub(_prevOpCode) && gbState.PC != _prevProgramCounter + GameboyDisUtils::GetOpSize(_prevOpCode)) { + if (GameboyDisUtils::IsJumpToSub(_prevOpCode) && gbState.PC != _prevProgramCounter + + GameboyDisUtils::GetOpSize(_prevOpCode)) + { //CALL and RST, and PC doesn't match the next instruction, so the call was (probably) done uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Gameboy); uint16_t returnPc = _prevProgramCounter + opSize; AddressInfo src = _gameboy->GetAbsoluteAddress(_prevProgramCounter); AddressInfo ret = _gameboy->GetAbsoluteAddress(returnPc); - _callstackManager->Push(src, _prevProgramCounter, addressInfo, gbState.PC, ret, returnPc, StackFrameFlags::None); - } else if(GameboyDisUtils::IsReturnInstruction(_prevOpCode) && gbState.PC != _prevProgramCounter + GameboyDisUtils::GetOpSize(_prevOpCode)) { + _callstackManager->Push(src, _prevProgramCounter, addressInfo, gbState.PC, ret, returnPc, + StackFrameFlags::None); + } + else if (GameboyDisUtils::IsReturnInstruction(_prevOpCode) && gbState.PC != _prevProgramCounter + + GameboyDisUtils::GetOpSize(_prevOpCode)) + { //RET used, and PC doesn't match the next instruction, so the ret was (probably) taken _callstackManager->Pop(addressInfo, gbState.PC); } - if(_step->BreakAddress == (int32_t)gbState.PC && GameboyDisUtils::IsReturnInstruction(_prevOpCode)) { + if (_step->BreakAddress == (int32_t)gbState.PC && GameboyDisUtils::IsReturnInstruction(_prevOpCode)) + { //RET/RETI found, if we're on the expected return address, break immediately (for step over/step out) _step->StepCount = 0; } - if(_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) + { bool needBreak = false; - switch(value) { - case 0x40: - needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnNopLoad); - breakSource = BreakSource::GbNopLoad; - break; + switch (value) + { + case 0x40: + needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnNopLoad); + breakSource = BreakSource::GbNopLoad; + break; - case 0xD3: case 0xDB: case 0xDD: case 0xE3: case 0xE4: case 0xEB: case 0xEC: case 0xED: case 0xF4: case 0xFC: case 0xFD: - needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOpCode); - breakSource = BreakSource::GbInvalidOpCode; - break; + case 0xD3: + case 0xDB: + case 0xDD: + case 0xE3: + case 0xE4: + case 0xEB: + case 0xEC: + case 0xED: + case 0xF4: + case 0xFC: + case 0xFD: + needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOpCode); + breakSource = BreakSource::GbInvalidOpCode; + break; } - if(needBreak) { + if (needBreak) + { _step->StepCount = 0; } } @@ -118,30 +144,43 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t _prevOpCode = value; _prevProgramCounter = gbState.PC; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _console->GetMasterClock()); - } else if(type == MemoryOperationType::ExecOperand) { - if(addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) { + } + else if (type == MemoryOperationType::ExecOperand) + { + if (addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code); } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _console->GetMasterClock()); - } else { - if(addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) { + } + else + { + if (addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data); } - if(addr < 0xFE00 || addr >= 0xFF80) { - if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock())) { + if (addr < 0xFE00 || addr >= 0xFF80) + { + if (_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock())) + { //Memory access was a read on an uninitialized memory address - if(_enableBreakOnUninitRead) { - if(_memoryAccessCounter->GetReadCount(addressInfo) == 1) { + if (_enableBreakOnUninitRead) + { + if (_memoryAccessCounter->GetReadCount(addressInfo) == 1) + { //Only warn the first time _debugger->Log("[GB] Uninitialized memory read: $" + HexUtilities::ToHex(addr)); } - if(_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled) && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnUninitRead)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled) && _settings->CheckDebuggerFlag( + DebuggerFlags::BreakOnUninitRead)) + { breakSource = BreakSource::BreakOnUninitMemoryRead; _step->StepCount = 0; } @@ -149,25 +188,30 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t } } - if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) { + if (addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) + { _eventManager->AddEvent(DebugEventType::Register, operation); } } - _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource); + _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, + breakSource); } void GbDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); - if(addressInfo.Type == SnesMemoryType::GbWorkRam || addressInfo.Type == SnesMemoryType::GbCartRam || addressInfo.Type == SnesMemoryType::GbHighRam) { + if (addressInfo.Type == SnesMemoryType::GbWorkRam || addressInfo.Type == SnesMemoryType::GbCartRam || addressInfo. + Type == SnesMemoryType::GbHighRam) + { _disassembler->InvalidateCache(addressInfo, CpuType::Gameboy); } - if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) { + if (addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) + { _eventManager->AddEvent(DebugEventType::Register, operation); } @@ -184,24 +228,35 @@ void GbDebugger::Step(int32_t stepCount, StepType type) StepRequest step; GbCpuState gbState = _gameboy->GetState().Cpu; - if((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && gbState.Halted) { + if ((type == StepType::StepOver || type == StepType::StepOut || type == StepType::Step) && gbState.Halted) + { //CPU isn't running - use the PPU to break execution instead step.PpuStepCount = 1; - } else { - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break; - case StepType::StepOver: - if(GameboyDisUtils::IsJumpToSub(_prevOpCode)) { - step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Gameboy); - } else { - //For any other instruction, step over is the same as step into - step.StepCount = 1; - } - break; + } + else + { + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; + case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); + break; + case StepType::StepOver: + if (GameboyDisUtils::IsJumpToSub(_prevOpCode)) + { + step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Gameboy); + } + else + { + //For any other instruction, step over is the same as step into + step.StepCount = 1; + } + break; - case StepType::PpuStep: step.PpuStepCount = stepCount; break; - case StepType::SpecificScanline: step.BreakScanline = stepCount; break; + case StepType::PpuStep: step.PpuStepCount = stepCount; + break; + case StepType::SpecificScanline: step.BreakScanline = stepCount; + break; } } _step.reset(new StepRequest(step)); @@ -218,14 +273,17 @@ void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc) void GbDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) { - if(_step->PpuStepCount > 0) { + if (_step->PpuStepCount > 0) + { _step->PpuStepCount--; - if(_step->PpuStepCount == 0) { + if (_step->PpuStepCount == 0) + { _debugger->SleepUntilResume(BreakSource::PpuStep); } } - if(cycle == 0 && scanline == _step->BreakScanline) { + if (cycle == 0 && scanline == _step->BreakScanline) + { _step->BreakScanline = -1; _debugger->SleepUntilResume(BreakSource::PpuStep); } @@ -254,4 +312,4 @@ shared_ptr GbDebugger::GetCodeDataLogger() BreakpointManager* GbDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/GbDebugger.h b/Core/GbDebugger.h index 8a9090a..eb7a525 100644 --- a/Core/GbDebugger.h +++ b/Core/GbDebugger.h @@ -55,4 +55,4 @@ public: shared_ptr GetCallstackManager(); shared_ptr GetCodeDataLogger(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/GbDmaController.cpp b/Core/GbDmaController.cpp index b089c11..5005d69 100644 --- a/Core/GbDmaController.cpp +++ b/Core/GbDmaController.cpp @@ -19,13 +19,16 @@ GbDmaControllerState GbDmaController::GetState() void GbDmaController::Exec() { - if(_cpu->IsHalted()) { + if (_cpu->IsHalted()) + { //OAM DMA is halted while the CPU is in halt mode, and resumes when the CPU resumes return; } - if(_state.DmaCounter > 0) { - if(_state.DmaCounter <= 160) { + if (_state.DmaCounter > 0) + { + if (_state.DmaCounter <= 160) + { _memoryManager->WriteDma(0xFE00 + (160 - _state.DmaCounter), _state.DmaReadBuffer); } @@ -33,8 +36,10 @@ void GbDmaController::Exec() _state.DmaReadBuffer = _memoryManager->ReadDma((_state.OamDmaSource << 8) + (160 - _state.DmaCounter)); } - if(_state.DmaStartDelay > 0) { - if(--_state.DmaStartDelay == 0) { + if (_state.DmaStartDelay > 0) + { + if (--_state.DmaStartDelay == 0) + { _state.InternalDest = _state.OamDmaSource; _state.DmaCounter = 161; } @@ -59,8 +64,9 @@ void GbDmaController::Write(uint8_t value) uint8_t GbDmaController::ReadCgb(uint16_t addr) { - switch(addr) { - case 0xFF55: return _state.CgbDmaLength | (_state.CgbHdmaDone ? 0x80 : 0); + switch (addr) + { + case 0xFF55: return _state.CgbDmaLength | (_state.CgbHdmaDone ? 0x80 : 0); } return 0; @@ -68,40 +74,55 @@ uint8_t GbDmaController::ReadCgb(uint16_t addr) void GbDmaController::WriteCgb(uint16_t addr, uint8_t value) { - switch(addr) { - case 0xFF51: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF) | (value << 8); break; - case 0xFF52: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF00) | (value & 0xF0); break; - case 0xFF53: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF) | (value << 8); break; - case 0xFF54: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF00) | (value & 0xF0); break; - case 0xFF55: { + switch (addr) + { + case 0xFF51: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF) | (value << 8); + break; + case 0xFF52: _state.CgbDmaSource = (_state.CgbDmaSource & 0xFF00) | (value & 0xF0); + break; + case 0xFF53: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF) | (value << 8); + break; + case 0xFF54: _state.CgbDmaDest = (_state.CgbDmaDest & 0xFF00) | (value & 0xF0); + break; + case 0xFF55: + { bool hdmaMode = (value & 0x80) != 0; _state.CgbDmaLength = value & 0x7F; - if(!hdmaMode) { - if(_state.CgbHdmaRunning) { + if (!hdmaMode) + { + if (_state.CgbHdmaRunning) + { //"If HDMA5 is written during a HDMA copy, the behaviour depends on the written bit 7. // - New bit 7 is 0: Stop copy. HDMA5 new value is ( 80h OR written_value ). // - New bit 7 is 1: Restart copy. New size is the value of written_value bits 0-6. //This means that HDMA can't switch to GDMA with only one write. It must be stopped first." _state.CgbHdmaRunning = false; _state.CgbHdmaDone = true; - } else { + } + else + { //4 cycles for setup _memoryManager->Exec(); _memoryManager->Exec(); - do { + do + { ProcessDmaBlock(); - } while(_state.CgbDmaLength != 0x7F); + } + while (_state.CgbDmaLength != 0x7F); } - } else { + } + else + { //"After writing a value to HDMA5 that starts the HDMA copy, the upper bit (that indicates HDMA mode when set to '1') will be cleared" _state.CgbHdmaDone = false; _state.CgbHdmaRunning = true; //"If a HDMA transfer is started when the screen is off, one block is copied. " //" When a HDMA transfer is started during HBL it will start right away." - if(!_ppu->IsLcdEnabled() || _ppu->GetMode() == PpuMode::HBlank) { + if (!_ppu->IsLcdEnabled() || _ppu->GetMode() == PpuMode::HBlank) + { ProcessHdma(); } } @@ -112,7 +133,8 @@ void GbDmaController::WriteCgb(uint16_t addr, uint8_t value) void GbDmaController::ProcessHdma() { - if(_state.CgbHdmaRunning) { + if (_state.CgbHdmaRunning) + { //4 cycles for setup _memoryManager->Exec(); _memoryManager->Exec(); @@ -124,13 +146,15 @@ void GbDmaController::ProcessHdma() void GbDmaController::ProcessDmaBlock() { //TODO check invalid dma sources/etc. - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { uint16_t dst = 0x8000 | ((_state.CgbDmaDest + i) & 0x1FFF); //2 or 4 cycles per byte transfered (2x more cycles in high speed mode - effective speed is the same in both modes _memoryManager->Exec(); uint8_t value = _memoryManager->Read(_state.CgbDmaSource + i); - if(_memoryManager->IsHighSpeed()) { + if (_memoryManager->IsHighSpeed()) + { _memoryManager->Exec(); } _memoryManager->Write(dst, value); @@ -141,7 +165,8 @@ void GbDmaController::ProcessDmaBlock() _state.CgbDmaDest += 16; _state.CgbDmaLength = (_state.CgbDmaLength - 1) & 0x7F; - if(_state.CgbHdmaRunning && _state.CgbDmaLength == 0x7F) { + if (_state.CgbHdmaRunning && _state.CgbDmaLength == 0x7F) + { _state.CgbHdmaRunning = false; _state.CgbHdmaDone = true; } diff --git a/Core/GbDmaController.h b/Core/GbDmaController.h index 3eb13f9..98945a2 100644 --- a/Core/GbDmaController.h +++ b/Core/GbDmaController.h @@ -14,7 +14,7 @@ private: GbMemoryManager* _memoryManager; GbPpu* _ppu; GbCpu* _cpu; - + void ProcessDmaBlock(); public: @@ -35,4 +35,4 @@ public: void ProcessHdma(); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbEventManager.cpp b/Core/GbEventManager.cpp index aad38ad..df6f6ac 100644 --- a/Core/GbEventManager.cpp +++ b/Core/GbEventManager.cpp @@ -17,8 +17,8 @@ GbEventManager::GbEventManager(Debugger* debugger, GbCpu* cpu, GbPpu* ppu) _cpu = cpu; _ppu = ppu; - _ppuBuffer = new uint16_t[456*GbEventManager::ScreenHeight]; - memset(_ppuBuffer, 0, 456*GbEventManager::ScreenHeight * sizeof(uint16_t)); + _ppuBuffer = new uint16_t[456 * GbEventManager::ScreenHeight]; + memset(_ppuBuffer, 0, 456 * GbEventManager::ScreenHeight * sizeof(uint16_t)); } GbEventManager::~GbEventManager() @@ -63,8 +63,10 @@ DebugEventInfo GbEventManager::GetEvent(uint16_t scanline, uint16_t cycle, Event { auto lock = _lock.AcquireSafe(); - for(DebugEventInfo& evt : _sentEvents) { - if(evt.Cycle == cycle && evt.Scanline == scanline) { + for (DebugEventInfo& evt : _sentEvents) + { + if (evt.Cycle == cycle && evt.Scanline == scanline) + { return evt; } } @@ -93,85 +95,132 @@ void GbEventManager::FilterEvents(EventViewerDisplayOptions& options) _sentEvents.clear(); vector events = _snapshot; - if(options.ShowPreviousFrameEvents && _snapshotScanline != 0) { + if (options.ShowPreviousFrameEvents && _snapshotScanline != 0) + { uint32_t key = (_snapshotScanline << 16) + _snapshotCycle; - for(DebugEventInfo& evt : _prevDebugEvents) { + for (DebugEventInfo& evt : _prevDebugEvents) + { uint32_t evtKey = (evt.Scanline << 16) + evt.Cycle; - if(evtKey > key) { + if (evtKey > key) + { events.push_back(evt); } } } - for(DebugEventInfo& evt : events) { - bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite; + for (DebugEventInfo& evt : events) + { + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == + MemoryOperationType::DmaWrite; bool showEvent = false; - switch(evt.Type) { - default: break; - case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; break; - case DebugEventType::Irq: showEvent = options.ShowIrq; break; - case DebugEventType::Register: - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg >= 0xFE00 && reg <= 0xFE9F) { - showEvent = isWrite ? options.ShowPpuRegisterOamWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF42 && reg <= 0xFF43) { - showEvent = isWrite ? options.ShowPpuRegisterBgScrollWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0x8000 && reg <= 0x9FFF) { - showEvent = isWrite ? options.ShowPpuRegisterVramWrites : options.ShowPpuRegisterReads; - } else if((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) { - showEvent = isWrite ? options.ShowPpuRegisterCgramWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF4A && reg <= 0xFF4B) { - showEvent = isWrite ? options.ShowPpuRegisterWindowWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF40 && reg <= 0xFF70) { - showEvent = isWrite ? options.ShowPpuRegisterOtherWrites : options.ShowPpuRegisterReads; - } else if(reg >= 0xFF10 && reg <= 0xFF3F) { - showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; - } else { - showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; - } - break; + switch (evt.Type) + { + default: break; + case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; + break; + case DebugEventType::Irq: showEvent = options.ShowIrq; + break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg >= 0xFE00 && reg <= 0xFE9F) + { + showEvent = isWrite ? options.ShowPpuRegisterOamWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF42 && reg <= 0xFF43) + { + showEvent = isWrite ? options.ShowPpuRegisterBgScrollWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0x8000 && reg <= 0x9FFF) + { + showEvent = isWrite ? options.ShowPpuRegisterVramWrites : options.ShowPpuRegisterReads; + } + else if ((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) + { + showEvent = isWrite ? options.ShowPpuRegisterCgramWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF4A && reg <= 0xFF4B) + { + showEvent = isWrite ? options.ShowPpuRegisterWindowWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF40 && reg <= 0xFF70) + { + showEvent = isWrite ? options.ShowPpuRegisterOtherWrites : options.ShowPpuRegisterReads; + } + else if (reg >= 0xFF10 && reg <= 0xFF3F) + { + showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; + } + else + { + showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; + } + break; } - if(showEvent) { + if (showEvent) + { _sentEvents.push_back(evt); } } } -void GbEventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, EventViewerDisplayOptions& options) +void GbEventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, + EventViewerDisplayOptions& options) { - bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite; + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == + MemoryOperationType::DmaWrite; uint32_t color = 0; uint32_t ppuReadColor = options.PpuRegisterReadColor; - switch(evt.Type) { - default: break; - case DebugEventType::Breakpoint: color = options.BreakpointColor; break; - case DebugEventType::Irq: color = options.IrqColor; break; - case DebugEventType::Register: - uint16_t reg = evt.Operation.Address & 0xFFFF; - if(reg >= 0xFE00 && reg <= 0xFE9F) { - color = isWrite ? options.PpuRegisterWriteOamColor : ppuReadColor; - } else if(reg >= 0xFF42 && reg <= 0xFF43) { - color = isWrite ? options.PpuRegisterWriteBgScrollColor : ppuReadColor; - } else if(reg >= 0x8000 && reg <= 0x9FFF) { - color = isWrite ? options.PpuRegisterWriteVramColor : ppuReadColor; - } else if((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) { - color = isWrite ? options.PpuRegisterWriteCgramColor : ppuReadColor; - } else if(reg >= 0xFF4A && reg <= 0xFF4B) { - color = isWrite ? options.PpuRegisterWriteWindowColor : ppuReadColor; - } else if(reg >= 0xFF40 && reg <= 0xFF70) { - color = isWrite ? options.PpuRegisterWriteOtherColor : ppuReadColor; - } else if(reg >= 0xFF10 && reg <= 0xFF3F) { - color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; - } else { - color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; - } - break; + switch (evt.Type) + { + default: break; + case DebugEventType::Breakpoint: color = options.BreakpointColor; + break; + case DebugEventType::Irq: color = options.IrqColor; + break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if (reg >= 0xFE00 && reg <= 0xFE9F) + { + color = isWrite ? options.PpuRegisterWriteOamColor : ppuReadColor; + } + else if (reg >= 0xFF42 && reg <= 0xFF43) + { + color = isWrite ? options.PpuRegisterWriteBgScrollColor : ppuReadColor; + } + else if (reg >= 0x8000 && reg <= 0x9FFF) + { + color = isWrite ? options.PpuRegisterWriteVramColor : ppuReadColor; + } + else if ((reg >= 0xFF47 && reg <= 0xFF49) || (reg >= 0xFF68 && reg <= 0xFF6B)) + { + color = isWrite ? options.PpuRegisterWriteCgramColor : ppuReadColor; + } + else if (reg >= 0xFF4A && reg <= 0xFF4B) + { + color = isWrite ? options.PpuRegisterWriteWindowColor : ppuReadColor; + } + else if (reg >= 0xFF40 && reg <= 0xFF70) + { + color = isWrite ? options.PpuRegisterWriteOtherColor : ppuReadColor; + } + else if (reg >= 0xFF10 && reg <= 0xFF3F) + { + color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; + } + else + { + color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; + } + break; } - if(drawBackground) { + if (drawBackground) + { color = 0xFF000000 | ((color >> 1) & 0x7F7F7F); - } else { + } + else + { color |= 0xFF000000; } @@ -182,10 +231,13 @@ void GbEventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_ uint32_t y = std::min(evt.Scanline * 2, _scanlineCount * 2); uint32_t x = evt.Cycle * 2; - for(int i = iMin; i <= iMax; i++) { - for(int j = jMin; j <= jMax; j++) { + for (int i = iMin; i <= iMax; i++) + { + for (int j = jMin; j <= jMax; j++) + { int32_t pos = (y + i) * GbEventManager::ScanlineWidth + x + j; - if(pos < 0 || pos >= GbEventManager::ScanlineWidth * (int)_scanlineCount * 2) { + if (pos < 0 || pos >= GbEventManager::ScanlineWidth * (int)_scanlineCount * 2) + { continue; } buffer[pos] = color; @@ -202,9 +254,12 @@ uint32_t GbEventManager::TakeEventSnapshot(EventViewerDisplayOptions options) uint16_t cycle = _ppu->GetState().Cycle; uint16_t scanline = _ppu->GetState().Scanline; - if(scanline >= GbEventManager::VBlankScanline || scanline == 0) { + if (scanline >= GbEventManager::VBlankScanline || scanline == 0) + { memcpy(_ppuBuffer, _ppu->GetEventViewerBuffer(), 456 * GbEventManager::ScreenHeight * sizeof(uint16_t)); - } else { + } + else + { uint32_t size = 456 * GbEventManager::ScreenHeight; uint32_t offset = 456 * scanline; memcpy(_ppuBuffer, _ppu->GetEventViewerBuffer(), offset * sizeof(uint16_t)); @@ -222,32 +277,39 @@ void GbEventManager::GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, Eve { auto lock = _lock.AcquireSafe(); - if(_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * GbEventManager::ScanlineWidth * 4) { + if (_snapshotScanline < 0 || bufferSize < _scanlineCount * 2 * GbEventManager::ScanlineWidth * 4) + { return; } - uint16_t *src = _ppuBuffer; - for(uint32_t y = 0, len = GbEventManager::ScreenHeight*2; y < len; y++) { - for(uint32_t x = 0; x < GbEventManager::ScanlineWidth; x++) { + uint16_t* src = _ppuBuffer; + for (uint32_t y = 0, len = GbEventManager::ScreenHeight * 2; y < len; y++) + { + for (uint32_t x = 0; x < GbEventManager::ScanlineWidth; x++) + { int srcOffset = (y >> 1) * 456 + (x >> 1); - buffer[y*GbEventManager::ScanlineWidth + x] = DefaultVideoFilter::ToArgb(src[srcOffset]); + buffer[y * GbEventManager::ScanlineWidth + x] = DefaultVideoFilter::ToArgb(src[srcOffset]); } } constexpr uint32_t currentScanlineColor = 0xFFFFFF55; uint32_t scanlineOffset = _snapshotScanline * 2 * GbEventManager::ScanlineWidth; - if(_snapshotScanline != 0) { - for(int i = 0; i < GbEventManager::ScanlineWidth; i++) { + if (_snapshotScanline != 0) + { + for (int i = 0; i < GbEventManager::ScanlineWidth; i++) + { buffer[scanlineOffset + i] = currentScanlineColor; buffer[scanlineOffset + GbEventManager::ScanlineWidth + i] = currentScanlineColor; } } FilterEvents(options); - for(DebugEventInfo &evt : _sentEvents) { + for (DebugEventInfo& evt : _sentEvents) + { DrawEvent(evt, true, buffer, options); } - for(DebugEventInfo &evt : _sentEvents) { + for (DebugEventInfo& evt : _sentEvents) + { DrawEvent(evt, false, buffer, options); } } diff --git a/Core/GbEventManager.h b/Core/GbEventManager.h index 29ea6f2..cd2b5f1 100644 --- a/Core/GbEventManager.h +++ b/Core/GbEventManager.h @@ -14,7 +14,7 @@ class Debugger; class GbEventManager final : public IEventManager { private: - static constexpr int ScanlineWidth = 456*2; + static constexpr int ScanlineWidth = 456 * 2; static constexpr int ScreenHeight = 154; static constexpr int VBlankScanline = 144; diff --git a/Core/GbMbc1.h b/Core/GbMbc1.h index 23c75d2..a85f7ec 100644 --- a/Core/GbMbc1.h +++ b/Core/GbMbc1.h @@ -26,13 +26,16 @@ public: Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, (_mode ? (_ramBank << 5) : 0) * prgBankSize, true); uint8_t prgBank = _prgBank | (_ramBank << 5); - Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, prgBank*prgBankSize, true); + Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, prgBank * prgBankSize, true); - if(_ramEnabled) { + if (_ramEnabled) + { uint8_t ramBank = _mode ? _ramBank : 0; - Map(0xA000, 0xBFFF, GbMemoryType::CartRam, ramBank*ramBankSize, false); + Map(0xA000, 0xBFFF, GbMemoryType::CartRam, ramBank * ramBankSize, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -46,11 +49,16 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - switch(addr & 0x6000) { - case 0x0000: _ramEnabled = ((value & 0x0F) == 0x0A); break; - case 0x2000: _prgBank = std::max(1, value & 0x1F); break; - case 0x4000: _ramBank = value & 0x03; break; - case 0x6000: _mode = (value & 0x01) != 0; break; + switch (addr & 0x6000) + { + case 0x0000: _ramEnabled = ((value & 0x0F) == 0x0A); + break; + case 0x2000: _prgBank = std::max(1, value & 0x1F); + break; + case 0x4000: _ramBank = value & 0x03; + break; + case 0x6000: _mode = (value & 0x01) != 0; + break; } RefreshMappings(); } @@ -59,4 +67,4 @@ public: { s.Stream(_ramEnabled, _prgBank, _ramBank, _mode); } -}; \ No newline at end of file +}; diff --git a/Core/GbMbc2.h b/Core/GbMbc2.h index c1677c1..15808e7 100644 --- a/Core/GbMbc2.h +++ b/Core/GbMbc2.h @@ -14,8 +14,9 @@ public: void InitCart() override { _memoryManager->MapRegisters(0x0000, 0x3FFF, RegisterAccess::Write); - - for(int i = 0; i < 512; i++) { + + for (int i = 0; i < 512; i++) + { //Ensure cart RAM contains $F in the upper nibble, no matter the contents of save ram _cartRam[i] |= 0xF0; } @@ -29,12 +30,16 @@ public: Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); - if(_ramEnabled) { - for(int i = 0; i < 16; i++) { - Map(0xA000+0x200*i, 0xA1FF+0x200*i, GbMemoryType::CartRam, 0, false); + if (_ramEnabled) + { + for (int i = 0; i < 16; i++) + { + Map(0xA000 + 0x200 * i, 0xA1FF + 0x200 * i, GbMemoryType::CartRam, 0, false); } _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Write); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -48,14 +53,20 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - if(addr >= 0xA000 && addr <= 0xBFFF) { + if (addr >= 0xA000 && addr <= 0xBFFF) + { //Cut off the top 4 bits for all cart ram writes //Set top nibble to $F to mimic open bus _cartRam[addr & 0x1FF] = (value & 0x0F) | 0xF0; - } else { - switch(addr & 0x100) { - case 0x000: _ramEnabled = ((value & 0x0F) == 0x0A); break; - case 0x100: _prgBank = std::max(1, value & 0x0F); break; + } + else + { + switch (addr & 0x100) + { + case 0x000: _ramEnabled = ((value & 0x0F) == 0x0A); + break; + case 0x100: _prgBank = std::max(1, value & 0x0F); + break; } RefreshMappings(); } @@ -65,4 +76,4 @@ public: { s.Stream(_ramEnabled, _prgBank); } -}; \ No newline at end of file +}; diff --git a/Core/GbMbc3.h b/Core/GbMbc3.h index 75535df..9f4f02f 100644 --- a/Core/GbMbc3.h +++ b/Core/GbMbc3.h @@ -32,12 +32,17 @@ public: Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, 0, true); Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); - if(_ramRtcEnabled && _ramBank <= 3) { + if (_ramRtcEnabled && _ramBank <= 3) + { Map(0xA000, 0xBFFF, GbMemoryType::CartRam, _ramBank, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); - } else if(_hasRtcTimer && _ramRtcEnabled && _ramBank >= 0x08 && _ramBank <= 0x0C) { + } + else if (_hasRtcTimer && _ramRtcEnabled && _ramBank >= 0x08 && _ramBank <= 0x0C) + { _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::ReadWrite); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -45,18 +50,20 @@ public: uint8_t ReadRegister(uint16_t addr) override { - if(_ramRtcEnabled) { + if (_ramRtcEnabled) + { //Disabled RAM/RTC registers returns 0xFF on reads (?) return 0xFF; } - + //RTC register read (TODO) - switch(_ramBank) { - case 0x08: return _rtcRegisters[0]; //Seconds - case 0x09: return _rtcRegisters[1]; //Minutes - case 0x0A: return _rtcRegisters[2]; //Hours - case 0x0B: return _rtcRegisters[3]; //Day counter - case 0x0C: return _rtcRegisters[4]; //Day counter (upper bit) + carry/halt flags + switch (_ramBank) + { + case 0x08: return _rtcRegisters[0]; //Seconds + case 0x09: return _rtcRegisters[1]; //Minutes + case 0x0A: return _rtcRegisters[2]; //Hours + case 0x0B: return _rtcRegisters[3]; //Day counter + case 0x0C: return _rtcRegisters[4]; //Day counter (upper bit) + carry/halt flags } //Not reached @@ -65,24 +72,37 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - if(addr <= 0x7FFF) { - switch(addr & 0x6000) { - case 0x0000: _ramRtcEnabled = ((value & 0x0F) == 0x0A); break; - case 0x2000: _prgBank = std::max(1, value); break; - case 0x4000: _ramBank = value & 0x0F; break; - case 0x6000: - //RTC register read latch - break; + if (addr <= 0x7FFF) + { + switch (addr & 0x6000) + { + case 0x0000: _ramRtcEnabled = ((value & 0x0F) == 0x0A); + break; + case 0x2000: _prgBank = std::max(1, value); + break; + case 0x4000: _ramBank = value & 0x0F; + break; + case 0x6000: + //RTC register read latch + break; } RefreshMappings(); - } else if(addr >= 0xA000 && addr <= 0xBFFF) { + } + else if (addr >= 0xA000 && addr <= 0xBFFF) + { //RTC register write (TODO) - switch(_ramBank) { - case 0x08: _rtcRegisters[0] = value; break; //Seconds - case 0x09: _rtcRegisters[1] = value; break; //Minutes - case 0x0A: _rtcRegisters[2] = value; break; //Hours - case 0x0B: _rtcRegisters[3] = value; break; //Day counter - case 0x0C: _rtcRegisters[4] = value; break; //Day counter (upper bit) + carry/halt flags + switch (_ramBank) + { + case 0x08: _rtcRegisters[0] = value; + break; //Seconds + case 0x09: _rtcRegisters[1] = value; + break; //Minutes + case 0x0A: _rtcRegisters[2] = value; + break; //Hours + case 0x0B: _rtcRegisters[3] = value; + break; //Day counter + case 0x0C: _rtcRegisters[4] = value; + break; //Day counter (upper bit) + carry/halt flags } } } @@ -92,4 +112,4 @@ public: s.Stream(_ramRtcEnabled, _prgBank, _ramBank); s.StreamArray(_rtcRegisters, 5); } -}; \ No newline at end of file +}; diff --git a/Core/GbMbc5.h b/Core/GbMbc5.h index 163eb8e..db7b192 100644 --- a/Core/GbMbc5.h +++ b/Core/GbMbc5.h @@ -25,10 +25,13 @@ public: Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, 0, true); Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); - if(_ramEnabled) { + if (_ramEnabled) + { Map(0xA000, 0xBFFF, GbMemoryType::CartRam, _ramBank * ramBankSize, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); - } else { + } + else + { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } @@ -42,24 +45,25 @@ public: void WriteRegister(uint16_t addr, uint8_t value) override { - switch(addr & 0x7000) { - case 0x0000: - case 0x1000: - _ramEnabled = (value == 0x0A); - break; - - case 0x2000: - _prgBank = (value & 0xFF) | (_prgBank & 0x100); - break; + switch (addr & 0x7000) + { + case 0x0000: + case 0x1000: + _ramEnabled = (value == 0x0A); + break; - case 0x3000: - _prgBank = (_prgBank & 0xFF) | ((value & 0x01) << 8); - break; + case 0x2000: + _prgBank = (value & 0xFF) | (_prgBank & 0x100); + break; - case 0x4000: - case 0x5000: - _ramBank = value & 0x0F; - break; + case 0x3000: + _prgBank = (_prgBank & 0xFF) | ((value & 0x01) << 8); + break; + + case 0x4000: + case 0x5000: + _ramBank = value & 0x0F; + break; } RefreshMappings(); } @@ -68,4 +72,4 @@ public: { s.Stream(_ramEnabled, _prgBank, _ramBank); } -}; \ No newline at end of file +}; diff --git a/Core/GbMemoryManager.cpp b/Core/GbMemoryManager.cpp index 220496a..17e9a4b 100644 --- a/Core/GbMemoryManager.cpp +++ b/Core/GbMemoryManager.cpp @@ -18,7 +18,8 @@ #include "../Utilities/Serializer.h" #include "../Utilities/HexUtilities.h" -void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, GbDmaController* dmaController) +void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, + GbDmaController* dmaController) { _highRam = gameboy->DebugGetMemory(SnesMemoryType::GbHighRam); @@ -65,9 +66,11 @@ void GbMemoryManager::RefreshMappings() _cart->RefreshMappings(); - if(!_state.DisableBootRom) { + if (!_state.DisableBootRom) + { Map(0x0000, 0x00FF, GbMemoryType::BootRom, 0, true); - if(_gameboy->IsCgb()) { + if (_gameboy->IsCgb()) + { Map(0x0200, 0x08FF, GbMemoryType::BootRom, 0x200, true); } } @@ -79,13 +82,16 @@ void GbMemoryManager::Exec() _state.ApuCycleCount += _state.CgbHighSpeed ? 1 : 2; _timer->Exec(); _ppu->Exec(); - if((_state.CycleCount & 0x03) == 0) { + if ((_state.CycleCount & 0x03) == 0) + { _dmaController->Exec(); } - if(_state.SerialBitCount && (_state.CycleCount & 0x1FF) == 0) { + if (_state.SerialBitCount && (_state.CycleCount & 0x1FF) == 0) + { _state.SerialData = (_state.SerialData << 1) | 0x01; - if(--_state.SerialBitCount == 0) { + if (--_state.SerialBitCount == 0) + { //"It will be notified that the transfer is complete in two ways: //SC's Bit 7 will be cleared" _state.SerialControl &= 0x7F; @@ -98,7 +104,8 @@ void GbMemoryManager::Exec() void GbMemoryManager::MapRegisters(uint16_t start, uint16_t end, RegisterAccess access) { - for(int i = start; i < end; i += 0x100) { + for (int i = start; i < end; i += 0x100) + { _state.IsReadRegister[i >> 8] = ((int)access & (int)RegisterAccess::Read) != 0; _state.IsWriteRegister[i >> 8] = ((int)access & (int)RegisterAccess::Write) != 0; } @@ -109,13 +116,16 @@ void GbMemoryManager::Map(uint16_t start, uint16_t end, GbMemoryType type, uint3 uint8_t* src = _gameboy->DebugGetMemory((SnesMemoryType)type); uint32_t size = _gameboy->DebugGetMemorySize((SnesMemoryType)type); - if(size > 0) { - while(offset >= size) { + if (size > 0) + { + while (offset >= size) + { offset -= size; } - + src += offset; - for(int i = start; i < end; i += 0x100) { + for (int i = start; i < end; i += 0x100) + { _reads[i >> 8] = src; _writes[i >> 8] = readonly ? nullptr : src; @@ -123,23 +133,28 @@ void GbMemoryManager::Map(uint16_t start, uint16_t end, GbMemoryType type, uint3 _state.MemoryOffset[i >> 8] = offset; _state.MemoryAccessType[i >> 8] = readonly ? RegisterAccess::Read : RegisterAccess::ReadWrite; - if(src) { + if (src) + { src += 0x100; offset = (offset + 0x100); - if(offset >= size) { + if (offset >= size) + { offset = 0; src = _gameboy->DebugGetMemory((SnesMemoryType)type); } } } - } else { + } + else + { Unmap(start, end); } } void GbMemoryManager::Unmap(uint16_t start, uint16_t end) { - for(int i = start; i < end; i += 0x100) { + for (int i = start; i < end; i += 0x100) + { _reads[i >> 8] = nullptr; _writes[i >> 8] = nullptr; @@ -149,13 +164,16 @@ void GbMemoryManager::Unmap(uint16_t start, uint16_t end) } } -template +template uint8_t GbMemoryManager::Read(uint16_t addr) { uint8_t value = 0; - if(_state.IsReadRegister[addr >> 8]) { + if (_state.IsReadRegister[addr >> 8]) + { value = ReadRegister(addr); - } else if(_reads[addr >> 8]) { + } + else if (_reads[addr >> 8]) + { value = _reads[addr >> 8][(uint8_t)addr]; } _console->ProcessMemoryRead(addr, value, opType); @@ -176,36 +194,48 @@ void GbMemoryManager::WriteDma(uint16_t addr, uint8_t value) uint8_t GbMemoryManager::ReadDma(uint16_t addr) { uint8_t value = 0; - if(_reads[addr >> 8]) { + if (_reads[addr >> 8]) + { value = _reads[addr >> 8][(uint8_t)addr]; - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { value = ReadRegister(addr); } _console->ProcessMemoryRead(addr, value, MemoryOperationType::DmaRead); return value; } -template +template void GbMemoryManager::Write(uint16_t addr, uint8_t value) { _console->ProcessMemoryWrite(addr, value, type); - if(_state.IsWriteRegister[addr >> 8]) { + if (_state.IsWriteRegister[addr >> 8]) + { WriteRegister(addr, value); - } else if(_writes[addr >> 8]) { + } + else if (_writes[addr >> 8]) + { _writes[addr >> 8][(uint8_t)addr] = value; } } uint8_t GbMemoryManager::DebugRead(uint16_t addr) { - if(_state.IsReadRegister[addr >> 8]) { - if(addr >= 0xFE00) { + if (_state.IsReadRegister[addr >> 8]) + { + if (addr >= 0xFE00) + { return PeekRegister(addr); - } else { + } + else + { //Avoid potential read side effects return 0xFF; } - } else if(_reads[addr >> 8]) { + } + else if (_reads[addr >> 8]) + { return _reads[addr >> 8][(uint8_t)addr]; } return 0; @@ -213,16 +243,20 @@ uint8_t GbMemoryManager::DebugRead(uint16_t addr) void GbMemoryManager::DebugWrite(uint16_t addr, uint8_t value) { - if(_state.IsWriteRegister[addr >> 8]) { + if (_state.IsWriteRegister[addr >> 8]) + { //Do not write to registers via debug tools - } else if(_writes[addr >> 8]) { + } + else if (_writes[addr >> 8]) + { _writes[addr >> 8][(uint8_t)addr] = value; } } uint8_t* GbMemoryManager::GetMappedBlock(uint16_t addr) { - if(_reads[addr >> 8]) { + if (_reads[addr >> 8]) + { return _reads[addr >> 8]; } return nullptr; @@ -231,89 +265,128 @@ uint8_t* GbMemoryManager::GetMappedBlock(uint16_t addr) uint8_t GbMemoryManager::PeekRegister(uint16_t addr) { //Peek on oam/vram to avoid triggering the invalid oam/vram access break options - if(addr >= 0xFE00 && addr <= 0xFE9F) { + if (addr >= 0xFE00 && addr <= 0xFE9F) + { return _ppu->PeekOam((uint8_t)addr); - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { return _ppu->PeekVram(addr); - } else if(addr >= 0xFF10 && addr <= 0xFF3F) { + } + else if (addr >= 0xFF10 && addr <= 0xFF3F) + { return _apu->Peek(addr); - } else { + } + else + { return ReadRegister(addr); } } uint8_t GbMemoryManager::ReadRegister(uint16_t addr) { - if(addr >= 0xFF00) { - if(addr == 0xFFFF) { + if (addr >= 0xFF00) + { + if (addr == 0xFFFF) + { return _state.IrqEnabled; //IE - Interrupt Enable (R/W) - } else if(addr == 0xFF46) { + } + else if (addr == 0xFF46) + { return _dmaController->Read(); - } else if(addr >= 0xFF80) { + } + else if (addr >= 0xFF80) + { return _highRam[addr & 0x7F]; //80-FE - } else if(addr >= 0xFF4C) { - if(_gameboy->IsCgb()) { - switch(addr) { + } + else if (addr >= 0xFF4C) + { + if (_gameboy->IsCgb()) + { + switch (addr) + { //FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch - case 0xFF4D: - if(_ppu->IsCgbEnabled()) { - return ( - (_state.CgbHighSpeed ? 0x80 : 0) | - (_state.CgbSwitchSpeedRequest ? 0x01 : 0) | - 0x7E - ); - } - return 0xFF; - - case 0xFF55: //CGB - DMA - return _ppu->IsCgbEnabled() ? _dmaController->ReadCgb(addr) : 0xFF; + case 0xFF4D: + if (_ppu->IsCgbEnabled()) + { + return ( + (_state.CgbHighSpeed ? 0x80 : 0) | + (_state.CgbSwitchSpeedRequest ? 0x01 : 0) | + 0x7E + ); + } + return 0xFF; - case 0xFF4F: //CGB - VRAM bank - case 0xFF68: case 0xFF69: case 0xFF6A: case 0xFF6B: //CGB - Palette - return _ppu->ReadCgbRegister(addr); + case 0xFF55: //CGB - DMA + return _ppu->IsCgbEnabled() ? _dmaController->ReadCgb(addr) : 0xFF; + + case 0xFF4F: //CGB - VRAM bank + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: //CGB - Palette + return _ppu->ReadCgbRegister(addr); //FF70 - SVBK - CGB Mode Only - WRAM Bank - case 0xFF70: return _ppu->IsCgbEnabled() ? (_state.CgbWorkRamBank | 0xF8) : 0xFF; - case 0xFF72: return _state.CgbRegFF72; - case 0xFF73: return _state.CgbRegFF73; - - case 0xFF74: - if(_ppu->IsCgbEnabled()) { - return _state.CgbRegFF74; - } - return 0xFF; + case 0xFF70: return _ppu->IsCgbEnabled() ? (_state.CgbWorkRamBank | 0xF8) : 0xFF; + case 0xFF72: return _state.CgbRegFF72; + case 0xFF73: return _state.CgbRegFF73; - case 0xFF75: return _state.CgbRegFF75 | 0x8F; - - case 0xFF76: case 0xFF77: - return _apu->ReadCgbRegister(addr); + case 0xFF74: + if (_ppu->IsCgbEnabled()) + { + return _state.CgbRegFF74; + } + return 0xFF; + + case 0xFF75: return _state.CgbRegFF75 | 0x8F; + + case 0xFF76: + case 0xFF77: + return _apu->ReadCgbRegister(addr); } } LogDebug("[Debug] GB - Missing read handler: $" + HexUtilities::ToHex(addr)); return 0xFF; //4C-7F, open bus - } else if(addr >= 0xFF40) { + } + else if (addr >= 0xFF40) + { return _ppu->Read(addr); //40-4B - } else if(addr >= 0xFF10) { + } + else if (addr >= 0xFF10) + { return _apu->Read(addr); //10-3F - } else { + } + else + { //00-0F - switch(addr) { - case 0xFF00: return ReadInputPort(); break; - - case 0xFF01: return _state.SerialData; //SB - Serial transfer data (R/W) - case 0xFF02: return _state.SerialControl | 0x7E; //SC - Serial Transfer Control (R/W) + switch (addr) + { + case 0xFF00: return ReadInputPort(); + break; - case 0xFF04: case 0xFF05: case 0xFF06: case 0xFF07: - return _timer->Read(addr); + case 0xFF01: return _state.SerialData; //SB - Serial transfer data (R/W) + case 0xFF02: return _state.SerialControl | 0x7E; //SC - Serial Transfer Control (R/W) - case 0xFF0F: return _state.IrqRequests | 0xE0; break; //IF - Interrupt flags (R/W) + case 0xFF04: + case 0xFF05: + case 0xFF06: + case 0xFF07: + return _timer->Read(addr); - default: return 0xFF; //Open bus + case 0xFF0F: return _state.IrqRequests | 0xE0; + break; //IF - Interrupt flags (R/W) + + default: return 0xFF; //Open bus } } - } else if(addr >= 0xFE00) { + } + else if (addr >= 0xFE00) + { return _ppu->ReadOam((uint8_t)addr); - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { return _ppu->ReadVram(addr); } @@ -322,100 +395,150 @@ uint8_t GbMemoryManager::ReadRegister(uint16_t addr) void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value) { - if(addr >= 0xFF00) { - if(addr == 0xFFFF) { + if (addr >= 0xFF00) + { + if (addr == 0xFFFF) + { _state.IrqEnabled = value; //IE register - } else if(addr == 0xFF46) { + } + else if (addr == 0xFF46) + { _dmaController->Write(value); - } else if(addr >= 0xFF80) { + } + else if (addr >= 0xFF80) + { _highRam[addr & 0x7F] = value; //80-FE - } else if(addr >= 0xFF4C) { + } + else if (addr >= 0xFF4C) + { //4C-7F - if(addr == 0xFF50) { - if(value & 0x01) { + if (addr == 0xFF50) + { + if (value & 0x01) + { _state.DisableBootRom = true; RefreshMappings(); } - } else if(_gameboy->IsCgb()) { - switch(addr) { - case 0xFF4D: - //FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch - if(_ppu->IsCgbEnabled()) { - _state.CgbSwitchSpeedRequest = (value & 0x01) != 0; - } - break; - - case 0xFF51: case 0xFF52: case 0xFF53: case 0xFF54: case 0xFF55: //CGB - DMA - if(_ppu->IsCgbEnabled()) { - _dmaController->WriteCgb(addr, value); - } - break; - - case 0xFF4C: //CGB - "LCDMODE", set by boot rom to turn off CGB features for the LCD for DMG games - if(!_state.DisableBootRom) { - _ppu->WriteCgbRegister(addr, value); - } - break; - - case 0xFF4F: //CGB - VRAM banking - case 0xFF68: case 0xFF69: case 0xFF6A: case 0xFF6B: //CGB - Palette - _ppu->WriteCgbRegister(addr, value); - break; - - case 0xFF70: - //FF70 - SVBK - CGB Mode Only - WRAM Bank - if(_ppu->IsCgbEnabled()) { - _state.CgbWorkRamBank = std::max(1, value & 0x07); - RefreshMappings(); - } - break; - - case 0xFF72: _state.CgbRegFF72 = value; break; - case 0xFF73: _state.CgbRegFF73 = value; break; - case 0xFF74: - if(_ppu->IsCgbEnabled()) { - _state.CgbRegFF74 = value; - } - break; - - case 0xFF75: _state.CgbRegFF75 = value; break; - - default: - LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); - break; - } } - } else if(addr >= 0xFF40) { - _ppu->Write(addr, value); //40-4B - } else if(addr >= 0xFF10) { - _apu->Write(addr, value); //10-3F - } else { - //00-0F - switch(addr) { - case 0xFF00: WriteInputPort(value); break; - case 0xFF01: _state.SerialData = value; break; //FF01 - SB - Serial transfer data (R/W) - case 0xFF02: - //FF02 - SC - Serial Transfer Control (R/W) - _state.SerialControl = value & (_gameboy->IsCgb() ? 0x83 : 0x81); - if((_state.SerialControl & 0x80) && (_state.SerialControl & 0x01)) { - _state.SerialBitCount = 8; - } else { - _state.SerialBitCount = 0; + else if (_gameboy->IsCgb()) + { + switch (addr) + { + case 0xFF4D: + //FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch + if (_ppu->IsCgbEnabled()) + { + _state.CgbSwitchSpeedRequest = (value & 0x01) != 0; } break; - case 0xFF04: case 0xFF05: case 0xFF06: case 0xFF07: - _timer->Write(addr, value); + case 0xFF51: + case 0xFF52: + case 0xFF53: + case 0xFF54: + case 0xFF55: //CGB - DMA + if (_ppu->IsCgbEnabled()) + { + _dmaController->WriteCgb(addr, value); + } break; - case 0xFF0F: _state.IrqRequests = value & 0x1F; break; //IF - Interrupt flags (R/W) + case 0xFF4C: //CGB - "LCDMODE", set by boot rom to turn off CGB features for the LCD for DMG games + if (!_state.DisableBootRom) + { + _ppu->WriteCgbRegister(addr, value); + } + break; + + case 0xFF4F: //CGB - VRAM banking + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: //CGB - Palette + _ppu->WriteCgbRegister(addr, value); + break; + + case 0xFF70: + //FF70 - SVBK - CGB Mode Only - WRAM Bank + if (_ppu->IsCgbEnabled()) + { + _state.CgbWorkRamBank = std::max(1, value & 0x07); + RefreshMappings(); + } + break; + + case 0xFF72: _state.CgbRegFF72 = value; + break; + case 0xFF73: _state.CgbRegFF73 = value; + break; + case 0xFF74: + if (_ppu->IsCgbEnabled()) + { + _state.CgbRegFF74 = value; + } + break; + + case 0xFF75: _state.CgbRegFF75 = value; + break; + + default: + LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); + break; + } } } - } else if(addr >= 0xFE00) { + else if (addr >= 0xFF40) + { + _ppu->Write(addr, value); //40-4B + } + else if (addr >= 0xFF10) + { + _apu->Write(addr, value); //10-3F + } + else + { + //00-0F + switch (addr) + { + case 0xFF00: WriteInputPort(value); + break; + case 0xFF01: _state.SerialData = value; + break; //FF01 - SB - Serial transfer data (R/W) + case 0xFF02: + //FF02 - SC - Serial Transfer Control (R/W) + _state.SerialControl = value & (_gameboy->IsCgb() ? 0x83 : 0x81); + if ((_state.SerialControl & 0x80) && (_state.SerialControl & 0x01)) + { + _state.SerialBitCount = 8; + } + else + { + _state.SerialBitCount = 0; + } + break; + + case 0xFF04: + case 0xFF05: + case 0xFF06: + case 0xFF07: + _timer->Write(addr, value); + break; + + case 0xFF0F: _state.IrqRequests = value & 0x1F; + break; //IF - Interrupt flags (R/W) + } + } + } + else if (addr >= 0xFE00) + { _ppu->WriteOam((uint8_t)addr, value, false); - } else if(addr >= 0x8000 && addr <= 0x9FFF) { + } + else if (addr >= 0x8000 && addr <= 0x9FFF) + { _ppu->WriteVram(addr, value); - } else { + } + else + { _cart->WriteRegister(addr, value); } } @@ -433,16 +556,26 @@ void GbMemoryManager::ClearIrqRequest(uint8_t source) uint8_t GbMemoryManager::ProcessIrqRequests() { uint8_t irqsToProcess = _state.IrqRequests & _state.IrqEnabled; - if(irqsToProcess) { - if(irqsToProcess & GbIrqSource::VerticalBlank) { + if (irqsToProcess) + { + if (irqsToProcess & GbIrqSource::VerticalBlank) + { return GbIrqSource::VerticalBlank; - } else if(irqsToProcess & GbIrqSource::LcdStat) { + } + else if (irqsToProcess & GbIrqSource::LcdStat) + { return GbIrqSource::LcdStat; - } else if(irqsToProcess & GbIrqSource::Timer) { + } + else if (irqsToProcess & GbIrqSource::Timer) + { return GbIrqSource::Timer; - } else if(irqsToProcess & GbIrqSource::Serial) { + } + else if (irqsToProcess & GbIrqSource::Serial) + { return GbIrqSource::Serial; - } else if(irqsToProcess & GbIrqSource::Joypad) { + } + else if (irqsToProcess & GbIrqSource::Joypad) + { return GbIrqSource::Joypad; } } @@ -487,28 +620,39 @@ uint8_t GbMemoryManager::ReadInputPort() //Bit 0 - P10 Input Right or Button A (0=Pressed) (Read Only) uint8_t result = 0x0F; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy(); - if((_state.InputSelect & 0x30) == 0x30) { + if ((_state.InputSelect & 0x30) == 0x30) + { result = sgb->GetInputIndex(); - } else { - if(!(_state.InputSelect & 0x20)) { + } + else + { + if (!(_state.InputSelect & 0x20)) + { result &= sgb->GetInput() >> 4; } - if(!(_state.InputSelect & 0x10)) { + if (!(_state.InputSelect & 0x10)) + { result &= sgb->GetInput() & 0x0F; } } - } else { + } + else + { BaseControlDevice* controller = (SnesController*)_controlManager->GetControlDevice(0).get(); - if(controller && controller->GetControllerType() == ControllerType::SnesController) { - if(!(_state.InputSelect & 0x20)) { + if (controller && controller->GetControllerType() == ControllerType::SnesController) + { + if (!(_state.InputSelect & 0x20)) + { result &= ~(controller->IsPressed(SnesController::A) ? 0x01 : 0); result &= ~(controller->IsPressed(SnesController::B) ? 0x02 : 0); result &= ~(controller->IsPressed(SnesController::Select) ? 0x04 : 0); result &= ~(controller->IsPressed(SnesController::Start) ? 0x08 : 0); } - if(!(_state.InputSelect & 0x10)) { + if (!(_state.InputSelect & 0x10)) + { result &= ~(controller->IsPressed(SnesController::Right) ? 0x01 : 0); result &= ~(controller->IsPressed(SnesController::Left) ? 0x02 : 0); result &= ~(controller->IsPressed(SnesController::Up) ? 0x04 : 0); @@ -523,7 +667,8 @@ uint8_t GbMemoryManager::ReadInputPort() void GbMemoryManager::WriteInputPort(uint8_t value) { _state.InputSelect = value; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { _console->GetCartridge()->GetSuperGameboy()->ProcessInputPortWrite(value & 0x30); } } @@ -542,10 +687,13 @@ void GbMemoryManager::Serialize(Serializer& s) s.StreamArray(_state.IsReadRegister, 0x100); s.StreamArray(_state.IsWriteRegister, 0x100); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { //Restore mappings based on state - for(int i = 0; i < 0x100; i++) { - Map(i*0x100, i*0x100+0xFF, _state.MemoryType[i], _state.MemoryOffset[i], _state.MemoryAccessType[i] == RegisterAccess::ReadWrite ? false : true); + for (int i = 0; i < 0x100; i++) + { + Map(i * 0x100, i * 0x100 + 0xFF, _state.MemoryType[i], _state.MemoryOffset[i], + _state.MemoryAccessType[i] == RegisterAccess::ReadWrite ? false : true); } RefreshMappings(); } @@ -556,4 +704,4 @@ template uint8_t GbMemoryManager::Read(uint16_t template uint8_t GbMemoryManager::Read(uint16_t addr); template uint8_t GbMemoryManager::Read(uint16_t addr); template void GbMemoryManager::Write(uint16_t addr, uint8_t value); -template void GbMemoryManager::Write(uint16_t addr, uint8_t value); \ No newline at end of file +template void GbMemoryManager::Write(uint16_t addr, uint8_t value); diff --git a/Core/GbMemoryManager.h b/Core/GbMemoryManager.h index 27c150b..8bb0383 100644 --- a/Core/GbMemoryManager.h +++ b/Core/GbMemoryManager.h @@ -31,7 +31,7 @@ private: GbDmaController* _dmaController = nullptr; uint8_t* _highRam = nullptr; - + uint8_t* _reads[0x100] = {}; uint8_t* _writes[0x100] = {}; @@ -42,7 +42,8 @@ public: GbMemoryManagerState GetState(); - void Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, GbDmaController* dmaController); + void Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, + GbDmaController* dmaController); void MapRegisters(uint16_t start, uint16_t end, RegisterAccess access); void Map(uint16_t start, uint16_t end, GbMemoryType type, uint32_t offset, bool readonly); void Unmap(uint16_t start, uint16_t end); @@ -50,14 +51,14 @@ public: void Exec(); - template + template uint8_t Read(uint16_t addr); bool IsOamDmaRunning(); void WriteDma(uint16_t addr, uint8_t value); uint8_t ReadDma(uint16_t addr); - template + template void Write(uint16_t addr, uint8_t value); uint8_t PeekRegister(uint16_t addr); @@ -74,7 +75,7 @@ public: uint64_t GetCycleCount(); uint64_t GetApuCycleCount(); - + uint8_t ReadInputPort(); void WriteInputPort(uint8_t value); diff --git a/Core/GbNoiseChannel.cpp b/Core/GbNoiseChannel.cpp index 4d95426..509a66f 100644 --- a/Core/GbNoiseChannel.cpp +++ b/Core/GbNoiseChannel.cpp @@ -26,9 +26,11 @@ void GbNoiseChannel::Disable() void GbNoiseChannel::ClockLengthCounter() { - if(_state.LengthEnabled && _state.Length > 0) { + if (_state.LengthEnabled && _state.Length > 0) + { _state.Length--; - if(_state.Length == 0) { + if (_state.Length == 0) + { //"Length becoming 0 should clear status" _state.Enabled = false; } @@ -37,13 +39,18 @@ void GbNoiseChannel::ClockLengthCounter() void GbNoiseChannel::ClockEnvelope() { - if(_state.EnvTimer > 0) { + if (_state.EnvTimer > 0) + { _state.EnvTimer--; - if(_state.EnvTimer == 0) { - if(_state.EnvRaiseVolume && _state.Volume < 0x0F) { + if (_state.EnvTimer == 0) + { + if (_state.EnvRaiseVolume && _state.Volume < 0x0F) + { _state.Volume++; - } else if(!_state.EnvRaiseVolume && _state.Volume > 0) { + } + else if (!_state.EnvRaiseVolume && _state.Volume > 0) + { _state.Volume--; } @@ -59,29 +66,37 @@ uint8_t GbNoiseChannel::GetOutput() uint32_t GbNoiseChannel::GetPeriod() { - if(_state.Divisor == 0) { + if (_state.Divisor == 0) + { return 8 << _state.PeriodShift; - } else { + } + else + { return (16 * _state.Divisor) << _state.PeriodShift; } } void GbNoiseChannel::Exec(uint32_t clocksToRun) { - if(_state.PeriodShift >= 14) { + if (_state.PeriodShift >= 14) + { //Using a noise channel clock shift of 14 or 15 results in the LFSR receiving no clocks. return; } _state.Timer -= clocksToRun; - if(_state.Enabled) { + if (_state.Enabled) + { _state.Output = ((_state.ShiftRegister & 0x01) ^ 0x01) * _state.Volume; - } else { + } + else + { _state.Output = 0; } - if(_state.Timer == 0) { + if (_state.Timer == 0) + { _state.Timer = GetPeriod(); //When clocked by the frequency timer, the low two bits (0 and 1) are XORed, all bits are shifted right by one, @@ -90,7 +105,8 @@ void GbNoiseChannel::Exec(uint32_t clocksToRun) uint8_t xorResult = (_state.ShiftRegister & 0x01) ^ (shiftedValue & 0x01); _state.ShiftRegister = (xorResult << 14) | shiftedValue; - if(_state.ShortWidthMode) { + if (_state.ShortWidthMode) + { //If width mode is 1 (NR43), the XOR result is ALSO put into bit 6 AFTER the shift, resulting in a 7-bit LFSR. _state.ShiftRegister &= ~0x40; _state.ShiftRegister |= (xorResult << 6); @@ -100,27 +116,29 @@ void GbNoiseChannel::Exec(uint32_t clocksToRun) uint8_t GbNoiseChannel::Read(uint16_t addr) { - constexpr uint8_t openBusBits[5] = { 0xFF, 0xFF, 0x00, 0x00, 0xBF }; + constexpr uint8_t openBusBits[5] = {0xFF, 0xFF, 0x00, 0x00, 0xBF}; uint8_t value = 0; - switch(addr) { - case 2: - value = ( - (_state.EnvVolume << 4) | - (_state.EnvRaiseVolume ? 0x08 : 0) | - _state.EnvPeriod - ); - break; + switch (addr) + { + case 2: + value = ( + (_state.EnvVolume << 4) | + (_state.EnvRaiseVolume ? 0x08 : 0) | + _state.EnvPeriod + ); + break; - case 3: - value = ( - (_state.PeriodShift << 4) | - (_state.ShortWidthMode ? 0x08 : 0) | - _state.Divisor - ); - break; + case 3: + value = ( + (_state.PeriodShift << 4) | + (_state.ShortWidthMode ? 0x08 : 0) | + _state.Divisor + ); + break; - case 4: value = _state.LengthEnabled ? 0x40 : 0; break; + case 4: value = _state.LengthEnabled ? 0x40 : 0; + break; } return value | openBusBits[addr]; @@ -128,30 +146,34 @@ uint8_t GbNoiseChannel::Read(uint16_t addr) void GbNoiseChannel::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0: break; - case 1: - _state.Length = 64 - (value & 0x3F); - break; + switch (addr) + { + case 0: break; + case 1: + _state.Length = 64 - (value & 0x3F); + break; - case 2: - _state.EnvPeriod = value & 0x07; - _state.EnvRaiseVolume = (value & 0x08) != 0; - _state.EnvVolume = (value & 0xF0) >> 4; + case 2: + _state.EnvPeriod = value & 0x07; + _state.EnvRaiseVolume = (value & 0x08) != 0; + _state.EnvVolume = (value & 0xF0) >> 4; - if(!(value & 0xF8)) { - _state.Enabled = false; - } - break; + if (!(value & 0xF8)) + { + _state.Enabled = false; + } + break; - case 3: - _state.PeriodShift = (value & 0xF0) >> 4; - _state.ShortWidthMode = (value & 0x08) != 0; - _state.Divisor = value & 0x07; - break; + case 3: + _state.PeriodShift = (value & 0xF0) >> 4; + _state.ShortWidthMode = (value & 0x08) != 0; + _state.Divisor = value & 0x07; + break; - case 4: { - if(value & 0x80) { + case 4: + { + if (value & 0x80) + { //Writing a value to NRx4 with bit 7 set causes the following things to occur : //Channel is enabled, if volume is not 0 or raise volume flag is set @@ -164,7 +186,8 @@ void GbNoiseChannel::Write(uint16_t addr, uint8_t value) _state.ShiftRegister = 0x7FFF; //If length counter is zero, it is set to 64 (256 for wave channel). - if(_state.Length == 0) { + if (_state.Length == 0) + { _state.Length = 64; _state.LengthEnabled = false; } diff --git a/Core/GbNoiseChannel.h b/Core/GbNoiseChannel.h index e5073e5..08cc37a 100644 --- a/Core/GbNoiseChannel.h +++ b/Core/GbNoiseChannel.h @@ -31,4 +31,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbPpu.cpp b/Core/GbPpu.cpp index bcdb4df..283885c 100644 --- a/Core/GbPpu.cpp +++ b/Core/GbPpu.cpp @@ -15,9 +15,10 @@ #include "../Utilities/HexUtilities.h" #include "../Utilities/Serializer.h" -constexpr uint16_t evtColors[6] = { 0x18C6, 0x294A, 0x108C, 0x4210, 0x3084, 0x1184 }; +constexpr uint16_t evtColors[6] = {0x18C6, 0x294A, 0x108C, 0x4210, 0x3084, 0x1184}; -void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, uint8_t* vram, uint8_t* oam) +void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, + uint8_t* vram, uint8_t* oam) { _console = console; _gameboy = gameboy; @@ -76,10 +77,12 @@ uint16_t* GbPpu::GetPreviousEventViewerBuffer() void GbPpu::Exec() { - if(!_state.LcdEnabled) { + if (!_state.LcdEnabled) + { //LCD is disabled, prevent IRQs, etc. //Not quite correct in terms of frame pacing - if(_gameboy->GetApuCycleCount() - _lastFrameTime > 70224) { + if (_gameboy->GetApuCycleCount() - _lastFrameTime > 70224) + { //More than a full frame's worth of time has passed since the last frame, send another blank frame _lastFrameTime = _gameboy->GetApuCycleCount(); SendFrame(); @@ -88,9 +91,11 @@ void GbPpu::Exec() } uint8_t cyclesToRun = _memoryManager->IsHighSpeed() ? 1 : 2; - for(int i = 0; i < cyclesToRun; i++) { + for (int i = 0; i < cyclesToRun; i++) + { _state.Cycle++; - if(_state.IdleCycles > 0) { + if (_state.IdleCycles > 0) + { _state.IdleCycles--; ProcessPpuCycle(); continue; @@ -104,32 +109,44 @@ void GbPpu::ExecCycle() { PpuMode oldMode = _state.IrqMode; - if(_state.Scanline < 144) { - if(_state.Scanline == 0 && _isFirstFrame) { + if (_state.Scanline < 144) + { + if (_state.Scanline == 0 && _isFirstFrame) + { ProcessFirstScanlineAfterPowerOn(); - } else { + } + else + { ProcessVisibleScanline(); } - } else { + } + else + { ProcessVblankScanline(); } - if(_state.Mode == PpuMode::Drawing) { + if (_state.Mode == PpuMode::Drawing) + { RunDrawCycle(); - if(_drawnPixels == 160) { + if (_drawnPixels == 160) + { //Mode turns to hblank on the same cycle as the last pixel is output (IRQ is on next cycle) _state.Mode = PpuMode::HBlank; - if(_state.Scanline < 143) { + if (_state.Scanline < 143) + { //"This mode will transfer one block (16 bytes) during each H-Blank. No data is transferred during VBlank (LY = 143 – 153)" _dmaController->ProcessHdma(); } } - } else if(_state.Mode == PpuMode::OamEvaluation) { + } + else if (_state.Mode == PpuMode::OamEvaluation) + { RunSpriteEvaluation(); } bool coincidenceFlag = (_state.LyCompare == _state.LyForCompare); - if(_state.IrqMode != oldMode || _state.LyCoincidenceFlag != coincidenceFlag) { + if (_state.IrqMode != oldMode || _state.LyCoincidenceFlag != coincidenceFlag) + { _state.LyCoincidenceFlag = coincidenceFlag; UpdateStatIrq(); } @@ -139,176 +156,203 @@ void GbPpu::ExecCycle() void GbPpu::ProcessVblankScanline() { - switch(_state.Cycle) { - case 2: - if(_state.Scanline == 144) { - _state.IrqMode = PpuMode::OamEvaluation; + switch (_state.Cycle) + { + case 2: + if (_state.Scanline == 144) + { + _state.IrqMode = PpuMode::OamEvaluation; + } + break; + + case 4: + if (_state.Scanline < 153) + { + _state.LyForCompare = _state.Scanline; + if (_state.Scanline == 144) + { + _state.Mode = PpuMode::VBlank; + _state.IrqMode = PpuMode::VBlank; + _windowCounter = -1; + _memoryManager->RequestIrq(GbIrqSource::VerticalBlank); + SendFrame(); } - break; + } + break; - case 4: - if(_state.Scanline < 153) { - _state.LyForCompare = _state.Scanline; - if(_state.Scanline == 144) { - _state.Mode = PpuMode::VBlank; - _state.IrqMode = PpuMode::VBlank; - _windowCounter = -1; - _memoryManager->RequestIrq(GbIrqSource::VerticalBlank); - SendFrame(); - } + case 6: + if (_state.Scanline == 153) + { + _state.Ly = 0; + _state.LyForCompare = _state.Scanline; + } + break; + + case 8: + if (_state.Scanline == 153) + { + _state.LyForCompare = -1; + } + break; + + case 12: + if (_state.Scanline == 153) + { + _state.LyForCompare = 0; + } + _state.IdleCycles = 456 - 12 - 1; + break; + + case 456: + _state.Cycle = 0; + _state.Scanline++; + + if (_state.Scanline == 154) + { + _state.Scanline = 0; + _state.Ly = 0; + _state.LyForCompare = 0; + + if (_console->IsDebugging()) + { + _console->ProcessEvent(EventType::GbStartFrame); + _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] + ? _eventViewerBuffers[1] + : _eventViewerBuffers[0]; } - break; - - case 6: - if(_state.Scanline == 153) { - _state.Ly = 0; - _state.LyForCompare = _state.Scanline; - } - break; - - case 8: - if(_state.Scanline == 153) { - _state.LyForCompare = -1; - } - break; - - case 12: - if(_state.Scanline == 153) { - _state.LyForCompare = 0; - } - _state.IdleCycles = 456 - 12 - 1; - break; - - case 456: - _state.Cycle = 0; - _state.Scanline++; - - if(_state.Scanline == 154) { - _state.Scanline = 0; - _state.Ly = 0; - _state.LyForCompare = 0; - - if(_console->IsDebugging()) { - _console->ProcessEvent(EventType::GbStartFrame); - _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; - } - } else { - _state.Ly = _state.Scanline; - _state.LyForCompare = -1; - } - break; + } + else + { + _state.Ly = _state.Scanline; + _state.LyForCompare = -1; + } + break; } } void GbPpu::ProcessFirstScanlineAfterPowerOn() { - if(_drawnPixels == 160) { + if (_drawnPixels == 160) + { //IRQ flag for Hblank is 1 cycle late compared to the mode register _state.IrqMode = PpuMode::HBlank; _drawnPixels = 0; _state.IdleCycles = 448 - _state.Cycle - 1; } - switch(_state.Cycle) { - case 1: - _state.IrqMode = PpuMode::NoIrq; - break; + switch (_state.Cycle) + { + case 1: + _state.IrqMode = PpuMode::NoIrq; + break; - case 79: - _latchWindowX = _state.WindowX; - _latchWindowY = _state.WindowY; - _latchWindowEnabled = _state.WindowEnabled; - _state.Mode = PpuMode::Drawing; - _state.IrqMode = PpuMode::Drawing; - ResetRenderer(); - _rendererIdle = true; - break; + case 79: + _latchWindowX = _state.WindowX; + _latchWindowY = _state.WindowY; + _latchWindowEnabled = _state.WindowEnabled; + _state.Mode = PpuMode::Drawing; + _state.IrqMode = PpuMode::Drawing; + ResetRenderer(); + _rendererIdle = true; + break; - case 84: - _rendererIdle = false; - break; + case 84: + _rendererIdle = false; + break; - case 448: - _state.Cycle = 0; - _state.Scanline++; - _drawnPixels = 0; - _state.Mode = PpuMode::HBlank; - _state.IrqMode = PpuMode::HBlank; - break; + case 448: + _state.Cycle = 0; + _state.Scanline++; + _drawnPixels = 0; + _state.Mode = PpuMode::HBlank; + _state.IrqMode = PpuMode::HBlank; + break; } } void GbPpu::ProcessVisibleScanline() { - if(_drawnPixels == 160) { + if (_drawnPixels == 160) + { //IRQ flag for Hblank is 1 cycle late compared to the mode register _state.IrqMode = PpuMode::HBlank; _drawnPixels = 0; _state.IdleCycles = 456 - _state.Cycle - 1; } - switch(_state.Cycle) { - case 3: - _state.Ly = _state.Scanline; + switch (_state.Cycle) + { + case 3: + _state.Ly = _state.Scanline; - if(_state.Scanline > 0) { - //On scanlines 1-143, the OAM IRQ fires 1 cycle early - _state.IrqMode = PpuMode::OamEvaluation; - _state.LyForCompare = -1; - } else { - //On scanline 0, hblank gets set for 1 cycle here - _state.Mode = PpuMode::HBlank; - } - break; - - case 4: - _spriteCount = 0; - _state.LyForCompare = _state.Scanline; - _state.Mode = PpuMode::OamEvaluation; + if (_state.Scanline > 0) + { + //On scanlines 1-143, the OAM IRQ fires 1 cycle early _state.IrqMode = PpuMode::OamEvaluation; - break; + _state.LyForCompare = -1; + } + else + { + //On scanline 0, hblank gets set for 1 cycle here + _state.Mode = PpuMode::HBlank; + } + break; - case 5: - //Turning on OAM IRQs in the middle of evaluation has no effect? - //Or is this a patch to get the proper behavior for the STAT write bug? - _state.IrqMode = PpuMode::NoIrq; - break; + case 4: + _spriteCount = 0; + _state.LyForCompare = _state.Scanline; + _state.Mode = PpuMode::OamEvaluation; + _state.IrqMode = PpuMode::OamEvaluation; + break; - case 84: - _latchWindowX = _state.WindowX; - _latchWindowY = _state.WindowY; - _latchWindowEnabled = _state.WindowEnabled; - _state.Mode = PpuMode::Drawing; - _state.IrqMode = PpuMode::Drawing; - _rendererIdle = true; - ResetRenderer(); - break; + case 5: + //Turning on OAM IRQs in the middle of evaluation has no effect? + //Or is this a patch to get the proper behavior for the STAT write bug? + _state.IrqMode = PpuMode::NoIrq; + break; - case 89: - _rendererIdle = false; - break; + case 84: + _latchWindowX = _state.WindowX; + _latchWindowY = _state.WindowY; + _latchWindowEnabled = _state.WindowEnabled; + _state.Mode = PpuMode::Drawing; + _state.IrqMode = PpuMode::Drawing; + _rendererIdle = true; + ResetRenderer(); + break; - case 456: - _state.Cycle = 0; - _state.Scanline++; - if(_state.Scanline == 144) { - _state.Ly = 144; - _state.LyForCompare = -1; - } - break; + case 89: + _rendererIdle = false; + break; + + case 456: + _state.Cycle = 0; + _state.Scanline++; + if (_state.Scanline == 144) + { + _state.Ly = 144; + _state.LyForCompare = -1; + } + break; } } void GbPpu::ProcessPpuCycle() { - if(_console->IsDebugging()) { + if (_console->IsDebugging()) + { _console->ProcessPpuCycle(); - if(_state.Mode <= PpuMode::OamEvaluation) { + if (_state.Mode <= PpuMode::OamEvaluation) + { _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = evtColors[(int)_state.Mode]; - } else if(_prevDrawnPixels != _drawnPixels && _drawnPixels > 0) { + } + else if (_prevDrawnPixels != _drawnPixels && _drawnPixels > 0) + { uint16_t color = _currentBuffer[_state.Scanline * 256 + (_drawnPixels - 1)]; _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = color; - } else { + } + else + { _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = evtColors[(int)_evtColor]; } _prevDrawnPixels = _drawnPixels; @@ -317,14 +361,16 @@ void GbPpu::ProcessPpuCycle() void GbPpu::RunDrawCycle() { - if(_rendererIdle) { + if (_rendererIdle) + { //Idle cycles _evtColor = EvtColor::RenderingIdle; return; } bool fetchWindow = _latchWindowEnabled && _drawnPixels >= _latchWindowX - 7 && _state.Scanline >= _latchWindowY; - if(_fetchWindow != fetchWindow) { + if (_fetchWindow != fetchWindow) + { //Switched between window & background, reset fetcher & pixel FIFO _fetchWindow = fetchWindow; _fetchColumn = 0; @@ -339,39 +385,55 @@ void GbPpu::RunDrawCycle() } FindNextSprite(); - if(_fetchSprite >= 0 && _bgFetcher.Step >= 5 && _bgFifo.Size > 0) { + if (_fetchSprite >= 0 && _bgFetcher.Step >= 5 && _bgFifo.Size > 0) + { _evtColor = EvtColor::RenderingOamLoad; ClockSpriteFetcher(); FindNextSprite(); return; } - if(_fetchSprite == -1 && _bgFifo.Size > 0) { - if(_drawnPixels >= 0) { + if (_fetchSprite == -1 && _bgFifo.Size > 0) + { + if (_drawnPixels >= 0) + { uint16_t outOffset = _state.Scanline * 256 + _drawnPixels; GbFifoEntry entry = _bgFifo.Content[_bgFifo.Position]; GbFifoEntry sprite = _oamFifo.Content[_oamFifo.Position]; - if(sprite.Color != 0 && (entry.Color == 0 || (!(sprite.Attributes & 0x80) && !(entry.Attributes & 0x80)) || (_state.CgbEnabled && !_state.BgEnabled))) { + if (sprite.Color != 0 && (entry.Color == 0 || (!(sprite.Attributes & 0x80) && !(entry.Attributes & 0x80)) || ( + _state.CgbEnabled && !_state.BgEnabled))) + { //Use sprite pixel if: // -BG color is 0, OR // -Sprite is background priority AND BG does not have its priority bit set, OR // -On CGB, the "bg enabled" flag is cleared, causing all sprites to appear above BG tiles - if(_state.CgbEnabled) { + if (_state.CgbEnabled) + { _currentBuffer[outOffset] = _state.CgbObjPalettes[sprite.Color | ((sprite.Attributes & 0x07) << 2)]; - } else { - uint8_t colorIndex = (((sprite.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (sprite.Color * 2)) & 0x03; - if(_gameboy->IsSgb()) { + } + else + { + uint8_t colorIndex = (((sprite.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (sprite. + Color * 2)) & 0x03; + if (_gameboy->IsSgb()) + { _gameboy->GetSgb()->WriteLcdColor(_state.Scanline, (uint8_t)_drawnPixels, colorIndex); - } + } _currentBuffer[outOffset] = _state.CgbObjPalettes[((sprite.Attributes & 0x10) ? 4 : 0) | colorIndex]; } - } else { - if(_state.CgbEnabled) { + } + else + { + if (_state.CgbEnabled) + { _currentBuffer[outOffset] = _state.CgbBgPalettes[entry.Color | ((entry.Attributes & 0x07) << 2)]; - } else { + } + else + { uint8_t colorIndex = (_state.BgPalette >> (entry.Color * 2)) & 0x03; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { _gameboy->GetSgb()->WriteLcdColor(_state.Scanline, (uint8_t)_drawnPixels, colorIndex); } _currentBuffer[outOffset] = _state.CgbBgPalettes[colorIndex]; @@ -382,7 +444,8 @@ void GbPpu::RunDrawCycle() _bgFifo.Pop(); _drawnPixels++; - if(_oamFifo.Size > 0) { + if (_oamFifo.Size > 0) + { _oamFifo.Pop(); } } @@ -392,23 +455,28 @@ void GbPpu::RunDrawCycle() void GbPpu::RunSpriteEvaluation() { - if(_state.Cycle & 0x01) { - if(_spriteCount < 10) { + if (_state.Cycle & 0x01) + { + if (_spriteCount < 10) + { uint8_t spriteIndex = ((_state.Cycle - 4) >> 1) * 4; int16_t sprY = _dmaController->IsOamDmaRunning() ? 0xFF : ((int16_t)_oam[spriteIndex] - 16); - if(_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) { + if (_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) + { _spriteX[_spriteCount] = _oam[spriteIndex + 1]; _spriteIndexes[_spriteCount] = spriteIndex; _spriteCount++; } } - } else { + } + else + { //TODO check proper timing for even&odd cycles } } void GbPpu::ResetRenderer() -{ +{ //Reset fetcher & pixel FIFO _oamFifo.Reset(); _oamFetcher.Step = 0; @@ -425,8 +493,10 @@ void GbPpu::ResetRenderer() void GbPpu::ClockSpriteFetcher() { - switch(_oamFetcher.Step++) { - case 1: { + switch (_oamFetcher.Step++) + { + case 1: + { //Fetch tile index int16_t sprY = (int16_t)_oam[_fetchSprite] - 16; uint8_t sprTile = _oam[_fetchSprite + 2]; @@ -434,8 +504,11 @@ void GbPpu::ClockSpriteFetcher() bool vMirror = (sprAttr & 0x40) != 0; uint16_t tileBank = _state.CgbEnabled ? ((sprAttr & 0x08) ? 0x2000 : 0x0000) : 0; - uint8_t sprOffsetY = vMirror ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) : (_state.Scanline - sprY); - if(_state.LargeSprites) { + uint8_t sprOffsetY = vMirror + ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) + : (_state.Scanline - sprY); + if (_state.LargeSprites) + { sprTile &= 0xFE; } @@ -445,9 +518,11 @@ void GbPpu::ClockSpriteFetcher() break; } - case 3: _oamFetcher.LowByte = _vram[_oamFetcher.Addr]; break; + case 3: _oamFetcher.LowByte = _vram[_oamFetcher.Addr]; + break; - case 5: { + case 5: + { //Fetch sprite data (high byte) _oamFetcher.HighByte = _vram[_oamFetcher.Addr + 1]; PushSpriteToPixelFifo(); @@ -458,9 +533,12 @@ void GbPpu::ClockSpriteFetcher() void GbPpu::FindNextSprite() { - if(_fetchSprite < 0 && (_state.SpritesEnabled || _state.CgbEnabled)) { - for(int i = 0; i < _spriteCount; i++) { - if((int)_spriteX[i] - 8 == _drawnPixels) { + if (_fetchSprite < 0 && (_state.SpritesEnabled || _state.CgbEnabled)) + { + for (int i = 0; i < _spriteCount; i++) + { + if ((int)_spriteX[i] - 8 == _drawnPixels) + { _fetchSprite = _spriteIndexes[i]; _spriteX[i] = 0xFF; //Prevent processing the same sprite again _oamFetcher.Step = 0; @@ -474,15 +552,20 @@ void GbPpu::ClockTileFetcher() { _evtColor = EvtColor::RenderingBgLoad; - switch(_bgFetcher.Step++) { - case 1: { + switch (_bgFetcher.Step++) + { + case 1: + { //Fetch tile index uint16_t tilemapAddr; uint8_t yOffset; - if(_fetchWindow) { + if (_fetchWindow) + { tilemapAddr = _state.WindowTilemapSelect ? 0x1C00 : 0x1800; yOffset = (uint8_t)_windowCounter; - } else { + } + else + { tilemapAddr = _state.BgTilemapSelect ? 0x1C00 : 0x1800; yOffset = _state.ScrollY + _state.Scanline; } @@ -504,28 +587,33 @@ void GbPpu::ClockTileFetcher() break; } - case 3: { + case 3: + { //Fetch tile data (low byte) _bgFetcher.LowByte = _vram[_bgFetcher.Addr]; break; } - case 5: { + case 5: + { //Fetch tile data (high byte) _bgFetcher.HighByte = _vram[_bgFetcher.Addr + 1]; - + //Fallthrough } - case 6: - case 7: - if(_bgFifo.Size == 0) { - PushTileToPixelFifo(); - } else if(_bgFetcher.Step == 8) { - //Wait until fifo is empty to push pixels - _bgFetcher.Step = 7; - } - break; + case 6: + case 7: + if (_bgFifo.Size == 0) + { + PushTileToPixelFifo(); + } + else if (_bgFetcher.Step == 8) + { + //Wait until fifo is empty to push pixels + _bgFetcher.Step = 7; + } + break; } } @@ -534,19 +622,22 @@ void GbPpu::PushSpriteToPixelFifo() _fetchSprite = -1; _oamFetcher.Step = 0; - if(!_state.SpritesEnabled) { + if (!_state.SpritesEnabled) + { return; } uint8_t pos = _oamFifo.Position; //Overlap sprite - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { uint8_t shift = (_oamFetcher.Attributes & 0x20) ? i : (7 - i); uint8_t bits = ((_oamFetcher.LowByte >> shift) & 0x01); bits |= ((_oamFetcher.HighByte >> shift) & 0x01) << 1; - if(bits > 0 && _oamFifo.Content[pos].Color == 0) { + if (bits > 0 && _oamFifo.Content[pos].Color == 0) + { _oamFifo.Content[pos].Color = bits; _oamFifo.Content[pos].Attributes = _oamFetcher.Attributes; } @@ -558,7 +649,8 @@ void GbPpu::PushSpriteToPixelFifo() void GbPpu::PushTileToPixelFifo() { //Add new tile to fifo - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { uint8_t shift = (_bgFetcher.Attributes & 0x20) ? i : (7 - i); uint8_t bits = ((_bgFetcher.LowByte >> shift) & 0x01); bits |= ((_bgFetcher.HighByte >> shift) & 0x01) << 1; @@ -578,12 +670,13 @@ void GbPpu::UpdateStatIrq() bool irqFlag = ( _state.LcdEnabled && ((_state.LyCoincidenceFlag && (_state.Status & GbPpuStatusFlags::CoincidenceIrq)) || - (_state.IrqMode == PpuMode::HBlank && (_state.Status & GbPpuStatusFlags::HBlankIrq)) || - (_state.IrqMode == PpuMode::OamEvaluation && (_state.Status & GbPpuStatusFlags::OamIrq)) || - (_state.IrqMode == PpuMode::VBlank && (_state.Status & GbPpuStatusFlags::VBlankIrq))) + (_state.IrqMode == PpuMode::HBlank && (_state.Status & GbPpuStatusFlags::HBlankIrq)) || + (_state.IrqMode == PpuMode::OamEvaluation && (_state.Status & GbPpuStatusFlags::OamIrq)) || + (_state.IrqMode == PpuMode::VBlank && (_state.Status & GbPpuStatusFlags::VBlankIrq))) ); - if(irqFlag && !_state.StatIrqFlag) { + if (irqFlag && !_state.StatIrqFlag) + { _memoryManager->RequestIrq(GbIrqSource::LcdStat); } _state.StatIrqFlag = irqFlag; @@ -624,7 +717,8 @@ void GbPpu::SendFrame() _console->ProcessEvent(EventType::GbEndFrame); _state.FrameCount++; - if(_gameboy->IsSgb()) { + if (_gameboy->IsSgb()) + { return; } @@ -632,11 +726,15 @@ void GbPpu::SendFrame() _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone); - if(_isFirstFrame) { - if(!_state.CgbEnabled) { + if (_isFirstFrame) + { + if (!_state.CgbEnabled) + { //Send blank frame on the first frame after enabling LCD (DMG only) std::fill(_currentBuffer, _currentBuffer + 256 * 239, 0x7FFF); - } else { + } + else + { //CGB repeats the previous frame? uint16_t* src = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0]; std::copy(src, src + 256 * 239, _currentBuffer); @@ -647,9 +745,12 @@ void GbPpu::SendFrame() #ifdef LIBRETRO _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, 256, 239, _state.FrameCount, false); #else - if(_console->GetRewindManager()->IsRewinding()) { + if (_console->GetRewindManager()->IsRewinding()) + { _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, 256, 239, _state.FrameCount, true); - } else { + } + else + { _console->GetVideoDecoder()->UpdateFrame(_currentBuffer, 256, 239, _state.FrameCount); } #endif @@ -658,7 +759,8 @@ void GbPpu::SendFrame() uint8_t prevInput = _memoryManager->ReadInputPort(); _console->ProcessEndOfFrame(); uint8_t newInput = _memoryManager->ReadInputPort(); - if(prevInput != newInput) { + if (prevInput != newInput) + { _memoryManager->RequestIrq(GbIrqSource::Joypad); } @@ -667,17 +769,22 @@ void GbPpu::SendFrame() void GbPpu::UpdatePalette() { - if(!_gameboy->IsCgb()) { + if (!_gameboy->IsCgb()) + { GameboyConfig cfg = _console->GetSettings()->GetGameboyConfig(); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { //Set palette based on settings (DMG) - uint16_t bgColor = ((cfg.BgColors[i] & 0xF8) << 7) | ((cfg.BgColors[i] & 0xF800) >> 6) | ((cfg.BgColors[i] & 0xF80000) >> 19); + uint16_t bgColor = ((cfg.BgColors[i] & 0xF8) << 7) | ((cfg.BgColors[i] & 0xF800) >> 6) | ((cfg.BgColors[i] & + 0xF80000) >> 19); _state.CgbBgPalettes[i] = bgColor; - uint16_t obj0Color = ((cfg.Obj0Colors[i] & 0xF8) << 7) | ((cfg.Obj0Colors[i] & 0xF800) >> 6) | ((cfg.Obj0Colors[i] & 0xF80000) >> 19); + uint16_t obj0Color = ((cfg.Obj0Colors[i] & 0xF8) << 7) | ((cfg.Obj0Colors[i] & 0xF800) >> 6) | ((cfg.Obj0Colors + [i] & 0xF80000) >> 19); _state.CgbObjPalettes[i] = obj0Color; - - uint16_t obj1Color = ((cfg.Obj1Colors[i] & 0xF8) << 7) | ((cfg.Obj1Colors[i] & 0xF800) >> 6) | ((cfg.Obj1Colors[i] & 0xF80000) >> 19); + + uint16_t obj1Color = ((cfg.Obj1Colors[i] & 0xF8) << 7) | ((cfg.Obj1Colors[i] & 0xF800) >> 6) | ((cfg.Obj1Colors + [i] & 0xF80000) >> 19); _state.CgbObjPalettes[i + 4] = obj1Color; } } @@ -685,116 +792,136 @@ void GbPpu::UpdatePalette() uint8_t GbPpu::Read(uint16_t addr) { - switch(addr) { - case 0xFF40: return _state.Control; - case 0xFF41: - //FF41 - STAT - LCDC Status (R/W) - return ( - 0x80 | - (_state.Status & 0x78) | - (_state.LyCoincidenceFlag ? 0x04 : 0x00) | - (int)_state.Mode - ); + switch (addr) + { + case 0xFF40: return _state.Control; + case 0xFF41: + //FF41 - STAT - LCDC Status (R/W) + return ( + 0x80 | + (_state.Status & 0x78) | + (_state.LyCoincidenceFlag ? 0x04 : 0x00) | + (int)_state.Mode + ); - case 0xFF42: return _state.ScrollY; //FF42 - SCY - Scroll Y (R/W) - case 0xFF43: return _state.ScrollX; //FF43 - SCX - Scroll X (R/W) - case 0xFF44: return _state.Ly; //FF44 - LY - LCDC Y-Coordinate (R) - case 0xFF45: return _state.LyCompare; //FF45 - LYC - LY Compare (R/W) - case 0xFF47: return _state.BgPalette; //FF47 - BGP - BG Palette Data (R/W) - Non CGB Mode Only - case 0xFF48: return _state.ObjPalette0; //FF48 - OBP0 - Object Palette 0 Data (R/W) - Non CGB Mode Only - case 0xFF49: return _state.ObjPalette1; //FF49 - OBP1 - Object Palette 1 Data (R/W) - Non CGB Mode Only - case 0xFF4A: return _state.WindowY; //FF4A - WY - Window Y Position (R/W) - case 0xFF4B: return _state.WindowX; //FF4B - WX - Window X Position minus 7 (R/W) + case 0xFF42: return _state.ScrollY; //FF42 - SCY - Scroll Y (R/W) + case 0xFF43: return _state.ScrollX; //FF43 - SCX - Scroll X (R/W) + case 0xFF44: return _state.Ly; //FF44 - LY - LCDC Y-Coordinate (R) + case 0xFF45: return _state.LyCompare; //FF45 - LYC - LY Compare (R/W) + case 0xFF47: return _state.BgPalette; //FF47 - BGP - BG Palette Data (R/W) - Non CGB Mode Only + case 0xFF48: return _state.ObjPalette0; //FF48 - OBP0 - Object Palette 0 Data (R/W) - Non CGB Mode Only + case 0xFF49: return _state.ObjPalette1; //FF49 - OBP1 - Object Palette 1 Data (R/W) - Non CGB Mode Only + case 0xFF4A: return _state.WindowY; //FF4A - WY - Window Y Position (R/W) + case 0xFF4B: return _state.WindowX; //FF4B - WX - Window X Position minus 7 (R/W) } - + LogDebug("[Debug] GB - Missing read handler: $" + HexUtilities::ToHex(addr)); return 0xFF; } void GbPpu::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0xFF40: - _state.Control = value; - if(_state.LcdEnabled != ((value & 0x80) != 0)) { - _state.LcdEnabled = (value & 0x80) != 0; - - if(!_state.LcdEnabled) { - //Reset LCD to top of screen when it gets turned off - if(_state.Mode != PpuMode::VBlank) { - _console->BreakImmediately(BreakSource::GbDisableLcdOutsideVblank); - SendFrame(); - } + switch (addr) + { + case 0xFF40: + _state.Control = value; + if (_state.LcdEnabled != ((value & 0x80) != 0)) + { + _state.LcdEnabled = (value & 0x80) != 0; - _state.Cycle = 0; - _state.Scanline = 0; - _state.Ly = 0; - _state.LyForCompare = 0; - _state.Mode = PpuMode::HBlank; + if (!_state.LcdEnabled) + { + //Reset LCD to top of screen when it gets turned off + if (_state.Mode != PpuMode::VBlank) + { + _console->BreakImmediately(BreakSource::GbDisableLcdOutsideVblank); + SendFrame(); + } - _lastFrameTime = _gameboy->GetApuCycleCount(); - - //"If the HDMA started when the screen was on, when the screen is switched off it will copy one block after the switch." - _dmaController->ProcessHdma(); - } else { - _isFirstFrame = true; - _state.Cycle = -1; - _state.IdleCycles = 0; - ResetRenderer(); - _state.LyCoincidenceFlag = _state.LyCompare == _state.LyForCompare; - UpdateStatIrq(); - - if(_console->IsDebugging()) { - _console->ProcessEvent(EventType::GbStartFrame); + _state.Cycle = 0; + _state.Scanline = 0; + _state.Ly = 0; + _state.LyForCompare = 0; + _state.Mode = PpuMode::HBlank; - _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; - for(int i = 0; i < 456 * 154; i++) { - _currentEventViewerBuffer[i] = 0x18C6; - } + _lastFrameTime = _gameboy->GetApuCycleCount(); + + //"If the HDMA started when the screen was on, when the screen is switched off it will copy one block after the switch." + _dmaController->ProcessHdma(); + } + else + { + _isFirstFrame = true; + _state.Cycle = -1; + _state.IdleCycles = 0; + ResetRenderer(); + _state.LyCoincidenceFlag = _state.LyCompare == _state.LyForCompare; + UpdateStatIrq(); + + if (_console->IsDebugging()) + { + _console->ProcessEvent(EventType::GbStartFrame); + + _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] + ? _eventViewerBuffers[1] + : _eventViewerBuffers[0]; + for (int i = 0; i < 456 * 154; i++) + { + _currentEventViewerBuffer[i] = 0x18C6; } } } - _state.WindowTilemapSelect = (value & 0x40) != 0; - _state.WindowEnabled = (value & 0x20) != 0; - _state.BgTileSelect = (value & 0x10) != 0; - _state.BgTilemapSelect = (value & 0x08) != 0; - _state.LargeSprites = (value & 0x04) != 0; - _state.SpritesEnabled = (value & 0x02) != 0; - _state.BgEnabled = (value & 0x01) != 0; - break; + } + _state.WindowTilemapSelect = (value & 0x40) != 0; + _state.WindowEnabled = (value & 0x20) != 0; + _state.BgTileSelect = (value & 0x10) != 0; + _state.BgTilemapSelect = (value & 0x08) != 0; + _state.LargeSprites = (value & 0x04) != 0; + _state.SpritesEnabled = (value & 0x02) != 0; + _state.BgEnabled = (value & 0x01) != 0; + break; - case 0xFF41: - if(!_gameboy->IsCgb()) { - //STAT write bug (DMG ONLY) - //Writing to STAT causes all IRQ types to be turned on for a single cycle - _state.Status = 0xF8 | (_state.Status & 0x07); - UpdateStatIrq(); - } - - _state.Status = value & 0xF8; + case 0xFF41: + if (!_gameboy->IsCgb()) + { + //STAT write bug (DMG ONLY) + //Writing to STAT causes all IRQ types to be turned on for a single cycle + _state.Status = 0xF8 | (_state.Status & 0x07); UpdateStatIrq(); - break; + } - case 0xFF42: _state.ScrollY = value; break; - case 0xFF43: _state.ScrollX = value; break; - case 0xFF45: - _state.LyCompare = value; - if(_state.LcdEnabled) { - _state.IdleCycles = 0; - _state.LyCoincidenceFlag = (_state.LyCompare == _state.LyForCompare); - UpdateStatIrq(); - } - break; + _state.Status = value & 0xF8; + UpdateStatIrq(); + break; - case 0xFF47: _state.BgPalette = value; break; - case 0xFF48: _state.ObjPalette0 = value; break; - case 0xFF49: _state.ObjPalette1 = value; break; - case 0xFF4A: _state.WindowY = value; break; - case 0xFF4B: _state.WindowX = value; break; + case 0xFF42: _state.ScrollY = value; + break; + case 0xFF43: _state.ScrollX = value; + break; + case 0xFF45: + _state.LyCompare = value; + if (_state.LcdEnabled) + { + _state.IdleCycles = 0; + _state.LyCoincidenceFlag = (_state.LyCompare == _state.LyForCompare); + UpdateStatIrq(); + } + break; - default: - LogDebug("[Debug] GB - Missing write handler: $" + HexUtilities::ToHex(addr)); - break; + case 0xFF47: _state.BgPalette = value; + break; + case 0xFF48: _state.ObjPalette0 = value; + break; + case 0xFF49: _state.ObjPalette1 = value; + break; + case 0xFF4A: _state.WindowY = value; + break; + case 0xFF4B: _state.WindowX = value; + break; + + default: + LogDebug("[Debug] GB - Missing write handler: $" + HexUtilities::ToHex(addr)); + break; } } @@ -810,11 +937,14 @@ bool GbPpu::IsVramWriteAllowed() uint8_t GbPpu::ReadVram(uint16_t addr) { - if(IsVramReadAllowed()) { + if (IsVramReadAllowed()) + { uint16_t vramAddr = (_state.CgbVramBank << 13) | (addr & 0x1FFF); _console->ProcessPpuRead(vramAddr, _vram[vramAddr], SnesMemoryType::GbVideoRam); return _vram[vramAddr]; - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidVramAccess); return 0xFF; } @@ -827,44 +957,56 @@ uint8_t GbPpu::PeekVram(uint16_t addr) void GbPpu::WriteVram(uint16_t addr, uint8_t value) { - if(IsVramWriteAllowed()) { + if (IsVramWriteAllowed()) + { uint16_t vramAddr = (_state.CgbVramBank << 13) | (addr & 0x1FFF); _console->ProcessPpuWrite(vramAddr, value, SnesMemoryType::GbVideoRam); _vram[vramAddr] = value; - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidVramAccess); } } bool GbPpu::IsOamWriteAllowed() { - if(_memoryManager->IsOamDmaRunning()) { + if (_memoryManager->IsOamDmaRunning()) + { return false; } - if(_state.Scanline == 0 && _isFirstFrame) { + if (_state.Scanline == 0 && _isFirstFrame) + { return _state.Mode == PpuMode::HBlank && _state.Cycle != 77 && _state.Cycle != 78; - } else { + } + else + { return _state.Mode <= PpuMode::VBlank || (_state.Cycle >= 80 && _state.Cycle < 84); } } bool GbPpu::IsOamReadAllowed() { - if(_memoryManager->IsOamDmaRunning()) { + if (_memoryManager->IsOamDmaRunning()) + { return false; } - if(_state.Scanline == 0 && _isFirstFrame) { + if (_state.Scanline == 0 && _isFirstFrame) + { return _state.Mode == PpuMode::HBlank; - } else { + } + else + { return _state.Mode == PpuMode::VBlank || (_state.Mode == PpuMode::HBlank && _state.Cycle != 3); } } uint8_t GbPpu::PeekOam(uint8_t addr) { - if(addr < 0xA0) { + if (addr < 0xA0) + { return IsOamReadAllowed() ? _oam[addr] : 0xFF; } return 0; @@ -872,11 +1014,15 @@ uint8_t GbPpu::PeekOam(uint8_t addr) uint8_t GbPpu::ReadOam(uint8_t addr) { - if(addr < 0xA0) { - if(IsOamReadAllowed()) { + if (addr < 0xA0) + { + if (IsOamReadAllowed()) + { _console->ProcessPpuRead(addr, _oam[addr], SnesMemoryType::GbSpriteRam); return _oam[addr]; - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidOamAccess); return 0xFF; } @@ -889,14 +1035,20 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma) //During DMA or rendering/oam evaluation, ignore writes to OAM //The DMA controller is always allowed to write to OAM (presumably the PPU can't read OAM during that time? TODO implement) //On the DMG, there is a 4 clock gap (80 to 83) between OAM evaluation & rendering where writing is allowed - if(addr < 0xA0) { - if(forDma) { + if (addr < 0xA0) + { + if (forDma) + { _oam[addr] = value; _console->ProcessPpuWrite(addr, value, SnesMemoryType::GbSpriteRam); - } else if(IsOamWriteAllowed()) { + } + else if (IsOamWriteAllowed()) + { _oam[addr] = value; _console->ProcessPpuWrite(addr, value, SnesMemoryType::GbSpriteRam); - } else { + } + else + { _console->BreakImmediately(BreakSource::GbInvalidOamAccess); } } @@ -904,16 +1056,21 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma) uint8_t GbPpu::ReadCgbRegister(uint16_t addr) { - if(!_state.CgbEnabled) { + if (!_state.CgbEnabled) + { return 0xFF; } - switch(addr) { - case 0xFF4F: return _state.CgbVramBank | 0xFE; - case 0xFF68: return _state.CgbBgPalPosition | (_state.CgbBgPalAutoInc ? 0x80 : 0) | 0x40; - case 0xFF69: return (_state.CgbBgPalettes[_state.CgbBgPalPosition >> 1] >> ((_state.CgbBgPalPosition & 0x01) ? 8 : 0) & 0xFF); - case 0xFF6A: return _state.CgbObjPalPosition | (_state.CgbObjPalAutoInc ? 0x80 : 0) | 0x40; - case 0xFF6B: return (_state.CgbObjPalettes[_state.CgbObjPalPosition >> 1] >> ((_state.CgbObjPalPosition & 0x01) ? 8 : 0) & 0xFF); + switch (addr) + { + case 0xFF4F: return _state.CgbVramBank | 0xFE; + case 0xFF68: return _state.CgbBgPalPosition | (_state.CgbBgPalAutoInc ? 0x80 : 0) | 0x40; + case 0xFF69: return (_state.CgbBgPalettes[_state.CgbBgPalPosition >> 1] >> ((_state.CgbBgPalPosition & 0x01) ? 8 : 0) + & 0xFF); + case 0xFF6A: return _state.CgbObjPalPosition | (_state.CgbObjPalAutoInc ? 0x80 : 0) | 0x40; + case 0xFF6B: return (_state.CgbObjPalettes[_state.CgbObjPalPosition >> 1] >> ((_state.CgbObjPalPosition & 0x01) + ? 8 + : 0) & 0xFF); } LogDebug("[Debug] GBC - Missing read handler: $" + HexUtilities::ToHex(addr)); return 0xFF; @@ -921,54 +1078,64 @@ uint8_t GbPpu::ReadCgbRegister(uint16_t addr) void GbPpu::WriteCgbRegister(uint16_t addr, uint8_t value) { - if(!_state.CgbEnabled && _memoryManager->IsBootRomDisabled()) { + if (!_state.CgbEnabled && _memoryManager->IsBootRomDisabled()) + { return; } - switch(addr) { - case 0xFF4C: _state.CgbEnabled = (value & 0x0C) == 0; break; - case 0xFF4F: _state.CgbVramBank = value & 0x01; break; - - case 0xFF68: - //FF68 - BCPS/BGPI - CGB Mode Only - Background Palette Index - _state.CgbBgPalPosition = value & 0x3F; - _state.CgbBgPalAutoInc = (value & 0x80) != 0; - break; + switch (addr) + { + case 0xFF4C: _state.CgbEnabled = (value & 0x0C) == 0; + break; + case 0xFF4F: _state.CgbVramBank = value & 0x01; + break; - case 0xFF69: { + case 0xFF68: + //FF68 - BCPS/BGPI - CGB Mode Only - Background Palette Index + _state.CgbBgPalPosition = value & 0x3F; + _state.CgbBgPalAutoInc = (value & 0x80) != 0; + break; + + case 0xFF69: + { //FF69 - BCPD/BGPD - CGB Mode Only - Background Palette Data WriteCgbPalette(_state.CgbBgPalPosition, _state.CgbBgPalettes, _state.CgbBgPalAutoInc, value); break; } - case 0xFF6A: - //FF6A - OCPS/OBPI - CGB Mode Only - Sprite Palette Index - _state.CgbObjPalPosition = value & 0x3F; - _state.CgbObjPalAutoInc = (value & 0x80) != 0; - break; + case 0xFF6A: + //FF6A - OCPS/OBPI - CGB Mode Only - Sprite Palette Index + _state.CgbObjPalPosition = value & 0x3F; + _state.CgbObjPalAutoInc = (value & 0x80) != 0; + break; - case 0xFF6B: - //FF6B - OCPD/OBPD - CGB Mode Only - Sprite Palette Data - WriteCgbPalette(_state.CgbObjPalPosition, _state.CgbObjPalettes, _state.CgbObjPalAutoInc, value); - break; + case 0xFF6B: + //FF6B - OCPD/OBPD - CGB Mode Only - Sprite Palette Data + WriteCgbPalette(_state.CgbObjPalPosition, _state.CgbObjPalettes, _state.CgbObjPalAutoInc, value); + break; - default: - LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); - break; + default: + LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr)); + break; } } void GbPpu::WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t value) { - if(_state.Mode <= PpuMode::OamEvaluation) { - if(pos & 0x01) { + if (_state.Mode <= PpuMode::OamEvaluation) + { + if (pos & 0x01) + { pal[pos >> 1] = (pal[pos >> 1] & 0xFF) | ((value & 0x7F) << 8); - } else { + } + else + { pal[pos >> 1] = (pal[pos >> 1] & 0xFF00) | value; } } - if(autoInc) { + if (autoInc) + { pos = (pos + 1) & 0x3F; } } @@ -976,9 +1143,12 @@ void GbPpu::WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t v void GbPpu::Serialize(Serializer& s) { s.Stream( - _state.Scanline, _state.Cycle, _state.Mode, _state.LyCompare, _state.BgPalette, _state.ObjPalette0, _state.ObjPalette1, - _state.ScrollX, _state.ScrollY, _state.WindowX, _state.WindowY, _state.Control, _state.LcdEnabled, _state.WindowTilemapSelect, - _state.WindowEnabled, _state.BgTileSelect, _state.BgTilemapSelect, _state.LargeSprites, _state.SpritesEnabled, _state.BgEnabled, + _state.Scanline, _state.Cycle, _state.Mode, _state.LyCompare, _state.BgPalette, _state.ObjPalette0, + _state.ObjPalette1, + _state.ScrollX, _state.ScrollY, _state.WindowX, _state.WindowY, _state.Control, _state.LcdEnabled, + _state.WindowTilemapSelect, + _state.WindowEnabled, _state.BgTileSelect, _state.BgTilemapSelect, _state.LargeSprites, _state.SpritesEnabled, + _state.BgEnabled, _state.Status, _state.FrameCount, _lastFrameTime, _state.LyCoincidenceFlag, _state.CgbBgPalAutoInc, _state.CgbBgPalPosition, _state.CgbObjPalAutoInc, _state.CgbObjPalPosition, _state.CgbVramBank, _state.CgbEnabled, @@ -996,7 +1166,8 @@ void GbPpu::Serialize(Serializer& s) _bgFifo.Position, _bgFifo.Size, _oamFifo.Position, _oamFifo.Size ); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { s.Stream(_bgFifo.Content[i].Color, _bgFifo.Content[i].Attributes); s.Stream(_oamFifo.Content[i].Color, _oamFifo.Content[i].Attributes); } diff --git a/Core/GbPpu.h b/Core/GbPpu.h index ff0415c..c541054 100644 --- a/Core/GbPpu.h +++ b/Core/GbPpu.h @@ -76,7 +76,8 @@ private: public: virtual ~GbPpu(); - void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, uint8_t* vram, uint8_t* oam); + void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, + uint8_t* vram, uint8_t* oam); GbPpuState GetState(); uint16_t* GetOutputBuffer(); @@ -109,6 +110,6 @@ public: uint8_t ReadCgbRegister(uint16_t addr); void WriteCgbRegister(uint16_t addr, uint8_t value); - + void Serialize(Serializer& s) override; }; diff --git a/Core/GbSquareChannel.cpp b/Core/GbSquareChannel.cpp index 8cbfa52..341b5a4 100644 --- a/Core/GbSquareChannel.cpp +++ b/Core/GbSquareChannel.cpp @@ -26,30 +26,37 @@ void GbSquareChannel::Disable() void GbSquareChannel::ClockSweepUnit() { - if(!_state.SweepEnabled) { + if (!_state.SweepEnabled) + { return; } - if(_state.SweepTimer > 0 && _state.SweepPeriod > 0) { + if (_state.SweepTimer > 0 && _state.SweepPeriod > 0) + { _state.SweepTimer--; - if(_state.SweepTimer == 0) { + if (_state.SweepTimer == 0) + { _state.SweepTimer = _state.SweepPeriod; //"When it generates a clock and the sweep's internal enabled flag is set and the sweep period is not zero, a new frequency is calculated and the overflow" uint16_t newFreq = GetSweepTargetFrequency(); - if(_state.SweepShift > 0 && newFreq < 2048) { + if (_state.SweepShift > 0 && newFreq < 2048) + { //"If the new frequency is 2047 or less and the sweep shift is not zero, this new frequency is written back to the shadow frequency and square 1's frequency in NR13 and NR14," _state.Frequency = _state.SweepFreq; _state.SweepFreq = newFreq; newFreq = GetSweepTargetFrequency(); - if(newFreq >= 2048) { + if (newFreq >= 2048) + { //"then frequency calculation and overflow check are run AGAIN immediately using this new value, but this second new frequency is not written back." _state.SweepEnabled = false; _state.Enabled = false; } - } else { + } + else + { _state.SweepEnabled = false; _state.Enabled = false; } @@ -60,18 +67,23 @@ void GbSquareChannel::ClockSweepUnit() uint16_t GbSquareChannel::GetSweepTargetFrequency() { uint16_t shiftResult = (_state.SweepFreq >> _state.SweepShift); - if(_state.SweepNegate) { + if (_state.SweepNegate) + { return _state.SweepFreq - shiftResult; - } else { + } + else + { return _state.SweepFreq + shiftResult; } } void GbSquareChannel::ClockLengthCounter() { - if(_state.LengthEnabled && _state.Length > 0) { + if (_state.LengthEnabled && _state.Length > 0) + { _state.Length--; - if(_state.Length == 0) { + if (_state.Length == 0) + { //"Length becoming 0 should clear status" _state.Enabled = false; } @@ -80,15 +92,22 @@ void GbSquareChannel::ClockLengthCounter() void GbSquareChannel::ClockEnvelope() { - if(_state.EnvTimer > 0 && !_state.EnvStopped) { + if (_state.EnvTimer > 0 && !_state.EnvStopped) + { _state.EnvTimer--; - if(_state.EnvTimer == 0) { - if(_state.EnvRaiseVolume && _state.Volume < 0x0F) { + if (_state.EnvTimer == 0) + { + if (_state.EnvRaiseVolume && _state.Volume < 0x0F) + { _state.Volume++; - } else if(!_state.EnvRaiseVolume && _state.Volume > 0) { + } + else if (!_state.EnvRaiseVolume && _state.Volume > 0) + { _state.Volume--; - } else { + } + else + { _state.EnvStopped = true; } @@ -105,14 +124,18 @@ uint8_t GbSquareChannel::GetOutput() void GbSquareChannel::Exec(uint32_t clocksToRun) { _state.Timer -= clocksToRun; - if(_state.Enabled) { + if (_state.Enabled) + { _state.Output = _dutySequences[_state.Duty][_state.DutyPos] * _state.Volume; - } else { + } + else + { _state.Output = 0; } - if(_state.Timer == 0) { + if (_state.Timer == 0) + { _state.Timer = (2048 - _state.Frequency) * 4; _state.DutyPos = (_state.DutyPos + 1) & 0x07; } @@ -120,29 +143,32 @@ void GbSquareChannel::Exec(uint32_t clocksToRun) uint8_t GbSquareChannel::Read(uint16_t addr) { - constexpr uint8_t openBusBits[5] = { 0x80, 0x3F, 0x00, 0xFF, 0xBF }; + constexpr uint8_t openBusBits[5] = {0x80, 0x3F, 0x00, 0xFF, 0xBF}; uint8_t value = 0; - switch(addr) { - case 0: - value = ( - (_state.SweepPeriod << 4) | - (_state.SweepNegate ? 0x08 : 0) | - _state.SweepShift - ); - break; + switch (addr) + { + case 0: + value = ( + (_state.SweepPeriod << 4) | + (_state.SweepNegate ? 0x08 : 0) | + _state.SweepShift + ); + break; - case 1: value = _state.Duty << 6; break; + case 1: value = _state.Duty << 6; + break; - case 2: - value = ( - (_state.EnvVolume << 4) | - (_state.EnvRaiseVolume ? 0x08 : 0) | - _state.EnvPeriod - ); - break; + case 2: + value = ( + (_state.EnvVolume << 4) | + (_state.EnvRaiseVolume ? 0x08 : 0) | + _state.EnvPeriod + ); + break; - case 4: value = _state.LengthEnabled ? 0x40 : 0; break; + case 4: value = _state.LengthEnabled ? 0x40 : 0; + break; } return value | openBusBits[addr]; @@ -150,30 +176,35 @@ uint8_t GbSquareChannel::Read(uint16_t addr) void GbSquareChannel::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0: - _state.SweepShift = value & 0x07; - _state.SweepNegate = (value & 0x08) != 0; - _state.SweepPeriod = (value & 0x70) >> 4; - break; + switch (addr) + { + case 0: + _state.SweepShift = value & 0x07; + _state.SweepNegate = (value & 0x08) != 0; + _state.SweepPeriod = (value & 0x70) >> 4; + break; - case 1: - _state.Length = 64 - (value & 0x3F); - _state.Duty = (value & 0xC0) >> 6; - break; + case 1: + _state.Length = 64 - (value & 0x3F); + _state.Duty = (value & 0xC0) >> 6; + break; - case 2: + case 2: { - if(_state.EnvPeriod == 0 && !_state.EnvStopped) { + if (_state.EnvPeriod == 0 && !_state.EnvStopped) + { //"If the old envelope period was zero and the envelope is still doing automatic updates, volume is incremented by 1" _state.Volume++; - } else if(!_state.EnvRaiseVolume) { + } + else if (!_state.EnvRaiseVolume) + { //"otherwise if the envelope was in subtract mode, volume is incremented by 2" _state.Volume += 2; } bool raiseVolume = (value & 0x08) != 0; - if(raiseVolume != _state.EnvRaiseVolume) { + if (raiseVolume != _state.EnvRaiseVolume) + { //"If the mode was changed (add to subtract or subtract to add), volume is set to 16 - volume." _state.Volume = 16 - _state.Volume; } @@ -185,20 +216,23 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) _state.EnvRaiseVolume = raiseVolume; _state.EnvVolume = (value & 0xF0) >> 4; - if(!(value & 0xF8)) { + if (!(value & 0xF8)) + { _state.Enabled = false; } break; } - case 3: - _state.Frequency = (_state.Frequency & 0x700) | value; - break; + case 3: + _state.Frequency = (_state.Frequency & 0x700) | value; + break; - case 4: { + case 4: + { _state.Frequency = (_state.Frequency & 0xFF) | ((value & 0x07) << 8); - if(value & 0x80) { + if (value & 0x80) + { //"Writing a value to NRx4 with bit 7 set causes the following things to occur :" //"Channel is enabled, if volume is not 0 or raise volume flag is set" @@ -208,7 +242,8 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) _state.Timer = (2048 - _state.Frequency) * 4; //"If length counter is zero, it is set to 64 (256 for wave channel)." - if(_state.Length == 0) { + if (_state.Length == 0) + { _state.Length = 64; _state.LengthEnabled = false; } @@ -230,9 +265,11 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) _state.SweepTimer = _state.SweepPeriod; _state.SweepEnabled = _state.SweepPeriod > 0 || _state.SweepShift > 0; - if(_state.SweepShift > 0) { + if (_state.SweepShift > 0) + { _state.SweepFreq = GetSweepTargetFrequency(); - if(_state.SweepFreq > 2047) { + if (_state.SweepFreq > 2047) + { _state.SweepEnabled = false; _state.Enabled = false; } @@ -248,8 +285,10 @@ void GbSquareChannel::Write(uint16_t addr, uint8_t value) void GbSquareChannel::Serialize(Serializer& s) { s.Stream( - _state.SweepPeriod, _state.SweepNegate, _state.SweepShift, _state.SweepTimer, _state.SweepEnabled, _state.SweepFreq, - _state.Volume, _state.EnvVolume, _state.EnvRaiseVolume, _state.EnvPeriod, _state.EnvTimer, _state.Duty, _state.Frequency, + _state.SweepPeriod, _state.SweepNegate, _state.SweepShift, _state.SweepTimer, _state.SweepEnabled, + _state.SweepFreq, + _state.Volume, _state.EnvVolume, _state.EnvRaiseVolume, _state.EnvPeriod, _state.EnvTimer, _state.Duty, + _state.Frequency, _state.Length, _state.LengthEnabled, _state.Enabled, _state.Timer, _state.DutyPos, _state.Output ); } diff --git a/Core/GbSquareChannel.h b/Core/GbSquareChannel.h index d628592..424dfec 100644 --- a/Core/GbSquareChannel.h +++ b/Core/GbSquareChannel.h @@ -10,10 +10,10 @@ class GbSquareChannel final : public ISerializable { private: const uint8_t _dutySequences[4][8] = { - { 0, 1, 1, 1, 1, 1, 1, 1 }, - { 0, 0, 1, 1, 1, 1, 1, 1 }, - { 0, 0, 0, 0, 1, 1, 1, 1 }, - { 0, 0, 0, 0, 0, 0, 1, 1 } + {0, 1, 1, 1, 1, 1, 1, 1}, + {0, 0, 1, 1, 1, 1, 1, 1}, + {0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 1, 1} }; GbSquareState _state = {}; @@ -27,7 +27,7 @@ public: bool Enabled(); void Disable(); - void ClockSweepUnit(); + void ClockSweepUnit(); uint16_t GetSweepTargetFrequency(); void ClockLengthCounter(); @@ -41,4 +41,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbTimer.cpp b/Core/GbTimer.cpp index 6cd4314..9cdbd02 100644 --- a/Core/GbTimer.cpp +++ b/Core/GbTimer.cpp @@ -8,7 +8,7 @@ void GbTimer::Init(GbMemoryManager* memoryManager, GbApu* apu) { _apu = apu; _memoryManager = memoryManager; - + _state = {}; _state.TimerDivider = 1024; @@ -28,9 +28,11 @@ GbTimerState GbTimer::GetState() void GbTimer::Exec() { - if((_state.Divider & 0x03) == 2) { + if ((_state.Divider & 0x03) == 2) + { _state.Reloaded = false; - if(_state.NeedReload) { + if (_state.NeedReload) + { ReloadCounter(); } } @@ -47,15 +49,18 @@ void GbTimer::ReloadCounter() void GbTimer::SetDivider(uint16_t newValue) { - if(_state.TimerEnabled && !(newValue & _state.TimerDivider) && (_state.Divider & _state.TimerDivider)) { + if (_state.TimerEnabled && !(newValue & _state.TimerDivider) && (_state.Divider & _state.TimerDivider)) + { _state.Counter++; - if(_state.Counter == 0) { + if (_state.Counter == 0) + { _state.NeedReload = true; } } uint16_t frameSeqBit = _memoryManager->IsHighSpeed() ? 0x2000 : 0x1000; - if(!(newValue & frameSeqBit) && (_state.Divider & frameSeqBit)) { + if (!(newValue & frameSeqBit) && (_state.Divider & frameSeqBit)) + { _apu->ClockFrameSequencer(); } @@ -64,68 +69,85 @@ void GbTimer::SetDivider(uint16_t newValue) uint8_t GbTimer::Read(uint16_t addr) { - switch(addr) { - case 0xFF04: return _state.Divider >> 8; - case 0xFF05: return _state.Counter; //FF05 - TIMA - Timer counter (R/W) - case 0xFF06: return _state.Modulo; //FF06 - TMA - Timer Modulo (R/W) - case 0xFF07: return _state.Control | 0xF8; //FF07 - TAC - Timer Control (R/W) + switch (addr) + { + case 0xFF04: return _state.Divider >> 8; + case 0xFF05: return _state.Counter; //FF05 - TIMA - Timer counter (R/W) + case 0xFF06: return _state.Modulo; //FF06 - TMA - Timer Modulo (R/W) + case 0xFF07: return _state.Control | 0xF8; //FF07 - TAC - Timer Control (R/W) } return 0; } void GbTimer::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0xFF04: - SetDivider(0); - break; + switch (addr) + { + case 0xFF04: + SetDivider(0); + break; - case 0xFF05: - //FF05 - TIMA - Timer counter (R/W) - if(_state.NeedReload) { - //Writing to TIMA when a reload is pending will cancel the reload and IRQ request - _state.NeedReload = false; - } + case 0xFF05: + //FF05 - TIMA - Timer counter (R/W) + if (_state.NeedReload) + { + //Writing to TIMA when a reload is pending will cancel the reload and IRQ request + _state.NeedReload = false; + } - if(!_state.Reloaded) { - //Writes to TIMA on the cycle TIMA was reloaded with TMA are ignored - _state.Counter = value; - } - break; + if (!_state.Reloaded) + { + //Writes to TIMA on the cycle TIMA was reloaded with TMA are ignored + _state.Counter = value; + } + break; - case 0xFF06: - //FF06 - TMA - Timer Modulo (R/W) - _state.Modulo = value; - if(_state.Reloaded) { - //Writing to TMA on the same cycle it was reloaded into TIMA will also update TIMA - _state.Counter = value; - } - break; + case 0xFF06: + //FF06 - TMA - Timer Modulo (R/W) + _state.Modulo = value; + if (_state.Reloaded) + { + //Writing to TMA on the same cycle it was reloaded into TIMA will also update TIMA + _state.Counter = value; + } + break; - case 0xFF07: { + case 0xFF07: + { //FF07 - TAC - Timer Control (R/W) _state.Control = value; bool enabled = (value & 0x04) != 0; uint16_t newDivider = 0; - switch(value & 0x03) { - case 0: newDivider = 1 << 9; break; - case 1: newDivider = 1 << 3; break; - case 2: newDivider = 1 << 5; break; - case 3: newDivider = 1 << 7; break; + switch (value & 0x03) + { + case 0: newDivider = 1 << 9; + break; + case 1: newDivider = 1 << 3; + break; + case 2: newDivider = 1 << 5; + break; + case 3: newDivider = 1 << 7; + break; } - if(_state.TimerEnabled) { + if (_state.TimerEnabled) + { //When changing the value of TAC, the TIMA register can get incremented due to a glitch bool incrementCounter; - if(enabled) { + if (enabled) + { incrementCounter = (_state.Divider & _state.TimerDivider) != 0 && (_state.Divider & newDivider) == 0; - } else { + } + else + { incrementCounter = (_state.Divider & _state.TimerDivider) != 0; } - if(incrementCounter) { + if (incrementCounter) + { _state.Counter++; - if(_state.Counter == 0) { + if (_state.Counter == 0) + { ReloadCounter(); } } @@ -140,5 +162,6 @@ void GbTimer::Write(uint16_t addr, uint8_t value) void GbTimer::Serialize(Serializer& s) { - s.Stream(_state.Divider, _state.Counter, _state.Modulo, _state.Control, _state.TimerEnabled, _state.TimerDivider, _state.NeedReload, _state.Reloaded); + s.Stream(_state.Divider, _state.Counter, _state.Modulo, _state.Control, _state.TimerEnabled, _state.TimerDivider, + _state.NeedReload, _state.Reloaded); } diff --git a/Core/GbTimer.h b/Core/GbTimer.h index ff23e98..a5306ef 100644 --- a/Core/GbTimer.h +++ b/Core/GbTimer.h @@ -13,7 +13,7 @@ private: GbMemoryManager* _memoryManager = nullptr; GbApu* _apu = nullptr; GbTimerState _state = {}; - + void SetDivider(uint16_t value); void ReloadCounter(); @@ -30,4 +30,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/GbTypes.h b/Core/GbTypes.h index 959bc03..7ad253e 100644 --- a/Core/GbTypes.h +++ b/Core/GbTypes.h @@ -14,7 +14,7 @@ struct GbCpuState uint8_t C; uint8_t D; uint8_t E; - + uint8_t H; uint8_t L; @@ -50,7 +50,7 @@ class Register16 { uint8_t* _low; uint8_t* _high; - + public: Register16(uint8_t* high, uint8_t* low) { @@ -157,7 +157,7 @@ struct GbPpuState PpuMode Mode; PpuMode IrqMode; bool StatIrqFlag; - + uint8_t Ly; int16_t LyForCompare; @@ -186,11 +186,11 @@ struct GbPpuState bool CgbEnabled; uint8_t CgbVramBank; - + uint8_t CgbBgPalPosition; bool CgbBgPalAutoInc; uint16_t CgbBgPalettes[4 * 8]; - + uint8_t CgbObjPalPosition; bool CgbObjPalAutoInc; uint16_t CgbObjPalettes[4 * 8]; @@ -348,7 +348,7 @@ struct GbMemoryManagerState { uint64_t CycleCount; uint64_t ApuCycleCount; - + uint8_t CgbWorkRamBank; bool CgbSwitchSpeedRequest; bool CgbHighSpeed; @@ -385,7 +385,7 @@ struct GbState { GbType Type; GbCpuState Cpu; - GbPpuState Ppu; + GbPpuState Ppu; GbApuDebugState Apu; GbMemoryManagerState MemoryManager; GbTimerState Timer; diff --git a/Core/GbWaveChannel.cpp b/Core/GbWaveChannel.cpp index ab6bfac..dd44d13 100644 --- a/Core/GbWaveChannel.cpp +++ b/Core/GbWaveChannel.cpp @@ -29,9 +29,11 @@ void GbWaveChannel::Disable() void GbWaveChannel::ClockLengthCounter() { - if(_state.LengthEnabled && _state.Length > 0) { + if (_state.LengthEnabled && _state.Length > 0) + { _state.Length--; - if(_state.Length == 0) { + if (_state.Length == 0) + { //"Length becoming 0 should clear status" _state.Enabled = false; } @@ -48,13 +50,17 @@ void GbWaveChannel::Exec(uint32_t clocksToRun) _state.Timer -= clocksToRun; //The DAC receives the current value from the upper/lower nibble of the sample buffer, shifted right by the volume control. - if(_state.Volume && _state.Enabled) { + if (_state.Volume && _state.Enabled) + { _state.Output = _state.SampleBuffer >> (_state.Volume - 1); - } else { + } + else + { _state.Output = 0; } - if(_state.Timer == 0) { + if (_state.Timer == 0) + { //The wave channel's frequency timer period is set to (2048-frequency)*2. _state.Timer = (2048 - _state.Frequency) * 2; @@ -63,9 +69,12 @@ void GbWaveChannel::Exec(uint32_t clocksToRun) _state.Position = (_state.Position + 1) & 0x1F; //then a sample is read into the sample buffer from this NEW position. - if(_state.Position & 0x01) { + if (_state.Position & 0x01) + { _state.SampleBuffer = _state.Ram[_state.Position >> 1] & 0x0F; - } else { + } + else + { _state.SampleBuffer = _state.Ram[_state.Position >> 1] >> 4; } } @@ -73,13 +82,17 @@ void GbWaveChannel::Exec(uint32_t clocksToRun) uint8_t GbWaveChannel::Read(uint16_t addr) { - constexpr uint8_t openBusBits[5] = { 0x7F, 0xFF, 0x9F, 0xFF, 0xBF }; + constexpr uint8_t openBusBits[5] = {0x7F, 0xFF, 0x9F, 0xFF, 0xBF}; uint8_t value = 0; - switch(addr) { - case 0: value = _state.DacEnabled ? 0x80 : 0; break; - case 2: value = _state.Volume << 5; break; - case 4: value = _state.LengthEnabled ? 0x40 : 0; break; + switch (addr) + { + case 0: value = _state.DacEnabled ? 0x80 : 0; + break; + case 2: value = _state.Volume << 5; + break; + case 4: value = _state.LengthEnabled ? 0x40 : 0; + break; } return value | openBusBits[addr]; @@ -87,28 +100,31 @@ uint8_t GbWaveChannel::Read(uint16_t addr) void GbWaveChannel::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0: - _state.DacEnabled = (value & 0x80) != 0; - _state.Enabled &= _state.DacEnabled; - break; + switch (addr) + { + case 0: + _state.DacEnabled = (value & 0x80) != 0; + _state.Enabled &= _state.DacEnabled; + break; - case 1: - _state.Length = 256 - value; - break; + case 1: + _state.Length = 256 - value; + break; - case 2: - _state.Volume = (value & 0x60) >> 5; - break; + case 2: + _state.Volume = (value & 0x60) >> 5; + break; - case 3: - _state.Frequency = (_state.Frequency & 0x700) | value; - break; + case 3: + _state.Frequency = (_state.Frequency & 0x700) | value; + break; - case 4: { + case 4: + { _state.Frequency = (_state.Frequency & 0xFF) | ((value & 0x07) << 8); - if(value & 0x80) { + if (value & 0x80) + { //Start playback //Channel is enabled, if DAC is enabled @@ -118,7 +134,8 @@ void GbWaveChannel::Write(uint16_t addr, uint8_t value) _state.Timer = (2048 - _state.Frequency) * 2; //If length counter is zero, it is set to 64 (256 for wave channel). - if(_state.Length == 0) { + if (_state.Length == 0) + { _state.Length = 256; _state.LengthEnabled = false; } diff --git a/Core/GbWaveChannel.h b/Core/GbWaveChannel.h index 9f510f9..5901be0 100644 --- a/Core/GbWaveChannel.h +++ b/Core/GbWaveChannel.h @@ -31,4 +31,4 @@ public: uint8_t ReadRam(uint16_t addr); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/Gsu.Instructions.cpp b/Core/Gsu.Instructions.cpp index ccf933e..66a61d5 100644 --- a/Core/Gsu.Instructions.cpp +++ b/Core/Gsu.Instructions.cpp @@ -5,7 +5,8 @@ void Gsu::STOP() { - if(!_state.IrqDisabled) { + if (!_state.IrqDisabled) + { _state.SFR.Irq = true; _cpu->SetIrqSource(IrqSource::Coprocessor); } @@ -23,7 +24,8 @@ void Gsu::NOP() void Gsu::CACHE() { - if(_state.CacheBase != (_state.R[15] & 0xFFF0)) { + if (_state.CacheBase != (_state.R[15] & 0xFFF0)) + { _state.CacheBase = _state.R[15] & 0xFFF0; InvalidateCache(); } @@ -33,7 +35,8 @@ void Gsu::CACHE() void Gsu::Branch(bool branch) { int8_t offset = (int8_t)ReadOperand(); - if(branch) { + if (branch) + { WriteRegister(15, _state.R[15] + offset); } } @@ -95,14 +98,17 @@ void Gsu::BVS() void Gsu::JMP(uint8_t reg) { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LJMP _state.ProgramBank = _state.R[reg] & 0x7F; WriteRegister(15, ReadSrcReg()); - + _state.CacheBase = _state.R[15] & 0xFFF0; InvalidateCache(); - } else { + } + else + { //JMP WriteRegister(15, _state.R[reg]); } @@ -111,11 +117,14 @@ void Gsu::JMP(uint8_t reg) void Gsu::TO(uint8_t reg) { - if(_state.SFR.Prefix) { + if (_state.SFR.Prefix) + { //MOVE WriteRegister(reg, ReadSrcReg()); ResetFlags(); - } else { + } + else + { //TO _state.DestReg = reg; } @@ -123,14 +132,17 @@ void Gsu::TO(uint8_t reg) void Gsu::FROM(uint8_t reg) { - if(_state.SFR.Prefix) { + if (_state.SFR.Prefix) + { //MOVES WriteDestReg(_state.R[reg]); _state.SFR.Overflow = (_state.R[reg] & 0x80) != 0; _state.SFR.Sign = (_state.R[reg] & 0x8000) != 0; _state.SFR.Zero = (_state.R[reg] == 0); ResetFlags(); - } else { + } + else + { //FROM _state.SrcReg = reg; } @@ -147,7 +159,8 @@ void Gsu::STORE(uint8_t reg) { _state.RamAddress = _state.R[reg]; WriteRam(_state.RamAddress, (uint8_t)ReadSrcReg()); - if(!_state.SFR.Alt1) { + if (!_state.SFR.Alt1) + { WriteRam(_state.RamAddress ^ 0x01, ReadSrcReg() >> 8); } ResetFlags(); @@ -157,7 +170,8 @@ void Gsu::LOAD(uint8_t reg) { _state.RamAddress = _state.R[reg]; uint16_t value = ReadRamBuffer(_state.RamAddress); - if(!_state.SFR.Alt1) { + if (!_state.SFR.Alt1) + { value |= ReadRamBuffer(_state.RamAddress ^ 0x01) << 8; } WriteDestReg(value); @@ -169,9 +183,10 @@ void Gsu::LOOP() _state.R[12]--; _state.SFR.Zero = (_state.R[12] == 0); _state.SFR.Sign = (_state.R[12] & 0x8000) != 0; - + //Loop until counter hits zero - if(!_state.SFR.Zero) { + if (!_state.SFR.Zero) + { WriteRegister(15, _state.R[13]); } @@ -220,15 +235,19 @@ void Gsu::SWAP() void Gsu::Add(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operand = reg; - } else { + } + else + { operand = _state.R[reg]; } uint32_t result = ReadSrcReg() + operand; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //ADC - Add with carry result += (uint8_t)_state.SFR.Carry; } @@ -245,15 +264,19 @@ void Gsu::Add(uint8_t reg) void Gsu::SubCompare(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2 && !_state.SFR.Alt1) { + if (_state.SFR.Alt2 && !_state.SFR.Alt1) + { //Immediate value, SUB #val operand = reg; - } else { + } + else + { operand = _state.R[reg]; } int32_t result = ReadSrcReg() - operand; - if(!_state.SFR.Alt2 && _state.SFR.Alt1) { + if (!_state.SFR.Alt2 && _state.SFR.Alt1) + { //SBC - SUB with carry result -= _state.SFR.Carry ? 0 : 1; } @@ -263,7 +286,8 @@ void Gsu::SubCompare(uint8_t reg) _state.SFR.Sign = (result & 0x8000) != 0; _state.SFR.Zero = (result & 0xFFFF) == 0; - if(!_state.SFR.Alt2 || !_state.SFR.Alt1) { + if (!_state.SFR.Alt2 || !_state.SFR.Alt1) + { //SUB/SBC, other CMP (and no write occurs for CMP) WriteDestReg(result); } @@ -273,22 +297,28 @@ void Gsu::SubCompare(uint8_t reg) void Gsu::MULT(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operand = reg; - } else { + } + else + { operand = _state.R[reg]; } uint16_t value; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //UMULT - Unsigned multiply value = (uint16_t)((uint8_t)ReadSrcReg() * (uint8_t)operand); - } else { + } + else + { //MULT - Signed multiply value = (uint16_t)((int8_t)ReadSrcReg() * (int8_t)operand); } - + WriteDestReg(value); _state.SFR.Sign = (value & 0x8000) != 0; _state.SFR.Zero = value == 0; @@ -302,7 +332,8 @@ void Gsu::FMultLMult() { uint32_t multResult = (int16_t)ReadSrcReg() * (int16_t)_state.R[6]; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LMULT - "16x16 signed multiply", LSB in R4, MSB in DREG _state.R[4] = multResult; } @@ -321,18 +352,24 @@ void Gsu::FMultLMult() void Gsu::AndBitClear(uint8_t reg) { uint16_t operand; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operand = reg; - } else { + } + else + { operand = _state.R[reg]; } uint16_t value; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //Bit clear value = ReadSrcReg() & ~operand; - } else { + } + else + { //AND value = ReadSrcReg() & operand; } @@ -380,7 +417,7 @@ void Gsu::LSR() { uint16_t src = ReadSrcReg(); _state.SFR.Carry = (src & 0x01) != 0; - + uint16_t dst = src >> 1; WriteDestReg(dst); _state.SFR.Zero = dst == 0; @@ -407,7 +444,8 @@ void Gsu::ASR() _state.SFR.Carry = (src & 0x01) != 0; uint16_t dst = (int16_t)src >> 1; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { dst += (src + 1) >> 16; } @@ -420,7 +458,7 @@ void Gsu::ASR() void Gsu::ROR() { uint16_t src = ReadSrcReg(); - + uint16_t dst = (src >> 1) | ((int)_state.SFR.Carry << 15); _state.SFR.Carry = (src & 0x01) != 0; @@ -452,19 +490,24 @@ void Gsu::HIB() void Gsu::IbtSmsLms(uint8_t reg) { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LMS - "Load word data from RAM, short address" _state.RamAddress = ReadOperand() << 1; uint8_t lsb = ReadRamBuffer(_state.RamAddress); uint8_t msb = ReadRamBuffer(_state.RamAddress | 0x01); WriteRegister(reg, (msb << 8) | lsb); - } else if(_state.SFR.Alt2) { + } + else if (_state.SFR.Alt2) + { //SMS - "Store word data to RAM, short address" _state.RamAddress = ReadOperand() << 1; WriteRam(_state.RamAddress, (uint8_t)_state.R[reg]); WriteRam(_state.RamAddress | 0x01, _state.R[reg] >> 8); - } else { + } + else + { //IBT - "Load immediate byte data" WriteRegister(reg, (int8_t)ReadOperand()); } @@ -473,7 +516,8 @@ void Gsu::IbtSmsLms(uint8_t reg) void Gsu::IwtLmSm(uint8_t reg) { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //LM - Load memory _state.RamAddress = ReadOperand(); _state.RamAddress |= ReadOperand() << 8; @@ -481,14 +525,18 @@ void Gsu::IwtLmSm(uint8_t reg) uint8_t lsb = ReadRamBuffer(_state.RamAddress); uint8_t msb = ReadRamBuffer(_state.RamAddress ^ 0x01); WriteRegister(reg, (msb << 8) | lsb); - } else if(_state.SFR.Alt2) { + } + else if (_state.SFR.Alt2) + { //SM - Store Memory _state.RamAddress = ReadOperand(); _state.RamAddress |= ReadOperand() << 8; WriteRam(_state.RamAddress, (uint8_t)_state.R[reg]); WriteRam(_state.RamAddress ^ 0x01, _state.R[reg] >> 8); - } else { + } + else + { //IWT - Load immediate word uint8_t lsb = ReadOperand(); uint8_t msb = ReadOperand(); @@ -500,19 +548,25 @@ void Gsu::IwtLmSm(uint8_t reg) void Gsu::OrXor(uint8_t operand) { uint16_t operandValue; - if(_state.SFR.Alt2) { + if (_state.SFR.Alt2) + { //Immediate value operandValue = operand; - } else { + } + else + { //Indirect register value operandValue = _state.R[operand]; } uint16_t value; - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //XOR value = ReadSrcReg() ^ operandValue; - } else { + } + else + { //OR value = ReadSrcReg() | operandValue; } @@ -540,14 +594,19 @@ void Gsu::DEC(uint8_t reg) void Gsu::GetCRamBRomB() { - if(!_state.SFR.Alt2) { + if (!_state.SFR.Alt2) + { //GETC - "Get byte from ROM to color register" _state.ColorReg = GetColor(ReadRomBuffer()); - } else if(!_state.SFR.Alt1) { + } + else if (!_state.SFR.Alt1) + { //RAMB - "Set RAM data bank" WaitRamOperation(); _state.RamBank = ReadSrcReg() & 0x01; - } else { + } + else + { //ROMB - "Set ROM data bank" WaitRomOperation(); _state.RomBank = ReadSrcReg() & 0x7F; @@ -557,16 +616,23 @@ void Gsu::GetCRamBRomB() void Gsu::GETB() { - if(_state.SFR.Alt2 && _state.SFR.Alt1) { + if (_state.SFR.Alt2 && _state.SFR.Alt1) + { //GETBS - "Get signed byte from ROM buffer" WriteDestReg((int8_t)ReadRomBuffer()); - } else if(_state.SFR.Alt2) { + } + else if (_state.SFR.Alt2) + { //GETBL - "Get low byte from ROM buffer" WriteDestReg((ReadSrcReg() & 0xFF00) | ReadRomBuffer()); - } else if(_state.SFR.Alt1) { + } + else if (_state.SFR.Alt1) + { //GETBH - "Get high byte from ROM buffer" WriteDestReg((ReadSrcReg() & 0xFF) | (ReadRomBuffer() << 8)); - } else { + } + else + { //GETB - "Get byte from ROM buffer" WriteDestReg(ReadRomBuffer()); } @@ -575,13 +641,16 @@ void Gsu::GETB() void Gsu::PlotRpix() { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //RPIX - "Read pixel color" uint8_t value = ReadPixel((uint8_t)_state.R[1], (uint8_t)_state.R[2]); _state.SFR.Zero = (value == 0); _state.SFR.Sign = (value & 0x8000); WriteDestReg(value); - } else { + } + else + { //PLOT DrawPixel((uint8_t)_state.R[1], (uint8_t)_state.R[2]); _state.R[1]++; @@ -591,7 +660,8 @@ void Gsu::PlotRpix() void Gsu::ColorCMode() { - if(_state.SFR.Alt1) { + if (_state.SFR.Alt1) + { //CMODE - "Set plot mode" uint8_t value = (uint8_t)ReadSrcReg(); _state.PlotTransparent = (value & 0x01) != 0; @@ -599,7 +669,9 @@ void Gsu::ColorCMode() _state.ColorHighNibble = (value & 0x04) != 0; _state.ColorFreezeHigh = (value & 0x08) != 0; _state.ObjMode = (value & 0x10) != 0; - } else { + } + else + { //COLOR - "Set plot color" _state.ColorReg = GetColor((uint8_t)ReadSrcReg()); } @@ -608,12 +680,17 @@ void Gsu::ColorCMode() uint16_t Gsu::GetTileIndex(uint8_t x, uint8_t y) { - switch(_state.ObjMode ? 3 : _state.ScreenHeight) { - default: - case 0: return ((x & 0xF8) << 1) + ((y & 0xF8) >> 3); break; - case 1: return ((x & 0xF8) << 1) + ((x & 0xF8) >> 1) + ((y & 0xF8) >> 3); break; - case 2: return ((x & 0xF8) << 1) + ((x & 0xF8) << 0) + ((y & 0xF8) >> 3); break; - case 3: return ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; + switch (_state.ObjMode ? 3 : _state.ScreenHeight) + { + default: + case 0: return ((x & 0xF8) << 1) + ((y & 0xF8) >> 3); + break; + case 1: return ((x & 0xF8) << 1) + ((x & 0xF8) >> 1) + ((y & 0xF8) >> 3); + break; + case 2: return ((x & 0xF8) << 1) + ((x & 0xF8) << 0) + ((y & 0xF8) >> 3); + break; + case 3: return ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); + break; } } @@ -629,11 +706,12 @@ uint8_t Gsu::ReadPixel(uint8_t x, uint8_t y) WritePixelCache(_state.PrimaryCache); uint32_t tileAddress = GetTileAddress(x, y); - + x = (x & 7) ^ 7; uint8_t data = 0; - for(int i = 0; i < _state.PlotBpp; i++) { + for (int i = 0; i < _state.PlotBpp; i++) + { //Select which byte to read/write based on the current bit (0/1, 16/17, 32/33, 48/49) uint8_t byteOffset = ((i >> 1) << 4) + (i & 0x01); data |= ((ReadGsu(tileAddress + byteOffset, MemoryOperationType::Read) >> x) & 1) << i; @@ -647,36 +725,42 @@ bool Gsu::IsTransparentPixel() { uint8_t color = _state.ColorFreezeHigh ? (_state.ColorReg & 0x0F) : _state.ColorReg; - switch(_state.PlotBpp) { - default: - case 2: return (color & 0x03) == 0; - case 4: return (color & 0x0F) == 0; - case 8: return color == 0; + switch (_state.PlotBpp) + { + default: + case 2: return (color & 0x03) == 0; + case 4: return (color & 0x0F) == 0; + case 8: return color == 0; } } void Gsu::DrawPixel(uint8_t x, uint8_t y) { - if(!_state.PlotTransparent && IsTransparentPixel()) { + if (!_state.PlotTransparent && IsTransparentPixel()) + { return; } uint8_t color = _state.ColorReg; - if(_state.PlotDither && _state.PlotBpp != 8) { - if((x ^ y) & 0x01) { + if (_state.PlotDither && _state.PlotBpp != 8) + { + if ((x ^ y) & 0x01) + { color >>= 4; } color &= 0x0F; } - if(_state.PrimaryCache.X != (x & 0xF8) || _state.PrimaryCache.Y != y) { + if (_state.PrimaryCache.X != (x & 0xF8) || _state.PrimaryCache.Y != y) + { FlushPrimaryCache(x, y); } uint8_t xOffset = (x & 7) ^ 7; _state.PrimaryCache.Pixels[xOffset] = color; _state.PrimaryCache.ValidBits |= (1 << xOffset); - if(_state.PrimaryCache.ValidBits == 0xFF) { + if (_state.PrimaryCache.ValidBits == 0xFF) + { FlushPrimaryCache(x, y); } } @@ -690,24 +774,28 @@ void Gsu::FlushPrimaryCache(uint8_t x, uint8_t y) _state.PrimaryCache.Y = y; } -void Gsu::WritePixelCache(GsuPixelCache &cache) +void Gsu::WritePixelCache(GsuPixelCache& cache) { - if(cache.ValidBits == 0) { + if (cache.ValidBits == 0) + { return; } uint32_t tileAddress = GetTileAddress(cache.X, cache.Y); - for(int i = 0; i < _state.PlotBpp; i++) { + for (int i = 0; i < _state.PlotBpp; i++) + { uint8_t value = 0; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { value |= ((cache.Pixels[x] >> i) & 0x01) << x; } //Select which byte to read/write based on the current bit (0/1, 16/17, 32/33, 48/49) uint8_t byte = ((i >> 1) << 4) + (i & 0x01); - if(cache.ValidBits != 0xFF) { + if (cache.ValidBits != 0xFF) + { //Read the pixels in memory before to merge them before writing the cache's content to memory Step(_state.ClockSelect ? 5 : 6); value &= cache.ValidBits; @@ -724,12 +812,14 @@ void Gsu::WritePixelCache(GsuPixelCache &cache) uint8_t Gsu::GetColor(uint8_t value) { - if(_state.ColorHighNibble) { + if (_state.ColorHighNibble) + { return (_state.ColorReg & 0xF0) | (value >> 4); } - if(_state.ColorFreezeHigh) { + if (_state.ColorFreezeHigh) + { return (_state.ColorReg & 0xF0) | (value & 0x0F); } return value; -} \ No newline at end of file +} diff --git a/Core/Gsu.cpp b/Core/Gsu.cpp index e3aca33..bd94398 100644 --- a/Core/Gsu.cpp +++ b/Core/Gsu.cpp @@ -12,7 +12,7 @@ #include "BatteryManager.h" #include "../Utilities/HexUtilities.h" -Gsu::Gsu(Console *console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType::Register) +Gsu::Gsu(Console* console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType::Register) { _console = console; _memoryManager = console->GetMemoryManager().get(); @@ -31,15 +31,18 @@ Gsu::Gsu(Console *console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType _gsuRam = new uint8_t[_gsuRamSize]; _settings->InitializeRam(_gsuRam, _gsuRamSize); - for(uint32_t i = 0; i < _gsuRamSize / 0x1000; i++) { - _gsuRamHandlers.push_back(unique_ptr(new RamHandler(_gsuRam, i * 0x1000, _gsuRamSize, SnesMemoryType::GsuWorkRam))); + for (uint32_t i = 0; i < _gsuRamSize / 0x1000; i++) + { + _gsuRamHandlers.push_back( + unique_ptr(new RamHandler(_gsuRam, i * 0x1000, _gsuRamSize, SnesMemoryType::GsuWorkRam))); _gsuCpuRamHandlers.push_back(unique_ptr(new GsuRamHandler(_state, _gsuRamHandlers.back().get()))); } - + //CPU mappings - MemoryMappings *cpuMappings = _memoryManager->GetMemoryMappings(); - vector> &prgRomHandlers = _console->GetCartridge()->GetPrgRomHandlers(); - for(unique_ptr &handler : prgRomHandlers) { + MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); + vector>& prgRomHandlers = _console->GetCartridge()->GetPrgRomHandlers(); + for (unique_ptr& handler : prgRomHandlers) + { _gsuCpuRomHandlers.push_back(unique_ptr(new GsuRomHandler(_state, handler.get()))); } @@ -47,7 +50,8 @@ Gsu::Gsu(Console *console, uint32_t gsuRamSize) : BaseCoprocessor(SnesMemoryType cpuMappings->RegisterHandler(0x00, 0x3F, 0x3000, 0x3FFF, this); cpuMappings->RegisterHandler(0x80, 0xBF, 0x3000, 0x3FFF, this); - for(int i = 0; i < 0x3F; i++) { + for (int i = 0; i < 0x3F; i++) + { cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, _gsuCpuRamHandlers); cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, _gsuCpuRamHandlers); } @@ -76,7 +80,8 @@ Gsu::~Gsu() void Gsu::ProcessEndOfFrame() { uint8_t clockMultiplier = _settings->GetEmulationConfig().GsuClockSpeed / 100; - if(_clockMultiplier != clockMultiplier) { + if (_clockMultiplier != clockMultiplier) + { _state.CycleCount = _state.CycleCount / _clockMultiplier * clockMultiplier; _clockMultiplier = clockMultiplier; } @@ -86,11 +91,13 @@ void Gsu::Run() { uint64_t targetCycle = _memoryManager->GetMasterClock() * _clockMultiplier; - while(!_stopped && _state.CycleCount < targetCycle) { + while (!_stopped && _state.CycleCount < targetCycle) + { Exec(); } - if(targetCycle > _state.CycleCount) { + if (targetCycle > _state.CycleCount) + { Step(targetCycle - _state.CycleCount); } } @@ -99,148 +106,382 @@ void Gsu::Exec() { uint8_t opCode = ReadOpCode(); - switch(opCode) { - case 0x00: STOP(); break; - case 0x01: NOP(); break; - case 0x02: CACHE(); break; - case 0x03: LSR(); break; - case 0x04: ROL(); break; - case 0x05: BRA(); break; - case 0x06: BLT(); break; - case 0x07: BGE(); break; - case 0x08: BNE(); break; - case 0x09: BEQ(); break; - case 0x0A: BPL(); break; - case 0x0B: BMI(); break; - case 0x0C: BCC(); break; - case 0x0D: BCS(); break; - case 0x0E: BCV(); break; - case 0x0F: BVS(); break; + switch (opCode) + { + case 0x00: STOP(); + break; + case 0x01: NOP(); + break; + case 0x02: CACHE(); + break; + case 0x03: LSR(); + break; + case 0x04: ROL(); + break; + case 0x05: BRA(); + break; + case 0x06: BLT(); + break; + case 0x07: BGE(); + break; + case 0x08: BNE(); + break; + case 0x09: BEQ(); + break; + case 0x0A: BPL(); + break; + case 0x0B: BMI(); + break; + case 0x0C: BCC(); + break; + case 0x0D: BCS(); + break; + case 0x0E: BCV(); + break; + case 0x0F: BVS(); + break; - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: - TO(opCode & 0x0F); - break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + TO(opCode & 0x0F); + break; - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: - WITH(opCode & 0x0F); - break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + WITH(opCode & 0x0F); + break; - case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3A: case 0x3B: - STORE(opCode & 0x0F); - break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + STORE(opCode & 0x0F); + break; - case 0x3C: LOOP(); break; - case 0x3D: ALT1(); break; - case 0x3E: ALT2(); break; - case 0x3F: ALT3(); break; + case 0x3C: LOOP(); + break; + case 0x3D: ALT1(); + break; + case 0x3E: ALT2(); + break; + case 0x3F: ALT3(); + break; - case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4A: case 0x4B: - LOAD(opCode & 0x0F); - break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + LOAD(opCode & 0x0F); + break; - case 0x4C: PlotRpix(); break; - case 0x4D: SWAP(); break; - case 0x4E: ColorCMode(); break; - case 0x4F: NOT(); break; + case 0x4C: PlotRpix(); + break; + case 0x4D: SWAP(); + break; + case 0x4E: ColorCMode(); + break; + case 0x4F: NOT(); + break; - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: - Add(opCode & 0x0F); - break; + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + Add(opCode & 0x0F); + break; - case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: - SubCompare(opCode & 0x0F); - break; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + SubCompare(opCode & 0x0F); + break; - case 0x70: MERGE(); break; + case 0x70: MERGE(); + break; - case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: - AndBitClear(opCode & 0x0F); - break; + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + AndBitClear(opCode & 0x0F); + break; - case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: - MULT(opCode & 0x0F); - break; + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + MULT(opCode & 0x0F); + break; - case 0x90: SBK(); break; + case 0x90: SBK(); + break; - case 0x91: LINK(1); break; - case 0x92: LINK(2); break; - case 0x93: LINK(3); break; - case 0x94: LINK(4); break; + case 0x91: LINK(1); + break; + case 0x92: LINK(2); + break; + case 0x93: LINK(3); + break; + case 0x94: LINK(4); + break; - case 0x95: SignExtend(); break; + case 0x95: SignExtend(); + break; - case 0x96: ASR(); break; - case 0x97: ROR(); break; + case 0x96: ASR(); + break; + case 0x97: ROR(); + break; - case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: - JMP(opCode & 0x0F); - break; + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + JMP(opCode & 0x0F); + break; - case 0x9E: LOB(); break; - case 0x9F: FMultLMult(); break; + case 0x9E: LOB(); + break; + case 0x9F: FMultLMult(); + break; - case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: - case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: - IbtSmsLms(opCode & 0x0F); - break; + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + IbtSmsLms(opCode & 0x0F); + break; - case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: - case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: - FROM(opCode & 0x0F); - break; + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + FROM(opCode & 0x0F); + break; - case 0xC0: HIB(); break; + case 0xC0: HIB(); + break; - case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: - case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: - OrXor(opCode & 0x0F); - break; + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + OrXor(opCode & 0x0F); + break; - case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: - case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: - INC(opCode & 0x0F); - break; + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + INC(opCode & 0x0F); + break; - case 0xDF: GetCRamBRomB(); break; + case 0xDF: GetCRamBRomB(); + break; - case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: - case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: - DEC(opCode & 0x0F); - break; + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + DEC(opCode & 0x0F); + break; - case 0xEF: GETB(); break; + case 0xEF: GETB(); + break; - case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: - case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: - IwtLmSm(opCode & 0x0F); - break; + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + IwtLmSm(opCode & 0x0F); + break; } _console->ProcessMemoryRead(_lastOpAddr, _state.ProgramReadBuffer, MemoryOperationType::ExecOpCode); - if(!_r15Changed) { + if (!_r15Changed) + { _state.R[15]++; - } else { + } + else + { _r15Changed = false; } } uint8_t Gsu::ReadGsu(uint32_t addr, MemoryOperationType opType) { - IMemoryHandler *handler = _mappings.GetHandler(addr); + IMemoryHandler* handler = _mappings.GetHandler(addr); uint8_t value; - if(handler) { + if (handler) + { value = handler->Read(addr); - } else { + } + else + { //TODO: Open bus? value = 0; LogDebug("[Debug] GSU - Missing read handler: " + HexUtilities::ToHex(addr)); @@ -252,10 +493,13 @@ uint8_t Gsu::ReadGsu(uint32_t addr, MemoryOperationType opType) void Gsu::WriteGsu(uint32_t addr, uint8_t value, MemoryOperationType opType) { - IMemoryHandler *handler = _mappings.GetHandler(addr); - if(handler) { + IMemoryHandler* handler = _mappings.GetHandler(addr); + if (handler) + { handler->Write(addr, value); - } else { + } + else + { LogDebug("[Debug] GSU - Missing write handler: " + HexUtilities::ToHex(addr)); } _console->ProcessMemoryWrite(addr, value, opType); @@ -264,20 +508,24 @@ void Gsu::WriteGsu(uint32_t addr, uint8_t value, MemoryOperationType opType) void Gsu::InitProgramCache(uint16_t cacheAddr) { uint16_t dest = (cacheAddr & 0x01F0); - - if(_state.ProgramBank <= 0x5F) { + + if (_state.ProgramBank <= 0x5F) + { WaitRomOperation(); WaitForRomAccess(); - } else { + } + else + { WaitRamOperation(); WaitForRamAccess(); } - + uint32_t srcBaseAddr = (_state.ProgramBank << 16) + _state.CacheBase + dest; - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { _cache[dest + i] = ReadGsu(srcBaseAddr + i, MemoryOperationType::Read); } - Step(_state.ClockSelect ? 5*16 : 6*16); + Step(_state.ClockSelect ? 5 * 16 : 6 * 16); _cacheValid[cacheAddr >> 4] = true; } @@ -301,19 +549,26 @@ uint8_t Gsu::ReadProgramByte(MemoryOperationType opType) { _lastOpAddr = (_state.ProgramBank << 16) | _state.R[15]; uint16_t cacheAddr = _state.R[15] - _state.CacheBase; - if(cacheAddr < 512) { - if(!_cacheValid[cacheAddr >> 4]) { + if (cacheAddr < 512) + { + if (!_cacheValid[cacheAddr >> 4]) + { InitProgramCache(cacheAddr & 0xFFF0); } - + Step(_state.ClockSelect ? 1 : 2); _console->ProcessMemoryRead(_lastOpAddr, _cache[cacheAddr], opType); return _cache[cacheAddr]; - } else { - if(_state.ProgramBank <= 0x5F) { + } + else + { + if (_state.ProgramBank <= 0x5F) + { WaitRomOperation(); WaitForRomAccess(); - } else { + } + else + { WaitRamOperation(); WaitForRamAccess(); } @@ -335,11 +590,14 @@ void Gsu::WriteDestReg(uint16_t value) void Gsu::WriteRegister(uint8_t reg, uint16_t value) { _state.R[reg] = value; - - if(reg == 14) { + + if (reg == 14) + { _state.SFR.RomReadPending = true; _state.RomDelay = _state.ClockSelect ? 5 : 6; - } else if(reg == 15) { + } + else if (reg == 15) + { _r15Changed = true; } } @@ -361,7 +619,8 @@ void Gsu::InvalidateCache() void Gsu::WaitRomOperation() { - if(_state.RomDelay) { + if (_state.RomDelay) + { //Wait for existing RAM operation to complete Step(_state.RomDelay); } @@ -369,7 +628,8 @@ void Gsu::WaitRomOperation() void Gsu::WaitRamOperation() { - if(_state.RamDelay) { + if (_state.RamDelay) + { //Wait for existing RAM operation to complete Step(_state.RamDelay); } @@ -377,7 +637,8 @@ void Gsu::WaitRamOperation() void Gsu::WaitForRomAccess() { - if(!_state.GsuRomAccess) { + if (!_state.GsuRomAccess) + { _waitForRomAccess = true; _stopped = true; } @@ -385,7 +646,8 @@ void Gsu::WaitForRomAccess() void Gsu::WaitForRamAccess() { - if(!_state.GsuRamAccess) { + if (!_state.GsuRamAccess) + { _waitForRamAccess = true; _stopped = true; } @@ -422,20 +684,25 @@ void Gsu::Step(uint64_t cycles) { _state.CycleCount += cycles; - if(_state.RomDelay) { + if (_state.RomDelay) + { _state.RomDelay -= std::min((uint8_t)cycles, _state.RomDelay); - if(_state.RomDelay == 0) { + if (_state.RomDelay == 0) + { WaitForRomAccess(); _state.RomReadBuffer = ReadGsu((_state.RomBank << 16) | _state.R[14], MemoryOperationType::Read); _state.SFR.RomReadPending = false; } } - if(_state.RamDelay) { + if (_state.RamDelay) + { _state.RamDelay -= std::min((uint8_t)cycles, _state.RamDelay); - if(_state.RamDelay == 0) { + if (_state.RamDelay == 0) + { WaitForRamAccess(); - WriteGsu(0x700000 | (_state.RamBank << 16) | _state.RamWriteAddress, _state.RamWriteValue, MemoryOperationType::Write); + WriteGsu(0x700000 | (_state.RamBank << 16) | _state.RamWriteAddress, _state.RamWriteValue, + MemoryOperationType::Write); } } } @@ -444,7 +711,7 @@ void Gsu::Reset() { _state = {}; _state.ProgramReadBuffer = 0x01; //Run a NOP on first cycle - + _console->GetSettings()->InitializeRam(_cache, 512); memset(_cacheValid, 0, sizeof(_cacheValid)); _waitForRomAccess = false; @@ -456,37 +723,69 @@ void Gsu::Reset() uint8_t Gsu::Read(uint32_t addr) { addr &= 0x33FF; - if(_state.SFR.Running && addr != 0x3030 && addr != 0x3031 && addr != 0x303B) { + if (_state.SFR.Running && addr != 0x3030 && addr != 0x3031 && addr != 0x303B) + { //"During GSU operation, only SFR, SCMR, and VCR may be accessed." return 0; } - switch(addr) { - case 0x3000: case 0x3002: case 0x3004: case 0x3006: case 0x3008: case 0x300A: case 0x300C:case 0x300E: - case 0x3010: case 0x3012: case 0x3014: case 0x3016: case 0x3018: case 0x301A: case 0x301C:case 0x301E: - return (uint8_t)_state.R[(addr >> 1) & 0x0F]; + switch (addr) + { + case 0x3000: + case 0x3002: + case 0x3004: + case 0x3006: + case 0x3008: + case 0x300A: + case 0x300C: + case 0x300E: + case 0x3010: + case 0x3012: + case 0x3014: + case 0x3016: + case 0x3018: + case 0x301A: + case 0x301C: + case 0x301E: + return (uint8_t)_state.R[(addr >> 1) & 0x0F]; - case 0x3001: case 0x3003: case 0x3005: case 0x3007: case 0x3009: case 0x300B: case 0x300D:case 0x300F: - case 0x3011: case 0x3013: case 0x3015: case 0x3017: case 0x3019: case 0x301B: case 0x301D:case 0x301F: - return _state.R[(addr >> 1) & 0x0F] >> 8; + case 0x3001: + case 0x3003: + case 0x3005: + case 0x3007: + case 0x3009: + case 0x300B: + case 0x300D: + case 0x300F: + case 0x3011: + case 0x3013: + case 0x3015: + case 0x3017: + case 0x3019: + case 0x301B: + case 0x301D: + case 0x301F: + return _state.R[(addr >> 1) & 0x0F] >> 8; - case 0x3030: return _state.SFR.GetFlagsLow(); - case 0x3031: { + case 0x3030: return _state.SFR.GetFlagsLow(); + case 0x3031: + { uint8_t flags = _state.SFR.GetFlagsHigh(); _state.SFR.Irq = false; _cpu->ClearIrqSource(IrqSource::Coprocessor); return flags; } - case 0x3034: return _state.ProgramBank; - case 0x3036: return _state.RomBank; - case 0x303B: return 0x04; //Version (can be 1 or 4?) - case 0x303C: return _state.RamBank; - case 0x303E: return (uint8_t)_state.CacheBase; - case 0x303F: return _state.CacheBase >> 8; + case 0x3034: return _state.ProgramBank; + case 0x3036: return _state.RomBank; + case 0x303B: return 0x04; //Version (can be 1 or 4?) + case 0x303C: return _state.RamBank; + case 0x303E: return (uint8_t)_state.CacheBase; + case 0x303F: return _state.CacheBase >> 8; } - - if(addr >= 0x3100 && addr <= 0x32FF) { + + if (addr >= 0x3100 && addr <= 0x32FF) + { return _cache[(_state.CacheBase + (addr - 0x3100)) & 0x1FF]; } @@ -499,33 +798,68 @@ uint8_t Gsu::Read(uint32_t addr) void Gsu::Write(uint32_t addr, uint8_t value) { addr &= 0x33FF; - if(_state.SFR.Running && addr != 0x3030 && addr != 0x303A) { + if (_state.SFR.Running && addr != 0x3030 && addr != 0x303A) + { //"During GSU operation, only SFR, SCMR, and VCR may be accessed." return; } - switch(addr) { - case 0x3000: case 0x3002: case 0x3004: case 0x3006: case 0x3008: case 0x300A: case 0x300C: case 0x300E: - case 0x3010: case 0x3012: case 0x3014: case 0x3016: case 0x3018: case 0x301A: case 0x301C: case 0x301E: - _state.RegisterLatch = value; - break; + switch (addr) + { + case 0x3000: + case 0x3002: + case 0x3004: + case 0x3006: + case 0x3008: + case 0x300A: + case 0x300C: + case 0x300E: + case 0x3010: + case 0x3012: + case 0x3014: + case 0x3016: + case 0x3018: + case 0x301A: + case 0x301C: + case 0x301E: + _state.RegisterLatch = value; + break; - case 0x3001: case 0x3003: case 0x3005: case 0x3007: case 0x3009: case 0x300B: case 0x300D: case 0x300F: - case 0x3011: case 0x3013: case 0x3015: case 0x3017: case 0x3019: case 0x301B: case 0x301D: case 0x301F: { + case 0x3001: + case 0x3003: + case 0x3005: + case 0x3007: + case 0x3009: + case 0x300B: + case 0x300D: + case 0x300F: + case 0x3011: + case 0x3013: + case 0x3015: + case 0x3017: + case 0x3019: + case 0x301B: + case 0x301D: + case 0x301F: + { uint8_t reg = (addr >> 1) & 0x0F; _state.R[reg] = (value << 8) | _state.RegisterLatch; - - if(reg == 14) { + + if (reg == 14) + { _state.SFR.RomReadPending = true; _state.RomDelay = _state.ClockSelect ? 5 : 6; - } else if(addr == 0x301F) { + } + else if (addr == 0x301F) + { _state.SFR.Running = true; UpdateRunningState(); } break; } - case 0x3030: { + case 0x3030: + { bool running = _state.SFR.Running; _state.SFR.Zero = (value & 0x02) != 0; _state.SFR.Carry = (value & 0x04) != 0; @@ -533,7 +867,8 @@ void Gsu::Write(uint32_t addr, uint8_t value) _state.SFR.Overflow = (value & 0x10) != 0; _state.SFR.Running = (value & 0x20) != 0; - if(running && !_state.SFR.Running) { + if (running && !_state.SFR.Running) + { _state.CacheBase = 0; InvalidateCache(); } @@ -541,43 +876,57 @@ void Gsu::Write(uint32_t addr, uint8_t value) break; } - case 0x3033: _state.BackupRamEnabled = (value & 0x01); break; - case 0x3034: _state.ProgramBank = (value & 0x7F); InvalidateCache(); break; - - case 0x3037: - _state.HighSpeedMode = (value & 0x20) != 0; - _state.IrqDisabled = (value & 0x80) != 0; + case 0x3033: _state.BackupRamEnabled = (value & 0x01); + break; + case 0x3034: _state.ProgramBank = (value & 0x7F); + InvalidateCache(); + break; + + case 0x3037: + _state.HighSpeedMode = (value & 0x20) != 0; + _state.IrqDisabled = (value & 0x80) != 0; + break; + + case 0x3038: _state.ScreenBase = value; + break; + case 0x3039: _state.ClockSelect = (value & 0x01); + break; + + case 0x303A: + _state.ColorGradient = (value & 0x03); + switch (_state.ColorGradient) + { + case 0: _state.PlotBpp = 2; break; - - case 0x3038: _state.ScreenBase = value; break; - case 0x3039: _state.ClockSelect = (value & 0x01); break; - - case 0x303A: - _state.ColorGradient = (value & 0x03); - switch(_state.ColorGradient) { - case 0: _state.PlotBpp = 2; break; - case 1: _state.PlotBpp = 4; break; - case 2: _state.PlotBpp = 4; break; - case 3: _state.PlotBpp = 8; break; - } - _state.ScreenHeight = ((value & 0x04) >> 2) | ((value & 0x20) >> 4); - _state.GsuRamAccess = (value & 0x08) != 0; - _state.GsuRomAccess = (value & 0x10) != 0; - - if(_state.GsuRamAccess) { - _waitForRamAccess = false; - } - if(_state.GsuRomAccess) { - _waitForRomAccess = false; - } - UpdateRunningState(); + case 1: _state.PlotBpp = 4; break; + case 2: _state.PlotBpp = 4; + break; + case 3: _state.PlotBpp = 8; + break; + } + _state.ScreenHeight = ((value & 0x04) >> 2) | ((value & 0x20) >> 4); + _state.GsuRamAccess = (value & 0x08) != 0; + _state.GsuRomAccess = (value & 0x10) != 0; + + if (_state.GsuRamAccess) + { + _waitForRamAccess = false; + } + if (_state.GsuRomAccess) + { + _waitForRomAccess = false; + } + UpdateRunningState(); + break; } - if(addr >= 0x3100 && addr <= 0x32FF) { + if (addr >= 0x3100 && addr <= 0x32FF) + { uint16_t cacheAddr = (_state.CacheBase + (addr - 0x3100)) & 0x1FF; _cache[cacheAddr] = value; - if((cacheAddr & 0x0F) == 0x0F) { + if ((cacheAddr & 0x0F) == 0x0F) + { _cacheValid[cacheAddr >> 4] = true; } } @@ -588,27 +937,32 @@ uint8_t Gsu::Peek(uint32_t addr) return 0; } -void Gsu::PeekBlock(uint32_t addr, uint8_t *output) +void Gsu::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } AddressInfo Gsu::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } -void Gsu::Serialize(Serializer &s) +void Gsu::Serialize(Serializer& s) { s.Stream( _state.CycleCount, _state.RegisterLatch, _state.ProgramBank, _state.RomBank, _state.RamBank, _state.IrqDisabled, - _state.HighSpeedMode, _state.ClockSelect, _state.BackupRamEnabled, _state.ScreenBase, _state.ColorGradient, _state.PlotBpp, - _state.ScreenHeight, _state.GsuRamAccess, _state.GsuRomAccess, _state.CacheBase, _state.PlotTransparent, _state.PlotDither, + _state.HighSpeedMode, _state.ClockSelect, _state.BackupRamEnabled, _state.ScreenBase, _state.ColorGradient, + _state.PlotBpp, + _state.ScreenHeight, _state.GsuRamAccess, _state.GsuRomAccess, _state.CacheBase, _state.PlotTransparent, + _state.PlotDither, _state.ColorHighNibble, _state.ColorFreezeHigh, _state.ObjMode, _state.ColorReg, _state.SrcReg, _state.DestReg, - _state.RomReadBuffer, _state.RomDelay, _state.ProgramReadBuffer, _state.RamWriteAddress, _state.RamWriteValue, _state.RamDelay, - _state.RamAddress, _state.PrimaryCache.X, _state.PrimaryCache.Y, _state.PrimaryCache.ValidBits, _state.SecondaryCache.X, + _state.RomReadBuffer, _state.RomDelay, _state.ProgramReadBuffer, _state.RamWriteAddress, _state.RamWriteValue, + _state.RamDelay, + _state.RamAddress, _state.PrimaryCache.X, _state.PrimaryCache.Y, _state.PrimaryCache.ValidBits, + _state.SecondaryCache.X, _state.SecondaryCache.Y, _state.SecondaryCache.ValidBits, - _state.SFR.Alt1, _state.SFR.Alt2, _state.SFR.Carry, _state.SFR.ImmHigh, _state.SFR.ImmLow, _state.SFR.Irq, _state.SFR.Overflow, + _state.SFR.Alt1, _state.SFR.Alt2, _state.SFR.Carry, _state.SFR.ImmHigh, _state.SFR.ImmLow, _state.SFR.Irq, + _state.SFR.Overflow, _state.SFR.Prefix, _state.SFR.RomReadPending, _state.SFR.Running, _state.SFR.Sign, _state.SFR.Zero ); @@ -672,12 +1026,14 @@ void Gsu::SetReg(GsuRegister reg, uint16_t value) case GsuRegister::GsuRegD: case GsuRegister::GsuRegE: case GsuRegister::GsuRegF: - { - _state.R[static_cast(reg) & 0xF] = value; - } break; + { + _state.R[static_cast(reg) & 0xF] = value; + } + break; case GsuRegister::GsuRegSFR: - { - _state.SFR.SetFlags(value); - } break; + { + _state.SFR.SetFlags(value); + } + break; } } diff --git a/Core/Gsu.h b/Core/Gsu.h index 744760b..03c4941 100644 --- a/Core/Gsu.h +++ b/Core/Gsu.h @@ -13,10 +13,10 @@ class EmuSettings; class Gsu : public BaseCoprocessor { private: - Console *_console; - MemoryManager *_memoryManager; - Cpu *_cpu; - EmuSettings *_settings; + Console* _console; + MemoryManager* _memoryManager; + Cpu* _cpu; + EmuSettings* _settings; uint8_t _clockMultiplier; GsuState _state; @@ -41,7 +41,7 @@ private: void InitProgramCache(uint16_t cacheAddr); - uint8_t ReadOperand(); + uint8_t ReadOperand(); uint8_t ReadOpCode(); uint8_t ReadProgramByte(MemoryOperationType opType); @@ -51,7 +51,7 @@ private: void ResetFlags(); void InvalidateCache(); - + void WaitRomOperation(); void WaitRamOperation(); @@ -69,7 +69,7 @@ private: void CACHE(); void Branch(bool branch); - + void BRA(); void BLT(); void BGE(); @@ -108,7 +108,7 @@ private: bool IsTransparentPixel(); void DrawPixel(uint8_t x, uint8_t y); void FlushPrimaryCache(uint8_t x, uint8_t y); - void WritePixelCache(GsuPixelCache &cache); + void WritePixelCache(GsuPixelCache& cache); uint8_t GetColor(uint8_t source); @@ -144,7 +144,7 @@ private: void GETB(); public: - Gsu(Console *console, uint32_t gsuRamSize); + Gsu(Console* console, uint32_t gsuRamSize); virtual ~Gsu(); void ProcessEndOfFrame() override; @@ -154,17 +154,17 @@ public: void LoadBattery() override; void SaveBattery() override; - + void Run() override; void Reset() override; uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t *output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; GsuState GetState(); MemoryMappings* GetMemoryMappings(); @@ -172,4 +172,4 @@ public: uint32_t DebugGetWorkRamSize(); void SetReg(GsuRegister reg, uint16_t value); -}; \ No newline at end of file +}; diff --git a/Core/GsuDebugger.cpp b/Core/GsuDebugger.cpp index 9d34ccb..1d11a38 100644 --- a/Core/GsuDebugger.cpp +++ b/Core/GsuDebugger.cpp @@ -37,24 +37,29 @@ void GsuDebugger::Reset() void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) { - if(type == MemoryOperationType::DummyRead) { + if (type == MemoryOperationType::DummyRead) + { //Ignore all dummy reads for now return; } AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; - if(type == MemoryOperationType::ExecOpCode) { - if(addressInfo.Type == SnesMemoryType::PrgRom) { + if (type == MemoryOperationType::ExecOpCode) + { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | CdlFlags::Gsu); } - if(_traceLogger->IsCpuLogged(CpuType::Gsu) || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) { + if (_traceLogger->IsCpuLogged(CpuType::Gsu) || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) + { GsuState gsuState = _gsu->GetState(); _disassembler->BuildCache(addressInfo, gsuState.SFR.GetFlagsHigh() & 0x13, CpuType::Gsu); - if(_traceLogger->IsCpuLogged(CpuType::Gsu)) { + if (_traceLogger->IsCpuLogged(CpuType::Gsu)) + { DebugState debugState; _debugger->GetState(debugState, true); debugState.Gsu.R[15] = addr; @@ -67,12 +72,16 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType _prevOpCode = value; _prevProgramCounter = addr; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else { - if(addressInfo.Type == SnesMemoryType::PrgRom) { + } + else + { + if (addressInfo.Type == SnesMemoryType::PrgRom) + { _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Gsu); } _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); @@ -84,7 +93,7 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType void GsuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); _disassembler->InvalidateCache(addressInfo, CpuType::Gsu); @@ -100,14 +109,16 @@ void GsuDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::StepOut: - case StepType::StepOver: - case StepType::Step: step.StepCount = stepCount; break; - - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + switch (type) + { + case StepType::StepOut: + case StepType::StepOver: + case StepType::Step: step.StepCount = stepCount; + break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -116,4 +127,4 @@ void GsuDebugger::Step(int32_t stepCount, StepType type) BreakpointManager* GsuDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/GsuDebugger.h b/Core/GsuDebugger.h index b07951a..53c7cdc 100644 --- a/Core/GsuDebugger.h +++ b/Core/GsuDebugger.h @@ -41,4 +41,4 @@ public: void Step(int32_t stepCount, StepType type); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/GsuDisUtils.cpp b/Core/GsuDisUtils.cpp index b5473ee..a01f756 100644 --- a/Core/GsuDisUtils.cpp +++ b/Core/GsuDisUtils.cpp @@ -6,9 +6,12 @@ #include "../Utilities/FastString.h" #include "../Utilities/HexUtilities.h" -void GsuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings *settings) +void GsuDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { - constexpr const char* registerNames[16] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; + constexpr const char* registerNames[16] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" + }; bool alt1 = (info.GetFlags() & 0x01) != 0; bool alt2 = (info.GetFlags() & 0x02) != 0; bool prefix = (info.GetFlags() & 0x10) != 0; @@ -17,194 +20,468 @@ void GsuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); - auto getJumpTarget = [&str, labelManager, memoryAddr, &info]() { + auto getJumpTarget = [&str, labelManager, memoryAddr, &info]() + { uint32_t jmpTarget = memoryAddr + (int8_t)info.GetByteCode()[1] + 2; - AddressInfo address = { (int32_t)jmpTarget, SnesMemoryType::GsuMemory }; + AddressInfo address = {(int32_t)jmpTarget, SnesMemoryType::GsuMemory}; string label = labelManager->GetLabel(address); - if(label.empty()) { + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex24(jmpTarget)); - } else { + } + else + { str.Write(label, true); } }; const char* reg = registerNames[opCode & 0x0F]; - switch(opCode) { - case 0x00: str.Write("STOP"); break; - case 0x01: str.Write("NOP"); break; - case 0x02: str.Write("CACHE"); break; - case 0x03: str.Write("LSR"); break; - case 0x04: str.Write("ROL"); break; - - case 0x05: str.WriteAll("BRA "); getJumpTarget(); break; - case 0x06: str.WriteAll("BLT "); getJumpTarget(); break; - case 0x07: str.WriteAll("BGE "); getJumpTarget(); break; - case 0x08: str.WriteAll("BNE "); getJumpTarget(); break; - case 0x09: str.WriteAll("BEQ "); getJumpTarget(); break; - case 0x0A: str.WriteAll("BPL "); getJumpTarget(); break; - case 0x0B: str.WriteAll("BMI "); getJumpTarget(); break; - case 0x0C: str.WriteAll("BCC "); getJumpTarget(); break; - case 0x0D: str.WriteAll("BCS "); getJumpTarget(); break; - case 0x0E: str.WriteAll("BCV "); getJumpTarget(); break; - case 0x0F: str.WriteAll("BVS "); getJumpTarget(); break; + switch (opCode) + { + case 0x00: str.Write("STOP"); + break; + case 0x01: str.Write("NOP"); + break; + case 0x02: str.Write("CACHE"); + break; + case 0x03: str.Write("LSR"); + break; + case 0x04: str.Write("ROL"); + break; - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: - str.WriteAll(prefix ? "MOVE R" : "TO R", reg); - break; + case 0x05: str.WriteAll("BRA "); + getJumpTarget(); + break; + case 0x06: str.WriteAll("BLT "); + getJumpTarget(); + break; + case 0x07: str.WriteAll("BGE "); + getJumpTarget(); + break; + case 0x08: str.WriteAll("BNE "); + getJumpTarget(); + break; + case 0x09: str.WriteAll("BEQ "); + getJumpTarget(); + break; + case 0x0A: str.WriteAll("BPL "); + getJumpTarget(); + break; + case 0x0B: str.WriteAll("BMI "); + getJumpTarget(); + break; + case 0x0C: str.WriteAll("BCC "); + getJumpTarget(); + break; + case 0x0D: str.WriteAll("BCS "); + getJumpTarget(); + break; + case 0x0E: str.WriteAll("BCV "); + getJumpTarget(); + break; + case 0x0F: str.WriteAll("BVS "); + getJumpTarget(); + break; - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: - str.WriteAll("WITH R", reg); - break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + str.WriteAll(prefix ? "MOVE R" : "TO R", reg); + break; - case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3A: case 0x3B: - str.WriteAll(alt1 ? "STB (R" : "STW (R", reg, ')'); - break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + str.WriteAll("WITH R", reg); + break; - case 0x3C: str.Write("LOOP"); break; - case 0x3D: str.Write("ALT1"); break; - case 0x3E: str.Write("ALT2"); break; - case 0x3F: str.Write("ALT3"); break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + str.WriteAll(alt1 ? "STB (R" : "STW (R", reg, ')'); + break; - case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4A: case 0x4B: - str.WriteAll(alt1 ? "LDB (R" : "LDW (R", reg, ')'); - break; + case 0x3C: str.Write("LOOP"); + break; + case 0x3D: str.Write("ALT1"); + break; + case 0x3E: str.Write("ALT2"); + break; + case 0x3F: str.Write("ALT3"); + break; - case 0x4C: str.Write(alt1 ? "RPIX" : "PLOT"); break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + str.WriteAll(alt1 ? "LDB (R" : "LDW (R", reg, ')'); + break; - case 0x4D: str.Write("SWAP"); break; - case 0x4E: str.Write(alt1 ? "CMODE" : "COLOR"); break; + case 0x4C: str.Write(alt1 ? "RPIX" : "PLOT"); + break; - case 0x4F: str.Write("NOT"); break; + case 0x4D: str.Write("SWAP"); + break; + case 0x4E: str.Write(alt1 ? "CMODE" : "COLOR"); + break; - case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: - str.Write(alt1 ? "ADC " : "ADD "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; + case 0x4F: str.Write("NOT"); + break; - case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: - if(alt2 && alt1) { - str.WriteAll("CMP R", reg); - } else { - if(!alt2 && alt1) { - str.Write("SBC "); - } else { - str.Write("SUB "); - } - if(alt2 && !alt1) { - str.WriteAll('#', reg); - } else { - str.WriteAll('R', reg); - } + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + str.Write(alt1 ? "ADC " : "ADD "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + if (alt2 && alt1) + { + str.WriteAll("CMP R", reg); + } + else + { + if (!alt2 && alt1) + { + str.Write("SBC "); } - break; - - case 0x70: str.Write("MERGE"); break; - - case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: - str.Write(alt1 ? "BIC " : "AND "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; - - case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: - case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: - str.Write(alt1 ? "UMULT " : "MULT "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; - - case 0x90: str.Write("SBK"); break; - - case 0x91: case 0x92: case 0x93: case 0x94: - str.WriteAll("LINK #", reg); - break; - - case 0x95: str.Write("SEX"); break; - - case 0x96: str.Write(alt1 ? "DIV2" : "ASR"); break; - case 0x97: str.Write("ROR"); break; - - case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: - str.WriteAll(alt1 ? "LJMP R" : "JMP R", reg); - break; - - case 0x9E: str.Write("LOB"); break; - case 0x9F: str.Write(alt1 ? "LMULT" : "FMULT"); break; - - case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: - case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: - if(alt1) { - str.WriteAll("LMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); - } else if(alt2) { - str.WriteAll("SMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); - } else { - str.WriteAll("IBT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[1])); + else + { + str.Write("SUB "); } - break; - - case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: - case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: - str.WriteAll(prefix ? "MOVES R" : "FROM R", reg); - break; - - case 0xC0: str.Write("HIB"); break; - - case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: - case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: - str.Write(alt1 ? "XOR " : "OR "); - str.WriteAll(alt2 ? '#' : 'R', reg); - break; - - case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: - case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: - str.WriteAll("INC R", reg); - break; - - case 0xDF: - if(!alt2) { - //GETC - "Get byte from ROM to color register" - str.Write("GETC"); - } else if(!alt1) { - //RAMB - "Set RAM data bank" - str.Write("RAMB"); - } else { - str.Write("ROMB"); + if (alt2 && !alt1) + { + str.WriteAll('#', reg); } - break; - - case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: - case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: - str.WriteAll("DEC R", reg); - break; - - case 0xEF: - if(alt2 && alt1) { - str.Write("GETBS"); - } else if(alt2) { - str.Write("GETBL"); - } else if(alt1) { - str.Write("GETBH"); - } else { - str.Write("GETB"); + else + { + str.WriteAll('R', reg); } - break; + } + break; - case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: - case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: - if(alt1) { - str.WriteAll("LM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1]), ')'); - } else if(alt2) { - str.WriteAll("SM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1]), ')'); - } else { - str.WriteAll("IWT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1])); - } - break; + case 0x70: str.Write("MERGE"); + break; + + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + str.Write(alt1 ? "BIC " : "AND "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + str.Write(alt1 ? "UMULT " : "MULT "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x90: str.Write("SBK"); + break; + + case 0x91: + case 0x92: + case 0x93: + case 0x94: + str.WriteAll("LINK #", reg); + break; + + case 0x95: str.Write("SEX"); + break; + + case 0x96: str.Write(alt1 ? "DIV2" : "ASR"); + break; + case 0x97: str.Write("ROR"); + break; + + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + str.WriteAll(alt1 ? "LJMP R" : "JMP R", reg); + break; + + case 0x9E: str.Write("LOB"); + break; + case 0x9F: str.Write(alt1 ? "LMULT" : "FMULT"); + break; + + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + if (alt1) + { + str.WriteAll("LMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); + } + else if (alt2) + { + str.WriteAll("SMS R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); + } + else + { + str.WriteAll("IBT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[1])); + } + break; + + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + str.WriteAll(prefix ? "MOVES R" : "FROM R", reg); + break; + + case 0xC0: str.Write("HIB"); + break; + + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + str.Write(alt1 ? "XOR " : "OR "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + str.WriteAll("INC R", reg); + break; + + case 0xDF: + if (!alt2) + { + //GETC - "Get byte from ROM to color register" + str.Write("GETC"); + } + else if (!alt1) + { + //RAMB - "Set RAM data bank" + str.Write("RAMB"); + } + else + { + str.Write("ROMB"); + } + break; + + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + str.WriteAll("DEC R", reg); + break; + + case 0xEF: + if (alt2 && alt1) + { + str.Write("GETBS"); + } + else if (alt2) + { + str.Write("GETBL"); + } + else if (alt1) + { + str.Write("GETBH"); + } + else + { + str.Write("GETB"); + } + break; + + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + if (alt1) + { + str.WriteAll("LM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), + HexUtilities::ToHex(info.GetByteCode()[1]), ')'); + } + else if (alt2) + { + str.WriteAll("SM R", reg, ",($", HexUtilities::ToHex(info.GetByteCode()[2]), + HexUtilities::ToHex(info.GetByteCode()[1]), ')'); + } + else + { + str.WriteAll("IWT R", reg, ",#$", HexUtilities::ToHex(info.GetByteCode()[2]), + HexUtilities::ToHex(info.GetByteCode()[1])); + } + break; } out += str.ToString(); @@ -216,20 +493,51 @@ int32_t GsuDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console bool alt1 = (info.GetFlags() & 0x01) != 0; bool alt2 = (info.GetFlags() & 0x02) != 0; - switch(opCode) { - case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: - case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: - if(alt1 || alt2) { - return 0x700000 | (info.GetByteCode()[1] << 1) | (state.RamBank << 16); - } - break; + switch (opCode) + { + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + if (alt1 || alt2) + { + return 0x700000 | (info.GetByteCode()[1] << 1) | (state.RamBank << 16); + } + break; - case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: - case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: - if(alt1 || alt2) { - return 0x700000 | info.GetByteCode()[1] | (info.GetByteCode()[2] << 8) | (state.RamBank << 16); - } - break; + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + if (alt1 || alt2) + { + return 0x700000 | info.GetByteCode()[1] | (info.GetByteCode()[2] << 8) | (state.RamBank << 16); + } + break; } return -1; diff --git a/Core/GsuDisUtils.h b/Core/GsuDisUtils.h index 47ea54e..d8aa52a 100644 --- a/Core/GsuDisUtils.h +++ b/Core/GsuDisUtils.h @@ -10,6 +10,7 @@ struct GsuState; class GsuDisUtils { public: - static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, GsuState& state); }; diff --git a/Core/GsuRamHandler.h b/Core/GsuRamHandler.h index 01daec8..890ce6e 100644 --- a/Core/GsuRamHandler.h +++ b/Core/GsuRamHandler.h @@ -6,11 +6,11 @@ class GsuRamHandler : public IMemoryHandler { private: - GsuState *_state; - IMemoryHandler *_handler; + GsuState* _state; + IMemoryHandler* _handler; public: - GsuRamHandler(GsuState &state, IMemoryHandler *handler) : IMemoryHandler(SnesMemoryType::GsuWorkRam) + GsuRamHandler(GsuState& state, IMemoryHandler* handler) : IMemoryHandler(SnesMemoryType::GsuWorkRam) { _handler = handler; _state = &state; @@ -18,7 +18,8 @@ public: uint8_t Read(uint32_t addr) override { - if(!_state->SFR.Running || !_state->GsuRamAccess) { + if (!_state->SFR.Running || !_state->GsuRamAccess) + { return _handler->Read(addr); } @@ -31,26 +32,31 @@ public: return Read(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = Read(i); } } void Write(uint32_t addr, uint8_t value) override { - if(!_state->SFR.Running || !_state->GsuRamAccess) { + if (!_state->SFR.Running || !_state->GsuRamAccess) + { _handler->Write(addr, value); } } AddressInfo GetAbsoluteAddress(uint32_t address) override { - if(!_state->SFR.Running || !_state->GsuRamAccess) { + if (!_state->SFR.Running || !_state->GsuRamAccess) + { return _handler->GetAbsoluteAddress(address); - } else { - return { -1, SnesMemoryType::Register }; + } + else + { + return {-1, SnesMemoryType::Register}; } } -}; \ No newline at end of file +}; diff --git a/Core/GsuRomHandler.h b/Core/GsuRomHandler.h index cf6b0e0..1222b99 100644 --- a/Core/GsuRomHandler.h +++ b/Core/GsuRomHandler.h @@ -6,11 +6,11 @@ class GsuRomHandler : public IMemoryHandler { private: - GsuState *_state; - IMemoryHandler *_romHandler; + GsuState* _state; + IMemoryHandler* _romHandler; public: - GsuRomHandler(GsuState &state, IMemoryHandler *romHandler) : IMemoryHandler(SnesMemoryType::PrgRom) + GsuRomHandler(GsuState& state, IMemoryHandler* romHandler) : IMemoryHandler(SnesMemoryType::PrgRom) { _romHandler = romHandler; _state = &state; @@ -18,22 +18,28 @@ public: uint8_t Read(uint32_t addr) override { - if(!_state->SFR.Running || !_state->GsuRomAccess) { + if (!_state->SFR.Running || !_state->GsuRomAccess) + { return _romHandler->Read(addr); } - if(addr & 0x01) { + if (addr & 0x01) + { return 0x01; } - switch(addr & 0x0E) { - default: - case 2: case 6: case 8: case 0x0C: - return 0; + switch (addr & 0x0E) + { + default: + case 2: + case 6: + case 8: + case 0x0C: + return 0; - case 4: return 0x04; - case 0x0A: return 0x08; - case 0x0E: return 0x0C; + case 4: return 0x04; + case 0x0A: return 0x08; + case 0x0E: return 0x0C; } } @@ -42,9 +48,10 @@ public: return Read(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = Read(i); } } @@ -56,10 +63,13 @@ public: AddressInfo GetAbsoluteAddress(uint32_t address) override { - if(!_state->SFR.Running || !_state->GsuRomAccess) { + if (!_state->SFR.Running || !_state->GsuRomAccess) + { return _romHandler->GetAbsoluteAddress(address); - } else { - return { -1, SnesMemoryType::Register }; + } + else + { + return {-1, SnesMemoryType::Register}; } } -}; \ No newline at end of file +}; diff --git a/Core/GsuTypes.h b/Core/GsuTypes.h index 2dabec2..0a1be6c 100644 --- a/Core/GsuTypes.h +++ b/Core/GsuTypes.h @@ -15,7 +15,7 @@ struct GsuFlags bool ImmHigh; bool Prefix; bool Irq; - + uint8_t GetFlagsLow() { return ( @@ -77,7 +77,7 @@ struct GsuState uint16_t R[16]; GsuFlags SFR; - + uint8_t RegisterLatch; uint8_t ProgramBank; @@ -89,7 +89,7 @@ struct GsuState bool ClockSelect; bool BackupRamEnabled; uint8_t ScreenBase; - + uint8_t ColorGradient; uint8_t PlotBpp; uint8_t ScreenHeight; @@ -107,7 +107,7 @@ struct GsuState uint8_t ColorReg; uint8_t SrcReg; uint8_t DestReg; - + uint8_t RomReadBuffer; uint8_t RomDelay; @@ -118,7 +118,7 @@ struct GsuState uint8_t RamDelay; uint16_t RamAddress; - + GsuPixelCache PrimaryCache; GsuPixelCache SecondaryCache; -}; \ No newline at end of file +}; diff --git a/Core/HandShakeMessage.h b/Core/HandShakeMessage.h index c60bdf6..ec4abb0 100644 --- a/Core/HandShakeMessage.h +++ b/Core/HandShakeMessage.h @@ -14,15 +14,18 @@ private: bool _spectator = false; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_emuVersion, _protocolVersion, _playerName, _hashedPassword, _spectator); } public: - HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) {} + HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } - HandShakeMessage(string playerName, string hashedPassword, bool spectator, uint32_t emuVersion) : NetMessage(MessageType::HandShake) + HandShakeMessage(string playerName, string hashedPassword, bool spectator, uint32_t emuVersion) : NetMessage( + MessageType::HandShake) { _emuVersion = emuVersion; _protocolVersion = HandShakeMessage::CurrentVersion; @@ -54,7 +57,8 @@ public: static string GetPasswordHash(string serverPassword, string connectionHash) { string saltedPassword = serverPassword + connectionHash; - vector dataToHash = vector(saltedPassword.c_str(), saltedPassword.c_str() + saltedPassword.size()); + vector dataToHash = vector(saltedPassword.c_str(), + saltedPassword.c_str() + saltedPassword.size()); return SHA1::GetHash(dataToHash); } }; diff --git a/Core/HistoryViewer.cpp b/Core/HistoryViewer.cpp index cbe2993..d24e9ed 100644 --- a/Core/HistoryViewer.cpp +++ b/Core/HistoryViewer.cpp @@ -39,12 +39,15 @@ uint32_t HistoryViewer::GetHistoryLength() void HistoryViewer::GetHistorySegments(uint32_t* segmentBuffer, uint32_t& bufferSize) { uint32_t segmentIndex = 0; - for (size_t i = 0; i < _history.size(); i++) { - if (_history[i].EndOfSegment) { + for (size_t i = 0; i < _history.size(); i++) + { + if (_history[i].EndOfSegment) + { segmentBuffer[segmentIndex] = (uint32_t)i; segmentIndex++; - if (segmentIndex == bufferSize) { + if (segmentIndex == bufferSize) + { //Reached buffer size, can't return any more values break; } @@ -61,7 +64,8 @@ uint32_t HistoryViewer::GetPosition() void HistoryViewer::SeekTo(uint32_t seekPosition) { //Seek to the specified position - if (seekPosition < _history.size()) { + if (seekPosition < _history.size()) + { _console->Lock(); bool wasPaused = _console->IsPaused(); @@ -73,7 +77,8 @@ void HistoryViewer::SeekTo(uint32_t seekPosition) _console->GetSoundMixer()->StopAudio(true); _pollCounter = 0; - if (wasPaused) { + if (wasPaused) + { _console->Pause(); } @@ -83,13 +88,15 @@ void HistoryViewer::SeekTo(uint32_t seekPosition) bool HistoryViewer::CreateSaveState(string outputFile, uint32_t position) { - if (position < _history.size()) { + if (position < _history.size()) + { std::stringstream stateData; _console->GetSaveStateManager()->GetSaveStateHeader(stateData); _history[position].GetStateData(stateData); ofstream output(outputFile, ios::binary); - if (output) { + if (output) + { output << stateData.rdbuf(); output.close(); return true; @@ -120,16 +127,19 @@ bool HistoryViewer::SaveMovie(string movieFile, uint32_t startPosition, uint32_t void HistoryViewer::ResumeGameplay(shared_ptr console, uint32_t resumePosition) { console->Lock(); - if (_console->GetRomInfo().RomFile.GetSha1Hash() != console->GetRomInfo().RomFile.GetSha1Hash()) { + if (_console->GetRomInfo().RomFile.GetSha1Hash() != console->GetRomInfo().RomFile.GetSha1Hash()) + { //Load game on the main window if they aren't the same console->LoadRom(console->GetRomInfo().RomFile, console->GetRomInfo().PatchFile); // Mesen does console->Initialize(_console->GetRomPath(), _console->GetPatchFile()); // but that's probably equivalent } - if (resumePosition < _history.size()) { + if (resumePosition < _history.size()) + { _history[resumePosition].LoadState(console); } - else { + else + { _history[_history.size() - 1].LoadState(console); } console->Unlock(); @@ -137,16 +147,18 @@ void HistoryViewer::ResumeGameplay(shared_ptr console, uint32_t resumeP bool HistoryViewer::SetInput(BaseControlDevice* device) { - uint8_t port = device->GetPort(); - if (_position < _history.size()) { + if (_position < _history.size()) + { std::deque& stateData = _history[_position].InputLogs[port]; - if (_pollCounter < stateData.size()) { + if (_pollCounter < stateData.size()) + { ControlDeviceState state = stateData[_pollCounter]; device->SetRawState(state); } } - if (port == 0 && _pollCounter < HistoryViewer::BufferSize) { + if (port == 0 && _pollCounter < HistoryViewer::BufferSize) + { _pollCounter++; } return true; @@ -154,11 +166,13 @@ bool HistoryViewer::SetInput(BaseControlDevice* device) void HistoryViewer::ProcessEndOfFrame() { - if (_pollCounter == HistoryViewer::BufferSize) { + if (_pollCounter == HistoryViewer::BufferSize) + { _pollCounter = 0; _position++; - if (_position >= _history.size()) { + if (_position >= _history.size()) + { //Reached the end of history data _console->Pause(); return; diff --git a/Core/HistoryViewer.h b/Core/HistoryViewer.h index 5340ecc..e06a49c 100644 --- a/Core/HistoryViewer.h +++ b/Core/HistoryViewer.h @@ -36,4 +36,4 @@ public: // Inherited via IInputProvider bool SetInput(BaseControlDevice* device) override; -}; \ No newline at end of file +}; diff --git a/Core/IAudioDevice.h b/Core/IAudioDevice.h index b371bfd..babbaad 100644 --- a/Core/IAudioDevice.h +++ b/Core/IAudioDevice.h @@ -12,8 +12,11 @@ struct AudioStatistics class IAudioDevice { public: - virtual ~IAudioDevice() {} - virtual void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) = 0; + virtual ~IAudioDevice() + { + } + + virtual void PlayBuffer(int16_t* soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) = 0; virtual void Stop() = 0; virtual void Pause() = 0; virtual void ProcessEndOfFrame() = 0; @@ -22,4 +25,4 @@ public: virtual void SetAudioDevice(string deviceName) = 0; virtual AudioStatistics GetStatistics() = 0; -}; \ No newline at end of file +}; diff --git a/Core/IDebugger.h b/Core/IDebugger.h index 0fc3384..60379e2 100644 --- a/Core/IDebugger.h +++ b/Core/IDebugger.h @@ -7,4 +7,4 @@ class IDebugger { public: virtual void Step(int32_t stepCount, StepType type) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IInputProvider.h b/Core/IInputProvider.h index d4dbab8..6f7f9d1 100644 --- a/Core/IInputProvider.h +++ b/Core/IInputProvider.h @@ -6,4 +6,4 @@ class IInputProvider { public: virtual bool SetInput(BaseControlDevice* device) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IInputRecorder.h b/Core/IInputRecorder.h index 3e7195d..866d94d 100644 --- a/Core/IInputRecorder.h +++ b/Core/IInputRecorder.h @@ -7,4 +7,4 @@ class IInputRecorder { public: virtual void RecordInput(vector> devices) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IKeyManager.h b/Core/IKeyManager.h index c9eed5b..0078078 100644 --- a/Core/IKeyManager.h +++ b/Core/IKeyManager.h @@ -23,7 +23,9 @@ struct MouseMovement class IKeyManager { public: - virtual ~IKeyManager() {} + virtual ~IKeyManager() + { + } virtual void RefreshState() = 0; virtual void UpdateDevices() = 0; @@ -36,4 +38,4 @@ public: virtual void SetKeyState(uint16_t scanCode, bool state) = 0; virtual void ResetKeyState() = 0; virtual void SetDisabled(bool disabled) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IMemoryHandler.h b/Core/IMemoryHandler.h index 63bb64f..a9ce13e 100644 --- a/Core/IMemoryHandler.h +++ b/Core/IMemoryHandler.h @@ -13,11 +13,13 @@ public: _memoryType = memType; } - virtual ~IMemoryHandler() {} + virtual ~IMemoryHandler() + { + } virtual uint8_t Read(uint32_t addr) = 0; virtual uint8_t Peek(uint32_t addr) = 0; - virtual void PeekBlock(uint32_t addr, uint8_t *output) = 0; + virtual void PeekBlock(uint32_t addr, uint8_t* output) = 0; virtual void Write(uint32_t addr, uint8_t value) = 0; __forceinline SnesMemoryType GetMemoryType() @@ -26,4 +28,4 @@ public: } virtual AddressInfo GetAbsoluteAddress(uint32_t address) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IMessageManager.h b/Core/IMessageManager.h index 1069a17..a37212c 100644 --- a/Core/IMessageManager.h +++ b/Core/IMessageManager.h @@ -21,7 +21,8 @@ private: uint64_t GetCurrentTime() { - return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + return std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()).count(); } public: @@ -38,7 +39,7 @@ public: return _title; } - string GetToastMessage() + string GetToastMessage() { return _message; } @@ -46,13 +47,20 @@ public: float GetOpacity() { uint64_t currentTime = GetCurrentTime(); - if(currentTime - _startTime < 200) { + if (currentTime - _startTime < 200) + { return (currentTime - _startTime) * 5.0f / 1000.0f; - } else if(_endTime - currentTime < 200) { + } + else if (_endTime - currentTime < 200) + { return (_endTime - currentTime) * 5.0f / 1000.0f; - } else if(currentTime >= _endTime) { + } + else if (currentTime >= _endTime) + { return 0.0f; - } else { + } + else + { return 1.0f; } } @@ -61,4 +69,4 @@ public: { return _endTime < GetCurrentTime(); } -}; \ No newline at end of file +}; diff --git a/Core/INotificationListener.h b/Core/INotificationListener.h index 21bcbbc..d2e7fad 100644 --- a/Core/INotificationListener.h +++ b/Core/INotificationListener.h @@ -26,4 +26,4 @@ class INotificationListener { public: virtual void ProcessNotification(ConsoleNotificationType type, void* parameter) = 0; -}; \ No newline at end of file +}; diff --git a/Core/IRenderingDevice.h b/Core/IRenderingDevice.h index a8612ea..0c0559c 100644 --- a/Core/IRenderingDevice.h +++ b/Core/IRenderingDevice.h @@ -4,10 +4,14 @@ class IRenderingDevice { - public: - virtual ~IRenderingDevice() {} - virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) = 0; - virtual void Render() = 0; - virtual void Reset() = 0; - virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = 0; -}; \ No newline at end of file +public: + virtual ~IRenderingDevice() + { + } + + virtual void UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height) = 0; + virtual void Render() = 0; + virtual void Reset() = 0; + virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = + 0; +}; diff --git a/Core/InputDataMessage.h b/Core/InputDataMessage.h index 4957bf5..9bc4da9 100644 --- a/Core/InputDataMessage.h +++ b/Core/InputDataMessage.h @@ -8,14 +8,16 @@ class InputDataMessage : public NetMessage private: ControlDeviceState _inputState; -protected: - void Serialize(Serializer &s) override +protected: + void Serialize(Serializer& s) override { s.StreamVector(_inputState.State); } public: - InputDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + InputDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } InputDataMessage(ControlDeviceState inputState) : NetMessage(MessageType::InputData) { @@ -26,4 +28,4 @@ public: { return _inputState; } -}; \ No newline at end of file +}; diff --git a/Core/InputHud.cpp b/Core/InputHud.cpp index 93224c1..e70879a 100644 --- a/Core/InputHud.cpp +++ b/Core/InputHud.cpp @@ -10,7 +10,7 @@ #include "DebugHud.h" #include "ControlManager.h" -static constexpr int color[2] = { 0x00111111, 0x00FFFFFF }; +static constexpr int color[2] = {0x00111111, 0x00FFFFFF}; InputHud::InputHud(Console* console) { @@ -19,71 +19,83 @@ InputHud::InputHud(Console* console) void InputHud::DrawController(int port, ControlDeviceState state, int x, int y, int frameNumber) { - SnesController controller(_console, 0, KeyMappingSet()); controller.SetRawState(state); shared_ptr hud = _console->GetDebugHud(); hud->DrawRectangle(0 + x, 0 + y, 35, 14, 0x80CCCCCC, true, 1, frameNumber); hud->DrawRectangle(0 + x, 0 + y, 35, 14, color[0], false, 1, frameNumber); - hud->DrawRectangle(5 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Up)], true, 1, frameNumber); - hud->DrawRectangle(5 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Down)], true, 1, frameNumber); - hud->DrawRectangle(2 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Left)], true, 1, frameNumber); - hud->DrawRectangle(8 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Right)], true, 1, frameNumber); + hud->DrawRectangle(5 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Up)], true, 1, + frameNumber); + hud->DrawRectangle(5 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Down)], true, 1, + frameNumber); + hud->DrawRectangle(2 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Left)], true, 1, + frameNumber); + hud->DrawRectangle(8 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Right)], true, 1, + frameNumber); hud->DrawRectangle(5 + x, 6 + y, 3, 3, color[0], true, 1, frameNumber); - hud->DrawRectangle(27 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::X)], true, 1, frameNumber); - hud->DrawRectangle(27 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::B)], true, 1, frameNumber); - hud->DrawRectangle(30 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::A)], true, 1, frameNumber); - hud->DrawRectangle(24 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Y)], true, 1, frameNumber); + hud->DrawRectangle(27 + x, 3 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::X)], true, 1, + frameNumber); + hud->DrawRectangle(27 + x, 9 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::B)], true, 1, + frameNumber); + hud->DrawRectangle(30 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::A)], true, 1, + frameNumber); + hud->DrawRectangle(24 + x, 6 + y, 3, 3, color[controller.IsPressed(SnesController::Buttons::Y)], true, 1, + frameNumber); - hud->DrawRectangle(4 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::L)], true, 1, frameNumber); - hud->DrawRectangle(26 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::R)], true, 1, frameNumber); + hud->DrawRectangle(4 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::L)], true, 1, + frameNumber); + hud->DrawRectangle(26 + x, 0 + y, 5, 2, color[controller.IsPressed(SnesController::Buttons::R)], true, 1, + frameNumber); - hud->DrawRectangle(13 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Select)], true, 1, frameNumber); - hud->DrawRectangle(18 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Start)], true, 1, frameNumber); + hud->DrawRectangle(13 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Select)], true, 1, + frameNumber); + hud->DrawRectangle(18 + x, 9 + y, 4, 2, color[controller.IsPressed(SnesController::Buttons::Start)], true, 1, + frameNumber); - switch(port) { - case 0: - //1 - hud->DrawLine(17 + x, 2 + y, 17 + x, 6 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); - break; + switch (port) + { + case 0: + //1 + hud->DrawLine(17 + x, 2 + y, 17 + x, 6 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); + break; - case 1: - //2 - hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawPixel(16 + x, 5 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - break; + case 1: + //2 + hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawPixel(16 + x, 5 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + break; - case 2: - //3 - hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - break; + case 2: + //3 + hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 3 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + break; - case 3: - //4 - hud->DrawLine(16 + x, 2 + y, 16 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawLine(18 + x, 2 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - break; + case 3: + //4 + hud->DrawLine(16 + x, 2 + y, 16 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawLine(18 + x, 2 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + break; - case 4: - //5 - hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); - hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); - hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); - hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); - break; + case 4: + //5 + hud->DrawLine(16 + x, 2 + y, 18 + x, 2 + y, color[0], 1, frameNumber); + hud->DrawPixel(16 + x, 3 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 4 + y, 18 + x, 4 + y, color[0], 1, frameNumber); + hud->DrawPixel(18 + x, 5 + y, color[0], 1, frameNumber); + hud->DrawLine(16 + x, 6 + y, 18 + x, 6 + y, color[0], 1, frameNumber); + break; } } @@ -97,66 +109,80 @@ void InputHud::DrawControllers(OverscanDimensions overscan, int frameNumber) int xOffset = cfg.DisplayInputHorizontally ? 38 : 0; int yOffset = cfg.DisplayInputHorizontally ? 0 : 16; - switch(cfg.DisplayInputPosition) { - default: - case InputDisplayPosition::TopLeft: - xStart = overscan.Left + 3; - yStart = overscan.Top + 3; - break; - case InputDisplayPosition::TopRight: - xStart = 256 - overscan.Right - 38; - yStart = overscan.Top + 3; - xOffset = -xOffset; - break; - case InputDisplayPosition::BottomLeft: - xStart = overscan.Left + 3; - yStart = 240 - overscan.Bottom - 18; - yOffset = -yOffset; - break; - case InputDisplayPosition::BottomRight: - xStart = 256 - overscan.Right - 38; - yStart = 240 - overscan.Bottom - 18; - xOffset = -xOffset; - yOffset = -yOffset; - break; + switch (cfg.DisplayInputPosition) + { + default: + case InputDisplayPosition::TopLeft: + xStart = overscan.Left + 3; + yStart = overscan.Top + 3; + break; + case InputDisplayPosition::TopRight: + xStart = 256 - overscan.Right - 38; + yStart = overscan.Top + 3; + xOffset = -xOffset; + break; + case InputDisplayPosition::BottomLeft: + xStart = overscan.Left + 3; + yStart = 240 - overscan.Bottom - 18; + yOffset = -yOffset; + break; + case InputDisplayPosition::BottomRight: + xStart = 256 - overscan.Right - 38; + yStart = 240 - overscan.Bottom - 18; + xOffset = -xOffset; + yOffset = -yOffset; + break; } - for(int i = 0; i < (int)controllerData.size(); i++) { - if(controllerData[i].Type == ControllerType::SnesController) { - if(cfg.DisplayInputPort[i]) { + for (int i = 0; i < (int)controllerData.size(); i++) + { + if (controllerData[i].Type == ControllerType::SnesController) + { + if (cfg.DisplayInputPort[i]) + { DrawController(i, controllerData[i].State, xStart, yStart, frameNumber); xStart += xOffset; yStart += yOffset; } - } else if(controllerData[i].Type == ControllerType::Multitap) { + } + else if (controllerData[i].Type == ControllerType::Multitap) + { uint64_t rawData = 0; - for(int j = (int)controllerData[i].State.State.size() - 1; j >= 0; j--) { + for (int j = (int)controllerData[i].State.State.size() - 1; j >= 0; j--) + { rawData <<= 8; rawData |= controllerData[i].State.State[j]; } ControlDeviceState controllers[4] = {}; - for(int j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) + { controllers[j].State.push_back(rawData & 0xFF); controllers[j].State.push_back((rawData >> 8) & 0x0F); rawData >>= 12; } - if(cfg.DisplayInputPort[i]) { + if (cfg.DisplayInputPort[i]) + { DrawController(i, controllers[0], xStart, yStart, frameNumber); xStart += xOffset; yStart += yOffset; } - for(int j = 1; j < 4; j++) { - if(cfg.DisplayInputPort[j + 1]) { + for (int j = 1; j < 4; j++) + { + if (cfg.DisplayInputPort[j + 1]) + { DrawController(j + 1, controllers[j], xStart, yStart, frameNumber); xStart += xOffset; yStart += yOffset; } } - } else if(controllerData[i].Type == ControllerType::SuperScope) { - if(cfg.DisplayInputPort[i]) { + } + else if (controllerData[i].Type == ControllerType::SuperScope) + { + if (cfg.DisplayInputPort[i]) + { SuperScope scope(_console, 0, KeyMappingSet()); scope.SetRawState(controllerData[i].State); MousePosition pos = scope.GetCoordinates(); @@ -165,16 +191,21 @@ void InputHud::DrawControllers(OverscanDimensions overscan, int frameNumber) hud->DrawRectangle(pos.X - 1, pos.Y - 1, 3, 3, 0x00111111, true, 1, frameNumber); hud->DrawRectangle(pos.X - 1, pos.Y - 1, 3, 3, 0x80CCCCCC, false, 1, frameNumber); } - } else if(controllerData[i].Type == ControllerType::SnesMouse) { - if(cfg.DisplayInputPort[i]) { + } + else if (controllerData[i].Type == ControllerType::SnesMouse) + { + if (cfg.DisplayInputPort[i]) + { SnesMouse mouse(_console, 0); mouse.SetRawState(controllerData[i].State); shared_ptr hud = _console->GetDebugHud(); hud->DrawRectangle(xStart + 12, yStart, 11, 14, 0x00AAAAAA, true, 1, frameNumber); hud->DrawRectangle(xStart + 12, yStart, 11, 14, color[0], false, 1, frameNumber); - hud->DrawRectangle(xStart + 13, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Left)], true, 1, frameNumber); - hud->DrawRectangle(xStart + 18, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Right)], true, 1, frameNumber); + hud->DrawRectangle(xStart + 13, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Left)], true, 1, + frameNumber); + hud->DrawRectangle(xStart + 18, yStart + 1, 4, 5, color[mouse.IsPressed(SnesMouse::Buttons::Right)], true, + 1, frameNumber); xStart += xOffset; yStart += yOffset; diff --git a/Core/InputHud.h b/Core/InputHud.h index fb3f2e0..acb793f 100644 --- a/Core/InputHud.h +++ b/Core/InputHud.h @@ -13,7 +13,7 @@ private: void DrawController(int port, ControlDeviceState state, int x, int y, int frameNumber); public: - InputHud(Console *console); + InputHud(Console* console); void DrawControllers(OverscanDimensions overscan, int frameNumber); -}; \ No newline at end of file +}; diff --git a/Core/InternalRegisters.cpp b/Core/InternalRegisters.cpp index 0cb41b2..5550274 100644 --- a/Core/InternalRegisters.cpp +++ b/Core/InternalRegisters.cpp @@ -44,7 +44,8 @@ void InternalRegisters::Reset() void InternalRegisters::ProcessAutoJoypadRead() { - if(!_state.EnableAutoJoypadRead) { + if (!_state.EnableAutoJoypadRead) + { return; } @@ -53,11 +54,13 @@ void InternalRegisters::ProcessAutoJoypadRead() controlManager->Write(0x4016, 1); controlManager->Write(0x4016, 0); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _state.ControllerData[i] = 0; } - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { uint8_t port1 = controlManager->Read(0x4016); uint8_t port2 = controlManager->Read(0x4017); @@ -86,142 +89,156 @@ void InternalRegisters::SetNmiFlag(bool nmiFlag) void InternalRegisters::SetIrqFlag(bool irqFlag) { _irqFlag = irqFlag && (_state.EnableHorizontalIrq || _state.EnableVerticalIrq); - if(_irqFlag) { + if (_irqFlag) + { _cpu->SetIrqSource(IrqSource::Ppu); - } else { + } + else + { _cpu->ClearIrqSource(IrqSource::Ppu); } } uint8_t InternalRegisters::Peek(uint16_t addr) { - switch(addr) { - case 0x4210: return (_nmiFlag ? 0x80 : 0) | 0x02; - case 0x4211: return (_irqFlag ? 0x80 : 0); - default: return Read(addr); + switch (addr) + { + case 0x4210: return (_nmiFlag ? 0x80 : 0) | 0x02; + case 0x4211: return (_irqFlag ? 0x80 : 0); + default: return Read(addr); } } uint8_t InternalRegisters::Read(uint16_t addr) { - switch(addr) { - case 0x4210: { + switch (addr) + { + case 0x4210: + { constexpr uint8_t cpuRevision = 0x02; - + uint8_t value = (_nmiFlag ? 0x80 : 0) | cpuRevision; //Reading $4210 on any cycle turns the NMI signal off (except presumably on the first PPU cycle (first 4 master clocks) of the NMI scanline.) //i.e: reading $4210 at the same it gets set will return it as set, and will keep it set. //Without this, Terranigma has corrupted sprites on some frames. - if(_memoryManager->GetHClock() >= 4 || _ppu->GetScanline() != _ppu->GetNmiScanline()) { + if (_memoryManager->GetHClock() >= 4 || _ppu->GetScanline() != _ppu->GetNmiScanline()) + { SetNmiFlag(false); } return value | (_memoryManager->GetOpenBus() & 0x70); } - case 0x4211: { + case 0x4211: + { uint8_t value = (_irqFlag ? 0x80 : 0); SetIrqFlag(false); return value | (_memoryManager->GetOpenBus() & 0x7F); } - case 0x4212: { + case 0x4212: + { uint16_t hClock = _memoryManager->GetHClock(); uint16_t scanline = _ppu->GetScanline(); uint16_t nmiScanline = _ppu->GetNmiScanline(); //TODO TIMING (set/clear timing) return ( (scanline >= nmiScanline ? 0x80 : 0) | - ((hClock >= 1*4 && hClock <= 274*4) ? 0 : 0x40) | - ((_state.EnableAutoJoypadRead && scanline >= nmiScanline && scanline <= nmiScanline + 2) ? 0x01 : 0) | //Auto joypad read in progress + ((hClock >= 1 * 4 && hClock <= 274 * 4) ? 0 : 0x40) | + ((_state.EnableAutoJoypadRead && scanline >= nmiScanline && scanline <= nmiScanline + 2) ? 0x01 : 0) | + //Auto joypad read in progress (_memoryManager->GetOpenBus() & 0x3E) ); } - case 0x4213: - //TODO RDIO - Programmable I/O port (in-port) - return 0; - - case 0x4214: - case 0x4215: - case 0x4216: - case 0x4217: - return _aluMulDiv.Read(addr); + case 0x4213: + //TODO RDIO - Programmable I/O port (in-port) + return 0; - case 0x4218: return (uint8_t)_state.ControllerData[0]; - case 0x4219: return (uint8_t)(_state.ControllerData[0] >> 8); - case 0x421A: return (uint8_t)_state.ControllerData[1]; - case 0x421B: return (uint8_t)(_state.ControllerData[1] >> 8); - case 0x421C: return (uint8_t)_state.ControllerData[2]; - case 0x421D: return (uint8_t)(_state.ControllerData[2] >> 8); - case 0x421E: return (uint8_t)_state.ControllerData[3]; - case 0x421F: return (uint8_t)(_state.ControllerData[3] >> 8); - - default: - LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); - return _memoryManager->GetOpenBus(); + case 0x4214: + case 0x4215: + case 0x4216: + case 0x4217: + return _aluMulDiv.Read(addr); + + case 0x4218: return (uint8_t)_state.ControllerData[0]; + case 0x4219: return (uint8_t)(_state.ControllerData[0] >> 8); + case 0x421A: return (uint8_t)_state.ControllerData[1]; + case 0x421B: return (uint8_t)(_state.ControllerData[1] >> 8); + case 0x421C: return (uint8_t)_state.ControllerData[2]; + case 0x421D: return (uint8_t)(_state.ControllerData[2] >> 8); + case 0x421E: return (uint8_t)_state.ControllerData[3]; + case 0x421F: return (uint8_t)(_state.ControllerData[3] >> 8); + + default: + LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); + return _memoryManager->GetOpenBus(); } } void InternalRegisters::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x4200: - _state.EnableNmi = (value & 0x80) != 0; - _state.EnableVerticalIrq = (value & 0x20) != 0; - _state.EnableHorizontalIrq = (value & 0x10) != 0; - _state.EnableAutoJoypadRead = (value & 0x01) != 0; - - SetNmiFlag(_nmiFlag); - SetIrqFlag(_irqFlag); - break; + switch (addr) + { + case 0x4200: + _state.EnableNmi = (value & 0x80) != 0; + _state.EnableVerticalIrq = (value & 0x20) != 0; + _state.EnableHorizontalIrq = (value & 0x10) != 0; + _state.EnableAutoJoypadRead = (value & 0x01) != 0; - case 0x4201: - //TODO WRIO - Programmable I/O port (out-port) - if((_state.IoPortOutput & 0x80) && !(value & 0x80)) { - _ppu->LatchLocationValues(); - } - _state.IoPortOutput = value; - break; + SetNmiFlag(_nmiFlag); + SetIrqFlag(_irqFlag); + break; - case 0x4202: - case 0x4203: - case 0x4204: - case 0x4205: - case 0x4206: - _aluMulDiv.Write(addr, value); - break; + case 0x4201: + //TODO WRIO - Programmable I/O port (out-port) + if ((_state.IoPortOutput & 0x80) && !(value & 0x80)) + { + _ppu->LatchLocationValues(); + } + _state.IoPortOutput = value; + break; - case 0x4207: - _state.HorizontalTimer = (_state.HorizontalTimer & 0x100) | value; - ProcessIrqCounters(); - break; + case 0x4202: + case 0x4203: + case 0x4204: + case 0x4205: + case 0x4206: + _aluMulDiv.Write(addr, value); + break; - case 0x4208: - _state.HorizontalTimer = (_state.HorizontalTimer & 0xFF) | ((value & 0x01) << 8); - ProcessIrqCounters(); - break; + case 0x4207: + _state.HorizontalTimer = (_state.HorizontalTimer & 0x100) | value; + ProcessIrqCounters(); + break; - case 0x4209: - _state.VerticalTimer = (_state.VerticalTimer & 0x100) | value; + case 0x4208: + _state.HorizontalTimer = (_state.HorizontalTimer & 0xFF) | ((value & 0x01) << 8); + ProcessIrqCounters(); + break; - //Calling this here fixes flashing issue in "Shin Nihon Pro Wrestling Kounin - '95 Tokyo Dome Battle 7" - //The write to change from scanline 16 to 17 occurs between both ProcessIrqCounter calls, which causes the IRQ - //line to always be high (since the previous check is on scanline 16, and the next check on scanline 17) - ProcessIrqCounters(); - break; + case 0x4209: + _state.VerticalTimer = (_state.VerticalTimer & 0x100) | value; - case 0x420A: - _state.VerticalTimer = (_state.VerticalTimer & 0xFF) | ((value & 0x01) << 8); - ProcessIrqCounters(); - break; + //Calling this here fixes flashing issue in "Shin Nihon Pro Wrestling Kounin - '95 Tokyo Dome Battle 7" + //The write to change from scanline 16 to 17 occurs between both ProcessIrqCounter calls, which causes the IRQ + //line to always be high (since the previous check is on scanline 16, and the next check on scanline 17) + ProcessIrqCounters(); + break; - case 0x420D: _state.EnableFastRom = (value & 0x01) != 0; break; + case 0x420A: + _state.VerticalTimer = (_state.VerticalTimer & 0xFF) | ((value & 0x01) << 8); + ProcessIrqCounters(); + break; - default: - LogDebug("[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); - break; + case 0x420D: _state.EnableFastRom = (value & 0x01) != 0; + break; + + default: + LogDebug( + "[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); + break; } } @@ -235,11 +252,13 @@ AluState InternalRegisters::GetAluState() return _aluMulDiv.GetState(); } -void InternalRegisters::Serialize(Serializer &s) +void InternalRegisters::Serialize(Serializer& s) { s.Stream( - _state.EnableFastRom, _nmiFlag, _state.EnableNmi, _state.EnableHorizontalIrq, _state.EnableVerticalIrq, _state.HorizontalTimer, - _state.VerticalTimer, _state.IoPortOutput, _state.ControllerData[0], _state.ControllerData[1], _state.ControllerData[2], _state.ControllerData[3], + _state.EnableFastRom, _nmiFlag, _state.EnableNmi, _state.EnableHorizontalIrq, _state.EnableVerticalIrq, + _state.HorizontalTimer, + _state.VerticalTimer, _state.IoPortOutput, _state.ControllerData[0], _state.ControllerData[1], + _state.ControllerData[2], _state.ControllerData[3], _irqLevel, _needIrq, _state.EnableAutoJoypadRead, _irqFlag ); diff --git a/Core/InternalRegisters.h b/Core/InternalRegisters.h index 8831d43..e0aae85 100644 --- a/Core/InternalRegisters.h +++ b/Core/InternalRegisters.h @@ -24,7 +24,7 @@ private: bool _irqLevel = false; uint8_t _needIrq = 0; bool _irqFlag = false; - + void SetIrqFlag(bool irqFlag); public: @@ -46,7 +46,7 @@ public: bool IsFastRomEnabled() { return _state.EnableFastRom; } uint16_t GetHorizontalTimer() { return _state.HorizontalTimer; } uint16_t GetVerticalTimer() { return _state.VerticalTimer; } - + uint8_t Peek(uint16_t addr); uint8_t Read(uint16_t addr); void Write(uint16_t addr, uint8_t value); @@ -54,28 +54,32 @@ public: InternalRegisterState GetState(); AluState GetAluState(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; void InternalRegisters::ProcessIrqCounters() { - if(_needIrq > 0) { + if (_needIrq > 0) + { _needIrq--; - if(_needIrq == 0) { + if (_needIrq == 0) + { SetIrqFlag(true); } } bool irqLevel = ( (_state.EnableHorizontalIrq || _state.EnableVerticalIrq) && - (!_state.EnableHorizontalIrq || (_state.HorizontalTimer <= 339 && (_ppu->GetCycle() == _state.HorizontalTimer) && (_ppu->GetLastScanline() != _ppu->GetRealScanline() || _state.HorizontalTimer < 339))) && + (!_state.EnableHorizontalIrq || (_state.HorizontalTimer <= 339 && (_ppu->GetCycle() == _state.HorizontalTimer) && + (_ppu->GetLastScanline() != _ppu->GetRealScanline() || _state.HorizontalTimer < 339))) && (!_state.EnableVerticalIrq || _ppu->GetRealScanline() == _state.VerticalTimer) ); - if(!_irqLevel && irqLevel) { + if (!_irqLevel && irqLevel) + { //Trigger IRQ signal 16 master clocks later _needIrq = 4; } _irqLevel = irqLevel; _cpu->SetNmiFlag(_state.EnableNmi & _nmiFlag); -} \ No newline at end of file +} diff --git a/Core/KeyManager.cpp b/Core/KeyManager.cpp index 13ea23f..7b8c6f1 100644 --- a/Core/KeyManager.cpp +++ b/Core/KeyManager.cpp @@ -6,7 +6,7 @@ #include "VideoDecoder.h" IKeyManager* KeyManager::_keyManager = nullptr; -MousePosition KeyManager::_mousePosition = { 0, 0 }; +MousePosition KeyManager::_mousePosition = {0, 0}; atomic KeyManager::_xMouseMovement; atomic KeyManager::_yMouseMovement; EmuSettings* KeyManager::_settings = nullptr; @@ -20,19 +20,21 @@ void KeyManager::RegisterKeyManager(IKeyManager* keyManager) void KeyManager::RefreshKeyState() { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->RefreshState(); } } -void KeyManager::SetSettings(EmuSettings *settings) +void KeyManager::SetSettings(EmuSettings* settings) { _settings = settings; } bool KeyManager::IsKeyPressed(uint32_t keyCode) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _settings->IsInputEnabled() && _keyManager->IsKeyPressed(keyCode); } return false; @@ -40,7 +42,8 @@ bool KeyManager::IsKeyPressed(uint32_t keyCode) bool KeyManager::IsMouseButtonPressed(MouseButton button) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _settings->IsInputEnabled() && _keyManager->IsMouseButtonPressed(button); } return false; @@ -48,7 +51,8 @@ bool KeyManager::IsMouseButtonPressed(MouseButton button) vector KeyManager::GetPressedKeys() { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->GetPressedKeys(); } return vector(); @@ -56,7 +60,8 @@ vector KeyManager::GetPressedKeys() string KeyManager::GetKeyName(uint32_t keyCode) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->GetKeyName(keyCode); } return ""; @@ -64,7 +69,8 @@ string KeyManager::GetKeyName(uint32_t keyCode) uint32_t KeyManager::GetKeyCode(string keyName) { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { return _keyManager->GetKeyCode(keyName); } return 0; @@ -72,7 +78,8 @@ uint32_t KeyManager::GetKeyCode(string keyName) void KeyManager::UpdateDevices() { - if(_keyManager != nullptr) { + if (_keyManager != nullptr) + { _keyManager->UpdateDevices(); } } @@ -97,18 +104,21 @@ MouseMovement KeyManager::GetMouseMovement(double videoScale, double mouseSensit void KeyManager::SetMousePosition(shared_ptr console, double x, double y) { - if(x < 0 || y < 0) { + if (x < 0 || y < 0) + { _mousePosition.X = -1; _mousePosition.Y = -1; - } else { + } + else + { OverscanDimensions overscan = console->GetSettings()->GetOverscan(); ScreenSize size = console->GetVideoDecoder()->GetScreenSize(true); - _mousePosition.X = (int32_t)(x*size.Width + overscan.Left); - _mousePosition.Y = (int32_t)(y*size.Height + overscan.Top); + _mousePosition.X = (int32_t)(x * size.Width + overscan.Left); + _mousePosition.Y = (int32_t)(y * size.Height + overscan.Top); } } MousePosition KeyManager::GetMousePosition() { return _mousePosition; -} \ No newline at end of file +} diff --git a/Core/KeyManager.h b/Core/KeyManager.h index 8a6450f..eb6ca12 100644 --- a/Core/KeyManager.h +++ b/Core/KeyManager.h @@ -26,10 +26,10 @@ public: static uint32_t GetKeyCode(string keyName); static void UpdateDevices(); - + static void SetMouseMovement(int16_t x, int16_t y); static MouseMovement GetMouseMovement(double videoScale, double mouseSensitivity); - + static void SetMousePosition(shared_ptr console, double x, double y); static MousePosition GetMousePosition(); -}; \ No newline at end of file +}; diff --git a/Core/LabelManager.cpp b/Core/LabelManager.cpp index 3f10cbb..bdce85a 100644 --- a/Core/LabelManager.cpp +++ b/Core/LabelManager.cpp @@ -4,7 +4,7 @@ #include "DebugUtilities.h" #include "DebugBreakHelper.h" -LabelManager::LabelManager(Debugger *debugger) +LabelManager::LabelManager(Debugger* debugger) { _debugger = debugger; } @@ -22,13 +22,16 @@ void LabelManager::SetLabel(uint32_t address, SnesMemoryType memType, string lab uint64_t key = GetLabelKey(address, memType); auto existingLabel = _codeLabels.find(key); - if(existingLabel != _codeLabels.end()) { + if (existingLabel != _codeLabels.end()) + { _codeLabelReverseLookup.erase(existingLabel->second.Label); } _codeLabels.erase(key); - if(!label.empty() || !comment.empty()) { - if(label.size() > 400) { + if (!label.empty() || !comment.empty()) + { + if (label.size() > 400) + { //Restrict labels to 400 bytes label = label.substr(0, 400); } @@ -44,48 +47,67 @@ void LabelManager::SetLabel(uint32_t address, SnesMemoryType memType, string lab int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType) { - switch(memType) { - case SnesMemoryType::PrgRom: return absoluteAddr | ((uint64_t)1 << 32); - case SnesMemoryType::WorkRam: return absoluteAddr | ((uint64_t)2 << 32); - case SnesMemoryType::SaveRam: return absoluteAddr | ((uint64_t)3 << 32); - case SnesMemoryType::Register: return absoluteAddr | ((uint64_t)4 << 32); - case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32); - case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32); - case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32); - case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32); - case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32); - case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32); - case SnesMemoryType::DspProgramRom: return absoluteAddr | ((uint64_t)11 << 32); - case SnesMemoryType::GbPrgRom: return absoluteAddr | ((uint64_t)12 << 32); - case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32); - case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32); - case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32); - case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32); - case SnesMemoryType::GameboyMemory: return absoluteAddr | ((uint64_t)17 << 32); - default: return -1; + switch (memType) + { + case SnesMemoryType::PrgRom: return absoluteAddr | ((uint64_t)1 << 32); + case SnesMemoryType::WorkRam: return absoluteAddr | ((uint64_t)2 << 32); + case SnesMemoryType::SaveRam: return absoluteAddr | ((uint64_t)3 << 32); + case SnesMemoryType::Register: return absoluteAddr | ((uint64_t)4 << 32); + case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32); + case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32); + case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32); + case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32); + case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32); + case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32); + case SnesMemoryType::DspProgramRom: return absoluteAddr | ((uint64_t)11 << 32); + case SnesMemoryType::GbPrgRom: return absoluteAddr | ((uint64_t)12 << 32); + case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32); + case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32); + case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32); + case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32); + case SnesMemoryType::GameboyMemory: return absoluteAddr | ((uint64_t)17 << 32); + default: return -1; } } SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key) { - switch(key & ~(uint64_t)0xFFFFFFFF) { - case ((uint64_t)1 << 32): return SnesMemoryType::PrgRom; break; - case ((uint64_t)2 << 32): return SnesMemoryType::WorkRam; break; - case ((uint64_t)3 << 32): return SnesMemoryType::SaveRam; break; - case ((uint64_t)4 << 32): return SnesMemoryType::Register; break; - case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; break; - case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; break; - case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; break; - case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; break; - case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; break; - case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; break; - case ((uint64_t)11 << 32): return SnesMemoryType::DspProgramRom; break; - case ((uint64_t)12 << 32): return SnesMemoryType::GbPrgRom; break; - case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; break; - case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; break; - case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; break; - case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; break; - case ((uint64_t)17 << 32): return SnesMemoryType::GameboyMemory; break; + switch (key & ~(uint64_t)0xFFFFFFFF) + { + case ((uint64_t)1 << 32): return SnesMemoryType::PrgRom; + break; + case ((uint64_t)2 << 32): return SnesMemoryType::WorkRam; + break; + case ((uint64_t)3 << 32): return SnesMemoryType::SaveRam; + break; + case ((uint64_t)4 << 32): return SnesMemoryType::Register; + break; + case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; + break; + case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; + break; + case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; + break; + case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; + break; + case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; + break; + case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; + break; + case ((uint64_t)11 << 32): return SnesMemoryType::DspProgramRom; + break; + case ((uint64_t)12 << 32): return SnesMemoryType::GbPrgRom; + break; + case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; + break; + case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; + break; + case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; + break; + case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; + break; + case ((uint64_t)17 << 32): return SnesMemoryType::GameboyMemory; + break; } throw std::runtime_error("Invalid label key"); @@ -93,30 +115,36 @@ SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key) string LabelManager::GetLabel(AddressInfo address) { - string label ; - if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { - if(address.Type == SnesMemoryType::GameboyMemory) { + string label; + if (address.Type <= DebugUtilities::GetLastCpuMemoryType()) + { + if (address.Type == SnesMemoryType::GameboyMemory) + { //Labels for GB registers - if(InternalGetLabel(address, label)) { + if (InternalGetLabel(address, label)) + { return label; } } address = _debugger->GetAbsoluteAddress(address); } - if(address.Address >= 0) { + if (address.Address >= 0) + { InternalGetLabel(address, label); } return label; } -bool LabelManager::InternalGetLabel(AddressInfo address, string &label) +bool LabelManager::InternalGetLabel(AddressInfo address, string& label) { int64_t key = GetLabelKey(address.Address, address.Type); - if(key >= 0) { + if (key >= 0) + { auto result = _codeLabels.find(key); - if(result != _codeLabels.end()) { + if (result != _codeLabels.end()) + { label = result->second.Label; return true; } @@ -128,9 +156,11 @@ string LabelManager::GetComment(AddressInfo absAddress) { uint64_t key = GetLabelKey(absAddress.Address, absAddress.Type); - if(key >= 0) { + if (key >= 0) + { auto result = _codeLabels.find(key); - if(result != _codeLabels.end()) { + if (result != _codeLabels.end()) + { return result->second.Comment; } } @@ -138,18 +168,22 @@ string LabelManager::GetComment(AddressInfo absAddress) return ""; } -bool LabelManager::GetLabelAndComment(AddressInfo address, LabelInfo &labelInfo) +bool LabelManager::GetLabelAndComment(AddressInfo address, LabelInfo& labelInfo) { - if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { + if (address.Type <= DebugUtilities::GetLastCpuMemoryType()) + { address = _debugger->GetAbsoluteAddress(address); } - if(address.Address >= 0) { + if (address.Address >= 0) + { int64_t key = GetLabelKey(address.Address, address.Type); - if(key >= 0) { + if (key >= 0) + { auto result = _codeLabels.find(key); - if(result != _codeLabels.end()) { + if (result != _codeLabels.end()) + { labelInfo = result->second; return true; } @@ -158,19 +192,21 @@ bool LabelManager::GetLabelAndComment(AddressInfo address, LabelInfo &labelInfo) return false; } -bool LabelManager::ContainsLabel(string &label) +bool LabelManager::ContainsLabel(string& label) { return _codeLabelReverseLookup.find(label) != _codeLabelReverseLookup.end(); } -int32_t LabelManager::GetLabelRelativeAddress(string &label, CpuType cpuType) +int32_t LabelManager::GetLabelRelativeAddress(string& label, CpuType cpuType) { auto result = _codeLabelReverseLookup.find(label); - if(result != _codeLabelReverseLookup.end()) { + if (result != _codeLabelReverseLookup.end()) + { uint64_t key = result->second; SnesMemoryType type = GetKeyMemoryType(key); - AddressInfo addr { (int32_t)(key & 0xFFFFFFFF), type }; - if(type <= DebugUtilities::GetLastCpuMemoryType()) { + AddressInfo addr{(int32_t)(key & 0xFFFFFFFF), type}; + if (type <= DebugUtilities::GetLastCpuMemoryType()) + { return addr.Address; } return _debugger->GetRelativeAddress(addr, cpuType).Address; @@ -181,13 +217,16 @@ int32_t LabelManager::GetLabelRelativeAddress(string &label, CpuType cpuType) bool LabelManager::HasLabelOrComment(AddressInfo address) { - if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { + if (address.Type <= DebugUtilities::GetLastCpuMemoryType()) + { address = _debugger->GetAbsoluteAddress(address); } - if(address.Address >= 0) { + if (address.Address >= 0) + { uint64_t key = GetLabelKey(address.Address, address.Type); - if(key >= 0) { + if (key >= 0) + { return _codeLabels.find(key) != _codeLabels.end(); } } diff --git a/Core/LabelManager.h b/Core/LabelManager.h index cf7a3df..a55dd3d 100644 --- a/Core/LabelManager.h +++ b/Core/LabelManager.h @@ -28,25 +28,25 @@ private: unordered_map _codeLabels; unordered_map _codeLabelReverseLookup; - Debugger *_debugger; + Debugger* _debugger; int64_t GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType); SnesMemoryType GetKeyMemoryType(uint64_t key); bool InternalGetLabel(AddressInfo address, string& label); public: - LabelManager(Debugger *debugger); + LabelManager(Debugger* debugger); void SetLabel(uint32_t address, SnesMemoryType memType, string label, string comment); void ClearLabels(); - int32_t GetLabelRelativeAddress(string &label, CpuType cpuType = CpuType::Cpu); + int32_t GetLabelRelativeAddress(string& label, CpuType cpuType = CpuType::Cpu); string GetLabel(AddressInfo address); string GetComment(AddressInfo absAddress); - bool GetLabelAndComment(AddressInfo address, LabelInfo &label); + bool GetLabelAndComment(AddressInfo address, LabelInfo& label); - bool ContainsLabel(string &label); + bool ContainsLabel(string& label); bool HasLabelOrComment(AddressInfo address); }; diff --git a/Core/LuaApi.cpp b/Core/LuaApi.cpp index 725a40c..1e3def8 100644 --- a/Core/LuaApi.cpp +++ b/Core/LuaApi.cpp @@ -57,45 +57,45 @@ void LuaApi::SetContext(ScriptingContext* context) _ppu = _console->GetPpu().get(); } -int LuaApi::GetLibrary(lua_State *lua) +int LuaApi::GetLibrary(lua_State* lua) { static const luaL_Reg apilib[] = { - { "read", LuaApi::ReadMemory }, - { "write", LuaApi::WriteMemory }, - { "readWord", LuaApi::ReadMemoryWord }, - { "writeWord", LuaApi::WriteMemoryWord }, - { "getPrgRomOffset", LuaApi::GetPrgRomOffset }, - { "addMemoryCallback", LuaApi::RegisterMemoryCallback }, - { "removeMemoryCallback", LuaApi::UnregisterMemoryCallback }, - { "addEventCallback", LuaApi::RegisterEventCallback }, - { "removeEventCallback", LuaApi::UnregisterEventCallback }, - { "drawString", LuaApi::DrawString }, - { "drawPixel", LuaApi::DrawPixel }, - { "drawLine", LuaApi::DrawLine }, - { "drawRectangle", LuaApi::DrawRectangle }, - { "clearScreen", LuaApi::ClearScreen }, - { "getScreenBuffer", LuaApi::GetScreenBuffer }, - { "setScreenBuffer", LuaApi::SetScreenBuffer }, - { "getPixel", LuaApi::GetPixel }, - { "getMouseState", LuaApi::GetMouseState }, - { "log", LuaApi::Log }, - { "displayMessage", LuaApi::DisplayMessage }, - { "reset", LuaApi::Reset }, - { "breakExecution", LuaApi::Break }, - { "resume", LuaApi::Resume }, - { "execute", LuaApi::Execute }, - { "rewind", LuaApi::Rewind }, - { "takeScreenshot", LuaApi::TakeScreenshot }, - { "isKeyPressed", LuaApi::IsKeyPressed }, - { "getInput", LuaApi::GetInput }, - { "getAccessCounters", LuaApi::GetAccessCounters }, - { "resetAccessCounters", LuaApi::ResetAccessCounters }, - { "getState", LuaApi::GetState }, - { "getScriptDataFolder", LuaApi::GetScriptDataFolder }, - { "getRomInfo", LuaApi::GetRomInfo }, - { "getLogWindowLog", LuaApi::GetLogWindowLog }, - { "getLabelAddress", LuaApi::GetLabelAddress }, - { NULL,NULL } + {"read", LuaApi::ReadMemory}, + {"write", LuaApi::WriteMemory}, + {"readWord", LuaApi::ReadMemoryWord}, + {"writeWord", LuaApi::WriteMemoryWord}, + {"getPrgRomOffset", LuaApi::GetPrgRomOffset}, + {"addMemoryCallback", LuaApi::RegisterMemoryCallback}, + {"removeMemoryCallback", LuaApi::UnregisterMemoryCallback}, + {"addEventCallback", LuaApi::RegisterEventCallback}, + {"removeEventCallback", LuaApi::UnregisterEventCallback}, + {"drawString", LuaApi::DrawString}, + {"drawPixel", LuaApi::DrawPixel}, + {"drawLine", LuaApi::DrawLine}, + {"drawRectangle", LuaApi::DrawRectangle}, + {"clearScreen", LuaApi::ClearScreen}, + {"getScreenBuffer", LuaApi::GetScreenBuffer}, + {"setScreenBuffer", LuaApi::SetScreenBuffer}, + {"getPixel", LuaApi::GetPixel}, + {"getMouseState", LuaApi::GetMouseState}, + {"log", LuaApi::Log}, + {"displayMessage", LuaApi::DisplayMessage}, + {"reset", LuaApi::Reset}, + {"breakExecution", LuaApi::Break}, + {"resume", LuaApi::Resume}, + {"execute", LuaApi::Execute}, + {"rewind", LuaApi::Rewind}, + {"takeScreenshot", LuaApi::TakeScreenshot}, + {"isKeyPressed", LuaApi::IsKeyPressed}, + {"getInput", LuaApi::GetInput}, + {"getAccessCounters", LuaApi::GetAccessCounters}, + {"resetAccessCounters", LuaApi::ResetAccessCounters}, + {"getState", LuaApi::GetState}, + {"getScriptDataFolder", LuaApi::GetScriptDataFolder}, + {"getRomInfo", LuaApi::GetRomInfo}, + {"getLogWindowLog", LuaApi::GetLogWindowLog}, + {"getLabelAddress", LuaApi::GetLabelAddress}, + {NULL,NULL} }; luaL_newlib(lua, apilib); @@ -205,7 +205,7 @@ int LuaApi::GetLibrary(lua_State *lua) return 1; } -int LuaApi::GetLabelAddress(lua_State *lua) +int LuaApi::GetLabelAddress(lua_State* lua) { LuaCallHelper l(lua); string label = l.ReadString(); @@ -214,7 +214,8 @@ int LuaApi::GetLabelAddress(lua_State *lua) std::shared_ptr lblMan = _debugger->GetLabelManager(); int32_t value = lblMan->GetLabelRelativeAddress(label); - if(value == -2) { + if (value == -2) + { //Check to see if the label is a multi-byte label instead string mbLabel = label + "+0"; value = lblMan->GetLabelRelativeAddress(mbLabel); @@ -226,7 +227,7 @@ int LuaApi::GetLabelAddress(lua_State *lua) return l.ReturnCount(); } -int LuaApi::ReadMemory(lua_State *lua) +int LuaApi::ReadMemory(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(3); @@ -242,7 +243,7 @@ int LuaApi::ReadMemory(lua_State *lua) return l.ReturnCount(); } -int LuaApi::WriteMemory(lua_State *lua) +int LuaApi::WriteMemory(lua_State* lua) { LuaCallHelper l(lua); int type = l.ReadInteger(); @@ -257,7 +258,7 @@ int LuaApi::WriteMemory(lua_State *lua) return l.ReturnCount(); } -int LuaApi::ReadMemoryWord(lua_State *lua) +int LuaApi::ReadMemoryWord(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(3); @@ -273,7 +274,7 @@ int LuaApi::ReadMemoryWord(lua_State *lua) return l.ReturnCount(); } -int LuaApi::WriteMemoryWord(lua_State *lua) +int LuaApi::WriteMemoryWord(lua_State* lua) { LuaCallHelper l(lua); int type = l.ReadInteger(); @@ -288,20 +289,20 @@ int LuaApi::WriteMemoryWord(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetPrgRomOffset(lua_State *lua) +int LuaApi::GetPrgRomOffset(lua_State* lua) { LuaCallHelper l(lua); int address = l.ReadInteger(); checkminparams(1); errorCond(address < 0 || address > 0xFFFF, "address must be between 0 and $FFFF"); - - AddressInfo relAddress { address, SnesMemoryType::CpuMemory }; + + AddressInfo relAddress{address, SnesMemoryType::CpuMemory}; int32_t prgRomOffset = _debugger->GetAbsoluteAddress(relAddress).Address; l.Return(prgRomOffset); return l.ReturnCount(); } -int LuaApi::RegisterMemoryCallback(lua_State *lua) +int LuaApi::RegisterMemoryCallback(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(5); @@ -312,21 +313,25 @@ int LuaApi::RegisterMemoryCallback(lua_State *lua) int reference = l.GetReference(); checkminparams(3); - if(endAddr == -1) { + if (endAddr == -1) + { endAddr = startAddr; } errorCond(startAddr > endAddr, "start address must be <= end address"); - errorCond(callbackType < CallbackType::CpuRead || callbackType > CallbackType::CpuExec, "the specified type is invalid"); + errorCond(callbackType < CallbackType::CpuRead || callbackType > CallbackType::CpuExec, + "the specified type is invalid"); errorCond(cpuType < CpuType::Cpu || cpuType > CpuType::Gameboy, "the cpu type is invalid"); errorCond(reference == LUA_NOREF, "the specified function could not be found"); _context->RegisterMemoryCallback(callbackType, startAddr, endAddr, cpuType, reference); - _context->Log("Registered memory callback from $" + HexUtilities::ToHex((uint32_t)startAddr) + " to $" + HexUtilities::ToHex((uint32_t)endAddr)); + _context->Log( + "Registered memory callback from $" + HexUtilities::ToHex((uint32_t)startAddr) + " to $" + HexUtilities::ToHex( + (uint32_t)endAddr)); l.Return(reference); return l.ReturnCount(); } -int LuaApi::UnregisterMemoryCallback(lua_State *lua) +int LuaApi::UnregisterMemoryCallback(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(5); @@ -339,7 +344,8 @@ int LuaApi::UnregisterMemoryCallback(lua_State *lua) checkminparams(3); - if(endAddr == -1) { + if (endAddr == -1) + { endAddr = startAddr; } @@ -350,7 +356,7 @@ int LuaApi::UnregisterMemoryCallback(lua_State *lua) return l.ReturnCount(); } -int LuaApi::RegisterEventCallback(lua_State *lua) +int LuaApi::RegisterEventCallback(lua_State* lua) { LuaCallHelper l(lua); EventType type = (EventType)l.ReadInteger(); @@ -363,7 +369,7 @@ int LuaApi::RegisterEventCallback(lua_State *lua) return l.ReturnCount(); } -int LuaApi::UnregisterEventCallback(lua_State *lua) +int LuaApi::UnregisterEventCallback(lua_State* lua) { LuaCallHelper l(lua); EventType type = (EventType)l.ReadInteger(); @@ -375,7 +381,7 @@ int LuaApi::UnregisterEventCallback(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawString(lua_State *lua) +int LuaApi::DrawString(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(7); @@ -394,7 +400,7 @@ int LuaApi::DrawString(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawLine(lua_State *lua) +int LuaApi::DrawLine(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(7); @@ -413,7 +419,7 @@ int LuaApi::DrawLine(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawPixel(lua_State *lua) +int LuaApi::DrawPixel(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(5); @@ -430,7 +436,7 @@ int LuaApi::DrawPixel(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DrawRectangle(lua_State *lua) +int LuaApi::DrawRectangle(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(8); @@ -450,7 +456,7 @@ int LuaApi::DrawRectangle(lua_State *lua) return l.ReturnCount(); } -int LuaApi::ClearScreen(lua_State *lua) +int LuaApi::ClearScreen(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -459,16 +465,20 @@ int LuaApi::ClearScreen(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetScreenBuffer(lua_State *lua) +int LuaApi::GetScreenBuffer(lua_State* lua) { LuaCallHelper l(lua); int multiplier = _ppu->IsHighResOutput() ? 2 : 1; lua_newtable(lua); - for(int y = 0; y < 239; y++) { - for(int x = 0; x < 256; x++) { - lua_pushinteger(lua, DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF); + for (int y = 0; y < 239; y++) + { + for (int x = 0; x < 256; x++) + { + lua_pushinteger( + lua, DefaultVideoFilter::ToArgb( + *(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF); lua_rawseti(lua, -2, (y << 8) + x); } } @@ -476,23 +486,24 @@ int LuaApi::GetScreenBuffer(lua_State *lua) return 1; } -int LuaApi::SetScreenBuffer(lua_State *lua) +int LuaApi::SetScreenBuffer(lua_State* lua) { LuaCallHelper l(lua); - uint32_t pixels[256*239] = {}; + uint32_t pixels[256 * 239] = {}; luaL_checktype(lua, 1, LUA_TTABLE); - for(int i = 0; i < 256*239; i++) { + for (int i = 0; i < 256 * 239; i++) + { lua_rawgeti(lua, 1, i); pixels[i] = l.ReadInteger() ^ 0xFF000000; } - + int startFrame = _console->GetFrameCount(); _console->GetDebugHud()->DrawScreenBuffer(pixels, startFrame); return l.ReturnCount(); } -int LuaApi::GetPixel(lua_State *lua) +int LuaApi::GetPixel(lua_State* lua) { LuaCallHelper l(lua); int y = l.ReadInteger(); @@ -503,11 +514,13 @@ int LuaApi::GetPixel(lua_State *lua) int multiplier = _ppu->IsHighResOutput() ? 2 : 1; //Ignores intensify & grayscale bits - l.Return(DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF); + l.Return( + DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & + 0xFFFFFF); return l.ReturnCount(); } -int LuaApi::GetMouseState(lua_State *lua) +int LuaApi::GetMouseState(lua_State* lua) { LuaCallHelper l(lua); MousePosition pos = KeyManager::GetMousePosition(); @@ -521,7 +534,7 @@ int LuaApi::GetMouseState(lua_State *lua) return 1; } -int LuaApi::Log(lua_State *lua) +int LuaApi::Log(lua_State* lua) { LuaCallHelper l(lua); string text = l.ReadString(); @@ -530,7 +543,7 @@ int LuaApi::Log(lua_State *lua) return l.ReturnCount(); } -int LuaApi::DisplayMessage(lua_State *lua) +int LuaApi::DisplayMessage(lua_State* lua) { LuaCallHelper l(lua); string text = l.ReadString(); @@ -540,7 +553,7 @@ int LuaApi::DisplayMessage(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Reset(lua_State *lua) +int LuaApi::Reset(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -549,7 +562,7 @@ int LuaApi::Reset(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Break(lua_State *lua) +int LuaApi::Break(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -558,7 +571,7 @@ int LuaApi::Break(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Resume(lua_State *lua) +int LuaApi::Resume(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -567,7 +580,7 @@ int LuaApi::Resume(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Execute(lua_State *lua) +int LuaApi::Execute(lua_State* lua) { LuaCallHelper l(lua); StepType type = (StepType)l.ReadInteger(); @@ -582,7 +595,7 @@ int LuaApi::Execute(lua_State *lua) return l.ReturnCount(); } -int LuaApi::Rewind(lua_State *lua) +int LuaApi::Rewind(lua_State* lua) { LuaCallHelper l(lua); int seconds = l.ReadInteger(); @@ -593,7 +606,7 @@ int LuaApi::Rewind(lua_State *lua) return l.ReturnCount(); } -int LuaApi::TakeScreenshot(lua_State *lua) +int LuaApi::TakeScreenshot(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -603,7 +616,7 @@ int LuaApi::TakeScreenshot(lua_State *lua) return l.ReturnCount(); } -int LuaApi::IsKeyPressed(lua_State *lua) +int LuaApi::IsKeyPressed(lua_State* lua) { LuaCallHelper l(lua); string keyName = l.ReadString(); @@ -614,14 +627,15 @@ int LuaApi::IsKeyPressed(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetInput(lua_State *lua) +int LuaApi::GetInput(lua_State* lua) { LuaCallHelper l(lua); int port = l.ReadInteger(); checkparams(); errorCond(port < 0 || port > 4, "Invalid port number - must be between 0 to 4"); - shared_ptr controller = std::dynamic_pointer_cast(_console->GetControlManager()->GetControlDevice(port)); + shared_ptr controller = std::dynamic_pointer_cast( + _console->GetControlManager()->GetControlDevice(port)); errorCond(controller == nullptr, "Input port must be connected to a standard controller"); lua_newtable(lua); @@ -640,7 +654,7 @@ int LuaApi::GetInput(lua_State *lua) return 1; } -int LuaApi::GetAccessCounters(lua_State *lua) +int LuaApi::GetAccessCounters(lua_State* lua) { LuaCallHelper l(lua); l.ForceParamCount(2); @@ -656,33 +670,37 @@ int LuaApi::GetAccessCounters(lua_State *lua) _debugger->GetMemoryAccessCounter()->GetAccessCounts(0, size, memoryType, counts.data()); lua_newtable(lua); - switch(operationType) { - default: - case MemoryOperationType::Read: - for(uint32_t i = 0; i < size; i++) { - lua_pushinteger(lua, counts[i].ReadCount); - lua_rawseti(lua, -2, i); - } - break; + switch (operationType) + { + default: + case MemoryOperationType::Read: + for (uint32_t i = 0; i < size; i++) + { + lua_pushinteger(lua, counts[i].ReadCount); + lua_rawseti(lua, -2, i); + } + break; - case MemoryOperationType::Write: - for(uint32_t i = 0; i < size; i++) { - lua_pushinteger(lua, counts[i].WriteCount); - lua_rawseti(lua, -2, i); - } - break; + case MemoryOperationType::Write: + for (uint32_t i = 0; i < size; i++) + { + lua_pushinteger(lua, counts[i].WriteCount); + lua_rawseti(lua, -2, i); + } + break; - case MemoryOperationType::ExecOpCode: - for(uint32_t i = 0; i < size; i++) { - lua_pushinteger(lua, counts[i].ExecCount); - lua_rawseti(lua, -2, i); - } - break; + case MemoryOperationType::ExecOpCode: + for (uint32_t i = 0; i < size; i++) + { + lua_pushinteger(lua, counts[i].ExecCount); + lua_rawseti(lua, -2, i); + } + break; } return 1; } -int LuaApi::ResetAccessCounters(lua_State *lua) +int LuaApi::ResetAccessCounters(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -690,19 +708,20 @@ int LuaApi::ResetAccessCounters(lua_State *lua) return l.ReturnCount(); } -int LuaApi::GetScriptDataFolder(lua_State *lua) +int LuaApi::GetScriptDataFolder(lua_State* lua) { LuaCallHelper l(lua); checkparams(); string baseFolder = FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "LuaScriptData"); FolderUtilities::CreateFolder(baseFolder); - string scriptFolder = FolderUtilities::CombinePath(baseFolder, FolderUtilities::GetFilename(_context->GetScriptName(), false)); + string scriptFolder = FolderUtilities::CombinePath( + baseFolder, FolderUtilities::GetFilename(_context->GetScriptName(), false)); FolderUtilities::CreateFolder(scriptFolder); l.Return(scriptFolder); return l.ReturnCount(); } -int LuaApi::GetRomInfo(lua_State *lua) +int LuaApi::GetRomInfo(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -717,16 +736,16 @@ int LuaApi::GetRomInfo(lua_State *lua) return 1; } -int LuaApi::GetLogWindowLog(lua_State *lua) +int LuaApi::GetLogWindowLog(lua_State* lua) { LuaCallHelper l(lua); checkparams(); - + l.Return(MessageManager::GetLog()); return l.ReturnCount(); } -int LuaApi::GetState(lua_State *lua) +int LuaApi::GetState(lua_State* lua) { LuaCallHelper l(lua); checkparams(); @@ -759,9 +778,9 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(hClock, state.Ppu.HClock); lua_pushboolvalue(forcedVblank, state.Ppu.ForcedVblank); lua_pushintvalue(screenBrightness, state.Ppu.ScreenBrightness); - + lua_starttable("mode7"); - + lua_starttable("matrix"); lua_pusharrayvalue(0, state.Ppu.Mode7.Matrix[0]); lua_pusharrayvalue(1, state.Ppu.Mode7.Matrix[0]); @@ -784,11 +803,12 @@ int LuaApi::GetState(lua_State *lua) lua_pushboolvalue(mode1Bg3Priority, state.Ppu.Mode1Bg3Priority); lua_pushintvalue(mainScreenLayers, state.Ppu.MainScreenLayers); lua_pushintvalue(subScreenLayers, state.Ppu.SubScreenLayers); - + lua_starttable("layers") - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { lua_pushinteger(lua, i); - + lua_newtable(lua); lua_pushintvalue(tilemapAddress, state.Ppu.Layers[i].TilemapAddress); lua_pushintvalue(chrAddress, state.Ppu.Layers[i].ChrAddress); @@ -796,34 +816,35 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(vScroll, state.Ppu.Layers[i].VScroll); lua_pushintvalue(doubleWidth, state.Ppu.Layers[i].DoubleWidth); lua_pushintvalue(doubleHeight, state.Ppu.Layers[i].DoubleHeight); - lua_pushintvalue(largeTiles, state.Ppu.Layers[i].LargeTiles); + lua_pushintvalue(largeTiles, state.Ppu.Layers[i].LargeTiles); lua_settable(lua, -3); } lua_endtable(); //end layers lua_starttable("windows") - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { lua_pushinteger(lua, i); lua_newtable(lua); lua_pushintvalue(activeLayers, ( - (uint8_t)state.Ppu.Window[i].ActiveLayers[0] | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[1] << 1) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[2] << 2) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[3] << 3) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[4] << 4) | - ((uint8_t)state.Ppu.Window[i].ActiveLayers[5] << 5) - )); + (uint8_t)state.Ppu.Window[i].ActiveLayers[0] | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[1] << 1) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[2] << 2) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[3] << 3) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[4] << 4) | + ((uint8_t)state.Ppu.Window[i].ActiveLayers[5] << 5) + )); lua_pushintvalue(invertedLayers, ( - (uint8_t)state.Ppu.Window[i].InvertedLayers[0] | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[1] << 1) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[2] << 2) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[3] << 3) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[4] << 4) | - ((uint8_t)state.Ppu.Window[i].InvertedLayers[5] << 5) - )); + (uint8_t)state.Ppu.Window[i].InvertedLayers[0] | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[1] << 1) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[2] << 2) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[3] << 3) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[4] << 4) | + ((uint8_t)state.Ppu.Window[i].InvertedLayers[5] << 5) + )); lua_pushintvalue(left, state.Ppu.Window[i].Left); lua_pushintvalue(right, state.Ppu.Window[i].Right); @@ -831,7 +852,7 @@ int LuaApi::GetState(lua_State *lua) lua_settable(lua, -3); } lua_endtable(); //end windows - + lua_pushboolvalue(windowMaskLogicBg0, (int)state.Ppu.MaskLogic[0]); lua_pushboolvalue(windowMaskLogicBg1, (int)state.Ppu.MaskLogic[1]); lua_pushboolvalue(windowMaskLogicBg2, (int)state.Ppu.MaskLogic[2]); @@ -859,7 +880,7 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(ppu1OpenBus, state.Ppu.Ppu1OpenBus); lua_pushintvalue(ppu2OpenBus, state.Ppu.Ppu2OpenBus); - + lua_pushintvalue(cgramAddress, state.Ppu.CgramAddress); lua_pushintvalue(cgramWriteBuffer, state.Ppu.CgramWriteBuffer); lua_pushboolvalue(cgramAddressLatch, state.Ppu.CgramAddressLatch); @@ -898,7 +919,7 @@ int LuaApi::GetState(lua_State *lua) lua_pushintvalue(x, state.Spc.X); lua_pushintvalue(y, state.Spc.Y); lua_endtable(); //end spc - + return 1; } -#endif \ No newline at end of file +#endif diff --git a/Core/LuaApi.h b/Core/LuaApi.h index 329b4d7..bb8f130 100644 --- a/Core/LuaApi.h +++ b/Core/LuaApi.h @@ -11,44 +11,44 @@ class MemoryDumper; class LuaApi { public: - static void SetContext(ScriptingContext *context); - static int GetLibrary(lua_State *lua); + static void SetContext(ScriptingContext* context); + static int GetLibrary(lua_State* lua); - static int GetLabelAddress(lua_State *lua); + static int GetLabelAddress(lua_State* lua); - static int ReadMemory(lua_State *lua); - static int WriteMemory(lua_State *lua); - static int ReadMemoryWord(lua_State *lua); - static int WriteMemoryWord(lua_State *lua); - static int GetPrgRomOffset(lua_State *lua); + static int ReadMemory(lua_State* lua); + static int WriteMemory(lua_State* lua); + static int ReadMemoryWord(lua_State* lua); + static int WriteMemoryWord(lua_State* lua); + static int GetPrgRomOffset(lua_State* lua); //static int RevertPrgChrChanges(lua_State *lua); - static int RegisterMemoryCallback(lua_State *lua); - static int UnregisterMemoryCallback(lua_State *lua); - static int RegisterEventCallback(lua_State *lua); - static int UnregisterEventCallback(lua_State *lua); - - static int DrawString(lua_State *lua); - static int DrawLine(lua_State *lua); - static int DrawPixel(lua_State *lua); - static int DrawRectangle(lua_State *lua); - static int ClearScreen(lua_State *lua); - static int GetScreenBuffer(lua_State *lua); - static int SetScreenBuffer(lua_State *lua); - static int GetPixel(lua_State *lua); - static int GetMouseState(lua_State *lua); + static int RegisterMemoryCallback(lua_State* lua); + static int UnregisterMemoryCallback(lua_State* lua); + static int RegisterEventCallback(lua_State* lua); + static int UnregisterEventCallback(lua_State* lua); - static int Log(lua_State *lua); - static int DisplayMessage(lua_State *lua); - - static int Reset(lua_State *lua); - static int Stop(lua_State *lua); - static int Break(lua_State *lua); - static int Resume(lua_State *lua); - static int Execute(lua_State *lua); - static int Rewind(lua_State *lua); + static int DrawString(lua_State* lua); + static int DrawLine(lua_State* lua); + static int DrawPixel(lua_State* lua); + static int DrawRectangle(lua_State* lua); + static int ClearScreen(lua_State* lua); + static int GetScreenBuffer(lua_State* lua); + static int SetScreenBuffer(lua_State* lua); + static int GetPixel(lua_State* lua); + static int GetMouseState(lua_State* lua); - static int TakeScreenshot(lua_State *lua); + static int Log(lua_State* lua); + static int DisplayMessage(lua_State* lua); + + static int Reset(lua_State* lua); + static int Stop(lua_State* lua); + static int Break(lua_State* lua); + static int Resume(lua_State* lua); + static int Execute(lua_State* lua); + static int Rewind(lua_State* lua); + + static int TakeScreenshot(lua_State* lua); /*static int SaveSavestate(lua_State *lua); static int LoadSavestate(lua_State *lua); @@ -57,23 +57,23 @@ public: static int GetSavestateData(lua_State *lua); static int ClearSavestateData(lua_State *lua);*/ - static int IsKeyPressed(lua_State *lua); + static int IsKeyPressed(lua_State* lua); - static int GetInput(lua_State *lua); + static int GetInput(lua_State* lua); //static int SetInput(lua_State *lua); /*static int AddCheat(lua_State *lua); static int ClearCheats(lua_State *lua);*/ - static int GetScriptDataFolder(lua_State *lua); - static int GetRomInfo(lua_State *lua); - static int GetLogWindowLog(lua_State *lua); + static int GetScriptDataFolder(lua_State* lua); + static int GetRomInfo(lua_State* lua); + static int GetLogWindowLog(lua_State* lua); //static int SetState(lua_State *lua); - static int GetState(lua_State *lua); + static int GetState(lua_State* lua); - static int GetAccessCounters(lua_State *lua); - static int ResetAccessCounters(lua_State *lua); + static int GetAccessCounters(lua_State* lua); + static int ResetAccessCounters(lua_State* lua); private: static Console* _console; diff --git a/Core/LuaCallHelper.cpp b/Core/LuaCallHelper.cpp index b0dc9b3..971d2ef 100644 --- a/Core/LuaCallHelper.cpp +++ b/Core/LuaCallHelper.cpp @@ -2,25 +2,29 @@ #ifndef LIBRETRO #include "LuaCallHelper.h" -LuaCallHelper::LuaCallHelper(lua_State *lua) : _lua(lua) +LuaCallHelper::LuaCallHelper(lua_State* lua) : _lua(lua) { _stackSize = lua_gettop(lua); } void LuaCallHelper::ForceParamCount(int paramCount) { - while(lua_gettop(_lua) < paramCount) { + while (lua_gettop(_lua) < paramCount) + { lua_pushnil(_lua); } } bool LuaCallHelper::CheckParamCount(int minParamCount) { - if(minParamCount >= 0 && _stackSize < _paramCount && _stackSize >= minParamCount) { + if (minParamCount >= 0 && _stackSize < _paramCount && _stackSize >= minParamCount) + { return true; } - if(_stackSize != _paramCount) { - string message = string("too ") + (_stackSize < _paramCount ? "few" : "many") + " parameters. expected " + std::to_string(_paramCount) + " got " + std::to_string(_stackSize); + if (_stackSize != _paramCount) + { + string message = string("too ") + (_stackSize < _paramCount ? "few" : "many") + " parameters. expected " + + std::to_string(_paramCount) + " got " + std::to_string(_stackSize); luaL_error(_lua, message.c_str()); return false; } @@ -31,7 +35,8 @@ double LuaCallHelper::ReadDouble() { _paramCount++; double value = 0; - if(lua_isnumber(_lua, -1)) { + if (lua_isnumber(_lua, -1)) + { value = lua_tonumber(_lua, -1); } lua_pop(_lua, 1); @@ -42,9 +47,12 @@ bool LuaCallHelper::ReadBool(bool defaultValue) { _paramCount++; bool value = defaultValue; - if(lua_isboolean(_lua, -1)) { + if (lua_isboolean(_lua, -1)) + { value = lua_toboolean(_lua, -1) != 0; - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { value = lua_tonumber(_lua, -1) != 0; } lua_pop(_lua, 1); @@ -55,10 +63,13 @@ Nullable LuaCallHelper::ReadOptionalBool() { _paramCount++; Nullable result; - if(lua_isboolean(_lua, -1)) { + if (lua_isboolean(_lua, -1)) + { result.HasValue = true; result.Value = lua_toboolean(_lua, -1) != 0; - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { result.HasValue = true; result.Value = lua_tonumber(_lua, -1) != 0; } @@ -70,10 +81,13 @@ Nullable LuaCallHelper::ReadOptionalInteger() { _paramCount++; Nullable result; - if(lua_isinteger(_lua, -1)) { + if (lua_isinteger(_lua, -1)) + { result.HasValue = true; result.Value = (uint32_t)lua_tointeger(_lua, -1); - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { result.HasValue = true; result.Value = (uint32_t)lua_tonumber(_lua, -1); } @@ -85,9 +99,12 @@ uint32_t LuaCallHelper::ReadInteger(uint32_t defaultValue) { _paramCount++; uint32_t value = defaultValue; - if(lua_isinteger(_lua, -1)) { + if (lua_isinteger(_lua, -1)) + { value = (uint32_t)lua_tointeger(_lua, -1); - } else if(lua_isnumber(_lua, -1)) { + } + else if (lua_isnumber(_lua, -1)) + { value = (uint32_t)lua_tonumber(_lua, -1); } lua_pop(_lua, 1); @@ -99,7 +116,8 @@ string LuaCallHelper::ReadString() _paramCount++; size_t len; string str; - if(lua_isstring(_lua, -1)) { + if (lua_isstring(_lua, -1)) + { const char* cstr = lua_tolstring(_lua, -1, &len); str = string(cstr, len); } @@ -110,9 +128,12 @@ string LuaCallHelper::ReadString() int LuaCallHelper::GetReference() { _paramCount++; - if(lua_isfunction(_lua, -1)) { + if (lua_isfunction(_lua, -1)) + { return luaL_ref(_lua, LUA_REGISTRYINDEX); - } else { + } + else + { lua_pop(_lua, 1); return LUA_NOREF; } @@ -147,4 +168,4 @@ int LuaCallHelper::ReturnCount() return _returnCount; } -#endif \ No newline at end of file +#endif diff --git a/Core/LuaCallHelper.h b/Core/LuaCallHelper.h index e4fc768..9711d6b 100644 --- a/Core/LuaCallHelper.h +++ b/Core/LuaCallHelper.h @@ -2,7 +2,7 @@ #include "stdafx.h" #include "../Lua/lua.hpp" -template +template struct Nullable { bool HasValue = false; @@ -38,4 +38,4 @@ public: void Return(string value); int ReturnCount(); -}; \ No newline at end of file +}; diff --git a/Core/LuaScriptingContext.cpp b/Core/LuaScriptingContext.cpp index e7cbae9..19cf63d 100644 --- a/Core/LuaScriptingContext.cpp +++ b/Core/LuaScriptingContext.cpp @@ -19,22 +19,28 @@ LuaScriptingContext::LuaScriptingContext(Debugger* debugger) : ScriptingContext( LuaScriptingContext::~LuaScriptingContext() { - if(_lua) { + if (_lua) + { //Cleanup all references, this is required to prevent crashes that can occur when calling lua_close std::unordered_set references; - for(int i = (int)CallbackType::CpuRead; i <= (int)CallbackType::CpuExec; i++) { - for(MemoryCallback &callback : _callbacks[i]) { + for (int i = (int)CallbackType::CpuRead; i <= (int)CallbackType::CpuExec; i++) + { + for (MemoryCallback& callback : _callbacks[i]) + { references.emplace(callback.Reference); } } - for(int i = (int)EventType::Reset; i < (int)EventType::EventTypeSize; i++) { - for(int &ref : _eventCallbacks[i]) { + for (int i = (int)EventType::Reset; i < (int)EventType::EventTypeSize; i++) + { + for (int& ref : _eventCallbacks[i]) + { references.emplace(ref); } } - for(const int &ref : references) { + for (const int& ref : references) + { luaL_unref(_lua, LUA_REGISTRYINDEX, ref); } @@ -48,9 +54,10 @@ void LuaScriptingContext::SetScriptTimeout(uint32_t timeout) _timeout = timeout; } -void LuaScriptingContext::ExecutionCountHook(lua_State *lua, lua_Debug *ar) +void LuaScriptingContext::ExecutionCountHook(lua_State* lua, lua_Debug* ar) { - if(_context->_timer.GetElapsedMS() > _timeout) { + if (_context->_timer.GetElapsedMS() > _timeout) + { luaL_error(lua, (std::string("Maximum execution time (") + std::to_string(_timeout) + " ms) exceeded.").c_str()); } } @@ -61,7 +68,7 @@ bool LuaScriptingContext::LoadScript(string scriptName, string scriptContent, De int iErr = 0; _lua = luaL_newstate(); - + _context = this; LuaApi::SetContext(this); @@ -78,10 +85,13 @@ bool LuaScriptingContext::LoadScript(string scriptName, string scriptContent, De luaL_requiref(_lua, "emu", LuaApi::GetLibrary, 1); Log("Loading script..."); - if((iErr = luaL_loadbufferx(_lua, scriptContent.c_str(), scriptContent.size(), ("@" + scriptName).c_str(), nullptr)) == 0) { + if ((iErr = luaL_loadbufferx(_lua, scriptContent.c_str(), scriptContent.size(), ("@" + scriptName).c_str(), + nullptr)) == 0) + { _timer.Reset(); lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); - if((iErr = lua_pcall(_lua, 0, LUA_MULTRET, 0)) == 0) { + if ((iErr = lua_pcall(_lua, 0, LUA_MULTRET, 0)) == 0) + { //Script loaded properly Log("Script loaded successfully."); _initDone = true; @@ -89,13 +99,15 @@ bool LuaScriptingContext::LoadScript(string scriptName, string scriptContent, De } } - if(lua_isstring(_lua, -1)) { + if (lua_isstring(_lua, -1)) + { Log(lua_tostring(_lua, -1)); } return false; } -void LuaScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) +void LuaScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) { ScriptingContext::UnregisterMemoryCallback(type, startAddr, endAddr, cpuType, reference); luaL_unref(_lua, LUA_REGISTRYINDEX, reference); @@ -107,18 +119,21 @@ void LuaScriptingContext::UnregisterEventCallback(EventType type, int reference) luaL_unref(_lua, LUA_REGISTRYINDEX, reference); } -void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) +void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) { - if(_callbacks[(int)type].empty()) { + if (_callbacks[(int)type].empty()) + { return; } _timer.Reset(); _context = this; - lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); + lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); LuaApi::SetContext(this); - for(MemoryCallback &callback: _callbacks[(int)type]) { - if(callback.Type != cpuType || addr < callback.StartAddress || addr > callback.EndAddress) { + for (MemoryCallback& callback : _callbacks[(int)type]) + { + if (callback.Type != cpuType || addr < callback.StartAddress || addr > callback.EndAddress) + { continue; } @@ -126,11 +141,15 @@ void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t &val lua_rawgeti(_lua, LUA_REGISTRYINDEX, callback.Reference); lua_pushinteger(_lua, addr); lua_pushinteger(_lua, value); - if(lua_pcall(_lua, 2, LUA_MULTRET, 0) != 0) { + if (lua_pcall(_lua, 2, LUA_MULTRET, 0) != 0) + { Log(lua_tostring(_lua, -1)); - } else { + } + else + { int returnParamCount = lua_gettop(_lua) - top; - if(returnParamCount && lua_isinteger(_lua, -1)) { + if (returnParamCount && lua_isinteger(_lua, -1)) + { int newValue = (int)lua_tointeger(_lua, -1); value = (uint8_t)newValue; } @@ -141,21 +160,24 @@ void LuaScriptingContext::InternalCallMemoryCallback(uint32_t addr, uint8_t &val int LuaScriptingContext::InternalCallEventCallback(EventType type) { - if(_eventCallbacks[(int)type].empty()) { + if (_eventCallbacks[(int)type].empty()) + { return 0; } _timer.Reset(); _context = this; - lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); + lua_sethook(_lua, LuaScriptingContext::ExecutionCountHook, LUA_MASKCOUNT, 1000); LuaApi::SetContext(this); LuaCallHelper l(_lua); - for(int &ref : _eventCallbacks[(int)type]) { + for (int& ref : _eventCallbacks[(int)type]) + { lua_rawgeti(_lua, LUA_REGISTRYINDEX, ref); - if(lua_pcall(_lua, 0, 0, 0) != 0) { + if (lua_pcall(_lua, 0, 0, 0) != 0) + { Log(lua_tostring(_lua, -1)); } } return l.ReturnCount(); } -#endif \ No newline at end of file +#endif diff --git a/Core/LuaScriptingContext.h b/Core/LuaScriptingContext.h index acc148e..5a9095f 100644 --- a/Core/LuaScriptingContext.h +++ b/Core/LuaScriptingContext.h @@ -20,7 +20,7 @@ private: static void ExecutionCountHook(lua_State* lua, lua_Debug* ar); protected: - void InternalCallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) override; + void InternalCallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) override; int InternalCallEventCallback(EventType type) override; public: @@ -30,7 +30,8 @@ public: static void SetScriptTimeout(uint32_t timeout); bool LoadScript(string scriptName, string scriptContent, Debugger* debugger) override; - - void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) override; + + void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) override; void UnregisterEventCallback(EventType type, int reference) override; }; diff --git a/Core/MemoryAccessCounter.cpp b/Core/MemoryAccessCounter.cpp index 9a3369d..704d2ea 100644 --- a/Core/MemoryAccessCounter.cpp +++ b/Core/MemoryAccessCounter.cpp @@ -11,7 +11,7 @@ #include "Gameboy.h" #include "BaseCartridge.h" -MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console *console) +MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console* console) { _debugger = debugger; _memoryManager = console->GetMemoryManager().get(); @@ -21,18 +21,21 @@ MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console *console) _cx4 = console->GetCartridge()->GetCx4(); _gameboy = console->GetCartridge()->GetGameboy(); - for(int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) { + for (int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) + { uint32_t memSize = _debugger->GetMemoryDumper()->GetMemorySize((SnesMemoryType)i); _counters[i].reserve(memSize); - for(uint32_t j = 0; j < memSize; j++) { - _counters[i].push_back({ j }); + for (uint32_t j = 0; j < memSize; j++) + { + _counters[i].push_back({j}); } } } bool MemoryAccessCounter::IsAddressUninitialized(AddressInfo& addressInfo) { - if(!DebugUtilities::IsRomMemory(addressInfo.Type)) { + if (!DebugUtilities::IsRomMemory(addressInfo.Type)) + { return _counters[(int)addressInfo.Type][addressInfo.Address].WriteCount == 0; } return false; @@ -43,16 +46,18 @@ uint64_t MemoryAccessCounter::GetReadCount(AddressInfo& addressInfo) return _counters[(int)addressInfo.Type][addressInfo.Address].ReadCount; } -bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo &addressInfo, uint64_t masterClock) +bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo& addressInfo, uint64_t masterClock) { - if(addressInfo.Address < 0) { + if (addressInfo.Address < 0) + { return false; } AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address]; counts.ReadCount++; counts.ReadStamp = masterClock; - if(counts.WriteCount == 0 && IsAddressUninitialized(addressInfo)) { + if (counts.WriteCount == 0 && IsAddressUninitialized(addressInfo)) + { //Mark address as read before being written to (if trying to read/execute) counts.UninitRead = true; return true; @@ -62,7 +67,8 @@ bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo &addressInfo, uint64_t m void MemoryAccessCounter::ProcessMemoryWrite(AddressInfo& addressInfo, uint64_t masterClock) { - if(addressInfo.Address < 0) { + if (addressInfo.Address < 0) + { return; } @@ -73,7 +79,8 @@ void MemoryAccessCounter::ProcessMemoryWrite(AddressInfo& addressInfo, uint64_t void MemoryAccessCounter::ProcessMemoryExec(AddressInfo& addressInfo, uint64_t masterClock) { - if(addressInfo.Address < 0) { + if (addressInfo.Address < 0) + { return; } @@ -85,80 +92,100 @@ void MemoryAccessCounter::ProcessMemoryExec(AddressInfo& addressInfo, uint64_t m void MemoryAccessCounter::ResetCounts() { DebugBreakHelper helper(_debugger); - for(int i = 0; i < (int)SnesMemoryType::Register; i++) { - for(uint32_t j = 0; j < _counters[i].size(); j++) { - _counters[i][j] = { j }; + for (int i = 0; i < (int)SnesMemoryType::Register; i++) + { + for (uint32_t j = 0; j < _counters[i].size(); j++) + { + _counters[i][j] = {j}; } } } -void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, AddressCounters counts[]) +void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, + AddressCounters counts[]) { - switch(memoryType) { - case SnesMemoryType::CpuMemory: - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { + switch (memoryType) + { + case SnesMemoryType::CpuMemory: + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; + } + } + break; + + case SnesMemoryType::SpcMemory: + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _spc->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; + } + } + break; + + case SnesMemoryType::Sa1Memory: + if (_sa1) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _sa1->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::SpcMemory: - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _spc->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { + case SnesMemoryType::GsuMemory: + if (_gsu) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::Sa1Memory: - if(_sa1) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _sa1->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } + case SnesMemoryType::Cx4Memory: + if (_cx4) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _cx4->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::GsuMemory: - if(_gsu) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } + case SnesMemoryType::GameboyMemory: + if (_gameboy) + { + for (uint32_t i = 0; i < length; i++) + { + AddressInfo info = _gameboy->GetAbsoluteAddress(offset + i); + if (info.Address >= 0) + { + counts[i] = _counters[(int)info.Type][info.Address]; } } - break; + } + break; - case SnesMemoryType::Cx4Memory: - if(_cx4) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _cx4->GetMemoryMappings()->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } - } - } - break; - - case SnesMemoryType::GameboyMemory: - if(_gameboy) { - for(uint32_t i = 0; i < length; i++) { - AddressInfo info = _gameboy->GetAbsoluteAddress(offset + i); - if(info.Address >= 0) { - counts[i] = _counters[(int)info.Type][info.Address]; - } - } - } - break; - - default: - memcpy(counts, _counters[(int)memoryType].data() + offset, length * sizeof(AddressCounters)); - break; + default: + memcpy(counts, _counters[(int)memoryType].data() + offset, length * sizeof(AddressCounters)); + break; } } diff --git a/Core/MemoryAccessCounter.h b/Core/MemoryAccessCounter.h index ee45494..d80785c 100644 --- a/Core/MemoryAccessCounter.h +++ b/Core/MemoryAccessCounter.h @@ -38,10 +38,10 @@ private: Cx4* _cx4; Gameboy* _gameboy; - bool IsAddressUninitialized(AddressInfo &addressInfo); + bool IsAddressUninitialized(AddressInfo& addressInfo); public: - MemoryAccessCounter(Debugger *debugger, Console *console); + MemoryAccessCounter(Debugger* debugger, Console* console); uint64_t GetReadCount(AddressInfo& addressInfo); @@ -52,4 +52,4 @@ public: void ResetCounts(); void GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, AddressCounters counts[]); -}; \ No newline at end of file +}; diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp index 0d0d48a..638eea1 100644 --- a/Core/MemoryDumper.cpp +++ b/Core/MemoryDumper.cpp @@ -29,214 +29,256 @@ MemoryDumper::MemoryDumper(Debugger* debugger) _cartridge = debugger->GetConsole()->GetCartridge().get(); } -void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t length) +void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t* buffer, uint32_t length) { - if(length > GetMemorySize(type)) { + if (length > GetMemorySize(type)) + { return; } uint8_t* dst = GetMemoryBuffer(type); - if(dst) { + if (dst) + { memcpy(dst, buffer, length); } } uint8_t* MemoryDumper::GetMemoryBuffer(SnesMemoryType type) { - switch(type) { - default: return nullptr; - case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom(); - case SnesMemoryType::WorkRam: return _memoryManager->DebugGetWorkRam(); - case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRam(); - case SnesMemoryType::VideoRam: return _ppu->GetVideoRam(); - case SnesMemoryType::SpriteRam: return _ppu->GetSpriteRam(); - case SnesMemoryType::CGRam: return _ppu->GetCgRam(); - case SnesMemoryType::SpcRam: return _spc->GetSpcRam(); - case SnesMemoryType::SpcRom: return _spc->GetSpcRom(); + switch (type) + { + default: return nullptr; + case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom(); + case SnesMemoryType::WorkRam: return _memoryManager->DebugGetWorkRam(); + case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRam(); + case SnesMemoryType::VideoRam: return _ppu->GetVideoRam(); + case SnesMemoryType::SpriteRam: return _ppu->GetSpriteRam(); + case SnesMemoryType::CGRam: return _ppu->GetCgRam(); + case SnesMemoryType::SpcRam: return _spc->GetSpcRam(); + case SnesMemoryType::SpcRom: return _spc->GetSpcRom(); - case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRom() : nullptr; - case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRom() : nullptr; - case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRam() : nullptr; + case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() + ? _cartridge->GetDsp()->DebugGetProgramRom() + : nullptr; + case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRom() : nullptr; + case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRam() : nullptr; - case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() ? _cartridge->GetSa1()->DebugGetInternalRam() : nullptr; - case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRam() : nullptr; - case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRam() : nullptr; - case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRam() : nullptr; - case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack() : nullptr; + case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() + ? _cartridge->GetSa1()->DebugGetInternalRam() + : nullptr; + case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRam() : nullptr; + case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRam() : nullptr; + case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRam() : nullptr; + case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() + ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack() + : nullptr; - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::GbSpriteRam: - return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemory(type) : nullptr; + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::GbSpriteRam: + return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemory(type) : nullptr; } } uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type) { - switch(type) { - default: return 0; - case SnesMemoryType::CpuMemory: return 0x1000000; - case SnesMemoryType::SpcMemory: return 0x10000; - case SnesMemoryType::Sa1Memory: return 0x1000000; - case SnesMemoryType::GsuMemory: return 0x1000000; - case SnesMemoryType::Cx4Memory: return 0x1000000; - case SnesMemoryType::GameboyMemory: return 0x10000; - case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize(); - case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize; - case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRamSize(); - case SnesMemoryType::VideoRam: return Ppu::VideoRamSize; - case SnesMemoryType::SpriteRam: return Ppu::SpriteRamSize; - case SnesMemoryType::CGRam: return Ppu::CgRamSize; - case SnesMemoryType::SpcRam: return Spc::SpcRamSize; - case SnesMemoryType::SpcRom: return Spc::SpcRomSize; - case SnesMemoryType::Register: return 0x10000; + switch (type) + { + default: return 0; + case SnesMemoryType::CpuMemory: return 0x1000000; + case SnesMemoryType::SpcMemory: return 0x10000; + case SnesMemoryType::Sa1Memory: return 0x1000000; + case SnesMemoryType::GsuMemory: return 0x1000000; + case SnesMemoryType::Cx4Memory: return 0x1000000; + case SnesMemoryType::GameboyMemory: return 0x10000; + case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize(); + case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize; + case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRamSize(); + case SnesMemoryType::VideoRam: return Ppu::VideoRamSize; + case SnesMemoryType::SpriteRam: return Ppu::SpriteRamSize; + case SnesMemoryType::CGRam: return Ppu::CgRamSize; + case SnesMemoryType::SpcRam: return Spc::SpcRamSize; + case SnesMemoryType::SpcRom: return Spc::SpcRomSize; + case SnesMemoryType::Register: return 0x10000; - case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRomSize() : 0; - case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRomSize() : 0; - case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRamSize() : 0; - - case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() ? _cartridge->GetSa1()->DebugGetInternalRamSize() : 0; - case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRamSize() : 0; - case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRamSize() : 0; - case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRamSize() : 0; - case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPackSize() : 0; - - case SnesMemoryType::GbPrgRom: - case SnesMemoryType::GbWorkRam: - case SnesMemoryType::GbVideoRam: - case SnesMemoryType::GbCartRam: - case SnesMemoryType::GbHighRam: - case SnesMemoryType::GbBootRom: - case SnesMemoryType::GbSpriteRam: - return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemorySize(type) : 0; + case SnesMemoryType::DspProgramRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetProgramRomSize() : 0; + case SnesMemoryType::DspDataRom: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRomSize() : 0; + case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRamSize() : 0; + + case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() + ? _cartridge->GetSa1()->DebugGetInternalRamSize() + : 0; + case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRamSize() : 0; + case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRamSize() : 0; + case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRamSize() : 0; + case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() + ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPackSize() + : 0; + + case SnesMemoryType::GbPrgRom: + case SnesMemoryType::GbWorkRam: + case SnesMemoryType::GbVideoRam: + case SnesMemoryType::GbCartRam: + case SnesMemoryType::GbHighRam: + case SnesMemoryType::GbBootRom: + case SnesMemoryType::GbSpriteRam: + return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemorySize(type) : 0; } } -void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer) +void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t* buffer) { - switch(type) { - case SnesMemoryType::CpuMemory: - for(int i = 0; i <= 0xFFFFFF; i+=0x1000) { - _memoryManager->PeekBlock(i, buffer+i); - } - break; + switch (type) + { + case SnesMemoryType::CpuMemory: + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _memoryManager->PeekBlock(i, buffer + i); + } + break; - case SnesMemoryType::SpcMemory: - for(int i = 0; i <= 0xFFFF; i++) { - buffer[i] = _spc->DebugRead(i); - } - break; - - case SnesMemoryType::Sa1Memory: - if(_cartridge->GetSa1()) { - for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { - _cartridge->GetSa1()->GetMemoryMappings()->PeekBlock(i, buffer + i); - } - } - break; + case SnesMemoryType::SpcMemory: + for (int i = 0; i <= 0xFFFF; i++) + { + buffer[i] = _spc->DebugRead(i); + } + break; - case SnesMemoryType::GsuMemory: - if(_cartridge->GetGsu()) { - for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { - _cartridge->GetGsu()->GetMemoryMappings()->PeekBlock(i, buffer + i); - } + case SnesMemoryType::Sa1Memory: + if (_cartridge->GetSa1()) + { + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _cartridge->GetSa1()->GetMemoryMappings()->PeekBlock(i, buffer + i); } - break; + } + break; - case SnesMemoryType::Cx4Memory: - if(_cartridge->GetCx4()) { - for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { - _cartridge->GetCx4()->GetMemoryMappings()->PeekBlock(i, buffer + i); - } + case SnesMemoryType::GsuMemory: + if (_cartridge->GetGsu()) + { + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _cartridge->GetGsu()->GetMemoryMappings()->PeekBlock(i, buffer + i); } - break; + } + break; - case SnesMemoryType::GameboyMemory: { - if(_cartridge->GetGameboy()) { + case SnesMemoryType::Cx4Memory: + if (_cartridge->GetCx4()) + { + for (int i = 0; i <= 0xFFFFFF; i += 0x1000) + { + _cartridge->GetCx4()->GetMemoryMappings()->PeekBlock(i, buffer + i); + } + } + break; + + case SnesMemoryType::GameboyMemory: + { + if (_cartridge->GetGameboy()) + { GbMemoryManager* memManager = _cartridge->GetGameboy()->GetMemoryManager(); - for(int i = 0; i <= 0xFFFF; i++) { + for (int i = 0; i <= 0xFFFF; i++) + { buffer[i] = memManager->DebugRead(i); } } break; } - default: - uint8_t* src = GetMemoryBuffer(type); - if(src) { - memcpy(buffer, src, GetMemorySize(type)); - } - break; + default: + uint8_t* src = GetMemoryBuffer(type); + if (src) + { + memcpy(buffer, src, GetMemorySize(type)); + } + break; } } void MemoryDumper::SetMemoryValues(SnesMemoryType memoryType, uint32_t address, uint8_t* data, uint32_t length) { DebugBreakHelper helper(_debugger); - for(uint32_t i = 0; i < length; i++) { - SetMemoryValue(memoryType, address+i, data[i], true); + for (uint32_t i = 0; i < length; i++) + { + SetMemoryValue(memoryType, address + i, data[i], true); } } void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, uint8_t value, bool disableSideEffects) { - if(address >= GetMemorySize(memoryType)) { + if (address >= GetMemorySize(memoryType)) + { return; } - if(disableSideEffects && memoryType <= DebugUtilities::GetLastCpuMemoryType()) { - AddressInfo addr = { (int32_t)address, memoryType }; + if (disableSideEffects && memoryType <= DebugUtilities::GetLastCpuMemoryType()) + { + AddressInfo addr = {(int32_t)address, memoryType}; addr = _debugger->GetAbsoluteAddress(addr); - if(addr.Address >= 0) { + if (addr.Address >= 0) + { SetMemoryValue(addr.Type, addr.Address, value, true); } return; } - auto invalidateCache = [=]() { - AddressInfo addr = { (int32_t)address, memoryType }; + auto invalidateCache = [=]() + { + AddressInfo addr = {(int32_t)address, memoryType}; _debugger->GetDisassembler()->InvalidateCache(addr, DebugUtilities::ToCpuType(memoryType)); }; - switch(memoryType) { - case SnesMemoryType::CpuMemory: _memoryManager->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::SpcMemory: _spc->DebugWrite(address, value); break; - case SnesMemoryType::Sa1Memory: _cartridge->GetSa1()->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::GsuMemory: _cartridge->GetGsu()->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::Cx4Memory: _cartridge->GetCx4()->GetMemoryMappings()->DebugWrite(address, value); break; - case SnesMemoryType::GameboyMemory: _cartridge->GetGameboy()->GetMemoryManager()->DebugWrite(address, value); break; + switch (memoryType) + { + case SnesMemoryType::CpuMemory: _memoryManager->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::SpcMemory: _spc->DebugWrite(address, value); + break; + case SnesMemoryType::Sa1Memory: _cartridge->GetSa1()->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::GsuMemory: _cartridge->GetGsu()->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::Cx4Memory: _cartridge->GetCx4()->GetMemoryMappings()->DebugWrite(address, value); + break; + case SnesMemoryType::GameboyMemory: _cartridge->GetGameboy()->GetMemoryManager()->DebugWrite(address, value); + break; - default: - uint8_t* src = GetMemoryBuffer(memoryType); - if(src) { - src[address] = value; - invalidateCache(); - } - break; + default: + uint8_t* src = GetMemoryBuffer(memoryType); + if (src) + { + src[address] = value; + invalidateCache(); + } + break; } } uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address, bool disableSideEffects) { - if(address >= GetMemorySize(memoryType)) { + if (address >= GetMemorySize(memoryType)) + { return 0; } - switch(memoryType) { - case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address); - case SnesMemoryType::SpcMemory: return _spc->DebugRead(address); - case SnesMemoryType::Sa1Memory: return _cartridge->GetSa1()->GetMemoryMappings()->Peek(address); - case SnesMemoryType::GsuMemory: return _cartridge->GetGsu()->GetMemoryMappings()->Peek(address); - case SnesMemoryType::Cx4Memory: return _cartridge->GetCx4()->GetMemoryMappings()->Peek(address); - case SnesMemoryType::GameboyMemory: return _cartridge->GetGameboy()->GetMemoryManager()->DebugRead(address); - - default: - uint8_t* src = GetMemoryBuffer(memoryType); - return src ? src[address] : 0; + switch (memoryType) + { + case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address); + case SnesMemoryType::SpcMemory: return _spc->DebugRead(address); + case SnesMemoryType::Sa1Memory: return _cartridge->GetSa1()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::GsuMemory: return _cartridge->GetGsu()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::Cx4Memory: return _cartridge->GetCx4()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::GameboyMemory: return _cartridge->GetGameboy()->GetMemoryManager()->DebugRead(address); + + default: + uint8_t* src = GetMemoryBuffer(memoryType); + return src ? src[address] : 0; } } @@ -248,9 +290,10 @@ uint16_t MemoryDumper::GetMemoryValueWord(SnesMemoryType memoryType, uint32_t ad return (msb << 8) | lsb; } -void MemoryDumper::SetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, uint16_t value, bool disableSideEffects) +void MemoryDumper::SetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, uint16_t value, + bool disableSideEffects) { DebugBreakHelper helper(_debugger); SetMemoryValue(memoryType, address, (uint8_t)value, disableSideEffects); SetMemoryValue(memoryType, address + 1, (uint8_t)(value >> 8), disableSideEffects); -} \ No newline at end of file +} diff --git a/Core/MemoryDumper.h b/Core/MemoryDumper.h index ec95ff3..fb41695 100644 --- a/Core/MemoryDumper.h +++ b/Core/MemoryDumper.h @@ -26,12 +26,12 @@ public: uint8_t* GetMemoryBuffer(SnesMemoryType type); uint32_t GetMemorySize(SnesMemoryType type); - void GetMemoryState(SnesMemoryType type, uint8_t *buffer); + void GetMemoryState(SnesMemoryType type, uint8_t* buffer); uint8_t GetMemoryValue(SnesMemoryType memoryType, uint32_t address, bool disableSideEffects = true); uint16_t GetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, bool disableSideEffects = true); void SetMemoryValueWord(SnesMemoryType memoryType, uint32_t address, uint16_t value, bool disableSideEffects = true); void SetMemoryValue(SnesMemoryType memoryType, uint32_t address, uint8_t value, bool disableSideEffects = true); void SetMemoryValues(SnesMemoryType memoryType, uint32_t address, uint8_t* data, uint32_t length); - void SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t length); -}; \ No newline at end of file + void SetMemoryState(SnesMemoryType type, uint8_t* buffer, uint32_t length); +}; diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 44243c1..97d9ff6 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -20,7 +20,7 @@ #include "../Utilities/Serializer.h" #include "../Utilities/HexUtilities.h" -void MemoryManager::Initialize(Console *console) +void MemoryManager::Initialize(Console* console) { _masterClock = 0; _openBus = 0; @@ -48,8 +48,10 @@ void MemoryManager::Initialize(Console *console) _workRam )); - for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) { - _workRamHandlers.push_back(unique_ptr(new RamHandler(_workRam, i, MemoryManager::WorkRamSize, SnesMemoryType::WorkRam))); + for (uint32_t i = 0; i < 128 * 1024; i += 0x1000) + { + _workRamHandlers.push_back( + unique_ptr(new RamHandler(_workRam, i, MemoryManager::WorkRamSize, SnesMemoryType::WorkRam))); } _mappings.RegisterHandler(0x7E, 0x7F, 0x0000, 0xFFFF, _workRamHandlers); @@ -87,37 +89,56 @@ void MemoryManager::Reset() void MemoryManager::GenerateMasterClockTable() { - for(int i = 0; i < 0x800; i++) { + for (int i = 0; i < 0x800; i++) + { uint8_t bank = (i & 0x300) >> 8; - if(bank == 1) { + if (bank == 1) + { //Banks $40-$7F - Slow _masterClockTable[i] = 8; - } else if(bank == 3) { + } + else if (bank == 3) + { //Banks $C0-$FF //Slow or fast (depending on register) _masterClockTable[i] = (i >= 0x400) ? 6 : 8; - } else { + } + else + { //Banks $00-$3F and $80-$BF uint8_t page = (i & 0xFF); - if(page <= 0x1F) { + if (page <= 0x1F) + { //Slow _masterClockTable[i] = 8; - } else if(page >= 0x20 && page <= 0x3F) { + } + else if (page >= 0x20 && page <= 0x3F) + { //Fast _masterClockTable[i] = 6; - } else if(page == 0x40 || page == 0x41) { + } + else if (page == 0x40 || page == 0x41) + { //Extra slow _masterClockTable[i] = 12; - } else if(page >= 0x42 && page <= 0x5F) { + } + else if (page >= 0x42 && page <= 0x5F) + { //Fast _masterClockTable[i] = 6; - } else if(page >= 0x60 && page <= 0x7F) { + } + else if (page >= 0x60 && page <= 0x7F) + { //Slow _masterClockTable[i] = 8; - } else if(bank == 0) { + } + else if (bank == 0) + { //Slow _masterClockTable[i] = 8; - } else { + } + else + { //page >= $80 //Slow or fast (depending on register) _masterClockTable[i] = (i >= 0x400) ? 6 : 8; @@ -149,28 +170,46 @@ void MemoryManager::IncMasterClock8() void MemoryManager::IncMasterClock40() { - Exec(); Exec(); Exec(); Exec(); Exec(); - Exec(); Exec(); Exec(); Exec(); Exec(); - Exec(); Exec(); Exec(); Exec(); Exec(); - Exec(); Exec(); Exec(); Exec(); Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); + Exec(); } void MemoryManager::IncMasterClockStartup() { - for(int i = 0; i < 182 / 2; i++) { + for (int i = 0; i < 182 / 2; i++) + { Exec(); } } void MemoryManager::IncrementMasterClockValue(uint16_t cyclesToRun) { - switch(cyclesToRun) { - case 12: Exec(); - case 10: Exec(); - case 8: Exec(); - case 6: Exec(); - case 4: Exec(); - case 2: Exec(); + switch (cyclesToRun) + { + case 12: Exec(); + case 10: Exec(); + case 8: Exec(); + case 6: Exec(); + case 4: Exec(); + case 2: Exec(); } } @@ -179,11 +218,13 @@ void MemoryManager::Exec() _masterClock += 2; _hClock += 2; - if(_hClock == _nextEventClock) { + if (_hClock == _nextEventClock) + { ProcessEvent(); - } - - if((_hClock & 0x03) == 0) { + } + + if ((_hClock & 0x03) == 0) + { _console->ProcessPpuCycle(); _regs->ProcessIrqCounters(); } @@ -193,48 +234,58 @@ void MemoryManager::Exec() void MemoryManager::ProcessEvent() { - switch(_nextEvent) { - case SnesEventType::HdmaInit: - _console->GetDmaController()->BeginHdmaInit(); - _nextEvent = SnesEventType::DramRefresh; - _nextEventClock = _dramRefreshPosition; - break; + switch (_nextEvent) + { + case SnesEventType::HdmaInit: + _console->GetDmaController()->BeginHdmaInit(); + _nextEvent = SnesEventType::DramRefresh; + _nextEventClock = _dramRefreshPosition; + break; - case SnesEventType::DramRefresh: - IncMasterClock40(); - _cpu->IncreaseCycleCount<5>(); + case SnesEventType::DramRefresh: + IncMasterClock40(); + _cpu->IncreaseCycleCount<5>(); - if(_ppu->GetScanline() < _ppu->GetVblankStart()) { - _nextEvent = SnesEventType::HdmaStart; - _nextEventClock = 276 * 4; - } else { - _nextEvent = SnesEventType::EndOfScanline; - _nextEventClock = 1360; - } - break; - - case SnesEventType::HdmaStart: - _console->GetDmaController()->BeginHdmaTransfer(); + if (_ppu->GetScanline() < _ppu->GetVblankStart()) + { + _nextEvent = SnesEventType::HdmaStart; + _nextEventClock = 276 * 4; + } + else + { _nextEvent = SnesEventType::EndOfScanline; _nextEventClock = 1360; - break; + } + break; - case SnesEventType::EndOfScanline: - if(_ppu->ProcessEndOfScanline(_hClock)) { - _hClock = 0; + case SnesEventType::HdmaStart: + _console->GetDmaController()->BeginHdmaTransfer(); + _nextEvent = SnesEventType::EndOfScanline; + _nextEventClock = 1360; + break; - if(_ppu->GetScanline() == 0) { - _nextEvent = SnesEventType::HdmaInit; - _nextEventClock = 12 + (_masterClock & 0x07); - } else { - _dramRefreshPosition = 538 - (_masterClock & 0x07); - _nextEvent = SnesEventType::DramRefresh; - _nextEventClock = _dramRefreshPosition; - } - } else { - _nextEventClock += 2; + case SnesEventType::EndOfScanline: + if (_ppu->ProcessEndOfScanline(_hClock)) + { + _hClock = 0; + + if (_ppu->GetScanline() == 0) + { + _nextEvent = SnesEventType::HdmaInit; + _nextEventClock = 12 + (_masterClock & 0x07); } - break; + else + { + _dramRefreshPosition = 538 - (_masterClock & 0x07); + _nextEvent = SnesEventType::DramRefresh; + _nextEventClock = _dramRefreshPosition; + } + } + else + { + _nextEventClock += 2; + } + break; } } @@ -243,12 +294,15 @@ uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type) IncrementMasterClockValue(_cpuSpeed - 4); uint8_t value; - IMemoryHandler *handler = _mappings.GetHandler(addr); - if(handler) { + IMemoryHandler* handler = _mappings.GetHandler(addr); + if (handler) + { value = handler->Read(addr); _memTypeBusA = handler->GetMemoryType(); _openBus = value; - } else { + } + else + { //open bus value = _openBus; LogDebug("[Debug] Read - missing handler: $" + HexUtilities::ToHex(addr)); @@ -267,26 +321,38 @@ uint8_t MemoryManager::ReadDma(uint32_t addr, bool forBusA) uint8_t value; IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { - if(forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) { + if (handler) + { + if (forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) + { //Trying to read from bus B using bus A returns open bus value = _openBus; - } else if(handler == _registerHandlerA.get()) { + } + else if (handler == _registerHandlerA.get()) + { uint16_t regAddr = addr & 0xFFFF; - if(regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) { + if (regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) + { //Trying to read the DMA controller with DMA returns open bus value = _openBus; - } else { + } + else + { value = handler->Read(addr); } - } else { + } + else + { value = handler->Read(addr); - if(handler != _registerHandlerB.get()) { + if (handler != _registerHandlerB.get()) + { _memTypeBusA = handler->GetMemoryType(); } } _openBus = value; - } else { + } + else + { //open bus value = _openBus; LogDebug("[Debug] Read - missing handler: $" + HexUtilities::ToHex(addr)); @@ -306,7 +372,7 @@ uint16_t MemoryManager::PeekWord(uint32_t addr) return _mappings.PeekWord(addr); } -void MemoryManager::PeekBlock(uint32_t addr, uint8_t *dest) +void MemoryManager::PeekBlock(uint32_t addr, uint8_t* dest) { _mappings.PeekBlock(addr, dest); } @@ -317,10 +383,13 @@ void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type _console->ProcessMemoryWrite(addr, value, type); IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { + if (handler) + { handler->Write(addr, value); _memTypeBusA = handler->GetMemoryType(); - } else { + } + else + { LogDebug("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); } } @@ -332,23 +401,35 @@ void MemoryManager::WriteDma(uint32_t addr, uint8_t value, bool forBusA) _console->ProcessMemoryWrite(addr, value, MemoryOperationType::DmaWrite); IMemoryHandler* handler = _mappings.GetHandler(addr); - if(handler) { - if(forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) { + if (handler) + { + if (forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) + { //Trying to write to bus B using bus A does nothing - } else if(handler == _registerHandlerA.get()) { + } + else if (handler == _registerHandlerA.get()) + { uint16_t regAddr = addr & 0xFFFF; - if(regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) { + if (regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) + { //Trying to write to the DMA controller with DMA does nothing - } else { + } + else + { handler->Write(addr, value); } - } else { + } + else + { handler->Write(addr, value); - if(handler != _registerHandlerB.get()) { + if (handler != _registerHandlerB.get()) + { _memTypeBusA = handler->GetMemoryType(); } } - } else { + } + else + { LogDebug("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); } } @@ -368,7 +449,7 @@ uint16_t MemoryManager::GetHClock() return _hClock; } -uint8_t * MemoryManager::DebugGetWorkRam() +uint8_t* MemoryManager::DebugGetWorkRam() { return _workRam; } @@ -410,12 +491,13 @@ bool MemoryManager::IsWorkRam(uint32_t cpuAddress) return handler && handler->GetMemoryType() == SnesMemoryType::WorkRam; } -void MemoryManager::Serialize(Serializer &s) +void MemoryManager::Serialize(Serializer& s) { s.Stream(_masterClock, _openBus, _cpuSpeed, _hClock, _dramRefreshPosition); s.StreamArray(_workRam, MemoryManager::WorkRamSize); - if(s.GetVersion() < 8) { + if (s.GetVersion() < 8) + { bool unusedHasEvent[1369]; s.StreamArray(unusedHasEvent, sizeof(unusedHasEvent)); } diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 0862845..66d5b37 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -35,12 +35,12 @@ private: shared_ptr _registerHandlerA; shared_ptr _registerHandlerB; - InternalRegisters *_regs; + InternalRegisters* _regs; Ppu* _ppu; Cpu* _cpu; BaseCartridge* _cart; CheatManager* _cheatManager; - uint8_t *_workRam; + uint8_t* _workRam; uint64_t _masterClock = 0; uint16_t _hClock = 0; @@ -80,7 +80,7 @@ public: uint8_t Peek(uint32_t addr); uint16_t PeekWord(uint32_t addr); - void PeekBlock(uint32_t addr, uint8_t * dest); + void PeekBlock(uint32_t addr, uint8_t* dest); void Write(uint32_t addr, uint8_t value, MemoryOperationType type); void WriteDma(uint32_t addr, uint8_t value, bool forBusA); @@ -100,5 +100,5 @@ public: bool IsRegister(uint32_t cpuAddress); bool IsWorkRam(uint32_t cpuAddress); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; }; diff --git a/Core/MemoryMappings.cpp b/Core/MemoryMappings.cpp index 9ce2930..1bf50c5 100644 --- a/Core/MemoryMappings.cpp +++ b/Core/MemoryMappings.cpp @@ -2,36 +2,46 @@ #include "MemoryMappings.h" #include "IMemoryHandler.h" -void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, vector> &handlers, uint16_t pageIncrement, uint16_t startPageNumber) +void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, + vector>& handlers, uint16_t pageIncrement, + uint16_t startPageNumber) { - if(handlers.empty()) { + if (handlers.empty()) + { return; } startPageNumber %= handlers.size(); uint32_t pageNumber = startPageNumber; - for(uint32_t i = startBank; i <= endBank; i++) { + for (uint32_t i = startBank; i <= endBank; i++) + { pageNumber += pageIncrement; - for(uint32_t j = startPage; j <= endPage; j += 0x1000) { + for (uint32_t j = startPage; j <= endPage; j += 0x1000) + { _handlers[(i << 4) | (j >> 12)] = handlers[pageNumber].get(); //MessageManager::Log("Map [$" + HexUtilities::ToHex(i) + ":" + HexUtilities::ToHex(j)[1] + "xxx] to page number " + HexUtilities::ToHex(pageNumber)); pageNumber++; - if(pageNumber >= handlers.size()) { + if (pageNumber >= handlers.size()) + { pageNumber = 0; } } } } -void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, IMemoryHandler* handler) +void MemoryMappings::RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, + IMemoryHandler* handler) { - if((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF || startBank > endBank || startAddr > endAddr) { + if ((startAddr & 0xFFF) != 0 || (endAddr & 0xFFF) != 0xFFF || startBank > endBank || startAddr > endAddr) + { throw std::runtime_error("invalid start/end address"); } - for(uint32_t bank = startBank; bank <= endBank; bank++) { - for(uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) { + for (uint32_t bank = startBank; bank <= endBank; bank++) + { + for (uint32_t addr = startAddr; addr < endAddr; addr += 0x1000) + { /*if(_handlers[addr >> 12]) { throw std::runtime_error("handler already set"); }*/ @@ -49,10 +59,13 @@ IMemoryHandler* MemoryMappings::GetHandler(uint32_t addr) AddressInfo MemoryMappings::GetAbsoluteAddress(uint32_t addr) { IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { return handler->GetAbsoluteAddress(addr); - } else { - return { -1, SnesMemoryType::CpuMemory }; + } + else + { + return {-1, SnesMemoryType::CpuMemory}; } } @@ -60,20 +73,26 @@ int MemoryMappings::GetRelativeAddress(AddressInfo& absAddress, uint8_t startBan { uint16_t startPosition = startBank << 4; - for(int i = startPosition; i <= 0xFFF; i++) { + for (int i = startPosition; i <= 0xFFF; i++) + { IMemoryHandler* handler = GetHandler(i << 12); - if(handler) { + if (handler) + { AddressInfo addrInfo = handler->GetAbsoluteAddress(absAddress.Address & 0xFFF); - if(addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) { + if (addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) + { return (i << 12) | (absAddress.Address & 0xFFF); } } } - for(int i = 0; i < startPosition; i++) { + for (int i = 0; i < startPosition; i++) + { IMemoryHandler* handler = GetHandler(i << 12); - if(handler) { + if (handler) + { AddressInfo addrInfo = handler->GetAbsoluteAddress(absAddress.Address & 0xFFF); - if(addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) { + if (addrInfo.Type == absAddress.Type && addrInfo.Address == absAddress.Address) + { return (i << 12) | (absAddress.Address & 0xFFF); } } @@ -86,7 +105,8 @@ uint8_t MemoryMappings::Peek(uint32_t addr) //Read, without triggering side-effects uint8_t value = 0; IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { value = handler->Peek(addr); } return value; @@ -99,12 +119,15 @@ uint16_t MemoryMappings::PeekWord(uint32_t addr) return (msb << 8) | lsb; } -void MemoryMappings::PeekBlock(uint32_t addr, uint8_t *dest) +void MemoryMappings::PeekBlock(uint32_t addr, uint8_t* dest) { IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { handler->PeekBlock(addr & ~0xFFF, dest); - } else { + } + else + { memset(dest, 0, 0x1000); } } @@ -112,7 +135,8 @@ void MemoryMappings::PeekBlock(uint32_t addr, uint8_t *dest) void MemoryMappings::DebugWrite(uint32_t addr, uint8_t value) { IMemoryHandler* handler = GetHandler(addr); - if(handler) { + if (handler) + { handler->Write(addr, value); } } diff --git a/Core/MemoryMappings.h b/Core/MemoryMappings.h index 489f358..2ef8137 100644 --- a/Core/MemoryMappings.h +++ b/Core/MemoryMappings.h @@ -10,8 +10,11 @@ private: IMemoryHandler* _handlers[0x100 * 0x10] = {}; public: - void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, vector>& handlers, uint16_t pageIncrement = 0, uint16_t startPageNumber = 0); - void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, IMemoryHandler* handler); + void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage, + vector>& handlers, uint16_t pageIncrement = 0, + uint16_t startPageNumber = 0); + void RegisterHandler(uint8_t startBank, uint8_t endBank, uint16_t startAddr, uint16_t endAddr, + IMemoryHandler* handler); IMemoryHandler* GetHandler(uint32_t addr); AddressInfo GetAbsoluteAddress(uint32_t addr); @@ -19,7 +22,7 @@ public: uint8_t Peek(uint32_t addr); uint16_t PeekWord(uint32_t addr); - void PeekBlock(uint32_t addr, uint8_t * dest); + void PeekBlock(uint32_t addr, uint8_t* dest); void DebugWrite(uint32_t addr, uint8_t value); }; diff --git a/Core/MesenMovie.cpp b/Core/MesenMovie.cpp index 93aef7b..ba6155e 100644 --- a/Core/MesenMovie.cpp +++ b/Core/MesenMovie.cpp @@ -29,12 +29,15 @@ MesenMovie::~MesenMovie() void MesenMovie::Stop() { - if(_playing) { - if(!_forTest) { + if (_playing) + { + if (!_forTest) + { MessageManager::DisplayMessage("Movies", "MovieEnded"); } - if(_console->GetSettings()->GetPreferences().PauseOnMovieEnd) { + if (_console->GetSettings()->GetPreferences().PauseOnMovieEnd) + { _console->Pause(); } @@ -45,20 +48,24 @@ void MesenMovie::Stop() _console->GetControlManager()->UnregisterInputProvider(this); } -bool MesenMovie::SetInput(BaseControlDevice *device) +bool MesenMovie::SetInput(BaseControlDevice* device) { uint32_t inputRowIndex = _console->GetControlManager()->GetPollCounter(); _lastPollCounter = inputRowIndex; - if(_inputData.size() > inputRowIndex && _inputData[inputRowIndex].size() > _deviceIndex) { + if (_inputData.size() > inputRowIndex && _inputData[inputRowIndex].size() > _deviceIndex) + { device->SetTextState(_inputData[inputRowIndex][_deviceIndex]); _deviceIndex++; - if(_deviceIndex >= _inputData[inputRowIndex].size()) { + if (_deviceIndex >= _inputData[inputRowIndex].size()) + { //Move to the next frame's data _deviceIndex = 0; } - } else { + } + else + { _console->GetMovieManager()->Stop(); } return true; @@ -78,13 +85,14 @@ vector MesenMovie::LoadBattery(string extension) void MesenMovie::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded) { + if (type == ConsoleNotificationType::GameLoaded) + { _console->GetControlManager()->RegisterInputProvider(this); _console->GetControlManager()->SetPollCounter(_lastPollCounter); } } -bool MesenMovie::Play(VirtualFile &file) +bool MesenMovie::Play(VirtualFile& file) { _movieFile = file; @@ -95,19 +103,23 @@ bool MesenMovie::Play(VirtualFile &file) _reader->LoadArchive(ss); stringstream settingsData, inputData; - if(!_reader->GetStream("GameSettings.txt", settingsData)) { + if (!_reader->GetStream("GameSettings.txt", settingsData)) + { MessageManager::Log("[Movie] File not found: GameSettings.txt"); return false; } - if(!_reader->GetStream("Input.txt", inputData)) { + if (!_reader->GetStream("Input.txt", inputData)) + { MessageManager::Log("[Movie] File not found: Input.txt"); return false; } - while(inputData) { + while (inputData) + { string line; std::getline(inputData, line); - if(line.substr(0, 1) == "|") { + if (line.substr(0, 1) == "|") + { _inputData.push_back(StringUtilities::Split(line.substr(1), '|')); } } @@ -115,9 +127,9 @@ bool MesenMovie::Play(VirtualFile &file) _deviceIndex = 0; ParseSettings(settingsData); - + _console->Lock(); - + _console->GetBatteryManager()->SetBatteryProvider(shared_from_this()); _console->GetNotificationManager()->RegisterNotificationListener(shared_from_this()); ApplySettings(); @@ -127,8 +139,9 @@ bool MesenMovie::Play(VirtualFile &file) //bool autoConfigureInput = _console->GetSettings()->CheckFlag(EmulationFlags::AutoConfigureInput); //_console->GetSettings()->ClearFlags(EmulationFlags::AutoConfigureInput); - ControlManager *controlManager = _console->GetControlManager().get(); - if(controlManager) { + ControlManager* controlManager = _console->GetControlManager().get(); + if (controlManager) + { //ControlManager can be empty if no game is loaded controlManager->SetPollCounter(0); } @@ -145,20 +158,27 @@ bool MesenMovie::Play(VirtualFile &file) _originalCheats = _console->GetCheatManager()->GetCheats(); controlManager->UpdateControlDevices(); - if(!_forTest) { + if (!_forTest) + { _console->PowerCycle(); - } else { + } + else + { controlManager->RegisterInputProvider(this); } - LoadCheats(); + LoadCheats(); stringstream saveStateData; - if(_reader->GetStream("SaveState.mss", saveStateData)) { - if(!_console->GetSaveStateManager()->LoadState(saveStateData, true)) { + if (_reader->GetStream("SaveState.mss", saveStateData)) + { + if (!_console->GetSaveStateManager()->LoadState(saveStateData, true)) + { _console->Resume(); return false; - } else { + } + else + { _console->GetControlManager()->SetPollCounter(0); } } @@ -170,32 +190,40 @@ bool MesenMovie::Play(VirtualFile &file) return true; } -template -T FromString(string name, const vector &enumNames, T defaultValue) +template +T FromString(string name, const vector& enumNames, T defaultValue) { - for(size_t i = 0; i < enumNames.size(); i++) { - if(name == enumNames[i]) { + for (size_t i = 0; i < enumNames.size(); i++) + { + if (name == enumNames[i]) + { return (T)i; } } return defaultValue; } -void MesenMovie::ParseSettings(stringstream &data) +void MesenMovie::ParseSettings(stringstream& data) { - while(!data.eof()) { + while (!data.eof()) + { string line; std::getline(data, line); - if(!line.empty()) { + if (!line.empty()) + { size_t index = line.find_first_of(' '); - if(index != string::npos) { + if (index != string::npos) + { string name = line.substr(0, index); string value = line.substr(index + 1); - if(name == "Cheat") { + if (name == "Cheat") + { _cheats.push_back(value); - } else { + } + else + { _settings[name] = value; } } @@ -242,15 +270,22 @@ void MesenMovie::ApplySettings() EmulationConfig emuConfig = settings->GetEmulationConfig(); InputConfig inputConfig = settings->GetInputConfig(); - inputConfig.Controllers[0].Type = FromString(LoadString(_settings, MovieKeys::Controller1), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[1].Type = FromString(LoadString(_settings, MovieKeys::Controller2), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[2].Type = FromString(LoadString(_settings, MovieKeys::Controller3), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[3].Type = FromString(LoadString(_settings, MovieKeys::Controller4), ControllerTypeNames, ControllerType::None); - inputConfig.Controllers[4].Type = FromString(LoadString(_settings, MovieKeys::Controller5), ControllerTypeNames, ControllerType::None); + inputConfig.Controllers[0].Type = FromString(LoadString(_settings, MovieKeys::Controller1), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[1].Type = FromString(LoadString(_settings, MovieKeys::Controller2), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[2].Type = FromString(LoadString(_settings, MovieKeys::Controller3), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[3].Type = FromString(LoadString(_settings, MovieKeys::Controller4), ControllerTypeNames, + ControllerType::None); + inputConfig.Controllers[4].Type = FromString(LoadString(_settings, MovieKeys::Controller5), ControllerTypeNames, + ControllerType::None); emuConfig.Region = FromString(LoadString(_settings, MovieKeys::Region), ConsoleRegionNames, ConsoleRegion::Ntsc); - if(!_forTest) { - emuConfig.RamPowerOnState = FromString(LoadString(_settings, MovieKeys::RamPowerOnState), RamStateNames, RamState::AllOnes); + if (!_forTest) + { + emuConfig.RamPowerOnState = FromString(LoadString(_settings, MovieKeys::RamPowerOnState), RamStateNames, + RamState::AllOnes); } emuConfig.PpuExtraScanlinesAfterNmi = LoadInt(_settings, MovieKeys::ExtraScanlinesAfterNmi); emuConfig.PpuExtraScanlinesBeforeNmi = LoadInt(_settings, MovieKeys::ExtraScanlinesBeforeNmi); @@ -260,44 +295,61 @@ void MesenMovie::ApplySettings() settings->SetInputConfig(inputConfig); } -uint32_t MesenMovie::LoadInt(std::unordered_map &settings, string name, uint32_t defaultValue) +uint32_t MesenMovie::LoadInt(std::unordered_map& settings, string name, uint32_t defaultValue) { auto result = settings.find(name); - if(result != settings.end()) { - try { + if (result != settings.end()) + { + try + { return (uint32_t)std::stoul(result->second); - } catch(std::exception&) { + } + catch (std::exception&) + { MessageManager::Log("[Movies] Invalid value for tag: " + name); return defaultValue; } - } else { + } + else + { return defaultValue; } } -bool MesenMovie::LoadBool(std::unordered_map &settings, string name) +bool MesenMovie::LoadBool(std::unordered_map& settings, string name) { auto result = settings.find(name); - if(result != settings.end()) { - if(result->second == "true") { + if (result != settings.end()) + { + if (result->second == "true") + { return true; - } else if(result->second == "false") { + } + else if (result->second == "false") + { return false; - } else { + } + else + { MessageManager::Log("[Movies] Invalid value for tag: " + name); return false; } - } else { + } + else + { return false; } } -string MesenMovie::LoadString(std::unordered_map &settings, string name) +string MesenMovie::LoadString(std::unordered_map& settings, string name) { auto result = settings.find(name); - if(result != settings.end()) { + if (result != settings.end()) + { return result->second; - } else { + } + else + { return ""; } } @@ -305,24 +357,29 @@ string MesenMovie::LoadString(std::unordered_map &settings, stri void MesenMovie::LoadCheats() { vector cheats; - for(string cheatData : _cheats) { + for (string cheatData : _cheats) + { CheatCode code; - if(LoadCheat(cheatData, code)) { + if (LoadCheat(cheatData, code)) + { cheats.push_back(code); } } _console->GetCheatManager()->SetCheats(cheats); } -bool MesenMovie::LoadCheat(string cheatData, CheatCode &code) +bool MesenMovie::LoadCheat(string cheatData, CheatCode& code) { vector data = StringUtilities::Split(cheatData, ' '); - if(data.size() == 2) { + if (data.size() == 2) + { code.Address = HexUtilities::FromHex(data[0]); code.Value = HexUtilities::FromHex(data[1]); return true; - } else { + } + else + { MessageManager::Log("[Movie] Invalid cheat definition: " + cheatData); } return false; diff --git a/Core/MesenMovie.h b/Core/MesenMovie.h index f1cc7fa..74c2ff0 100644 --- a/Core/MesenMovie.h +++ b/Core/MesenMovie.h @@ -10,7 +10,8 @@ class ZipReader; class Console; struct CheatCode; -class MesenMovie : public IMovie, public INotificationListener, public IBatteryProvider, public std::enable_shared_from_this +class MesenMovie : public IMovie, public INotificationListener, public IBatteryProvider, + public std::enable_shared_from_this { private: shared_ptr _console; @@ -28,23 +29,23 @@ private: bool _forTest; private: - void ParseSettings(stringstream &data); + void ParseSettings(stringstream& data); void ApplySettings(); bool LoadGame(); void Stop(); - uint32_t LoadInt(std::unordered_map &settings, string name, uint32_t defaultValue = 0); - bool LoadBool(std::unordered_map &settings, string name); - string LoadString(std::unordered_map &settings, string name); + uint32_t LoadInt(std::unordered_map& settings, string name, uint32_t defaultValue = 0); + bool LoadBool(std::unordered_map& settings, string name); + string LoadString(std::unordered_map& settings, string name); void LoadCheats(); - bool LoadCheat(string cheatData, CheatCode &code); + bool LoadCheat(string cheatData, CheatCode& code); public: MesenMovie(shared_ptr console, bool silent); virtual ~MesenMovie(); - bool Play(VirtualFile &file) override; + bool Play(VirtualFile& file) override; bool SetInput(BaseControlDevice* device) override; bool IsPlaying() override; @@ -52,5 +53,5 @@ public: vector LoadBattery(string extension) override; //Inherited via INotificationListener - void ProcessNotification(ConsoleNotificationType type, void * parameter) override; -}; \ No newline at end of file + void ProcessNotification(ConsoleNotificationType type, void* parameter) override; +}; diff --git a/Core/MessageManager.cpp b/Core/MessageManager.cpp index c5973af..6e98e73 100644 --- a/Core/MessageManager.cpp +++ b/Core/MessageManager.cpp @@ -2,80 +2,86 @@ #include "MessageManager.h" std::unordered_map MessageManager::_enResources = { - { "Cheats", u8"Cheats" }, - { "Debug", u8"Debug" }, - { "EmulationSpeed", u8"Emulation Speed" }, - { "ClockRate", u8"Clock Rate" }, - { "Error", u8"Error" }, - { "GameInfo", u8"Game Info" }, - { "GameLoaded", u8"Game loaded" }, - { "Input", u8"Input" }, - { "Patch", u8"Patch" }, - { "Movies", u8"Movies" }, - { "NetPlay", u8"Net Play" }, - { "Overclock", u8"Overclock" }, - { "Region", u8"Region" }, - { "SaveStates", u8"Save States" }, - { "ScreenshotSaved", u8"Screenshot Saved" }, - { "SoundRecorder", u8"Sound Recorder" }, - { "Test", u8"Test" }, - { "VideoRecorder", u8"Video Recorder" }, + {"Cheats", u8"Cheats"}, + {"Debug", u8"Debug"}, + {"EmulationSpeed", u8"Emulation Speed"}, + {"ClockRate", u8"Clock Rate"}, + {"Error", u8"Error"}, + {"GameInfo", u8"Game Info"}, + {"GameLoaded", u8"Game loaded"}, + {"Input", u8"Input"}, + {"Patch", u8"Patch"}, + {"Movies", u8"Movies"}, + {"NetPlay", u8"Net Play"}, + {"Overclock", u8"Overclock"}, + {"Region", u8"Region"}, + {"SaveStates", u8"Save States"}, + {"ScreenshotSaved", u8"Screenshot Saved"}, + {"SoundRecorder", u8"Sound Recorder"}, + {"Test", u8"Test"}, + {"VideoRecorder", u8"Video Recorder"}, - { "ApplyingPatch", u8"Applying patch: %1" }, - { "CheatApplied", u8"1 cheat applied." }, - { "CheatsApplied", u8"%1 cheats applied." }, - { "CheatsDisabled", u8"All cheats disabled." }, - { "CoinInsertedSlot", u8"Coin inserted (slot %1)" }, - { "ConnectedToServer", u8"Connected to server." }, - { "ConnectedAsPlayer", u8"Connected as player %1" }, - { "ConnectedAsSpectator", u8"Connected as spectator." }, - { "ConnectionLost", u8"Connection to server lost." }, - { "CouldNotConnect", u8"Could not connect to the server." }, - { "CouldNotInitializeAudioSystem", u8"Could not initialize audio system" }, - { "CouldNotFindRom", u8"Could not find matching game ROM. (%1)" }, - { "CouldNotWriteToFile", u8"Could not write to file: %1" }, - { "CouldNotLoadFile", u8"Could not load file: %1" }, - { "EmulationMaximumSpeed", u8"Maximum speed" }, - { "EmulationSpeedPercent", u8"%1%" }, - { "FdsDiskInserted", u8"Disk %1 Side %2 inserted." }, - { "Frame", u8"Frame" }, - { "GameCrash", u8"Game has crashed (%1)" }, - { "KeyboardModeDisabled", u8"Keyboard mode disabled." }, - { "KeyboardModeEnabled", u8"Keyboard mode enabled." }, - { "Lag", u8"Lag" }, - { "Mapper", u8"Mapper: %1, SubMapper: %2" }, - { "MovieEnded", u8"Movie ended." }, - { "MovieInvalid", u8"Invalid movie file." }, - { "MovieMissingRom", u8"Missing ROM required (%1) to play movie." }, - { "MovieNewerVersion", u8"Cannot load movies created by a more recent version of Mesen-S. Please download the latest version." }, - { "MovieIncompatibleVersion", u8"This movie is incompatible with this version of Mesen-S." }, - { "MoviePlaying", u8"Playing movie: %1" }, - { "MovieRecordingTo", u8"Recording to: %1" }, - { "MovieSaved", u8"Movie saved to file: %1" }, - { "NetplayVersionMismatch", u8"%1 is not running the same version of Mesen-S and has been disconnected." }, - { "NetplayNotAllowed", u8"This action is not allowed while connected to a server." }, - { "OverclockEnabled", u8"Overclocking enabled." }, - { "OverclockDisabled", u8"Overclocking disabled." }, - { "PrgSizeWarning", u8"PRG size is smaller than 32kb" }, - { "SaveStateEmpty", u8"Slot is empty." }, - { "SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen-S." }, - { "SaveStateInvalidFile", u8"Invalid save state file." }, - { "SaveStateWrongSystemSnes", u8"Error: State cannot be loaded (wrong console type: SNES)" }, - { "SaveStateWrongSystemGb", u8"Error: State cannot be loaded (wrong console type: Game Boy)" }, - { "SaveStateLoaded", u8"State #%1 loaded." }, - { "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." }, - { "SaveStateNewerVersion", u8"Cannot load save states created by a more recent version of Mesen-S. Please download the latest version." }, - { "SaveStateSaved", u8"State #%1 saved." }, - { "SaveStateSlotSelected", u8"Slot #%1 selected." }, - { "ScanlineTimingWarning", u8"PPU timing has been changed." }, - { "ServerStarted", u8"Server started (Port: %1)" }, - { "ServerStopped", u8"Server stopped" }, - { "SoundRecorderStarted", u8"Recording to: %1" }, - { "SoundRecorderStopped", u8"Recording saved to: %1" }, - { "TestFileSavedTo", u8"Test file saved to: %1" }, - { "UnsupportedMapper", u8"Unsupported mapper (%1), cannot load game." }, - { "VideoRecorderStarted", u8"Recording to: %1" }, - { "VideoRecorderStopped", u8"Recording saved to: %1" }, + {"ApplyingPatch", u8"Applying patch: %1"}, + {"CheatApplied", u8"1 cheat applied."}, + {"CheatsApplied", u8"%1 cheats applied."}, + {"CheatsDisabled", u8"All cheats disabled."}, + {"CoinInsertedSlot", u8"Coin inserted (slot %1)"}, + {"ConnectedToServer", u8"Connected to server."}, + {"ConnectedAsPlayer", u8"Connected as player %1"}, + {"ConnectedAsSpectator", u8"Connected as spectator."}, + {"ConnectionLost", u8"Connection to server lost."}, + {"CouldNotConnect", u8"Could not connect to the server."}, + {"CouldNotInitializeAudioSystem", u8"Could not initialize audio system"}, + {"CouldNotFindRom", u8"Could not find matching game ROM. (%1)"}, + {"CouldNotWriteToFile", u8"Could not write to file: %1"}, + {"CouldNotLoadFile", u8"Could not load file: %1"}, + {"EmulationMaximumSpeed", u8"Maximum speed"}, + {"EmulationSpeedPercent", u8"%1%"}, + {"FdsDiskInserted", u8"Disk %1 Side %2 inserted."}, + {"Frame", u8"Frame"}, + {"GameCrash", u8"Game has crashed (%1)"}, + {"KeyboardModeDisabled", u8"Keyboard mode disabled."}, + {"KeyboardModeEnabled", u8"Keyboard mode enabled."}, + {"Lag", u8"Lag"}, + {"Mapper", u8"Mapper: %1, SubMapper: %2"}, + {"MovieEnded", u8"Movie ended."}, + {"MovieInvalid", u8"Invalid movie file."}, + {"MovieMissingRom", u8"Missing ROM required (%1) to play movie."}, + { + "MovieNewerVersion", + u8"Cannot load movies created by a more recent version of Mesen-S. Please download the latest version." + }, + {"MovieIncompatibleVersion", u8"This movie is incompatible with this version of Mesen-S."}, + {"MoviePlaying", u8"Playing movie: %1"}, + {"MovieRecordingTo", u8"Recording to: %1"}, + {"MovieSaved", u8"Movie saved to file: %1"}, + {"NetplayVersionMismatch", u8"%1 is not running the same version of Mesen-S and has been disconnected."}, + {"NetplayNotAllowed", u8"This action is not allowed while connected to a server."}, + {"OverclockEnabled", u8"Overclocking enabled."}, + {"OverclockDisabled", u8"Overclocking disabled."}, + {"PrgSizeWarning", u8"PRG size is smaller than 32kb"}, + {"SaveStateEmpty", u8"Slot is empty."}, + {"SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen-S."}, + {"SaveStateInvalidFile", u8"Invalid save state file."}, + {"SaveStateWrongSystemSnes", u8"Error: State cannot be loaded (wrong console type: SNES)"}, + {"SaveStateWrongSystemGb", u8"Error: State cannot be loaded (wrong console type: Game Boy)"}, + {"SaveStateLoaded", u8"State #%1 loaded."}, + {"SaveStateMissingRom", u8"Missing ROM required (%1) to load save state."}, + { + "SaveStateNewerVersion", + u8"Cannot load save states created by a more recent version of Mesen-S. Please download the latest version." + }, + {"SaveStateSaved", u8"State #%1 saved."}, + {"SaveStateSlotSelected", u8"Slot #%1 selected."}, + {"ScanlineTimingWarning", u8"PPU timing has been changed."}, + {"ServerStarted", u8"Server started (Port: %1)"}, + {"ServerStopped", u8"Server stopped"}, + {"SoundRecorderStarted", u8"Recording to: %1"}, + {"SoundRecorderStopped", u8"Recording saved to: %1"}, + {"TestFileSavedTo", u8"Test file saved to: %1"}, + {"UnsupportedMapper", u8"Unsupported mapper (%1), cannot load game."}, + {"VideoRecorderStarted", u8"Recording to: %1"}, + {"VideoRecorderStopped", u8"Recording saved to: %1"}, }; std::list MessageManager::_log; @@ -93,7 +99,8 @@ void MessageManager::RegisterMessageManager(IMessageManager* messageManager) void MessageManager::UnregisterMessageManager(IMessageManager* messageManager) { auto lock = _messageLock.AcquireSafe(); - if(MessageManager::_messageManager == messageManager) { + if (MessageManager::_messageManager == messageManager) + { MessageManager::_messageManager = nullptr; } } @@ -105,7 +112,7 @@ void MessageManager::SetOsdState(bool enabled) string MessageManager::Localize(string key) { - std::unordered_map *resources = &_enResources; + std::unordered_map* resources = &_enResources; /*switch(EmulationSettings::GetDisplayLanguage()) { case Language::English: resources = &_enResources; break; case Language::French: resources = &_frResources; break; @@ -117,10 +124,12 @@ string MessageManager::Localize(string key) case Language::Catalan: resources = &_caResources; break; case Language::Chinese: resources = &_zhResources; break; }*/ - if(resources) { - if(resources->find(key) != resources->end()) { + if (resources) + { + if (resources->find(key) != resources->end()) + { return (*resources)[key]; - }/* else if(EmulationSettings::GetDisplayLanguage() != Language::English) { + } /* else if(EmulationSettings::GetDisplayLanguage() != Language::English) { //Fallback on English if resource key is missing another language resources = &_enResources; if(resources->find(key) != resources->end()) { @@ -134,9 +143,11 @@ string MessageManager::Localize(string key) void MessageManager::DisplayMessage(string title, string message, string param1, string param2) { - if(MessageManager::_messageManager) { + if (MessageManager::_messageManager) + { auto lock = _messageLock.AcquireSafe(); - if(!MessageManager::_messageManager) { + if (!MessageManager::_messageManager) + { return; } @@ -144,18 +155,23 @@ void MessageManager::DisplayMessage(string title, string message, string param1, message = Localize(message); size_t startPos = message.find(u8"%1"); - if(startPos != std::string::npos) { + if (startPos != std::string::npos) + { message.replace(startPos, 2, param1); } startPos = message.find(u8"%2"); - if(startPos != std::string::npos) { + if (startPos != std::string::npos) + { message.replace(startPos, 2, param2); } - if(_osdEnabled) { + if (_osdEnabled) + { MessageManager::_messageManager->DisplayMessage(title, message); - } else { + } + else + { MessageManager::Log("[" + title + "] " + message); } } @@ -165,10 +181,12 @@ void MessageManager::Log(string message) { #ifndef LIBRETRO auto lock = _logLock.AcquireSafe(); - if(message.empty()) { + if (message.empty()) + { message = "------------------------------------------------------"; } - if(_log.size() >= 1000) { + if (_log.size() >= 1000) + { _log.pop_front(); } _log.push_back(message); @@ -189,7 +207,8 @@ string MessageManager::GetLog() { auto lock = _logLock.AcquireSafe(); stringstream ss; - for(string &msg : _log) { + for (string& msg : _log) + { ss << msg << "\n"; } return ss.str(); diff --git a/Core/MessageManager.h b/Core/MessageManager.h index bbf14e1..a8b69b2 100644 --- a/Core/MessageManager.h +++ b/Core/MessageManager.h @@ -7,7 +7,7 @@ #include "../Utilities/SimpleLock.h" #ifdef _DEBUG - #define LogDebug(msg) MessageManager::Log(msg); +#define LogDebug(msg) MessageManager::Log(msg); #else #define LogDebug(msg) #endif @@ -22,7 +22,7 @@ private: static SimpleLock _logLock; static SimpleLock _messageLock; static std::list _log; - + public: static void SetOsdState(bool enabled); diff --git a/Core/MessageType.h b/Core/MessageType.h index c1318cc..7447485 100644 --- a/Core/MessageType.h +++ b/Core/MessageType.h @@ -12,4 +12,4 @@ enum class MessageType : uint8_t SelectController = 6, ForceDisconnect = 7, ServerInformation = 8 -}; \ No newline at end of file +}; diff --git a/Core/MovieDataMessage.h b/Core/MovieDataMessage.h index 3c22acd..2434652 100644 --- a/Core/MovieDataMessage.h +++ b/Core/MovieDataMessage.h @@ -10,14 +10,16 @@ private: ControlDeviceState _inputState; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_portNumber); s.StreamVector(_inputState.State); } public: - MovieDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + MovieDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } MovieDataMessage(ControlDeviceState state, uint8_t port) : NetMessage(MessageType::MovieData) { @@ -34,4 +36,4 @@ public: { return _inputState; } -}; \ No newline at end of file +}; diff --git a/Core/MovieManager.cpp b/Core/MovieManager.cpp index aecac96..55eb36a 100644 --- a/Core/MovieManager.cpp +++ b/Core/MovieManager.cpp @@ -15,7 +15,8 @@ MovieManager::MovieManager(shared_ptr console) void MovieManager::Record(RecordMovieOptions options) { shared_ptr recorder(new MovieRecorder(_console)); - if(recorder->Record(options)) { + if (recorder->Record(options)) + { _recorder = recorder; } } @@ -23,22 +24,27 @@ void MovieManager::Record(RecordMovieOptions options) void MovieManager::Play(VirtualFile file, bool forTest) { vector fileData; - if(file.IsValid() && file.ReadFile(fileData)) { + if (file.IsValid() && file.ReadFile(fileData)) + { shared_ptr player; - if(memcmp(fileData.data(), "PK", 2) == 0) { + if (memcmp(fileData.data(), "PK", 2) == 0) + { //Mesen movie ZipReader reader; reader.LoadArchive(fileData); vector files = reader.GetFileList(); - if(std::find(files.begin(), files.end(), "GameSettings.txt") != files.end()) { + if (std::find(files.begin(), files.end(), "GameSettings.txt") != files.end()) + { player.reset(new MesenMovie(_console, forTest)); } } - if(player && player->Play(file)) { + if (player && player->Play(file)) + { _player = player; - if(!forTest) { + if (!forTest) + { MessageManager::DisplayMessage("Movies", "MoviePlaying", file.GetFileName()); } } diff --git a/Core/MovieManager.h b/Core/MovieManager.h index 9d4b2a5..12d6171 100644 --- a/Core/MovieManager.h +++ b/Core/MovieManager.h @@ -11,7 +11,7 @@ class Console; class IMovie : public IInputProvider { public: - virtual bool Play(VirtualFile &file) = 0; + virtual bool Play(VirtualFile& file) = 0; virtual bool IsPlaying() = 0; }; @@ -30,4 +30,4 @@ public: void Stop(); bool Playing(); bool Recording(); -}; \ No newline at end of file +}; diff --git a/Core/MovieRecorder.cpp b/Core/MovieRecorder.cpp index 4c4a0da..ef82ad6 100644 --- a/Core/MovieRecorder.cpp +++ b/Core/MovieRecorder.cpp @@ -38,29 +38,37 @@ bool MovieRecorder::Record(RecordMovieOptions options) _saveStateData = stringstream(); _hasSaveState = false; - if(!_writer->Initialize(_filename)) { + if (!_writer->Initialize(_filename)) + { MessageManager::DisplayMessage("Movies", "CouldNotWriteToFile", FolderUtilities::GetFilename(_filename, true)); _writer.reset(); return false; - } else { + } + else + { _console->Lock(); _console->GetNotificationManager()->RegisterNotificationListener(shared_from_this()); - if(options.RecordFrom == RecordMovieFrom::StartWithoutSaveData) { + if (options.RecordFrom == RecordMovieFrom::StartWithoutSaveData) + { //Power cycle and ignore save data that exists on the disk _console->GetBatteryManager()->SetBatteryProvider(shared_from_this()); _console->PowerCycle(); - } else if(options.RecordFrom == RecordMovieFrom::StartWithSaveData) { + } + else if (options.RecordFrom == RecordMovieFrom::StartWithSaveData) + { //Power cycle and save existing battery files into the movie file _console->GetBatteryManager()->SetBatteryRecorder(shared_from_this()); _console->PowerCycle(); - } else if(options.RecordFrom == RecordMovieFrom::CurrentState) { + } + else if (options.RecordFrom == RecordMovieFrom::CurrentState) + { //Record from current state, store a save state in the movie file _console->GetControlManager()->RegisterInputRecorder(this); _console->GetSaveStateManager()->SaveState(_saveStateData); _hasSaveState = true; } - + _console->GetBatteryManager()->SetBatteryRecorder(nullptr); _console->Unlock(); @@ -70,12 +78,12 @@ bool MovieRecorder::Record(RecordMovieOptions options) } } -void MovieRecorder::GetGameSettings(stringstream &out) +void MovieRecorder::GetGameSettings(stringstream& out) { EmuSettings* settings = _console->GetSettings().get(); EmulationConfig emuConfig = settings->GetEmulationConfig(); InputConfig inputConfig = settings->GetInputConfig(); - + WriteString(out, MovieKeys::MesenVersion, settings->GetVersionString()); WriteInt(out, MovieKeys::MovieFormatVersion, MovieRecorder::MovieFormatVersion); @@ -84,20 +92,24 @@ void MovieRecorder::GetGameSettings(stringstream &out) WriteString(out, MovieKeys::Sha1, _console->GetCartridge()->GetSha1Hash()); VirtualFile patchFile = _console->GetRomInfo().PatchFile; - if(patchFile.IsValid()) { + if (patchFile.IsValid()) + { WriteString(out, MovieKeys::PatchFile, patchFile.GetFileName()); WriteString(out, MovieKeys::PatchFileSha1, patchFile.GetSha1Hash()); - + romFile.ApplyPatch(patchFile); WriteString(out, MovieKeys::PatchedRomSha1, romFile.GetSha1Hash()); } ConsoleRegion region = _console->GetRegion(); - switch(region) { - case ConsoleRegion::Auto: - case ConsoleRegion::Ntsc: WriteString(out, MovieKeys::Region, "NTSC"); break; + switch (region) + { + case ConsoleRegion::Auto: + case ConsoleRegion::Ntsc: WriteString(out, MovieKeys::Region, "NTSC"); + break; - case ConsoleRegion::Pal: WriteString(out, MovieKeys::Region, "PAL"); break; + case ConsoleRegion::Pal: WriteString(out, MovieKeys::Region, "PAL"); + break; } WriteString(out, MovieKeys::Controller1, ControllerTypeNames[(int)inputConfig.Controllers[0].Type]); @@ -109,36 +121,42 @@ void MovieRecorder::GetGameSettings(stringstream &out) WriteInt(out, MovieKeys::ExtraScanlinesBeforeNmi, emuConfig.PpuExtraScanlinesBeforeNmi); WriteInt(out, MovieKeys::ExtraScanlinesAfterNmi, emuConfig.PpuExtraScanlinesAfterNmi); WriteInt(out, MovieKeys::GsuClockSpeed, emuConfig.GsuClockSpeed); - - switch(emuConfig.RamPowerOnState) { - case RamState::AllZeros: WriteString(out, MovieKeys::RamPowerOnState, "AllZeros"); break; - case RamState::AllOnes: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); break; - case RamState::Random: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); break; //TODO: Random memory isn't supported for movies yet + + switch (emuConfig.RamPowerOnState) + { + case RamState::AllZeros: WriteString(out, MovieKeys::RamPowerOnState, "AllZeros"); + break; + case RamState::AllOnes: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); + break; + case RamState::Random: WriteString(out, MovieKeys::RamPowerOnState, "AllOnes"); + break; //TODO: Random memory isn't supported for movies yet } - for(CheatCode &code : _console->GetCheatManager()->GetCheats()) { + for (CheatCode& code : _console->GetCheatManager()->GetCheats()) + { out << "Cheat " << HexUtilities::ToHex24(code.Address) << " " << HexUtilities::ToHex(code.Value) << "\n"; } } -void MovieRecorder::WriteString(stringstream &out, string name, string value) +void MovieRecorder::WriteString(stringstream& out, string name, string value) { out << name << " " << value << "\n"; } -void MovieRecorder::WriteInt(stringstream &out, string name, uint32_t value) +void MovieRecorder::WriteInt(stringstream& out, string name, uint32_t value) { out << name << " " << std::to_string(value) << "\n"; } -void MovieRecorder::WriteBool(stringstream &out, string name, bool enabled) +void MovieRecorder::WriteBool(stringstream& out, string name, bool enabled) { out << name << " " << (enabled ? "true" : "false") << "\n"; } bool MovieRecorder::Stop() { - if(_writer) { + if (_writer) + { _console->GetControlManager()->UnregisterInputRecorder(this); _writer->AddFile(_inputData, "Input.txt"); @@ -147,7 +165,8 @@ bool MovieRecorder::Stop() GetGameSettings(out); _writer->AddFile(out, "GameSettings.txt"); - if(!_author.empty() || !_description.empty()) { + if (!_author.empty() || !_description.empty()) + { stringstream movieInfo; WriteString(movieInfo, "Author", _author); movieInfo << "Description\n" << _description; @@ -156,20 +175,24 @@ bool MovieRecorder::Stop() VirtualFile patchFile = _console->GetRomInfo().PatchFile; vector patchData; - if(patchFile.IsValid() && patchFile.ReadFile(patchData)) { + if (patchFile.IsValid() && patchFile.ReadFile(patchData)) + { _writer->AddFile(patchData, "PatchData.dat"); } - if(_hasSaveState) { + if (_hasSaveState) + { _writer->AddFile(_saveStateData, "SaveState.mss"); } - for(auto kvp : _batteryData) { + for (auto kvp : _batteryData) + { _writer->AddFile(kvp.second, "Battery" + kvp.first); } bool result = _writer->Save(); - if(result) { + if (result) + { MessageManager::DisplayMessage("Movies", "MovieSaved", FolderUtilities::GetFilename(_filename, true)); } return result; @@ -178,30 +201,36 @@ bool MovieRecorder::Stop() return false; } -bool MovieRecorder::CreateMovie(string movieFile, std::deque& data, uint32_t startPosition, uint32_t endPosition) +bool MovieRecorder::CreateMovie(string movieFile, std::deque& data, uint32_t startPosition, + uint32_t endPosition) { _filename = movieFile; _writer.reset(new ZipWriter()); - if (startPosition < data.size() && endPosition <= data.size() && _writer->Initialize(_filename)) { + if (startPosition < data.size() && endPosition <= data.size() && _writer->Initialize(_filename)) + { vector> devices = _console->GetControlManager()->GetControlDevices(); -// if (startPosition > 0 || _console->GetRomInfo().Header.SramSize || _console->GetSettings()->GetRamPowerOnState() == RamPowerOnState::Random) { // TODO? - //Create a movie from a savestate if we don't start from the beginning (or if the game has save ram, or if the power on ram state is random) - _hasSaveState = true; - _saveStateData = stringstream(); - _console->GetSaveStateManager()->GetSaveStateHeader(_saveStateData); - data[startPosition].GetStateData(_saveStateData); -// } + // if (startPosition > 0 || _console->GetRomInfo().Header.SramSize || _console->GetSettings()->GetRamPowerOnState() == RamPowerOnState::Random) { // TODO? + //Create a movie from a savestate if we don't start from the beginning (or if the game has save ram, or if the power on ram state is random) + _hasSaveState = true; + _saveStateData = stringstream(); + _console->GetSaveStateManager()->GetSaveStateHeader(_saveStateData); + data[startPosition].GetStateData(_saveStateData); + // } _inputData = stringstream(); - for (uint32_t i = startPosition; i < endPosition; i++) { + for (uint32_t i = startPosition; i < endPosition; i++) + { RewindData rewindData = data[i]; - for (uint32_t i = 0; i < 60; i++) { - for (shared_ptr& device : devices) { + for (uint32_t i = 0; i < 60; i++) + { + for (shared_ptr& device : devices) + { uint8_t port = device->GetPort(); - if (i < rewindData.InputLogs[port].size()) { + if (i < rewindData.InputLogs[port].size()) + { device->SetRawState(rewindData.InputLogs[port][i]); _inputData << ("|" + device->GetTextState()); } @@ -219,7 +248,8 @@ bool MovieRecorder::CreateMovie(string movieFile, std::deque& data, void MovieRecorder::RecordInput(vector> devices) { - for(shared_ptr &device : devices) { + for (shared_ptr& device : devices) + { _inputData << ("|" + device->GetTextState()); } _inputData << "\n"; @@ -235,9 +265,10 @@ vector MovieRecorder::LoadBattery(string extension) return vector(); } -void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void *parameter) +void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(type == ConsoleNotificationType::GameLoaded) { + if (type == ConsoleNotificationType::GameLoaded) + { _console->GetControlManager()->RegisterInputRecorder(this); } } diff --git a/Core/MovieRecorder.h b/Core/MovieRecorder.h index b2ec281..8767565 100644 --- a/Core/MovieRecorder.h +++ b/Core/MovieRecorder.h @@ -12,7 +12,8 @@ class Console; class RewindData; //struct CodeInfo; -class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this +class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, + public IBatteryProvider, public std::enable_shared_from_this { private: static const uint32_t MovieFormatVersion = 1; @@ -27,11 +28,11 @@ private: bool _hasSaveState = false; stringstream _saveStateData; - void GetGameSettings(stringstream &out); + void GetGameSettings(stringstream& out); //void WriteCheat(stringstream &out, CodeInfo &code); - void WriteString(stringstream &out, string name, string value); - void WriteInt(stringstream &out, string name, uint32_t value); - void WriteBool(stringstream &out, string name, bool enabled); + void WriteString(stringstream& out, string name, string value); + void WriteInt(stringstream& out, string name, uint32_t value); + void WriteBool(stringstream& out, string name, bool enabled); public: MovieRecorder(shared_ptr console); @@ -50,5 +51,5 @@ public: vector LoadBattery(string extension) override; // Inherited via INotificationListener - void ProcessNotification(ConsoleNotificationType type, void *parameter) override; + void ProcessNotification(ConsoleNotificationType type, void* parameter) override; }; diff --git a/Core/MovieTypes.h b/Core/MovieTypes.h index 7c324a6..9564c8a 100644 --- a/Core/MovieTypes.h +++ b/Core/MovieTypes.h @@ -58,4 +58,4 @@ namespace MovieKeys constexpr const char* RamPowerOnState = "RamPowerOnState"; constexpr const char* InputPollScanline = "InputPollScanline"; constexpr const char* GsuClockSpeed = "GsuClockSpeed"; -}; \ No newline at end of file +}; diff --git a/Core/Msu1.cpp b/Core/Msu1.cpp index e969bec..cea1ee0 100644 --- a/Core/Msu1.cpp +++ b/Core/Msu1.cpp @@ -8,11 +8,16 @@ Msu1* Msu1::Init(VirtualFile romFile, Spc* spc) { string romFolder = romFile.GetFolderPath(); string romName = FolderUtilities::GetFilename(romFile.GetFileName(), false); - if(ifstream(FolderUtilities::CombinePath(romFolder, romName + ".msu"))) { + if (ifstream(FolderUtilities::CombinePath(romFolder, romName + ".msu"))) + { return new Msu1(romFile, spc); - } else if(ifstream(FolderUtilities::CombinePath(romFolder, "msu1.rom"))) { + } + else if (ifstream(FolderUtilities::CombinePath(romFolder, "msu1.rom"))) + { return new Msu1(romFile, spc); - } else { + } + else + { return nullptr; } } @@ -23,71 +28,86 @@ Msu1::Msu1(VirtualFile romFile, Spc* spc) _romFolder = romFile.GetFolderPath(); _romName = FolderUtilities::GetFilename(romFile.GetFileName(), false); _dataFile.open(FolderUtilities::CombinePath(_romFolder, _romName) + ".msu", ios::binary); - if(_dataFile) { + if (_dataFile) + { _trackPath = FolderUtilities::CombinePath(_romFolder, _romName); - } else { + } + else + { _dataFile.open(FolderUtilities::CombinePath(_romFolder, "msu1.rom"), ios::binary); _trackPath = FolderUtilities::CombinePath(_romFolder, "track"); } - if(_dataFile) { + if (_dataFile) + { _dataFile.seekg(0, ios::end); _dataSize = (uint32_t)_dataFile.tellg(); - } else { + } + else + { _dataSize = 0; } } void Msu1::Write(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2000: _tmpDataPointer = (_tmpDataPointer & 0xFFFFFF00) | value; break; - case 0x2001: _tmpDataPointer = (_tmpDataPointer & 0xFFFF00FF) | (value << 8); break; - case 0x2002: _tmpDataPointer = (_tmpDataPointer & 0xFF00FFFF) | (value << 16); break; - case 0x2003: - _tmpDataPointer = (_tmpDataPointer & 0x00FFFFFF) | (value << 24); - _dataPointer = _tmpDataPointer; - _dataFile.seekg(_dataPointer, ios::beg); - break; + switch (addr) + { + case 0x2000: _tmpDataPointer = (_tmpDataPointer & 0xFFFFFF00) | value; + break; + case 0x2001: _tmpDataPointer = (_tmpDataPointer & 0xFFFF00FF) | (value << 8); + break; + case 0x2002: _tmpDataPointer = (_tmpDataPointer & 0xFF00FFFF) | (value << 16); + break; + case 0x2003: + _tmpDataPointer = (_tmpDataPointer & 0x00FFFFFF) | (value << 24); + _dataPointer = _tmpDataPointer; + _dataFile.seekg(_dataPointer, ios::beg); + break; - case 0x2004: _trackSelect = (_trackSelect & 0xFF00) | value; break; - case 0x2005: - _trackSelect = (_trackSelect & 0xFF) | (value << 8); - LoadTrack(); - break; + case 0x2004: _trackSelect = (_trackSelect & 0xFF00) | value; + break; + case 0x2005: + _trackSelect = (_trackSelect & 0xFF) | (value << 8); + LoadTrack(); + break; - case 0x2006: _volume = value; break; - case 0x2007: - if(!_audioBusy) { - _repeat = (value & 0x02) != 0; - _paused = (value & 0x01) == 0; - _pcmReader.SetLoopFlag(_repeat); - } - break; + case 0x2006: _volume = value; + break; + case 0x2007: + if (!_audioBusy) + { + _repeat = (value & 0x02) != 0; + _paused = (value & 0x01) == 0; + _pcmReader.SetLoopFlag(_repeat); + } + break; } } uint8_t Msu1::Read(uint16_t addr) { - switch(addr) { - case 0x2000: - //status - return (_dataBusy << 7) | (_audioBusy << 6) | (_repeat << 5) | ((!_paused) << 4) | (_trackMissing << 3) | 0x01; + switch (addr) + { + case 0x2000: + //status + return (_dataBusy << 7) | (_audioBusy << 6) | (_repeat << 5) | ((!_paused) << 4) | (_trackMissing << 3) | 0x01; - case 0x2001: - //data - if(!_dataBusy && _dataPointer < _dataSize) { - _dataPointer++; - return (uint8_t)_dataFile.get(); - } - return 0; + case 0x2001: + //data + if (!_dataBusy && _dataPointer < _dataSize) + { + _dataPointer++; + return (uint8_t)_dataFile.get(); + } + return 0; - case 0x2002: return 'S'; - case 0x2003: return '-'; - case 0x2004: return 'M'; - case 0x2005: return 'S'; - case 0x2006: return 'U'; - case 0x2007: return '1'; + case 0x2002: return 'S'; + case 0x2003: return '-'; + case 0x2004: return 'M'; + case 0x2005: return 'S'; + case 0x2006: return 'U'; + case 0x2007: return '1'; } return 0; @@ -95,7 +115,8 @@ uint8_t Msu1::Read(uint16_t addr) void Msu1::MixAudio(int16_t* buffer, size_t sampleCount, uint32_t sampleRate) { - if(!_paused) { + if (!_paused) + { _pcmReader.SetSampleRate(sampleRate); _pcmReader.ApplySamples(buffer, sampleCount, _spc->IsMuted() ? 0 : _volume); } @@ -106,11 +127,13 @@ void Msu1::LoadTrack(uint32_t startOffset) _trackMissing = !_pcmReader.Init(_trackPath + "-" + std::to_string(_trackSelect) + ".pcm", _repeat, startOffset); } -void Msu1::Serialize(Serializer &s) +void Msu1::Serialize(Serializer& s) { uint32_t offset = _pcmReader.GetOffset(); - s.Stream(_trackSelect, _tmpDataPointer, _dataPointer, _repeat, _paused, _volume, _trackMissing, _audioBusy, _dataBusy, offset); - if(!s.IsSaving()) { + s.Stream(_trackSelect, _tmpDataPointer, _dataPointer, _repeat, _paused, _volume, _trackMissing, _audioBusy, + _dataBusy, offset); + if (!s.IsSaving()) + { _dataFile.seekg(_dataPointer, ios::beg); LoadTrack(offset); } diff --git a/Core/Msu1.h b/Core/Msu1.h index 85cbab0..2a7f805 100644 --- a/Core/Msu1.h +++ b/Core/Msu1.h @@ -9,7 +9,7 @@ class Spc; class Msu1 final : public ISerializable { private: - Spc * _spc; + Spc* _spc; PcmReader _pcmReader; uint8_t _volume = 100; uint16_t _trackSelect = 0; @@ -27,18 +27,18 @@ private: ifstream _dataFile; uint32_t _dataSize; - + void LoadTrack(uint32_t startOffset = 8); public: Msu1(VirtualFile romFile, Spc* spc); - + static Msu1* Init(VirtualFile romFile, Spc* spc); void Write(uint16_t addr, uint8_t value); uint8_t Read(uint16_t addr); - - void MixAudio(int16_t *buffer, size_t sampleCount, uint32_t sampleRate); - - void Serialize(Serializer &s); -}; \ No newline at end of file + + void MixAudio(int16_t* buffer, size_t sampleCount, uint32_t sampleRate); + + void Serialize(Serializer& s); +}; diff --git a/Core/Multitap.cpp b/Core/Multitap.cpp index 5f1b8df..682a4f6 100644 --- a/Core/Multitap.cpp +++ b/Core/Multitap.cpp @@ -11,9 +11,11 @@ string Multitap::GetKeyNames() void Multitap::InternalSetStateFromInput() { - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { int offset = Multitap::ButtonCount * i; - for(KeyMapping keyMapping : _mappings[i]) { + for (KeyMapping keyMapping : _mappings[i]) + { SetPressedState(Buttons::A + offset, keyMapping.A); SetPressedState(Buttons::B + offset, keyMapping.B); SetPressedState(Buttons::X + offset, keyMapping.X); @@ -29,7 +31,8 @@ void Multitap::InternalSetStateFromInput() uint8_t turboFreq = 1 << (4 - _turboSpeed[i]); bool turboOn = (uint8_t)(_console->GetFrameCount() % turboFreq) < turboFreq / 2; - if(turboOn) { + if (turboOn) + { SetPressedState(Buttons::A + offset, keyMapping.TurboA); SetPressedState(Buttons::B + offset, keyMapping.TurboB); SetPressedState(Buttons::X + offset, keyMapping.TurboX); @@ -41,7 +44,7 @@ void Multitap::InternalSetStateFromInput() } } -void Multitap::UpdateControllerState(uint8_t controllerNumber, SnesController &controller) +void Multitap::UpdateControllerState(uint8_t controllerNumber, SnesController& controller) { int offset = Multitap::ButtonCount * controllerNumber; SetBitValue(Buttons::A + offset, controller.IsPressed(Buttons::A)); @@ -79,7 +82,7 @@ uint16_t Multitap::ToByte(uint8_t port) ((uint8_t)IsPressed(Buttons::R + offset) << 11); } -void Multitap::Serialize(Serializer & s) +void Multitap::Serialize(Serializer& s) { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer[0], _stateBuffer[1], _stateBuffer[2], _stateBuffer[3]); @@ -87,12 +90,15 @@ void Multitap::Serialize(Serializer & s) void Multitap::RefreshStateBuffer() { - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _stateBuffer[i] = ToByte(i); } } -Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console, port, keyMappings1) +Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, + KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice( + console, port, keyMappings1) { _turboSpeed[0] = keyMappings1.TurboSpeed; _turboSpeed[1] = keyMappings2.TurboSpeed; @@ -124,13 +130,15 @@ uint8_t Multitap::ReadRam(uint16_t addr) uint8_t portSelect = (_internalRegs->GetIoPortOutput() & selectBit) ? 0 : 2; uint8_t output = 0; - if(IsCurrentPort(addr)) { + if (IsCurrentPort(addr)) + { StrobeProcessRead(); output = _stateBuffer[portSelect] & 0x01; - output |= (_stateBuffer[portSelect + 1] & 0x01) << 1; //P3 & P5 are reported in bit 1 + output |= (_stateBuffer[portSelect + 1] & 0x01) << 1; //P3 & P5 are reported in bit 1 - if(_strobe) { + if (_strobe) + { //Bit 1 is always set when strobe is high output |= 0x02; } @@ -148,7 +156,8 @@ uint8_t Multitap::ReadRam(uint16_t addr) void Multitap::WriteRam(uint16_t addr, uint8_t value) { - if(addr == 0x4016) { + if (addr == 0x4016) + { StrobeProcessWrite(value); } } diff --git a/Core/Multitap.h b/Core/Multitap.h index e84b8c8..b9979cd 100644 --- a/Core/Multitap.h +++ b/Core/Multitap.h @@ -10,23 +10,25 @@ class Multitap : public BaseControlDevice { private: enum Buttons { A = 0, B, X, Y, L, R, Select, Start, Up, Down, Left, Right }; + static constexpr int ButtonCount = 12; vector _mappings[4]; uint8_t _turboSpeed[4] = {}; uint16_t _stateBuffer[4] = {}; - InternalRegisters *_internalRegs = nullptr; + InternalRegisters* _internalRegs = nullptr; protected: string GetKeyNames() override; void InternalSetStateFromInput() override; - void UpdateControllerState(uint8_t controllerNumber, SnesController &controller); + void UpdateControllerState(uint8_t controllerNumber, SnesController& controller); uint16_t ToByte(uint8_t port); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void RefreshStateBuffer() override; public: - Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4); + Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, + KeyMappingSet keyMappings3, KeyMappingSet keyMappings4); ControllerType GetControllerType() override; @@ -34,4 +36,4 @@ public: uint8_t ReadRam(uint16_t addr) override; void WriteRam(uint16_t addr, uint8_t value) override; -}; \ No newline at end of file +}; diff --git a/Core/NecDsp.cpp b/Core/NecDsp.cpp index 49b750c..691fb94 100644 --- a/Core/NecDsp.cpp +++ b/Core/NecDsp.cpp @@ -13,18 +13,23 @@ #include "FirmwareHelper.h" #include "../Utilities/FolderUtilities.h" -NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programRom, vector &dataRom) : BaseCoprocessor(SnesMemoryType::Register) +NecDsp::NecDsp(CoprocessorType type, Console* console, vector& programRom, + vector& dataRom) : BaseCoprocessor(SnesMemoryType::Register) { _console = console; _type = type; _memoryManager = console->GetMemoryManager().get(); _memoryType = SnesMemoryType::Register; - MemoryMappings *mm = _memoryManager->GetMemoryMappings(); - - if(type == CoprocessorType::ST010 || type == CoprocessorType::ST011) { - if(type == CoprocessorType::ST010) { + MemoryMappings* mm = _memoryManager->GetMemoryMappings(); + + if (type == CoprocessorType::ST010 || type == CoprocessorType::ST011) + { + if (type == CoprocessorType::ST010) + { _frequency = 11000000; - } else { + } + else + { _frequency = 22000000; } _registerMask = 0x0001; @@ -34,11 +39,14 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR mm->RegisterHandler(0xE0, 0xE0, 0x0000, 0x0FFF, this); mm->RegisterHandler(0x68, 0x6F, 0x0000, 0x0FFF, this); mm->RegisterHandler(0xE8, 0xEF, 0x0000, 0x0FFF, this); - } else { + } + else + { _ramSize = 0x100; _stackSize = 4; _frequency = 7600000; - if(console->GetCartridge()->GetCartFlags() & CartFlags::LoRom) { + if (console->GetCartridge()->GetCartFlags() & CartFlags::LoRom) + { _registerMask = 0x4000; mm->RegisterHandler(0x30, 0x3F, 0x8000, 0xFFFF, this); mm->RegisterHandler(0xB0, 0xBF, 0x8000, 0xFFFF, this); @@ -46,7 +54,9 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR //For Super Bases Loaded 2 mm->RegisterHandler(0x60, 0x6F, 0x0000, 0x7FFF, this); mm->RegisterHandler(0xE0, 0xEF, 0x0000, 0x7FFF, this); - } else if(console->GetCartridge()->GetCartFlags() & CartFlags::HiRom) { + } + else if (console->GetCartridge()->GetCartFlags() & CartFlags::HiRom) + { _registerMask = 0x1000; mm->RegisterHandler(0x00, 0x1F, 0x6000, 0x7FFF, this); mm->RegisterHandler(0x80, 0x9F, 0x6000, 0x7FFF, this); @@ -56,7 +66,7 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR _progSize = (uint32_t)programRom.size(); _progRom = new uint8_t[_progSize]; _prgCache = new uint32_t[_progSize / 3]; - _progMask = (_progSize / 3)- 1; + _progMask = (_progSize / 3) - 1; _dataSize = (uint32_t)dataRom.size() / 2; _dataRom = new uint16_t[_dataSize]; @@ -73,7 +83,8 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR memcpy(_progRom, programRom.data(), _progSize); BuildProgramCache(); - for(uint32_t i = 0; i < _dataSize; i++) { + for (uint32_t i = 0; i < _dataSize; i++) + { _dataRom[i] = dataRom[i * 2] | (dataRom[i * 2 + 1] << 8); } } @@ -86,23 +97,46 @@ NecDsp::~NecDsp() delete[] _ram; } -NecDsp* NecDsp::InitCoprocessor(CoprocessorType type, Console *console, vector &embeddedFirware) +NecDsp* NecDsp::InitCoprocessor(CoprocessorType type, Console* console, vector& embeddedFirware) { bool firmwareLoaded = false; vector programRom; vector dataRom; - switch(type) { - case CoprocessorType::DSP1: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP1, "dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP1B: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP1B, "dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP2: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP2, "dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP3: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP3, "dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::DSP4: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP4, "dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", programRom, dataRom, embeddedFirware); break; - case CoprocessorType::ST010: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::ST010, "st010.rom", "st010.program.rom", "st010.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break; - case CoprocessorType::ST011: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::ST011, "st011.rom", "st011.program.rom", "st011.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break; - default: break; + switch (type) + { + case CoprocessorType::DSP1: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP1, "dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP1B: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP1B, "dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP2: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP2, "dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP3: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP3, "dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::DSP4: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::DSP4, "dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", programRom, dataRom, + embeddedFirware); + break; + case CoprocessorType::ST010: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::ST010, "st010.rom", "st010.program.rom", "st010.data.rom", programRom, dataRom, + embeddedFirware, 0xC000, 0x1000); + break; + case CoprocessorType::ST011: firmwareLoaded = FirmwareHelper::LoadDspFirmware( + console, FirmwareType::ST011, "st011.rom", "st011.program.rom", "st011.data.rom", programRom, dataRom, + embeddedFirware, 0xC000, 0x1000); + break; + default: break; } - if(!firmwareLoaded) { + if (!firmwareLoaded) + { return nullptr; } @@ -117,14 +151,16 @@ void NecDsp::Reset() void NecDsp::LoadBattery() { - if(_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) { + if (_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) + { _console->GetBatteryManager()->LoadBattery(".srm", (uint8_t*)_ram, _ramSize * sizeof(uint16_t)); } } void NecDsp::SaveBattery() { - if(_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) { + if (_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) + { _console->GetBatteryManager()->SaveBattery(".srm", (uint8_t*)_ram, _ramSize * sizeof(uint16_t)); } } @@ -132,7 +168,8 @@ void NecDsp::SaveBattery() void NecDsp::BuildProgramCache() { //For the sake of performance, keep a precalculated array of 24-bit opcodes for each entry in the ROM - for(uint32_t i = 0; i < _progSize / 3; i++) { + for (uint32_t i = 0; i < _progSize / 3; i++) + { _prgCache[i] = _progRom[i * 3] | (_progRom[i * 3 + 1] << 8) | (_progRom[i * 3 + 2] << 16); } } @@ -147,20 +184,27 @@ void NecDsp::Run() { uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * (_frequency / _console->GetMasterClockRate())); - if(_inRqmLoop && !_console->IsDebugging()) { + if (_inRqmLoop && !_console->IsDebugging()) + { _cycleCount = targetCycle; return; } - while(_cycleCount < targetCycle) { + while (_cycleCount < targetCycle) + { ReadOpCode(); _state.PC++; - switch(_opCode & 0xC00000) { - case 0x000000: ExecOp(); break; - case 0x400000: ExecAndReturn(); break; - case 0x800000: Jump(); break; - case 0xC00000: Load(_opCode & 0x0F, (uint16_t)(_opCode >> 6)); break; + switch (_opCode & 0xC00000) + { + case 0x000000: ExecOp(); + break; + case 0x400000: ExecAndReturn(); + break; + case 0x800000: Jump(); + break; + case 0xC00000: Load(_opCode & 0x0F, (uint16_t)(_opCode >> 6)); + break; } //Store the multiplication's result @@ -176,28 +220,39 @@ uint8_t NecDsp::Read(uint32_t addr) { Run(); - if((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) { + if ((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) + { //RAM (Banks $68-$6F) uint16_t value = _ram[(addr >> 1) & _ramMask]; return (addr & 0x01) ? (uint8_t)(value >> 8) : (uint8_t)value; - } else if(addr & _registerMask) { + } + else if (addr & _registerMask) + { //SR return (_state.SR >> 8); - } else { + } + else + { //DR _inRqmLoop = false; - if(_state.SR & NecDspStatusFlags::DataRegControl) { + if (_state.SR & NecDspStatusFlags::DataRegControl) + { //8 bits _state.SR &= ~NecDspStatusFlags::RequestForMaster; return (uint8_t)_state.DR; - } else { + } + else + { //16 bits - if(_state.SR & NecDspStatusFlags::DataRegStatus) { + if (_state.SR & NecDspStatusFlags::DataRegStatus) + { _state.SR &= ~NecDspStatusFlags::RequestForMaster; _state.SR &= ~NecDspStatusFlags::DataRegStatus; return _state.DR >> 8; - } else { + } + else + { _state.SR |= NecDspStatusFlags::DataRegStatus; return (uint8_t)_state.DR; } @@ -209,29 +264,41 @@ void NecDsp::Write(uint32_t addr, uint8_t value) { Run(); - if((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) { + if ((_type == CoprocessorType::ST010 || _type == CoprocessorType::ST011) && (addr & 0x0F0000) >= 0x080000) + { //RAM (Banks $68-$6F) uint16_t ramAddr = (addr >> 1) & _ramMask; - if(addr & 0x01) { + if (addr & 0x01) + { _ram[ramAddr] = (_ram[ramAddr] & 0xFF) | (value << 8); - } else { + } + else + { _ram[ramAddr] = (_ram[ramAddr] & 0xFF00) | value; } - } else if(!(addr & _registerMask)) { + } + else if (!(addr & _registerMask)) + { //DR _inRqmLoop = false; - if(_state.SR & NecDspStatusFlags::DataRegControl) { + if (_state.SR & NecDspStatusFlags::DataRegControl) + { //8 bits _state.SR &= ~NecDspStatusFlags::RequestForMaster; _state.DR = (_state.DR & 0xFF00) | value; - } else { + } + else + { //16 bits - if(_state.SR & NecDspStatusFlags::DataRegStatus) { + if (_state.SR & NecDspStatusFlags::DataRegStatus) + { _state.SR &= ~NecDspStatusFlags::RequestForMaster; _state.SR &= ~NecDspStatusFlags::DataRegStatus; _state.DR = (_state.DR & 0xFF) | (value << 8); - } else { + } + else + { _state.SR |= NecDspStatusFlags::DataRegStatus; _state.DR = (_state.DR & 0xFF00) | value; } @@ -245,14 +312,14 @@ uint8_t NecDsp::Peek(uint32_t addr) return 0; } -void NecDsp::PeekBlock(uint32_t addr, uint8_t *output) +void NecDsp::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } AddressInfo NecDsp::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) @@ -268,78 +335,121 @@ void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) //Select the 2nd operand for the operation uint8_t pSelect = (_opCode >> 20) & 0x03; uint16_t p; - switch(pSelect) { - case 0: p = _ram[_state.DP & _ramMask]; break; - case 1: p = source; break; - case 2: p = _state.M; break; - case 3: p = _state.N; break; + switch (pSelect) + { + case 0: p = _ram[_state.DP & _ramMask]; + break; + case 1: p = source; + break; + case 2: p = _state.M; + break; + case 3: p = _state.N; + break; } //Perform the ALU operation, and set flags - switch(aluOperation) { - case 0x00: break; - case 0x01: result = acc | p; break; - case 0x02: result = acc & p; break; - case 0x03: result = acc ^ p; break; - case 0x04: result = acc - p; break; - case 0x05: result = acc + p; break; - case 0x06: result = acc - p - otherCarry; break; - case 0x07: result = acc + p + otherCarry; break; - case 0x08: result = acc - 1; p = 1; break; - case 0x09: result = acc + 1; p = 1; break; + switch (aluOperation) + { + case 0x00: break; + case 0x01: result = acc | p; + break; + case 0x02: result = acc & p; + break; + case 0x03: result = acc ^ p; + break; + case 0x04: result = acc - p; + break; + case 0x05: result = acc + p; + break; + case 0x06: result = acc - p - otherCarry; + break; + case 0x07: result = acc + p + otherCarry; + break; + case 0x08: result = acc - 1; + p = 1; + break; + case 0x09: result = acc + 1; + p = 1; + break; - case 0x0A: result = ~acc; break; - case 0x0B: result = (acc >> 1) | (acc & 0x8000); break; - case 0x0C: result = (acc << 1) | (uint8_t)otherCarry; break; - case 0x0D: result = (acc << 2) | 0x03; break; - case 0x0E: result = (acc << 4) | 0x0F; break; - case 0x0F: result = (acc << 8) | (acc >> 8); break; + case 0x0A: result = ~acc; + break; + case 0x0B: result = (acc >> 1) | (acc & 0x8000); + break; + case 0x0C: result = (acc << 1) | (uint8_t)otherCarry; + break; + case 0x0D: result = (acc << 2) | 0x03; + break; + case 0x0E: result = (acc << 4) | 0x0F; + break; + case 0x0F: result = (acc << 8) | (acc >> 8); + break; } flags.Zero = result == 0; flags.Sign0 = (result & 0x8000) >> 15; - if(!flags.Overflow1) { + if (!flags.Overflow1) + { flags.Sign1 = flags.Sign0; } - switch(aluOperation) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x0A: case 0x0D: case 0x0E: case 0x0F: - flags.Carry = false; - flags.Overflow0 = false; - flags.Overflow1 = false; - break; + switch (aluOperation) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x0A: + case 0x0D: + case 0x0E: + case 0x0F: + flags.Carry = false; + flags.Overflow0 = false; + flags.Overflow1 = false; + break; - case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: { + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + { uint16_t overflow = (acc ^ result) & (p ^ ((aluOperation & 0x01) ? result : acc)); flags.Overflow0 = (bool)((overflow & 0x8000) >> 15); - if(flags.Overflow0 && flags.Overflow1) { + if (flags.Overflow0 && flags.Overflow1) + { flags.Overflow1 = flags.Sign0 == flags.Sign1; - } else { + } + else + { flags.Overflow1 |= flags.Overflow0; } flags.Carry = (bool)(((acc ^ p ^ result ^ overflow) & 0x8000) >> 15); break; } - case 0x0B: - flags.Carry = (bool)(acc & 0x01); - flags.Overflow0 = false; - flags.Overflow1 = false; - break; + case 0x0B: + flags.Carry = (bool)(acc & 0x01); + flags.Overflow0 = false; + flags.Overflow1 = false; + break; - case 0x0C: - flags.Carry = (bool)((acc >> 15) & 0x01); - flags.Overflow0 = false; - flags.Overflow1 = false; - break; + case 0x0C: + flags.Carry = (bool)((acc >> 15) & 0x01); + flags.Overflow0 = false; + flags.Overflow1 = false; + break; } //Update selected accumulator/flags with the operation's results - if(accSelect) { + if (accSelect) + { _state.B = result; _state.FlagsB = flags; - } else { + } + else + { _state.A = result; _state.FlagsA = flags; } @@ -348,11 +458,15 @@ void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) void NecDsp::UpdateDataPointer() { uint16_t dp = _state.DP; - switch((_opCode >> 13) & 0x03) { - case 0: break; //NOP - case 1: dp = (dp & 0xF0) | ((dp + 1) & 0x0F); break; //Increment lower nibble, with no carry - case 2: dp = (dp & 0xF0) | ((dp - 1) & 0x0F); break; //Decrement lower nibble, with no carry - case 3: dp &= 0xF0; break; //Clear lower nibble + switch ((_opCode >> 13) & 0x03) + { + case 0: break; //NOP + case 1: dp = (dp & 0xF0) | ((dp + 1) & 0x0F); + break; //Increment lower nibble, with no carry + case 2: dp = (dp & 0xF0) | ((dp - 1) & 0x0F); + break; //Decrement lower nibble, with no carry + case 3: dp &= 0xF0; + break; //Clear lower nibble } uint8_t dpHighModify = (_opCode >> 9) & 0x0F; @@ -365,7 +479,8 @@ void NecDsp::ExecOp() uint16_t source = GetSourceValue((_opCode >> 4) & 0x0F); //First, process the ALU operation, if needed - if(aluOperation) { + if (aluOperation) + { RunApuOp(aluOperation, source); } @@ -373,13 +488,15 @@ void NecDsp::ExecOp() uint8_t dest = _opCode & 0x0F; Load(dest, source); - if(dest != 0x04) { + if (dest != 0x04) + { //Destination was not the data pointer (DP), update it UpdateDataPointer(); } uint8_t rpDecrement = (_opCode >> 8) & 0x01; - if(rpDecrement && dest != 0x05) { + if (rpDecrement && dest != 0x05) + { //Destination was not the rom pointer (RP), decrement it _state.RP--; } @@ -389,7 +506,7 @@ void NecDsp::ExecAndReturn() { ExecOp(); _state.SP = (_state.SP - 1) & _stackMask; - _state.PC = _stack[_state.SP]; + _state.PC = _stack[_state.SP]; } void NecDsp::Jump() @@ -400,67 +517,107 @@ void NecDsp::Jump() uint32_t jmpCond = 0; uint16_t jmpType = (_opCode >> 13) & 0x1FF; - switch(jmpType) { - case 0x00: _state.PC = _state.SerialOut; break; + switch (jmpType) + { + case 0x00: _state.PC = _state.SerialOut; + break; - case 0x80: jmpCond = !_state.FlagsA.Carry; break; - case 0x82: jmpCond = _state.FlagsA.Carry; break; - case 0x84: jmpCond = !_state.FlagsB.Carry; break; - case 0x86: jmpCond = _state.FlagsB.Carry; break; + case 0x80: jmpCond = !_state.FlagsA.Carry; + break; + case 0x82: jmpCond = _state.FlagsA.Carry; + break; + case 0x84: jmpCond = !_state.FlagsB.Carry; + break; + case 0x86: jmpCond = _state.FlagsB.Carry; + break; - case 0x88: jmpCond = !_state.FlagsA.Zero; break; - case 0x8A: jmpCond = _state.FlagsA.Zero; break; - case 0x8C: jmpCond = !_state.FlagsB.Zero; break; - case 0x8E: jmpCond = _state.FlagsB.Zero; break; + case 0x88: jmpCond = !_state.FlagsA.Zero; + break; + case 0x8A: jmpCond = _state.FlagsA.Zero; + break; + case 0x8C: jmpCond = !_state.FlagsB.Zero; + break; + case 0x8E: jmpCond = _state.FlagsB.Zero; + break; - case 0x90: jmpCond = !_state.FlagsA.Overflow0; break; - case 0x92: jmpCond = _state.FlagsA.Overflow0; break; - case 0x94: jmpCond = !_state.FlagsB.Overflow0; break; - case 0x96: jmpCond = _state.FlagsB.Overflow0; break; - case 0x98: jmpCond = !_state.FlagsA.Overflow1; break; - case 0x9A: jmpCond = _state.FlagsA.Overflow1; break; - case 0x9C: jmpCond = !_state.FlagsB.Overflow1; break; - case 0x9E: jmpCond = _state.FlagsB.Overflow1; break; + case 0x90: jmpCond = !_state.FlagsA.Overflow0; + break; + case 0x92: jmpCond = _state.FlagsA.Overflow0; + break; + case 0x94: jmpCond = !_state.FlagsB.Overflow0; + break; + case 0x96: jmpCond = _state.FlagsB.Overflow0; + break; + case 0x98: jmpCond = !_state.FlagsA.Overflow1; + break; + case 0x9A: jmpCond = _state.FlagsA.Overflow1; + break; + case 0x9C: jmpCond = !_state.FlagsB.Overflow1; + break; + case 0x9E: jmpCond = _state.FlagsB.Overflow1; + break; - case 0xA0: jmpCond = !_state.FlagsA.Sign0; break; - case 0xA2: jmpCond = _state.FlagsA.Sign0; break; - case 0xA4: jmpCond = !_state.FlagsB.Sign0; break; - case 0xA6: jmpCond = _state.FlagsB.Sign0; break; - case 0xA8: jmpCond = !_state.FlagsA.Sign1; break; - case 0xAA: jmpCond = _state.FlagsA.Sign1; break; - case 0xAC: jmpCond = !_state.FlagsB.Sign1; break; - case 0xAE: jmpCond = _state.FlagsB.Sign1; break; + case 0xA0: jmpCond = !_state.FlagsA.Sign0; + break; + case 0xA2: jmpCond = _state.FlagsA.Sign0; + break; + case 0xA4: jmpCond = !_state.FlagsB.Sign0; + break; + case 0xA6: jmpCond = _state.FlagsB.Sign0; + break; + case 0xA8: jmpCond = !_state.FlagsA.Sign1; + break; + case 0xAA: jmpCond = _state.FlagsA.Sign1; + break; + case 0xAC: jmpCond = !_state.FlagsB.Sign1; + break; + case 0xAE: jmpCond = _state.FlagsB.Sign1; + break; - case 0xB0: jmpCond = !(_state.DP & 0x0F); break; - case 0xB1: jmpCond = _state.DP & 0x0F; break; - case 0xB2: jmpCond = (_state.DP & 0x0F) == 0x0F; break; - case 0xB3: jmpCond = (_state.DP & 0x0F) != 0x0F; break; + case 0xB0: jmpCond = !(_state.DP & 0x0F); + break; + case 0xB1: jmpCond = _state.DP & 0x0F; + break; + case 0xB2: jmpCond = (_state.DP & 0x0F) == 0x0F; + break; + case 0xB3: jmpCond = (_state.DP & 0x0F) != 0x0F; + break; - case 0xB4: jmpCond = !(_state.SR & NecDspStatusFlags::SerialInControl); break; - case 0xB6: jmpCond = _state.SR & NecDspStatusFlags::SerialInControl; break; - case 0xB8: jmpCond = !(_state.SR & NecDspStatusFlags::SerialOutControl); break; - case 0xBA: jmpCond = _state.SR & NecDspStatusFlags::SerialOutControl; break; - case 0xBC: jmpCond = !(_state.SR & NecDspStatusFlags::RequestForMaster); break; - case 0xBE: jmpCond = _state.SR & NecDspStatusFlags::RequestForMaster; break; + case 0xB4: jmpCond = !(_state.SR & NecDspStatusFlags::SerialInControl); + break; + case 0xB6: jmpCond = _state.SR & NecDspStatusFlags::SerialInControl; + break; + case 0xB8: jmpCond = !(_state.SR & NecDspStatusFlags::SerialOutControl); + break; + case 0xBA: jmpCond = _state.SR & NecDspStatusFlags::SerialOutControl; + break; + case 0xBC: jmpCond = !(_state.SR & NecDspStatusFlags::RequestForMaster); + break; + case 0xBE: jmpCond = _state.SR & NecDspStatusFlags::RequestForMaster; + break; - case 0x100: _state.PC = target & ~0x2000; break; - case 0x101: _state.PC = target | 0x2000; break; + case 0x100: _state.PC = target & ~0x2000; + break; + case 0x101: _state.PC = target | 0x2000; + break; - case 0x140: - _stack[_state.SP] = _state.PC; - _state.SP = (_state.SP + 1) & _stackMask; - _state.PC = target & ~0x2000; - break; + case 0x140: + _stack[_state.SP] = _state.PC; + _state.SP = (_state.SP + 1) & _stackMask; + _state.PC = target & ~0x2000; + break; - case 0x141: - _stack[_state.SP] = _state.PC; - _state.SP = (_state.SP + 1) & _stackMask; - _state.PC = target | 0x2000; - break; + case 0x141: + _stack[_state.SP] = _state.PC; + _state.SP = (_state.SP + 1) & _stackMask; + _state.PC = target | 0x2000; + break; } - if(jmpCond) { - if((_state.PC - 1 == target) && (jmpType == 0xBC || jmpType == 0xBE)) { + if (jmpCond) + { + if ((_state.PC - 1 == target) && (jmpType == 0xBC || jmpType == 0xBE)) + { //CPU is in a wait loop for RQM, skip emulation until the CPU reads/writes from the IO registers _inRqmLoop = true; } @@ -470,69 +627,82 @@ void NecDsp::Jump() void NecDsp::Load(uint8_t dest, uint16_t value) { - switch(dest) { - case 0x00: break; - case 0x01: _state.A = value; break; - case 0x02: _state.B = value; break; - case 0x03: _state.TR = value; break; - case 0x04: _state.DP = value; break; - case 0x05: _state.RP = value; break; + switch (dest) + { + case 0x00: break; + case 0x01: _state.A = value; + break; + case 0x02: _state.B = value; + break; + case 0x03: _state.TR = value; + break; + case 0x04: _state.DP = value; + break; + case 0x05: _state.RP = value; + break; - case 0x06: - _state.DR = value; - _state.SR |= NecDspStatusFlags::RequestForMaster; - break; + case 0x06: + _state.DR = value; + _state.SR |= NecDspStatusFlags::RequestForMaster; + break; - case 0x07: - _state.SR = (_state.SR & 0x907C) | (value & ~0x907C); - break; + case 0x07: + _state.SR = (_state.SR & 0x907C) | (value & ~0x907C); + break; - case 0x08: _state.SerialOut = value; break; - case 0x09: _state.SerialOut = value; break; - case 0x0A: _state.K = value; break; + case 0x08: _state.SerialOut = value; + break; + case 0x09: _state.SerialOut = value; + break; + case 0x0A: _state.K = value; + break; - case 0x0B: - _state.K = value; - _state.L = _dataRom[_state.RP & _dataMask]; - break; + case 0x0B: + _state.K = value; + _state.L = _dataRom[_state.RP & _dataMask]; + break; - case 0x0C: - _state.L = value; - _state.K = _ram[(_state.DP | 0x40) & _ramMask]; - break; + case 0x0C: + _state.L = value; + _state.K = _ram[(_state.DP | 0x40) & _ramMask]; + break; - case 0x0D: _state.L = value; break; - case 0x0E: _state.TRB = value; break; - case 0x0F: _ram[_state.DP & _ramMask] = value; break; + case 0x0D: _state.L = value; + break; + case 0x0E: _state.TRB = value; + break; + case 0x0F: _ram[_state.DP & _ramMask] = value; + break; - default: - throw std::runtime_error("DSP-1: invalid destination"); + default: + throw std::runtime_error("DSP-1: invalid destination"); } } uint16_t NecDsp::GetSourceValue(uint8_t source) { - switch(source) { - case 0x00: return _state.TRB; - case 0x01: return _state.A; - case 0x02: return _state.B; - case 0x03: return _state.TR; - case 0x04: return _state.DP; - case 0x05: return _state.RP; - case 0x06: return _dataRom[_state.RP & _dataMask]; - case 0x07: return 0x8000 - _state.FlagsA.Sign1; + switch (source) + { + case 0x00: return _state.TRB; + case 0x01: return _state.A; + case 0x02: return _state.B; + case 0x03: return _state.TR; + case 0x04: return _state.DP; + case 0x05: return _state.RP; + case 0x06: return _dataRom[_state.RP & _dataMask]; + case 0x07: return 0x8000 - _state.FlagsA.Sign1; - case 0x08: - _state.SR |= NecDspStatusFlags::RequestForMaster; - return _state.DR; + case 0x08: + _state.SR |= NecDspStatusFlags::RequestForMaster; + return _state.DR; - case 0x09: return _state.DR; - case 0x0A: return _state.SR; - case 0x0B: return _state.SerialIn; - case 0x0C: return _state.SerialIn; - case 0x0D: return _state.K; - case 0x0E: return _state.L; - case 0x0F: return _ram[_state.DP & _ramMask]; + case 0x09: return _state.DR; + case 0x0A: return _state.SR; + case 0x0B: return _state.SerialIn; + case 0x0C: return _state.SerialIn; + case 0x0D: return _state.K; + case 0x0E: return _state.L; + case 0x0F: return _ram[_state.DP & _ramMask]; } throw std::runtime_error("DSP-1: invalid source"); } @@ -572,13 +742,15 @@ NecDspState NecDsp::GetState() return _state; } -void NecDsp::Serialize(Serializer &s) +void NecDsp::Serialize(Serializer& s) { s.Stream( _state.A, _state.B, _state.DP, _state.DR, _state.K, _state.L, _state.M, _state.N, _state.PC, - _state.RP, _state.SerialIn, _state.SerialOut, _state.SP, _state.SR, _state.TR, _state.TRB, - _state.FlagsA.Carry, _state.FlagsA.Overflow0, _state.FlagsA.Overflow1, _state.FlagsA.Sign0, _state.FlagsA.Sign1, _state.FlagsA.Zero, - _state.FlagsB.Carry, _state.FlagsB.Overflow0, _state.FlagsB.Overflow1, _state.FlagsB.Sign0, _state.FlagsB.Sign1, _state.FlagsB.Zero + _state.RP, _state.SerialIn, _state.SerialOut, _state.SP, _state.SR, _state.TR, _state.TRB, + _state.FlagsA.Carry, _state.FlagsA.Overflow0, _state.FlagsA.Overflow1, _state.FlagsA.Sign0, _state.FlagsA.Sign1, + _state.FlagsA.Zero, + _state.FlagsB.Carry, _state.FlagsB.Overflow0, _state.FlagsB.Overflow1, _state.FlagsB.Sign0, _state.FlagsB.Sign1, + _state.FlagsB.Zero ); s.Stream(_opCode, _cycleCount, _inRqmLoop); @@ -591,77 +763,94 @@ void NecDsp::SetReg(NecDspRegister reg, uint16_t value) switch (reg) { case NecDspRegister::NecDspRegA: - { - _state.A = value; - } break; + { + _state.A = value; + } + break; case NecDspRegister::NecDspRegFlagsA: - { - _state.FlagsA.SetFlags(value & 0xFF); - } break; + { + _state.FlagsA.SetFlags(value & 0xFF); + } + break; case NecDspRegister::NecDspRegB: - { - _state.B = value; - } break; + { + _state.B = value; + } + break; case NecDspRegister::NecDspRegFlagsB: - { - _state.FlagsB.SetFlags(value & 0xFF); - } break; + { + _state.FlagsB.SetFlags(value & 0xFF); + } + break; case NecDspRegister::NecDspRegTR: - { - _state.TR = value; - } break; + { + _state.TR = value; + } + break; case NecDspRegister::NecDspRegTRB: - { - _state.TRB = value; - } break; + { + _state.TRB = value; + } + break; case NecDspRegister::NecDspRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case NecDspRegister::NecDspRegRP: - { - _state.RP = value; - } break; + { + _state.RP = value; + } + break; case NecDspRegister::NecDspRegDP: - { - _state.DP = value; - } break; + { + _state.DP = value; + } + break; case NecDspRegister::NecDspRegDR: - { - _state.DR = value; - } break; + { + _state.DR = value; + } + break; case NecDspRegister::NecDspRegSR: - { - _state.SR = value; - } break; + { + _state.SR = value; + } + break; case NecDspRegister::NecDspRegK: - { - _state.K = value; - } break; + { + _state.K = value; + } + break; case NecDspRegister::NecDspRegL: - { - _state.L = value; - } break; + { + _state.L = value; + } + break; case NecDspRegister::NecDspRegM: - { - _state.M = value; - } break; + { + _state.M = value; + } + break; case NecDspRegister::NecDspRegN: - { - _state.N = value; - } break; + { + _state.N = value; + } + break; case NecDspRegister::NecDspRegSerialOut: - { - _state.SerialOut = value; - } break; + { + _state.SerialOut = value; + } + break; case NecDspRegister::NecDspRegSerialIn: - { - _state.SerialIn = value; - } break; + { + _state.SerialIn = value; + } + break; case NecDspRegister::NecDspRegSP: - { - _state.SP = value & 0xFF; - } break; + { + _state.SP = value & 0xFF; + } + break; } } - diff --git a/Core/NecDsp.h b/Core/NecDsp.h index 184356a..53246e4 100644 --- a/Core/NecDsp.h +++ b/Core/NecDsp.h @@ -19,10 +19,10 @@ private: double _frequency = 7600000; uint32_t _opCode = 0; - uint8_t *_progRom = nullptr; - uint32_t *_prgCache = nullptr; - uint16_t *_dataRom = nullptr; - uint16_t *_ram = nullptr; + uint8_t* _progRom = nullptr; + uint32_t* _prgCache = nullptr; + uint16_t* _dataRom = nullptr; + uint16_t* _ram = nullptr; uint16_t _stack[16]; uint32_t _progSize = 0; @@ -51,12 +51,12 @@ private: void Load(uint8_t dest, uint16_t value); uint16_t GetSourceValue(uint8_t source); - NecDsp(CoprocessorType type, Console* console, vector &programRom, vector &dataRom); + NecDsp(CoprocessorType type, Console* console, vector& programRom, vector& dataRom); public: virtual ~NecDsp(); - static NecDsp* InitCoprocessor(CoprocessorType type, Console* console, vector &embeddedFirmware); + static NecDsp* InitCoprocessor(CoprocessorType type, Console* console, vector& embeddedFirmware); void Reset() override; void Run() override; @@ -65,12 +65,12 @@ public: void SaveBattery() override; void BuildProgramCache(); - + uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; - + uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t * output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; uint8_t* DebugGetProgramRom(); @@ -81,7 +81,7 @@ public: uint32_t DebugGetDataRamSize(); NecDspState GetState(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(NecDspRegister reg, uint16_t value); -}; \ No newline at end of file +}; diff --git a/Core/NecDspDebugger.cpp b/Core/NecDspDebugger.cpp index f8768c1..dec3ec1 100644 --- a/Core/NecDspDebugger.cpp +++ b/Core/NecDspDebugger.cpp @@ -32,14 +32,21 @@ void NecDspDebugger::Reset() void NecDspDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType type) { - AddressInfo addressInfo = { (int32_t)addr, type == MemoryOperationType::ExecOpCode ? SnesMemoryType::DspProgramRom : SnesMemoryType::DspDataRom }; - MemoryOperationInfo operation { (uint32_t)addr, value, type }; + AddressInfo addressInfo = { + (int32_t)addr, + type == MemoryOperationType::ExecOpCode ? SnesMemoryType::DspProgramRom : SnesMemoryType::DspDataRom + }; + MemoryOperationInfo operation{(uint32_t)addr, value, type}; - if(type == MemoryOperationType::ExecOpCode) { - if(_traceLogger->IsCpuLogged(CpuType::NecDsp) || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) { + if (type == MemoryOperationType::ExecOpCode) + { + if (_traceLogger->IsCpuLogged(CpuType::NecDsp) || _settings->CheckDebuggerFlag( + DebuggerFlags::NecDspDebuggerEnabled)) + { _disassembler->BuildCache(addressInfo, 0, CpuType::NecDsp); - if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) { + if (_traceLogger->IsCpuLogged(CpuType::NecDsp)) + { DebugState debugState; _debugger->GetState(debugState, true); @@ -50,7 +57,8 @@ void NecDspDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationTy _prevProgramCounter = addr; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } } @@ -60,8 +68,8 @@ void NecDspDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationTy void NecDspDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { - AddressInfo addressInfo { addr, SnesMemoryType::DspDataRam }; //Writes never affect the DSP ROM - MemoryOperationInfo operation { addr, value, type }; + AddressInfo addressInfo{addr, SnesMemoryType::DspDataRam}; //Writes never affect the DSP ROM + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); } @@ -74,17 +82,19 @@ void NecDspDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - - case StepType::StepOut: - case StepType::StepOver: - step.StepCount = 1; - break; + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + case StepType::StepOut: + case StepType::StepOver: + step.StepCount = 1; + break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -98,4 +108,4 @@ shared_ptr NecDspDebugger::GetCallstackManager() BreakpointManager* NecDspDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/NecDspDebugger.h b/Core/NecDspDebugger.h index e8df7c7..ab1ba53 100644 --- a/Core/NecDspDebugger.h +++ b/Core/NecDspDebugger.h @@ -37,4 +37,4 @@ public: void Step(int32_t stepCount, StepType type); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/NecDspDisUtils.cpp b/Core/NecDspDisUtils.cpp index 7d61229..7a4936c 100644 --- a/Core/NecDspDisUtils.cpp +++ b/Core/NecDspDisUtils.cpp @@ -7,129 +7,204 @@ #include "../Utilities/FastString.h" #include "DebugTypes.h" -void NecDspDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager, EmuSettings* settings) +void NecDspDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { - constexpr const char* aluOperations[16] = { "NOP", "OR", "AND", "XOR", "SUB", "ADD", "SBC", "ADC", "DEC" , "INC", "CMP", "SHR1", "SHL1", "SHL2", "SHL4", "XCHG" }; - constexpr const char* sourceNames[16] = { "TRB", "A", "B", "TR", "DP", "RP", "ROM", "SGN", "DR", "DRNF", "SR", "SIM", "SIL" ,"K", "L", "MEM" }; - constexpr const char* destNames[16] = { "NON", "A", "B", "TR", "DP", "RP", "DR", "SR", "SOL", "SOM", "K", "KLR", "KLM", "L", "TRB", "MEM" }; - constexpr const char* dataPointerOp[4] = { "DPL:NOP", "DPL:INC", "DPL:DEC", "DPL:CLR" }; + constexpr const char* aluOperations[16] = { + "NOP", "OR", "AND", "XOR", "SUB", "ADD", "SBC", "ADC", "DEC", "INC", "CMP", "SHR1", "SHL1", "SHL2", "SHL4", "XCHG" + }; + constexpr const char* sourceNames[16] = { + "TRB", "A", "B", "TR", "DP", "RP", "ROM", "SGN", "DR", "DRNF", "SR", "SIM", "SIL", "K", "L", "MEM" + }; + constexpr const char* destNames[16] = { + "NON", "A", "B", "TR", "DP", "RP", "DR", "SR", "SOL", "SOM", "K", "KLR", "KLM", "L", "TRB", "MEM" + }; + constexpr const char* dataPointerOp[4] = {"DPL:NOP", "DPL:INC", "DPL:DEC", "DPL:CLR"}; FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); uint32_t opCode = *(uint32_t*)info.GetByteCode(); uint8_t operationType = (opCode >> 22) & 0x03; - if(operationType <= 1) { + if (operationType <= 1) + { //OP or RT uint8_t aluOperation = (opCode >> 16) & 0x0F; uint8_t source = (opCode >> 4) & 0x0F; uint8_t accSelect = (opCode >> 15) & 0x01; - if(aluOperation) { + if (aluOperation) + { str.WriteAll(aluOperations[aluOperation], " "); - if(aluOperation <= 7) { + if (aluOperation <= 7) + { uint8_t pSelect = (opCode >> 20) & 0x03; - switch(pSelect) { - case 0: str.Write("RAM,"); break; - case 1: str.WriteAll(sourceNames[source], ","); break; - case 2: str.Write("M,"); break; - case 3: str.Write("N,"); break; + switch (pSelect) + { + case 0: str.Write("RAM,"); + break; + case 1: str.WriteAll(sourceNames[source], ","); + break; + case 2: str.Write("M,"); + break; + case 3: str.Write("N,"); + break; } } str.Write(accSelect ? "B" : "A"); } - + uint8_t dest = opCode & 0x0F; - if(dest) { + if (dest) + { str.Delimiter(" | "); str.Write("MOV "); str.WriteAll(sourceNames[source], ","); str.Write(destNames[dest]); } - + uint8_t dpLow = (opCode >> 13) & 0x03; - if(dpLow) { + if (dpLow) + { str.Delimiter(" | "); str.Write(dataPointerOp[dpLow]); } uint8_t dpHighModify = (opCode >> 9) & 0x0F; - if(dpHighModify) { + if (dpHighModify) + { str.Delimiter(" | "); str.WriteAll("DPH:$", HexUtilities::ToHex(dpHighModify)); } uint8_t rpDecrement = (opCode >> 8) & 0x01; - if(rpDecrement) { + if (rpDecrement) + { str.Delimiter(" | "); str.Write("RP:DEC"); } - if(operationType == 1) { + if (operationType == 1) + { str.Delimiter(" | "); str.Write("RET"); - } else if(opCode == 0) { + } + else if (opCode == 0) + { str.Write("NOP"); } - } else if(operationType == 2) { + } + else if (operationType == 2) + { //Jump uint8_t bank = opCode & 0x03; uint16_t address = (opCode >> 2) & 0x7FF; uint16_t target = (memoryAddr & 0x2000) | (bank << 11) | address; - switch((opCode >> 13) & 0x1FF) { - case 0x00: str.Write("JMPSO"); target = 0; break; - case 0x80: str.Write("JNCA"); break; - case 0x82: str.Write("JCA"); break; - case 0x84: str.Write("JNCB"); break; - case 0x86: str.Write("JCB"); break; - case 0x88: str.Write("JNZA"); break; - case 0x8A: str.Write("JZA"); break; - case 0x8C: str.Write("JNZB"); break; - case 0x8E: str.Write("JZB"); break; - case 0x90: str.Write("JNOVA0"); break; - case 0x92: str.Write("JOVA0"); break; - case 0x94: str.Write("JNOVB0"); break; - case 0x96: str.Write("JOVB0"); break; - case 0x98: str.Write("JNOVA1"); break; - case 0x9A: str.Write("JOVA1"); break; - case 0x9C: str.Write("JNOVB1"); break; - case 0x9E: str.Write("JOVB1"); break; - case 0xA0: str.Write("JNSA0"); break; - case 0xA2: str.Write("JSA0"); break; - case 0xA4: str.Write("JNSB0"); break; - case 0xA6: str.Write("JSB0"); break; - case 0xA8: str.Write("JNSA1"); break; - case 0xAA: str.Write("JSA1"); break; - case 0xAC: str.Write("JNSB1"); break; - case 0xAE: str.Write("JSB1"); break; - case 0xB0: str.Write("JDPL0"); break; - case 0xB1: str.Write("JDPLN0"); break; - case 0xB2: str.Write("JDPLF"); break; - case 0xB3: str.Write("JDPLNF"); break; - case 0xB4: str.Write("JNSIAK"); break; - case 0xB6: str.Write("JSIAK"); break; - case 0xB8: str.Write("JNSOAK"); break; - case 0xBA: str.Write("JSOAK"); break; - case 0xBC: str.Write("JNRQM"); break; - case 0xBE: str.Write("JRQM"); break; - case 0x100: str.Write("LJMP"); target &= ~0x2000; break; - case 0x101: str.Write("HJMP"); target |= 0x2000; break; - case 0x140: str.Write("LCALL"); target &= ~0x2000; break; - case 0x141: str.Write("HCALL"); target |= 0x2000; break; - default: str.Write(""); break; + switch ((opCode >> 13) & 0x1FF) + { + case 0x00: str.Write("JMPSO"); + target = 0; + break; + case 0x80: str.Write("JNCA"); + break; + case 0x82: str.Write("JCA"); + break; + case 0x84: str.Write("JNCB"); + break; + case 0x86: str.Write("JCB"); + break; + case 0x88: str.Write("JNZA"); + break; + case 0x8A: str.Write("JZA"); + break; + case 0x8C: str.Write("JNZB"); + break; + case 0x8E: str.Write("JZB"); + break; + case 0x90: str.Write("JNOVA0"); + break; + case 0x92: str.Write("JOVA0"); + break; + case 0x94: str.Write("JNOVB0"); + break; + case 0x96: str.Write("JOVB0"); + break; + case 0x98: str.Write("JNOVA1"); + break; + case 0x9A: str.Write("JOVA1"); + break; + case 0x9C: str.Write("JNOVB1"); + break; + case 0x9E: str.Write("JOVB1"); + break; + case 0xA0: str.Write("JNSA0"); + break; + case 0xA2: str.Write("JSA0"); + break; + case 0xA4: str.Write("JNSB0"); + break; + case 0xA6: str.Write("JSB0"); + break; + case 0xA8: str.Write("JNSA1"); + break; + case 0xAA: str.Write("JSA1"); + break; + case 0xAC: str.Write("JNSB1"); + break; + case 0xAE: str.Write("JSB1"); + break; + case 0xB0: str.Write("JDPL0"); + break; + case 0xB1: str.Write("JDPLN0"); + break; + case 0xB2: str.Write("JDPLF"); + break; + case 0xB3: str.Write("JDPLNF"); + break; + case 0xB4: str.Write("JNSIAK"); + break; + case 0xB6: str.Write("JSIAK"); + break; + case 0xB8: str.Write("JNSOAK"); + break; + case 0xBA: str.Write("JSOAK"); + break; + case 0xBC: str.Write("JNRQM"); + break; + case 0xBE: str.Write("JRQM"); + break; + case 0x100: str.Write("LJMP"); + target &= ~0x2000; + break; + case 0x101: str.Write("HJMP"); + target |= 0x2000; + break; + case 0x140: str.Write("LCALL"); + target &= ~0x2000; + break; + case 0x141: str.Write("HCALL"); + target |= 0x2000; + break; + default: str.Write(""); + break; } str.Write(' '); - AddressInfo absAddress = { (int32_t)target*3, SnesMemoryType::DspProgramRom }; + AddressInfo absAddress = {(int32_t)target * 3, SnesMemoryType::DspProgramRom}; string label = labelManager->GetLabel(absAddress); - if(label.empty()) { + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex(target * 3)); - } else { + } + else + { str.Write(label, true); } - } else if(operationType == 3) { + } + else if (operationType == 3) + { //Load uint16_t value = opCode >> 6; uint8_t dest = opCode & 0x0F; diff --git a/Core/NecDspDisUtils.h b/Core/NecDspDisUtils.h index ef5cd75..16f2bdf 100644 --- a/Core/NecDspDisUtils.h +++ b/Core/NecDspDisUtils.h @@ -8,5 +8,6 @@ class EmuSettings; class NecDspDisUtils { public: - static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); }; diff --git a/Core/NetMessage.h b/Core/NetMessage.h index 825f7fc..bef1ff8 100644 --- a/Core/NetMessage.h +++ b/Core/NetMessage.h @@ -23,8 +23,8 @@ protected: } public: - virtual ~NetMessage() - { + virtual ~NetMessage() + { } void Initialize() @@ -38,7 +38,7 @@ public: return _type; } - void Send(Socket &socket) + void Send(Socket& socket) { Serializer s(SaveStateManager::FileFormatVersion); Serialize(s); @@ -53,5 +53,5 @@ public: } protected: - virtual void Serialize(Serializer &s) = 0; + virtual void Serialize(Serializer& s) = 0; }; diff --git a/Core/NotificationManager.cpp b/Core/NotificationManager.cpp index aa5f50c..65ef516 100644 --- a/Core/NotificationManager.cpp +++ b/Core/NotificationManager.cpp @@ -6,8 +6,10 @@ void NotificationManager::RegisterNotificationListener(shared_ptr listener : _listeners) { - if(listener.lock() == notificationListener) { + for (weak_ptr listener : _listeners) + { + if (listener.lock() == notificationListener) + { //This listener is already registered, do nothing return; } @@ -41,9 +43,11 @@ void NotificationManager::SendNotification(ConsoleNotificationType type, void* p } //Iterate on a copy without using a lock - for(weak_ptr notificationListener : listeners) { + for (weak_ptr notificationListener : listeners) + { shared_ptr listener = notificationListener.lock(); - if(listener) { + if (listener) + { listener->ProcessNotification(type, parameter); } } diff --git a/Core/NotificationManager.h b/Core/NotificationManager.h index e38a39d..1a20a31 100644 --- a/Core/NotificationManager.h +++ b/Core/NotificationManager.h @@ -9,7 +9,7 @@ private: SimpleLock _lock; vector> _listenersToAdd; vector> _listeners; - + void CleanupNotificationListeners(); public: diff --git a/Core/NtscFilter.cpp b/Core/NtscFilter.cpp index 85103b5..0c04198 100644 --- a/Core/NtscFilter.cpp +++ b/Core/NtscFilter.cpp @@ -7,7 +7,7 @@ NtscFilter::NtscFilter(shared_ptr console) : BaseVideoFilter(console) { memset(&_ntscData, 0, sizeof(_ntscData)); - _ntscSetup = { }; + _ntscSetup = {}; snes_ntsc_init(&_ntscData, &_ntscSetup); _ntscBuffer = new uint32_t[SNES_NTSC_OUT_WIDTH(256) * 480]; } @@ -17,10 +17,10 @@ FrameInfo NtscFilter::GetFrameInfo() OverscanDimensions overscan = GetOverscan(); int widthDivider = _baseFrameInfo.Width == 512 ? 2 : 1; int heightMultiplier = _baseFrameInfo.Width == 512 ? 1 : 2; - + FrameInfo frameInfo; - frameInfo.Width = SNES_NTSC_OUT_WIDTH(_baseFrameInfo.Width / widthDivider) - overscan.Left*2 - overscan.Right*2; - frameInfo.Height = _baseFrameInfo.Height * heightMultiplier - overscan.Top*2 - overscan.Bottom*2; + frameInfo.Width = SNES_NTSC_OUT_WIDTH(_baseFrameInfo.Width / widthDivider) - overscan.Left * 2 - overscan.Right * 2; + frameInfo.Height = _baseFrameInfo.Height * heightMultiplier - overscan.Top * 2 - overscan.Bottom * 2; return frameInfo; } @@ -28,9 +28,13 @@ void NtscFilter::OnBeforeApplyFilter() { VideoConfig cfg = _console->GetSettings()->GetVideoConfig(); - if(_ntscSetup.hue != cfg.Hue / 100.0 || _ntscSetup.saturation != cfg.Saturation / 100.0 || _ntscSetup.brightness != cfg.Brightness / 100.0 || _ntscSetup.contrast != cfg.Contrast / 100.0 || - _ntscSetup.artifacts != cfg.NtscArtifacts || _ntscSetup.bleed != cfg.NtscBleed || _ntscSetup.fringing != cfg.NtscFringing || _ntscSetup.gamma != cfg.NtscGamma || - (_ntscSetup.merge_fields == 1) != cfg.NtscMergeFields || _ntscSetup.resolution != cfg.NtscResolution || _ntscSetup.sharpness != cfg.NtscSharpness) { + if (_ntscSetup.hue != cfg.Hue / 100.0 || _ntscSetup.saturation != cfg.Saturation / 100.0 || _ntscSetup.brightness != + cfg.Brightness / 100.0 || _ntscSetup.contrast != cfg.Contrast / 100.0 || + _ntscSetup.artifacts != cfg.NtscArtifacts || _ntscSetup.bleed != cfg.NtscBleed || _ntscSetup.fringing != cfg. + NtscFringing || _ntscSetup.gamma != cfg.NtscGamma || + (_ntscSetup.merge_fields == 1) != cfg.NtscMergeFields || _ntscSetup.resolution != cfg.NtscResolution || _ntscSetup + .sharpness != cfg.NtscSharpness) + { _ntscSetup.hue = cfg.Hue; _ntscSetup.saturation = cfg.Saturation; _ntscSetup.brightness = cfg.Brightness; @@ -47,39 +51,56 @@ void NtscFilter::OnBeforeApplyFilter() } } -void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer) +void NtscFilter::ApplyFilter(uint16_t* ppuOutputBuffer) { FrameInfo frameInfo = GetFrameInfo(); OverscanDimensions overscan = GetOverscan(); - + bool useHighResOutput = _baseFrameInfo.Width == 512; uint32_t baseWidth = SNES_NTSC_OUT_WIDTH(256); uint32_t xOffset = overscan.Left * 2; uint32_t yOffset = overscan.Top * 2 * baseWidth; - if(useHighResOutput) { - snes_ntsc_blit_hires(&_ntscData, ppuOutputBuffer, 512, IsOddFrame() ? 0 : 1, 512, _baseFrameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 4); - } else { - snes_ntsc_blit(&_ntscData, ppuOutputBuffer, 256, IsOddFrame() ? 0 : 1, 256, _baseFrameInfo.Height, _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 8); + if (useHighResOutput) + { + snes_ntsc_blit_hires(&_ntscData, ppuOutputBuffer, 512, IsOddFrame() ? 0 : 1, 512, _baseFrameInfo.Height, + _ntscBuffer, SNES_NTSC_OUT_WIDTH(256) * 4); + } + else + { + snes_ntsc_blit(&_ntscData, ppuOutputBuffer, 256, IsOddFrame() ? 0 : 1, 256, _baseFrameInfo.Height, _ntscBuffer, + SNES_NTSC_OUT_WIDTH(256) * 8); } VideoConfig cfg = _console->GetSettings()->GetVideoConfig(); - if(cfg.ScanlineIntensity == 0) { - for(uint32_t i = 0; i < frameInfo.Height; i+=2) { - memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t)); - memcpy(GetOutputBuffer()+(i+1)*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t)); + if (cfg.ScanlineIntensity == 0) + { + for (uint32_t i = 0; i < frameInfo.Height; i += 2) + { + memcpy(GetOutputBuffer() + i * frameInfo.Width, _ntscBuffer + yOffset + xOffset + i * baseWidth, + frameInfo.Width * sizeof(uint32_t)); + memcpy(GetOutputBuffer() + (i + 1) * frameInfo.Width, _ntscBuffer + yOffset + xOffset + i * baseWidth, + frameInfo.Width * sizeof(uint32_t)); } - } else { + } + else + { uint8_t intensity = (uint8_t)((1.0 - cfg.ScanlineIntensity) * 255); - for(uint32_t i = 0; i < frameInfo.Height; i++) { - if(i & 0x01) { - uint32_t *in = _ntscBuffer + yOffset + xOffset + (i - 1) * baseWidth; - uint32_t *out = GetOutputBuffer() + i * frameInfo.Width; - for(uint32_t j = 0; j < frameInfo.Width; j++) { + for (uint32_t i = 0; i < frameInfo.Height; i++) + { + if (i & 0x01) + { + uint32_t* in = _ntscBuffer + yOffset + xOffset + (i - 1) * baseWidth; + uint32_t* out = GetOutputBuffer() + i * frameInfo.Width; + for (uint32_t j = 0; j < frameInfo.Width; j++) + { out[j] = ApplyScanlineEffect(in[j], intensity); } - } else { - memcpy(GetOutputBuffer()+i*frameInfo.Width, _ntscBuffer + yOffset + xOffset + i*baseWidth, frameInfo.Width * sizeof(uint32_t)); + } + else + { + memcpy(GetOutputBuffer() + i * frameInfo.Width, _ntscBuffer + yOffset + xOffset + i * baseWidth, + frameInfo.Width * sizeof(uint32_t)); } } } @@ -88,4 +109,4 @@ void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer) NtscFilter::~NtscFilter() { delete[] _ntscBuffer; -} \ No newline at end of file +} diff --git a/Core/NtscFilter.h b/Core/NtscFilter.h index 444bf4f..e93c81c 100644 --- a/Core/NtscFilter.h +++ b/Core/NtscFilter.h @@ -19,6 +19,6 @@ public: NtscFilter(shared_ptr console); virtual ~NtscFilter(); - virtual void ApplyFilter(uint16_t *ppuOutputBuffer); + virtual void ApplyFilter(uint16_t* ppuOutputBuffer); virtual FrameInfo GetFrameInfo(); -}; \ No newline at end of file +}; diff --git a/Core/Obc1.cpp b/Core/Obc1.cpp index 067d15f..b20651b 100644 --- a/Core/Obc1.cpp +++ b/Core/Obc1.cpp @@ -6,7 +6,7 @@ Obc1::Obc1(Console* console, uint8_t* saveRam, uint32_t saveRamSize) : BaseCoprocessor(SnesMemoryType::Register) { - MemoryMappings *mappings = console->GetMemoryManager()->GetMemoryMappings(); + MemoryMappings* mappings = console->GetMemoryManager()->GetMemoryMappings(); mappings->RegisterHandler(0x00, 0x3F, 0x6000, 0x7FFF, this); mappings->RegisterHandler(0x80, 0xBF, 0x6000, 0x7FFF, this); @@ -32,12 +32,13 @@ uint8_t Obc1::Read(uint32_t addr) { addr &= 0x1FFF; - switch(addr) { - case 0x1FF0: return ReadRam(GetLowAddress()); - case 0x1FF1: return ReadRam(GetLowAddress() + 1); - case 0x1FF2: return ReadRam(GetLowAddress() + 2); - case 0x1FF3: return ReadRam(GetLowAddress() + 3); - case 0x1FF4: return ReadRam(GetHighAddress()); + switch (addr) + { + case 0x1FF0: return ReadRam(GetLowAddress()); + case 0x1FF1: return ReadRam(GetLowAddress() + 1); + case 0x1FF2: return ReadRam(GetLowAddress() + 2); + case 0x1FF3: return ReadRam(GetLowAddress() + 3); + case 0x1FF4: return ReadRam(GetHighAddress()); } return ReadRam(addr); } @@ -46,18 +47,25 @@ void Obc1::Write(uint32_t addr, uint8_t value) { addr &= 0x1FFF; - switch(addr) { - case 0x1FF0: WriteRam(GetLowAddress(), value); break; - case 0x1FF1: WriteRam(GetLowAddress() + 1, value); break; - case 0x1FF2: WriteRam(GetLowAddress() + 2, value); break; - case 0x1FF3: WriteRam(GetLowAddress() + 3, value); break; - case 0x1FF4: { + switch (addr) + { + case 0x1FF0: WriteRam(GetLowAddress(), value); + break; + case 0x1FF1: WriteRam(GetLowAddress() + 1, value); + break; + case 0x1FF2: WriteRam(GetLowAddress() + 2, value); + break; + case 0x1FF3: WriteRam(GetLowAddress() + 3, value); + break; + case 0x1FF4: + { uint8_t shift = (ReadRam(0x1FF6) & 0x03) << 1; WriteRam(GetHighAddress(), ((value & 0x03) << shift) | (ReadRam(GetHighAddress()) & ~(0x03 << shift))); break; } - default: WriteRam(addr, value); break; + default: WriteRam(addr, value); + break; } } @@ -78,7 +86,7 @@ uint16_t Obc1::GetHighAddress() return (GetBaseAddress() | ((ReadRam(0x1FF6) & 0x7F) >> 2)) + 0x200; } -void Obc1::Serialize(Serializer &s) +void Obc1::Serialize(Serializer& s) { } @@ -87,12 +95,12 @@ uint8_t Obc1::Peek(uint32_t addr) return 0; } -void Obc1::PeekBlock(uint32_t addr, uint8_t *output) +void Obc1::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } AddressInfo Obc1::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; -} \ No newline at end of file + return {-1, SnesMemoryType::Register}; +} diff --git a/Core/Obc1.h b/Core/Obc1.h index 189417f..7acb45f 100644 --- a/Core/Obc1.h +++ b/Core/Obc1.h @@ -7,7 +7,7 @@ class Console; class Obc1 : public BaseCoprocessor { private: - uint8_t *_ram; + uint8_t* _ram; uint32_t _mask; uint16_t GetBaseAddress(); @@ -25,9 +25,9 @@ public: uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; - void Serialize(Serializer & s) override; - + void Serialize(Serializer& s) override; + uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t * output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; -}; \ No newline at end of file +}; diff --git a/Core/PcmReader.cpp b/Core/PcmReader.cpp index 04d63e9..68c6198 100644 --- a/Core/PcmReader.cpp +++ b/Core/PcmReader.cpp @@ -21,15 +21,18 @@ PcmReader::~PcmReader() bool PcmReader::Init(string filename, bool loop, uint32_t startOffset) { - if(_file) { + if (_file) + { _file.close(); } _file.open(filename, ios::binary); - if(_file) { + if (_file) + { _file.seekg(0, ios::end); _fileSize = (uint32_t)_file.tellg(); - if(_fileSize < 12) { + if (_fileSize < 12) + { return false; } @@ -53,7 +56,9 @@ bool PcmReader::Init(string filename, bool loop, uint32_t startOffset) _resampler.Reset(); return true; - } else { + } + else + { _done = true; return false; } @@ -66,7 +71,8 @@ bool PcmReader::IsPlaybackOver() void PcmReader::SetSampleRate(uint32_t sampleRate) { - if(sampleRate != _sampleRate) { + if (sampleRate != _sampleRate) + { _sampleRate = sampleRate; _resampler.SetSampleRates(PcmReader::PcmSampleRate, _sampleRate); @@ -78,7 +84,7 @@ void PcmReader::SetLoopFlag(bool loop) _loop = loop; } -void PcmReader::ReadSample(int16_t &left, int16_t &right) +void PcmReader::ReadSample(int16_t& left, int16_t& right) { uint8_t val[4]; _file.get(((char*)val)[0]); @@ -96,7 +102,8 @@ void PcmReader::LoadSamples(uint32_t samplesToLoad) int16_t left = 0; int16_t right = 0; - for(uint32_t i = _fileOffset; i < _fileSize && samplesRead < samplesToLoad; i+=4) { + for (uint32_t i = _fileOffset; i < _fileSize && samplesRead < samplesToLoad; i += 4) + { ReadSample(left, right); _pcmBuffer.push_back(left); @@ -108,42 +115,51 @@ void PcmReader::LoadSamples(uint32_t samplesToLoad) _fileOffset += 4; samplesRead++; - if(samplesRead < samplesToLoad && i + 4 >= _fileSize) { - if(_loop) { + if (samplesRead < samplesToLoad && i + 4 >= _fileSize) + { + if (_loop) + { i = _loopOffset * 4 + 8; _fileOffset = i; _file.seekg(_fileOffset, ios::beg); - } else { + } + else + { _done = true; } } } } -void PcmReader::ApplySamples(int16_t *buffer, size_t sampleCount, uint8_t volume) +void PcmReader::ApplySamples(int16_t* buffer, size_t sampleCount, uint8_t volume) { - if(_done) { + if (_done) + { return; } int32_t samplesNeeded = (int32_t)sampleCount - _leftoverSampleCount; - if(samplesNeeded > 0) { + if (samplesNeeded > 0) + { uint32_t samplesToLoad = samplesNeeded * PcmReader::PcmSampleRate / _sampleRate + 2; LoadSamples(samplesToLoad); } - uint32_t samplesRead = _resampler.Resample(_pcmBuffer.data(), (uint32_t)_pcmBuffer.size() / 2, _outputBuffer + _leftoverSampleCount*2); + uint32_t samplesRead = _resampler.Resample(_pcmBuffer.data(), (uint32_t)_pcmBuffer.size() / 2, + _outputBuffer + _leftoverSampleCount * 2); _pcmBuffer.clear(); uint32_t samplesToProcess = std::min((uint32_t)sampleCount * 2, (samplesRead + _leftoverSampleCount) * 2); - for(uint32_t i = 0; i < samplesToProcess; i++) { + for (uint32_t i = 0; i < samplesToProcess; i++) + { buffer[i] += (int16_t)((int32_t)_outputBuffer[i] * volume / 255); } //Calculate count of extra samples that couldn't be mixed with the rest of the audio and copy them to the beginning of the buffer //These will be mixed on the next call to ApplySamples _leftoverSampleCount = std::max(0, (int32_t)(samplesRead + _leftoverSampleCount) - (int32_t)sampleCount); - for(uint32_t i = 0; i < _leftoverSampleCount*2; i++) { + for (uint32_t i = 0; i < _leftoverSampleCount * 2; i++) + { _outputBuffer[i] = _outputBuffer[samplesToProcess + i]; } } @@ -151,4 +167,4 @@ void PcmReader::ApplySamples(int16_t *buffer, size_t sampleCount, uint8_t volume uint32_t PcmReader::GetOffset() { return _fileOffset; -} \ No newline at end of file +} diff --git a/Core/PcmReader.h b/Core/PcmReader.h index e81975a..4b1ca54 100644 --- a/Core/PcmReader.h +++ b/Core/PcmReader.h @@ -29,7 +29,7 @@ private: uint32_t _sampleRate; void LoadSamples(uint32_t samplesToLoad); - void ReadSample(int16_t &left, int16_t &right); + void ReadSample(int16_t& left, int16_t& right); public: PcmReader(); diff --git a/Core/PlayerListMessage.h b/Core/PlayerListMessage.h index cb7167e..8673978 100644 --- a/Core/PlayerListMessage.h +++ b/Core/PlayerListMessage.h @@ -8,19 +8,24 @@ private: vector _playerList; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { - if(s.IsSaving()) { + if (s.IsSaving()) + { uint32_t playerCount = (uint32_t)_playerList.size(); s.Stream(playerCount); - for(uint32_t i = 0; i < playerCount; i++) { + for (uint32_t i = 0; i < playerCount; i++) + { s.Stream(_playerList[i].Name, _playerList[i].ControllerPort, _playerList[i].IsHost); } - } else { + } + else + { uint32_t playerCount = 0; s.Stream(playerCount); - - for(uint32_t i = 0; i < playerCount; i++) { + + for (uint32_t i = 0; i < playerCount; i++) + { PlayerInfo playerInfo; s.Stream(playerInfo.Name, playerInfo.ControllerPort, playerInfo.IsHost); _playerList.push_back(playerInfo); @@ -29,7 +34,9 @@ protected: } public: - PlayerListMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + PlayerListMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } PlayerListMessage(vector playerList) : NetMessage(MessageType::PlayerList) { @@ -40,4 +47,4 @@ public: { return _playerList; } -}; \ No newline at end of file +}; diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 5e3e55d..1531210 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -18,14 +18,14 @@ #include "../Utilities/Serializer.h" static constexpr uint8_t _oamSizes[8][2][2] = { - { { 1, 1 }, { 2, 2 } }, //8x8 + 16x16 - { { 1, 1 }, { 4, 4 } }, //8x8 + 32x32 - { { 1, 1 }, { 8, 8 } }, //8x8 + 64x64 - { { 2, 2 }, { 4, 4 } }, //16x16 + 32x32 - { { 2, 2 }, { 8, 8 } }, //16x16 + 64x64 - { { 4, 4 }, { 8, 8 } }, //32x32 + 64x64 - { { 2, 4 }, { 4, 8 } }, //16x32 + 32x64 - { { 2, 4 }, { 4, 4 } } //16x32 + 32x32 + {{1, 1}, {2, 2}}, //8x8 + 16x16 + {{1, 1}, {4, 4}}, //8x8 + 32x32 + {{1, 1}, {8, 8}}, //8x8 + 64x64 + {{2, 2}, {4, 4}}, //16x16 + 32x32 + {{2, 2}, {8, 8}}, //16x16 + 64x64 + {{4, 4}, {8, 8}}, //32x32 + 64x64 + {{2, 4}, {4, 8}}, //16x32 + 32x64 + {{2, 4}, {4, 4}} //16x32 + 32x32 }; Ppu::Ppu(Console* console) @@ -56,11 +56,12 @@ void Ppu::PowerOn() _memoryManager = _console->GetMemoryManager().get(); _currentBuffer = _outputBuffers[0]; - + _state = {}; _state.ForcedVblank = true; _state.VramIncrementValue = 1; - if(_settings->GetEmulationConfig().EnableRandomPowerOnState) { + if (_settings->GetEmulationConfig().EnableRandomPowerOnState) + { RandomizeState(); } @@ -69,7 +70,7 @@ void Ppu::PowerOn() _settings->InitializeRam(_oamRam, Ppu::SpriteRamSize); memset(_spriteIndexes, 0xFF, sizeof(_spriteIndexes)); - + UpdateNmiScanline(); } @@ -94,11 +95,16 @@ uint16_t Ppu::GetCycle() { //"normally dots 323 and 327 are 6 master cycles instead of 4." uint16_t hClock = _memoryManager->GetHClock(); - if(hClock <= 1292) { + if (hClock <= 1292) + { return hClock >> 2; - } else if(hClock <= 1310) { + } + else if (hClock <= 1310) + { return (hClock - 2) >> 2; - } else { + } + else + { return (hClock - 4) >> 2; } } @@ -120,9 +126,10 @@ PpuState Ppu::GetState() return state; } -void Ppu::GetState(PpuState &state, bool returnPartialState) +void Ppu::GetState(PpuState& state, bool returnPartialState) { - if(!returnPartialState) { + if (!returnPartialState) + { state = _state; } state.Cycle = GetCycle(); @@ -131,42 +138,53 @@ void Ppu::GetState(PpuState &state, bool returnPartialState) state.FrameCount = _frameCount; } -template +template void Ppu::GetTilemapData(uint8_t layerIndex, uint8_t columnIndex) { /* The current layer's options */ - LayerConfig &config = _state.Layers[layerIndex]; + LayerConfig& config = _state.Layers[layerIndex]; uint16_t vScroll = config.VScroll; - uint16_t hScroll = hiResMode ? (config.HScroll << 1) : config.HScroll; - if(_hOffset || _vOffset) { + uint16_t hScroll = hiResMode ? (config.HScroll << 1) : config.HScroll; + if (_hOffset || _vOffset) + { uint16_t enableBit = layerIndex == 0 ? 0x2000 : 0x4000; - if(_state.BgMode == 4) { - if((_hOffset & 0x8000) == 0 && (_hOffset & enableBit)) { + if (_state.BgMode == 4) + { + if ((_hOffset & 0x8000) == 0 && (_hOffset & enableBit)) + { hScroll = (hScroll & 0x07) | (_hOffset & 0x3F8); } - if((_hOffset & 0x8000) != 0 && (_hOffset & enableBit)) { + if ((_hOffset & 0x8000) != 0 && (_hOffset & enableBit)) + { vScroll = (_hOffset & 0x3FF); } - } else { - if(_hOffset & enableBit) { + } + else + { + if (_hOffset & enableBit) + { hScroll = (hScroll & 0x07) | (_hOffset & 0x3F8); } - if(_vOffset & enableBit) { + if (_vOffset & enableBit) + { vScroll = (_vOffset & 0x3FF); } } } - if(hiResMode) { + if (hiResMode) + { hScroll >>= 1; } uint16_t realY = IsDoubleHeight() ? (_oddFrame ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; - if(_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) { + if (_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) + { //Keep the "scanline" to what it was at the start of this mosaic block realY -= _state.MosaicSize - _mosaicScanlineCounter; - if(IsDoubleHeight()) { + if (IsDoubleHeight()) + { realY -= _state.MosaicSize - _mosaicScanlineCounter; } } @@ -182,7 +200,8 @@ void Ppu::GetTilemapData(uint8_t layerIndex, uint8_t columnIndex) /* The current column index (in terms of 8x8 or 16x16 tiles) */ uint16_t column = columnIndex + (hScroll >> 3); - if(!hiResMode && config.LargeTiles) { + if (!hiResMode && config.LargeTiles) + { //For 16x16 tiles, need to return the same tile for 2 columns 8 pixel columns in a row column >>= 1; } @@ -193,11 +212,11 @@ void Ppu::GetTilemapData(uint8_t layerIndex, uint8_t columnIndex) _layerData[layerIndex].Tiles[columnIndex].VScroll = vScroll; } -template +template void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) { - LayerConfig &config = _state.Layers[layerIndex]; - TileData &tileData = _layerData[layerIndex].Tiles[column]; + LayerConfig& config = _state.Layers[layerIndex]; + TileData& tileData = _layerData[layerIndex].Tiles[column]; uint16_t tilemapData = tileData.TilemapData; bool largeTileWidth = hiResMode || config.LargeTiles; @@ -207,22 +226,26 @@ void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) uint16_t realY = IsDoubleHeight() ? (_oddFrame ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; - if(_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) { + if (_state.MosaicEnabled && (_state.MosaicEnabled & (1 << layerIndex))) + { //Keep the "scanline" to what it was at the start of this mosaic block realY -= _state.MosaicSize - _mosaicScanlineCounter; - if(IsDoubleHeight()) { + if (IsDoubleHeight()) + { realY -= _state.MosaicSize - _mosaicScanlineCounter + (_oddFrame ? 1 : 0); } } bool useSecondTile = secondTile; - if(!hiResMode && config.LargeTiles) { + if (!hiResMode && config.LargeTiles) + { //For 16x16 tiles, need to return the 2nd part of the tile every other column useSecondTile = (((column << 3) + config.HScroll) & 0x08) == 0x08; } uint16_t tileIndex = tilemapData & 0x3FF; - if(largeTileWidth) { + if (largeTileWidth) + { tileIndex = ( tileIndex + (config.LargeTiles ? (((realY + tileData.VScroll) & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + @@ -231,7 +254,7 @@ void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) } uint16_t tileStart = config.ChrAddress + tileIndex * 4 * bpp; - + uint8_t baseYOffset = (realY + tileData.VScroll) & 0x07; uint8_t yOffset = vMirror ? (7 - baseYOffset) : baseYOffset; @@ -241,7 +264,8 @@ void Ppu::GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane) void Ppu::GetHorizontalOffsetByte(uint8_t columnIndex) { - uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & (_state.Layers[2].DoubleWidth ? 0x3F : 0x1F); + uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & ( + _state.Layers[2].DoubleWidth ? 0x3F : 0x1F); uint16_t rowOffset = (_state.Layers[2].VScroll >> 3) & (_state.Layers[2].DoubleHeight ? 0x3F : 0x1F); _hOffset = _vram[(_state.Layers[2].TilemapAddress + columnOffset + (rowOffset << 5)) & 0x7FFF]; @@ -249,129 +273,217 @@ void Ppu::GetHorizontalOffsetByte(uint8_t columnIndex) void Ppu::GetVerticalOffsetByte(uint8_t columnIndex) { - uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & (_state.Layers[2].DoubleWidth ? 0x3F : 0x1F); + uint16_t columnOffset = (((columnIndex << 3) + (_state.Layers[2].HScroll & ~0x07)) >> 3) & ( + _state.Layers[2].DoubleWidth ? 0x3F : 0x1F); uint16_t rowOffset = (_state.Layers[2].VScroll >> 3) & (_state.Layers[2].DoubleHeight ? 0x3F : 0x1F); uint16_t tileOffset = columnOffset + (rowOffset << 5); //The vertical offset is 0x40 bytes later - but wraps around within the tilemap based on the tilemap size (0x800 or 0x1000 bytes) - uint16_t vOffsetAddr = _state.Layers[2].TilemapAddress + ((tileOffset + 0x20) & (_state.Layers[2].DoubleHeight ? 0x7FF : 0x3FF)); + uint16_t vOffsetAddr = _state.Layers[2].TilemapAddress + ((tileOffset + 0x20) & (_state.Layers[2].DoubleHeight + ? 0x7FF + : 0x3FF)); _vOffset = _vram[vOffsetAddr & 0x7FFF]; } void Ppu::FetchTileData() { - if(_state.ForcedVblank) { + if (_state.ForcedVblank) + { return; } - if(_fetchBgStart == 0) { + if (_fetchBgStart == 0) + { _hOffset = 0; _vOffset = 0; } - if(_state.BgMode == 0) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(3, x >> 3); break; - case 1: GetTilemapData(2, x >> 3); break; - case 2: GetTilemapData(1, x >> 3); break; - case 3: GetTilemapData(0, x >> 3); break; + if (_state.BgMode == 0) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(3, x >> 3); + break; + case 1: GetTilemapData(2, x >> 3); + break; + case 2: GetTilemapData(1, x >> 3); + break; + case 3: GetTilemapData(0, x >> 3); + break; - case 4: GetChrData(3, x >> 3, 0); break; - case 5: GetChrData(2, x >> 3, 0); break; - case 6: GetChrData(1, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 0); break; + case 4: GetChrData(3, x >> 3, 0); + break; + case 5: GetChrData(2, x >> 3, 0); + break; + case 6: GetChrData(1, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 0); + break; } } - } else if(_state.BgMode == 1) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(2, x >> 3); break; - case 1: GetTilemapData(1, x >> 3); break; - case 2: GetTilemapData(0, x >> 3); break; - case 3: GetChrData(2, x >> 3, 0); break; - case 4: GetChrData(1, x >> 3, 0); break; - case 5: GetChrData(1, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + } + else if (_state.BgMode == 1) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(2, x >> 3); + break; + case 1: GetTilemapData(1, x >> 3); + break; + case 2: GetTilemapData(0, x >> 3); + break; + case 3: GetChrData(2, x >> 3, 0); + break; + case 4: GetChrData(1, x >> 3, 0); + break; + case 5: GetChrData(1, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } - } else if(_state.BgMode == 2) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 2) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetHorizontalOffsetByte(x >> 3); break; - case 3: GetVerticalOffsetByte(x >> 3); break; + case 2: GetHorizontalOffsetByte(x >> 3); + break; + case 3: GetVerticalOffsetByte(x >> 3); + break; - case 4: GetChrData(1, x >> 3, 0); break; - case 5: GetChrData(1, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + case 4: GetChrData(1, x >> 3, 0); + break; + case 5: GetChrData(1, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } - } else if(_state.BgMode == 3) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 3) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetChrData(1, x >> 3, 0); break; - case 3: GetChrData(1, x >> 3, 1); break; + case 2: GetChrData(1, x >> 3, 0); + break; + case 3: GetChrData(1, x >> 3, 1); + break; - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 2); break; - case 7: GetChrData(0, x >> 3, 3); break; + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 2); + break; + case 7: GetChrData(0, x >> 3, 3); + break; } } - } else if(_state.BgMode == 4) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 4) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetHorizontalOffsetByte(x >> 3); break; + case 2: GetHorizontalOffsetByte(x >> 3); + break; - case 3: GetChrData(1, x >> 3, 0); break; + case 3: GetChrData(1, x >> 3, 0); + break; - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 2); break; - case 7: GetChrData(0, x >> 3, 3); break; + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 2); + break; + case 7: GetChrData(0, x >> 3, 3); + break; } } - } else if(_state.BgMode == 5) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 5) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetChrData(1, x >> 3, 0); break; - case 3: GetChrData(1, x >> 3, 0); break; + case 2: GetChrData(1, x >> 3, 0); + break; + case 3: GetChrData(1, x >> 3, 0); + break; - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } - } else if(_state.BgMode == 6) { - for(int x = _fetchBgStart; x <= _fetchBgEnd; x++) { - switch(x & 0x07) { - case 0: GetTilemapData(1, x >> 3); break; - case 1: GetTilemapData(0, x >> 3); break; + } + else if (_state.BgMode == 6) + { + for (int x = _fetchBgStart; x <= _fetchBgEnd; x++) + { + switch (x & 0x07) + { + case 0: GetTilemapData(1, x >> 3); + break; + case 1: GetTilemapData(0, x >> 3); + break; - case 2: GetHorizontalOffsetByte(x >> 3); break; - case 3: GetVerticalOffsetByte(x >> 3); break; - - case 4: GetChrData(0, x >> 3, 0); break; - case 5: GetChrData(0, x >> 3, 1); break; - case 6: GetChrData(0, x >> 3, 0); break; - case 7: GetChrData(0, x >> 3, 1); break; + case 2: GetHorizontalOffsetByte(x >> 3); + break; + case 3: GetVerticalOffsetByte(x >> 3); + break; + + case 4: GetChrData(0, x >> 3, 0); + break; + case 5: GetChrData(0, x >> 3, 1); + break; + case 6: GetChrData(0, x >> 3, 0); + break; + case 7: GetChrData(0, x >> 3, 1); + break; } } } @@ -379,32 +491,39 @@ void Ppu::FetchTileData() bool Ppu::ProcessEndOfScanline(uint16_t hClock) { - if(hClock >= 1364 || (hClock == 1360 && _scanline == 240 && _oddFrame && !_state.ScreenInterlace)) { + if (hClock >= 1364 || (hClock == 1360 && _scanline == 240 && _oddFrame && !_state.ScreenInterlace)) + { //"In non-interlace mode scanline 240 of every other frame (those with $213f.7=1) is only 1360 cycles." - if(_scanline < _vblankStartScanline) { + if (_scanline < _vblankStartScanline) + { RenderScanline(); - if(_scanline == 0) { + if (_scanline == 0) + { _overscanFrame = _state.OverscanMode; _mosaicScanlineCounter = _state.MosaicEnabled ? _state.MosaicSize + 1 : 0; //Update overclock timings once per frame UpdateNmiScanline(); - if(!_skipRender) { - if(!_interlacedFrame) { + if (!_skipRender) + { + if (!_interlacedFrame) + { _currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0]; } - + //If we're not skipping this frame, reset the high resolution/interlace flags _useHighResOutput = IsDoubleWidth() || _state.ScreenInterlace; _interlacedFrame = _state.ScreenInterlace; } } - - if(_mosaicScanlineCounter) { + + if (_mosaicScanlineCounter) + { _mosaicScanlineCounter--; - if(_state.MosaicEnabled && !_mosaicScanlineCounter) { + if (_state.MosaicEnabled && !_mosaicScanlineCounter) + { _mosaicScanlineCounter = _state.MosaicSize; } } @@ -421,8 +540,10 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) memset(_hasSpritePriority, 0, sizeof(_hasSpritePriority)); memcpy(_spritePriority, _spritePriorityCopy, sizeof(_spritePriority)); - for(int i = 0; i < 255; i++) { - if(_spritePriority[i] < 4) { + for (int i = 0; i < 255; i++) + { + if (_spritePriority[i] < 4) + { _hasSpritePriority[_spritePriority[i]] = true; } } @@ -438,18 +559,21 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) _scanline++; - if(_scanline == _nmiScanline) { + if (_scanline == _nmiScanline) + { ProcessLocationLatchRequest(); _latchRequest = false; //Reset OAM address at the start of vblank? - if(!_state.ForcedVblank) { + if (!_state.ForcedVblank) + { //TODO, the timing of this may be slightly off? should happen at H=10 based on anomie's docs _internalOamAddress = (_state.OamRamAddress << 1); } VideoConfig cfg = _settings->GetVideoConfig(); - _configVisibleLayers = (cfg.HideBgLayer0 ? 0 : 1) | (cfg.HideBgLayer1 ? 0 : 2) | (cfg.HideBgLayer2 ? 0 : 4) | (cfg.HideBgLayer3 ? 0 : 8) | (cfg.HideSprites ? 0 : 16); + _configVisibleLayers = (cfg.HideBgLayer0 ? 0 : 1) | (cfg.HideBgLayer1 ? 0 : 2) | (cfg.HideBgLayer2 ? 0 : 4) | ( + cfg.HideBgLayer3 ? 0 : 8) | (cfg.HideSprites ? 0 : 16); _console->ProcessEvent(EventType::EndFrame); @@ -459,7 +583,9 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) SendFrame(); _console->ProcessEndOfFrame(); - } else if(_scanline >= _vblankEndScanline + 1) { + } + else if (_scanline >= _vblankEndScanline + 1) + { //"Frames are 262 scanlines in non-interlace mode, while in interlace mode frames with $213f.7=0 are 263 scanlines" _oddFrame ^= 1; _regs->SetNmiFlag(false); @@ -475,8 +601,9 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) (_settings->GetEmulationSpeed() == 0 || _settings->GetEmulationSpeed() > 150) && _frameSkipTimer.GetElapsedMS() < 10 ); - - if(_console->IsRunAheadFrame()) { + + if (_console->IsRunAheadFrame()) + { _skipRender = true; } @@ -493,14 +620,20 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock) void Ppu::UpdateSpcState() { //When using overclocking, turn off the SPC during the extra scanlines - if(_overclockEnabled && _scanline > _vblankStartScanline) { - if(_scanline > _adjustedVblankEndScanline) { + if (_overclockEnabled && _scanline > _vblankStartScanline) + { + if (_scanline > _adjustedVblankEndScanline) + { //Disable APU for extra lines after NMI _spc->SetSpcState(false); - } else if(_scanline >= _vblankStartScanline && _scanline < _nmiScanline) { + } + else if (_scanline >= _vblankStartScanline && _scanline < _nmiScanline) + { //Disable APU for extra lines before NMI _spc->SetSpcState(false); - } else { + } + else + { _spc->SetSpcState(true); } } @@ -509,16 +642,25 @@ void Ppu::UpdateSpcState() void Ppu::UpdateNmiScanline() { EmulationConfig cfg = _settings->GetEmulationConfig(); - if(_console->GetRegion() == ConsoleRegion::Ntsc) { - if(!_state.ScreenInterlace || _oddFrame) { + if (_console->GetRegion() == ConsoleRegion::Ntsc) + { + if (!_state.ScreenInterlace || _oddFrame) + { _baseVblankEndScanline = 261; - } else { + } + else + { _baseVblankEndScanline = 262; } - } else { - if(!_state.ScreenInterlace || _oddFrame) { + } + else + { + if (!_state.ScreenInterlace || _oddFrame) + { _baseVblankEndScanline = 311; - } else { + } + else + { _baseVblankEndScanline = 312; } } @@ -533,18 +675,25 @@ void Ppu::UpdateNmiScanline() uint16_t Ppu::GetRealScanline() { - if(!_overclockEnabled) { + if (!_overclockEnabled) + { return _scanline; } - if(_scanline > _vblankStartScanline && _scanline <= _nmiScanline) { + if (_scanline > _vblankStartScanline && _scanline <= _nmiScanline) + { //Pretend to be just before vblank until extra scanlines are over return _vblankStartScanline - 1; - } else if(_scanline > _nmiScanline) { - if(_scanline > _adjustedVblankEndScanline) { + } + else if (_scanline > _nmiScanline) + { + if (_scanline > _adjustedVblankEndScanline) + { //Pretend to be at the end of vblank until extra scanlines are over return _baseVblankEndScanline; - } else { + } + else + { //Number the regular scanlines as they would normally be return _scanline - _nmiScanline + _vblankStartScanline; } @@ -565,26 +714,36 @@ uint16_t Ppu::GetLastScanline() void Ppu::EvaluateNextLineSprites() { - if(_spriteEvalStart == 0) { + if (_spriteEvalStart == 0) + { _spriteCount = 0; _oamEvaluationIndex = _state.EnableOamPriority ? ((_internalOamAddress & 0x1FC) >> 2) : 0; } - if(_state.ForcedVblank) { + if (_state.ForcedVblank) + { return; } - for(int i = _spriteEvalStart; i <= _spriteEvalEnd; i++) { - if(!(i & 0x01)) { + for (int i = _spriteEvalStart; i <= _spriteEvalEnd; i++) + { + if (!(i & 0x01)) + { //First cycle, read X & Y and high oam byte FetchSpritePosition(_oamEvaluationIndex << 2); - } else { + } + else + { //Second cycle: Check if sprite is in range, if so, keep its index - if(_currentSprite.IsVisible(_scanline, _state.ObjInterlace)) { - if(_spriteCount < 32) { + if (_currentSprite.IsVisible(_scanline, _state.ObjInterlace)) + { + if (_spriteCount < 32) + { _spriteIndexes[_spriteCount] = _oamEvaluationIndex; _spriteCount++; - } else { + } + else + { _rangeOver = true; } } @@ -596,13 +755,15 @@ void Ppu::EvaluateNextLineSprites() void Ppu::FetchSpriteData() { //From H=272 to 339, fetch a single word of CHR data on every cycle (for up to 34 sprites) - if(_fetchSpriteStart == 0) { + if (_fetchSpriteStart == 0) + { memset(_spritePriorityCopy, 0xFF, sizeof(_spritePriorityCopy)); _spriteTileCount = 0; _currentSprite.Index = 0xFF; - if(_spriteCount == 0) { + if (_spriteCount == 0) + { _spriteFetchingDone = true; return; } @@ -610,27 +771,36 @@ void Ppu::FetchSpriteData() _oamTimeIndex = _spriteIndexes[_spriteCount - 1]; } - for(int x = _fetchSpriteStart; x <= _fetchSpriteEnd; x++) { - if(x >= 2) { + for (int x = _fetchSpriteStart; x <= _fetchSpriteEnd; x++) + { + if (x >= 2) + { //Fetch the tile using the OAM data loaded on the past 2 cycles, before overwriting it in FetchSpriteAttributes below - if(!_state.ForcedVblank) { + if (!_state.ForcedVblank) + { FetchSpriteTile(x & 0x01); } - if((x & 1) && _spriteCount == 0 && _currentSprite.ColumnOffset == 0) { + if ((x & 1) && _spriteCount == 0 && _currentSprite.ColumnOffset == 0) + { //End this step _spriteFetchingDone = true; break; } } - if(_spriteCount > 0) { - if(x & 1) { + if (_spriteCount > 0) + { + if (x & 1) + { FetchSpriteAttributes((_oamTimeIndex << 2) | 0x02); - if(_spriteCount > 0) { + if (_spriteCount > 0) + { _oamTimeIndex = _spriteIndexes[_spriteCount - 1]; } - } else { + } + else + { FetchSpritePosition(_oamTimeIndex << 2); } } @@ -651,11 +821,13 @@ void Ppu::FetchSpritePosition(uint16_t oamAddress) _currentSprite.X = (int16_t)((sign | (oamValue & 0xFF)) << 7) >> 7; _currentSprite.Y = (oamValue >> 8); _currentSprite.Width = _oamSizes[_state.OamMode][largeSprite][0] << 3; - - if(spriteIndex != _currentSprite.Index) { + + if (spriteIndex != _currentSprite.Index) + { _currentSprite.Index = oamAddress >> 2; _currentSprite.ColumnOffset = (_currentSprite.Width / 8); - if(_currentSprite.X <= -8 && _currentSprite.X != -256) { + if (_currentSprite.X <= -8 && _currentSprite.X != -256) + { //Skip the first tiles of the sprite (because the tiles are hidden to the left of the screen) _currentSprite.ColumnOffset += _currentSprite.X / 8; } @@ -668,7 +840,8 @@ void Ppu::FetchSpritePosition(uint16_t oamAddress) void Ppu::FetchSpriteAttributes(uint16_t oamAddress) { _spriteTileCount++; - if(_spriteTileCount > 34) { + if (_spriteTileCount > 34) + { _timeOver = true; } @@ -679,20 +852,24 @@ void Ppu::FetchSpriteAttributes(uint16_t oamAddress) _currentSprite.HorizontalMirror = (flags & 0x40) != 0; _currentSprite.ColumnOffset--; - + uint8_t yOffset; int rowOffset; int yGap = (_scanline - _currentSprite.Y); - if(_state.ObjInterlace) { + if (_state.ObjInterlace) + { yGap <<= 1; yGap |= _oddFrame; } bool verticalMirror = (flags & 0x80) != 0; - if(verticalMirror) { + if (verticalMirror) + { yOffset = (_currentSprite.Height - 1 - yGap) & 0x07; rowOffset = (_currentSprite.Height - 1 - yGap) >> 3; - } else { + } + else + { yOffset = yGap & 0x07; rowOffset = yGap >> 3; } @@ -701,7 +878,9 @@ void Ppu::FetchSpriteAttributes(uint16_t oamAddress) uint8_t tileRow = (_oamRam[oamAddress] & 0xF0) >> 4; uint8_t tileColumn = _oamRam[oamAddress] & 0x0F; uint8_t row = (tileRow + rowOffset) & 0x0F; - uint8_t columnOffset = _currentSprite.HorizontalMirror ? _currentSprite.ColumnOffset : (columnCount - _currentSprite.ColumnOffset - 1); + uint8_t columnOffset = _currentSprite.HorizontalMirror + ? _currentSprite.ColumnOffset + : (columnCount - _currentSprite.ColumnOffset - 1); uint8_t tileIndex = (row << 4) | ((tileColumn + columnOffset) & 0x0F); uint16_t tileStart = (_state.OamBaseAddress + (tileIndex << 4) + (useSecondTable ? _state.OamAddressOffset : 0)); _currentSprite.FetchAddress = (tileStart + yOffset) & 0x7FFF; @@ -710,7 +889,8 @@ void Ppu::FetchSpriteAttributes(uint16_t oamAddress) int16_t endTileX = x + ((columnCount - _currentSprite.ColumnOffset - 1) << 3) + 8; _currentSprite.DrawX = _currentSprite.X + ((columnCount - _currentSprite.ColumnOffset - 1) << 3); - if(_currentSprite.ColumnOffset == 0 || endTileX >= 256) { + if (_currentSprite.ColumnOffset == 0 || endTileX >= 256) + { //Last tile of the sprite, or skip the remaining tiles (because the tiles are hidden to the right of the screen) _spriteCount--; _currentSprite.ColumnOffset = 0; @@ -723,19 +903,25 @@ void Ppu::FetchSpriteTile(bool secondCycle) uint16_t chrData = _vram[_currentSprite.FetchAddress]; _currentSprite.ChrData[secondCycle] = chrData; - if(!secondCycle) { + if (!secondCycle) + { _currentSprite.FetchAddress = (_currentSprite.FetchAddress + 8) & 0x7FFF; - } else { + } + else + { int16_t xPos = _currentSprite.DrawX; - for(int x = 0; x < 8; x++) { - if(xPos + x < 0 || xPos + x > 255) { + for (int x = 0; x < 8; x++) + { + if (xPos + x < 0 || xPos + x > 255) + { continue; } uint8_t xOffset = _currentSprite.HorizontalMirror ? ((7 - x) & 0x07) : x; uint8_t color = GetTilePixelColor<4>(_currentSprite.ChrData, 7 - xOffset); - if(color != 0) { + if (color != 0) + { _spriteColorsCopy[xPos + x] = color; _spritePriorityCopy[xPos + x] = _currentSprite.Priority; _spritePaletteCopy[xPos + x] = _currentSprite.Palette; @@ -746,7 +932,7 @@ void Ppu::FetchSpriteTile(bool secondCycle) void Ppu::RenderMode0() { - constexpr uint8_t spritePriorities[4] = { 3, 6, 9, 12 }; + constexpr uint8_t spritePriorities[4] = {3, 6, 9, 12}; RenderSprites(spritePriorities); RenderTilemap<0, 2, 8, 11, 0>(); @@ -757,21 +943,24 @@ void Ppu::RenderMode0() void Ppu::RenderMode1() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 7, 10 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 7, 10}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 6, 9>(); RenderTilemap<1, 4, 5, 8>(); - if(!_state.Mode1Bg3Priority) { + if (!_state.Mode1Bg3Priority) + { RenderTilemap<2, 2, 1, 3>(); - } else { + } + else + { RenderTilemap<2, 2, 1, 11>(); } } void Ppu::RenderMode2() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 3, 7>(); @@ -780,7 +969,7 @@ void Ppu::RenderMode2() void Ppu::RenderMode3() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 8, 3, 7>(); @@ -789,7 +978,7 @@ void Ppu::RenderMode3() void Ppu::RenderMode4() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 8, 3, 7>(); @@ -798,7 +987,7 @@ void Ppu::RenderMode4() void Ppu::RenderMode5() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 8 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 8}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 3, 7>(); @@ -807,7 +996,7 @@ void Ppu::RenderMode5() void Ppu::RenderMode6() { - constexpr uint8_t spritePriorities[4] = { 2, 3, 4, 6 }; + constexpr uint8_t spritePriorities[4] = {2, 3, 4, 6}; RenderSprites(spritePriorities); RenderTilemap<0, 4, 1, 5>(); @@ -815,11 +1004,12 @@ void Ppu::RenderMode6() void Ppu::RenderMode7() { - constexpr uint8_t spritePriorities[4] = { 2, 4, 6, 7 }; + constexpr uint8_t spritePriorities[4] = {2, 4, 6, 7}; RenderSprites(spritePriorities); RenderTilemapMode7<0, 3, 3>(); - if(_state.ExtBgEnabled) { + if (_state.ExtBgEnabled) + { RenderTilemapMode7<1, 1, 5>(); } } @@ -828,41 +1018,58 @@ void Ppu::RenderScanline() { int32_t hPos = GetCycle(); - if(hPos <= 255 || _spriteEvalEnd < 255) { + if (hPos <= 255 || _spriteEvalEnd < 255) + { _spriteEvalEnd = std::min(hPos, 255); - if(_spriteEvalStart <= _spriteEvalEnd) { + if (_spriteEvalStart <= _spriteEvalEnd) + { EvaluateNextLineSprites(); } _spriteEvalStart = _spriteEvalEnd + 1; } - if(!_skipRender && (hPos <= 263 || _fetchBgEnd < 263)) { + if (!_skipRender && (hPos <= 263 || _fetchBgEnd < 263)) + { //Fetch tilemap and tile CHR data, as needed, between H=0 and H=263 _fetchBgEnd = std::min(hPos, 263); - if(_fetchBgStart <= _fetchBgEnd) { + if (_fetchBgStart <= _fetchBgEnd) + { FetchTileData(); } _fetchBgStart = _fetchBgEnd + 1; - } + } //Render the scanline - if(!_skipRender && _drawStartX <= 255 && hPos > 22 && _scanline > 0) { + if (!_skipRender && _drawStartX <= 255 && hPos > 22 && _scanline > 0) + { _drawEndX = std::min(hPos - 22, 255); - if(_state.ForcedVblank) { + if (_state.ForcedVblank) + { //Forced blank, output black memset(_mainScreenBuffer + _drawStartX, 0, (_drawEndX - _drawStartX + 1) * 2); memset(_subScreenBuffer + _drawStartX, 0, (_drawEndX - _drawStartX + 1) * 2); - } else { - switch(_state.BgMode) { - case 0: RenderMode0(); break; - case 1: RenderMode1(); break; - case 2: RenderMode2(); break; - case 3: RenderMode3(); break; - case 4: RenderMode4(); break; - case 5: RenderMode5(); break; - case 6: RenderMode6(); break; - case 7: RenderMode7(); break; + } + else + { + switch (_state.BgMode) + { + case 0: RenderMode0(); + break; + case 1: RenderMode1(); + break; + case 2: RenderMode2(); + break; + case 3: RenderMode3(); + break; + case 4: RenderMode4(); + break; + case 5: RenderMode5(); + break; + case 6: RenderMode6(); + break; + case 7: RenderMode7(); + break; } RenderBgColor(); } @@ -873,12 +1080,14 @@ void Ppu::RenderScanline() _drawStartX = _drawEndX + 1; } - - if(hPos >= 270 && !_spriteFetchingDone) { + + if (hPos >= 270 && !_spriteFetchingDone) + { //Fetch sprite data from OAM and calculated which CHR data needs to be loaded (between H=270 and H=337) //Fetch sprite CHR data, as needed, between H=272 and H=339 _fetchSpriteEnd = std::min(hPos - 270, 69); - if(_fetchSpriteStart <= _fetchSpriteEnd) { + if (_fetchSpriteStart <= _fetchSpriteEnd) + { FetchSpriteData(); } _fetchSpriteStart = _fetchSpriteEnd + 1; @@ -888,12 +1097,15 @@ void Ppu::RenderScanline() void Ppu::RenderBgColor() { uint8_t pixelFlags = (_state.ColorMathEnabled & 0x20) ? PixelFlags::AllowColorMath : 0; - for(int x = _drawStartX; x <= _drawEndX; x++) { - if((_mainScreenFlags[x] & 0x0F) == 0) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + if ((_mainScreenFlags[x] & 0x0F) == 0) + { _mainScreenBuffer[x] = _cgram[0]; _mainScreenFlags[x] = pixelFlags; } - if(_subScreenPriority[x] == 0) { + if (_subScreenPriority[x] == 0) + { _subScreenBuffer[x] = _cgram[0]; } } @@ -901,7 +1113,8 @@ void Ppu::RenderBgColor() void Ppu::RenderSprites(const uint8_t priority[4]) { - if(!IsRenderRequired(Ppu::SpriteLayerIndex)) { + if (!IsRenderRequired(Ppu::SpriteLayerIndex)) + { return; } @@ -910,23 +1123,35 @@ void Ppu::RenderSprites(const uint8_t priority[4]) uint8_t mainWindowCount = 0; uint8_t subWindowCount = 0; - if(_state.WindowMaskMain[Ppu::SpriteLayerIndex]) { - mainWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1].ActiveLayers[Ppu::SpriteLayerIndex]; + if (_state.WindowMaskMain[Ppu::SpriteLayerIndex]) + { + mainWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[Ppu::SpriteLayerIndex]; } - if(_state.WindowMaskSub[Ppu::SpriteLayerIndex]) { - subWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1].ActiveLayers[Ppu::SpriteLayerIndex]; + if (_state.WindowMaskSub[Ppu::SpriteLayerIndex]) + { + subWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[Ppu::SpriteLayerIndex]; } - for(int x = _drawStartX; x <= _drawEndX; x++) { - if(_spritePriority[x] <= 3) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + if (_spritePriority[x] <= 3) + { uint8_t spritePrio = priority[_spritePriority[x]]; - if(drawMain && ((_mainScreenFlags[x] & 0x0F) < spritePrio) && !ProcessMaskWindow(mainWindowCount, x)) { + if (drawMain && ((_mainScreenFlags[x] & 0x0F) < spritePrio) && !ProcessMaskWindow( + mainWindowCount, x)) + { uint16_t paletteRamOffset = 128 + (_spritePalette[x] << 4) + _spriteColors[x]; _mainScreenBuffer[x] = _cgram[paletteRamOffset]; - _mainScreenFlags[x] = spritePrio | (((_state.ColorMathEnabled & 0x10) && _spritePalette[x] > 3) ? PixelFlags::AllowColorMath : 0); + _mainScreenFlags[x] = spritePrio | (((_state.ColorMathEnabled & 0x10) && _spritePalette[x] > 3) + ? PixelFlags::AllowColorMath + : 0); } - if(drawSub && (_subScreenPriority[x] < spritePrio) && !ProcessMaskWindow(subWindowCount, x)) { + if (drawSub && (_subScreenPriority[x] < spritePrio) && !ProcessMaskWindow( + subWindowCount, x)) + { uint16_t paletteRamOffset = 128 + (_spritePalette[x] << 4) + _spriteColors[x]; _subScreenBuffer[x] = _cgram[paletteRamOffset]; _subScreenPriority[x] = spritePrio; @@ -935,19 +1160,26 @@ void Ppu::RenderSprites(const uint8_t priority[4]) } } -template +template void Ppu::RenderTilemap() { bool drawMain = (bool)(((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); bool drawSub = (bool)(((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); - uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; - uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; + uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; + uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; uint16_t hScrollOriginal = _state.Layers[layerIndex].HScroll; uint16_t hScroll = hiResMode ? (hScrollOriginal << 1) : hScrollOriginal; - TileData* tileData = _layerData[layerIndex].Tiles; + TileData* tileData = _layerData[layerIndex].Tiles; uint8_t mosaicCounter = applyMosaic ? _state.MosaicSize - (_drawStartX % _state.MosaicSize) : 0; @@ -956,12 +1188,16 @@ void Ppu::RenderTilemap() uint8_t hiresSubColor; uint8_t pixelFlags = (((_state.ColorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0); - for(int x = _drawStartX; x <= _drawEndX; x++) { - if(hiResMode) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + if (hiResMode) + { lookupIndex = (x + (hScrollOriginal & 0x07)) >> 2; chrDataOffset = (lookupIndex & 0x01) * bpp / 2; lookupIndex >>= 1; - } else { + } + else + { lookupIndex = (x + (hScrollOriginal & 0x07)) >> 3; } @@ -970,15 +1206,18 @@ void Ppu::RenderTilemap() bool hMirror = (tilemapData & 0x4000) != 0; uint8_t color; - if(hiResMode) { + if (hiResMode) + { uint8_t xOffset = ((x << 1) + 1 + hScroll) & 0x07; uint8_t shift = hMirror ? xOffset : (7 - xOffset); color = GetTilePixelColor(chrData + chrDataOffset, shift); - + xOffset = ((x << 1) + hScroll) & 0x07; shift = hMirror ? xOffset : (7 - xOffset); hiresSubColor = GetTilePixelColor(chrData + chrDataOffset, shift); - } else { + } + else + { uint8_t xOffset = (x + hScroll) & 0x07; uint8_t shift = hMirror ? xOffset : (7 - xOffset); color = GetTilePixelColor(chrData, shift); @@ -987,86 +1226,112 @@ void Ppu::RenderTilemap() uint8_t paletteIndex = (tilemapData >> 10) & 0x07; uint8_t priority = (tilemapData & 0x2000) ? highPriority : normalPriority; - if(applyMosaic) { - if(mosaicCounter == _state.MosaicSize) { + if (applyMosaic) + { + if (mosaicCounter == _state.MosaicSize) + { mosaicCounter = 1; - if(hiResMode) { + if (hiResMode) + { color = hiresSubColor; } _mosaicColor[layerIndex] = (paletteIndex << 8) | color; _mosaicPriority[layerIndex] = priority; - } else { + } + else + { mosaicCounter++; color = _mosaicColor[layerIndex] & 0xFF; paletteIndex = _mosaicColor[layerIndex] >> 8; priority = _mosaicPriority[layerIndex]; - if(hiResMode) { + if (hiResMode) + { hiresSubColor = color; } - } + } } - if(color > 0) { + if (color > 0) + { uint16_t rgbColor = GetRgbColor(paletteIndex, color); - if(drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) { + if (drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) + { DrawMainPixel(x, rgbColor, priority | pixelFlags); } - if(!hiResMode && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) { + if (!hiResMode && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow( + subWindowCount, x)) + { DrawSubPixel(x, rgbColor, priority); } } - if(hiResMode) { - if(hiresSubColor > 0 && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) { - uint16_t hiresSubRgbColor = GetRgbColor(paletteIndex, hiresSubColor); + if (hiResMode) + { + if (hiresSubColor > 0 && drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow( + subWindowCount, x)) + { + uint16_t hiresSubRgbColor = GetRgbColor( + paletteIndex, hiresSubColor); DrawSubPixel(x, hiresSubRgbColor, priority); } } } } -template +template uint16_t Ppu::GetRgbColor(uint8_t paletteIndex, uint8_t colorIndex) { - if(bpp == 8 && directColorMode) { + if (bpp == 8 && directColorMode) + { return ( ((((colorIndex & 0x07) << 1) | (paletteIndex & 0x01)) << 1) | (((colorIndex & 0x38) | ((paletteIndex & 0x02) << 1)) << 4) | (((colorIndex & 0xC0) | ((paletteIndex & 0x04) << 3)) << 7) ); - } else if(bpp == 8) { + } + else if (bpp == 8) + { //Ignore palette bits for 256-color layers return _cgram[basePaletteOffset + colorIndex]; - } else { + } + else + { return _cgram[basePaletteOffset + paletteIndex * (1 << bpp) + colorIndex]; } } bool Ppu::IsRenderRequired(uint8_t layerIndex) { - if(((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) { + if (((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) + { return true; } - if(((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) { + if (((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01) + { return true; } return false; } -template +template uint8_t Ppu::GetTilePixelColor(const uint16_t chrData[4], const uint8_t shift) { uint8_t color; - if(bpp == 2) { + if (bpp == 2) + { color = (chrData[0] >> shift) & 0x01; color |= (chrData[0] >> (7 + shift)) & 0x02; - } else if(bpp == 4) { + } + else if (bpp == 4) + { color = (chrData[0] >> shift) & 0x01; color |= (chrData[0] >> (7 + shift)) & 0x02; color |= ((chrData[1] >> shift) & 0x01) << 2; color |= ((chrData[1] >> (7 + shift)) & 0x02) << 2; - } else if(bpp == 8) { + } + else if (bpp == 8) + { color = (chrData[0] >> shift) & 0x01; color |= (chrData[0] >> (7 + shift)) & 0x02; color |= ((chrData[1] >> shift) & 0x01) << 2; @@ -1075,24 +1340,33 @@ uint8_t Ppu::GetTilePixelColor(const uint16_t chrData[4], const uint8_t shift) color |= ((chrData[2] >> (7 + shift)) & 0x02) << 4; color |= ((chrData[3] >> shift) & 0x01) << 6; color |= ((chrData[3] >> (7 + shift)) & 0x02) << 6; - } else { + } + else + { throw std::runtime_error("unsupported bpp"); } return color; } -template +template void Ppu::RenderTilemapMode7() { - uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; - uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1].ActiveLayers[layerIndex] : 0; - + uint8_t mainWindowCount = _state.WindowMaskMain[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; + uint8_t subWindowCount = _state.WindowMaskSub[layerIndex] + ? (uint8_t)_state.Window[0].ActiveLayers[layerIndex] + (uint8_t)_state.Window[1]. + ActiveLayers[layerIndex] + : 0; + bool drawMain = (bool)(((_state.MainScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); bool drawSub = (bool)(((_state.SubScreenLayers & _configVisibleLayers) >> layerIndex) & 0x01); auto clip = [](int32_t val) { return (val & 0x2000) ? (val | ~0x3ff) : (val & 0x3ff); }; - if(_drawStartX == 0) { + if (_drawStartX == 0) + { //Keep the same scroll offsets for the entire scanline _state.Mode7.HScrollLatch = _state.Mode7.HScroll; _state.Mode7.VScrollLatch = _state.Mode7.VScroll; @@ -1104,7 +1378,8 @@ void Ppu::RenderTilemapMode7() int32_t centerY = ((int32_t)_state.Mode7.CenterY << 19) >> 19; uint16_t realY = _state.Mode7.VerticalMirroring ? (255 - _scanline) : _scanline; - if(applyMosaic) { + if (applyMosaic) + { //Keep the "scanline" to what it was at the start of this mosaic block realY -= _state.MosaicSize - _mosaicScanlineCounter; } @@ -1126,7 +1401,8 @@ void Ppu::RenderTilemapMode7() int16_t xStep = _state.Mode7.Matrix[0]; int16_t yStep = _state.Mode7.Matrix[2]; - if(_state.Mode7.HorizontalMirroring) { + if (_state.Mode7.HorizontalMirroring) + { //Calculate the value at the end of the scanline, and then start going backwards xValue += xStep * _drawEndX; yValue += yStep * _drawEndX; @@ -1136,69 +1412,92 @@ void Ppu::RenderTilemapMode7() xValue += xStep * _drawStartX; yValue += yStep * _drawStartX; - + uint8_t pixelFlags = ((_state.ColorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0; - for(int x = _drawStartX; x <= _drawEndX; x++) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { int32_t xOffset = xValue >> 8; int32_t yOffset = yValue >> 8; xValue += xStep; yValue += yStep; uint8_t tileIndex; - if(!_state.Mode7.LargeMap) { + if (!_state.Mode7.LargeMap) + { yOffset &= 0x3FF; xOffset &= 0x3FF; tileIndex = (uint8_t)_vram[((yOffset & ~0x07) << 4) | (xOffset >> 3)]; - } else { - if(yOffset < 0 || yOffset > 0x3FF || xOffset < 0 || xOffset > 0x3FF) { - if(_state.Mode7.FillWithTile0) { + } + else + { + if (yOffset < 0 || yOffset > 0x3FF || xOffset < 0 || xOffset > 0x3FF) + { + if (_state.Mode7.FillWithTile0) + { tileIndex = 0; - } else { + } + else + { //Draw nothing for this pixel, we're outside the map continue; } - } else { + } + else + { tileIndex = (uint8_t)_vram[((yOffset & ~0x07) << 4) | (xOffset >> 3)]; } } uint16_t colorIndex; uint8_t priority; - if(layerIndex == 1) { + if (layerIndex == 1) + { uint8_t color = _vram[((tileIndex << 6) + ((yOffset & 0x07) << 3) + (xOffset & 0x07))] >> 8; priority = (color & 0x80) ? highPriority : normalPriority; colorIndex = (color & 0x7F); - } else { + } + else + { priority = normalPriority; colorIndex = _vram[((tileIndex << 6) + ((yOffset & 0x07) << 3) + (xOffset & 0x07))] >> 8; } - if(applyMosaic) { - if(mosaicCounter == _state.MosaicSize) { + if (applyMosaic) + { + if (mosaicCounter == _state.MosaicSize) + { mosaicCounter = 1; _mosaicColor[layerIndex] = colorIndex; _mosaicPriority[layerIndex] = priority; - } else { + } + else + { mosaicCounter++; colorIndex = _mosaicColor[layerIndex]; priority = _mosaicPriority[layerIndex]; } } - if(colorIndex > 0) { + if (colorIndex > 0) + { uint16_t paletteColor; - if(directColorMode) { + if (directColorMode) + { paletteColor = ((colorIndex & 0x07) << 2) | ((colorIndex & 0x38) << 4) | ((colorIndex & 0xC0) << 7); - } else { + } + else + { paletteColor = _cgram[colorIndex]; } - - if(drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) { - DrawMainPixel(x, paletteColor, priority | pixelFlags); - } - if(drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) { + if (drawMain && (_mainScreenFlags[x] & 0x0F) < priority && !ProcessMaskWindow(mainWindowCount, x)) + { + DrawMainPixel(x, paletteColor, priority | pixelFlags); + } + + if (drawSub && _subScreenPriority[x] < priority && !ProcessMaskWindow(subWindowCount, x)) + { DrawSubPixel(x, paletteColor, priority); } } @@ -1219,11 +1518,14 @@ void Ppu::DrawSubPixel(uint8_t x, uint16_t color, uint8_t priority) void Ppu::ApplyColorMath() { - uint8_t activeWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::ColorWindowIndex] + (uint8_t)_state.Window[1].ActiveLayers[Ppu::ColorWindowIndex]; + uint8_t activeWindowCount = (uint8_t)_state.Window[0].ActiveLayers[Ppu::ColorWindowIndex] + (uint8_t)_state.Window[1] + .ActiveLayers[Ppu::ColorWindowIndex]; bool hiResMode = _state.HiResMode || _state.BgMode == 5 || _state.BgMode == 6; - if(hiResMode) { - for(int x = _drawStartX; x <= _drawEndX; x++) { + if (hiResMode) + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { bool isInsideWindow = ProcessMaskWindow(activeWindowCount, x); //Keep original subscreen color, which is used to apply color math to the main screen after @@ -1235,86 +1537,106 @@ void Ppu::ApplyColorMath() ApplyColorMathToPixel(_mainScreenBuffer[x], subPixel, x, isInsideWindow); } - } else { - for(int x = _drawStartX; x <= _drawEndX; x++) { + } + else + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { bool isInsideWindow = ProcessMaskWindow(activeWindowCount, x); ApplyColorMathToPixel(_mainScreenBuffer[x], _subScreenBuffer[x], x, isInsideWindow); } } } -void Ppu::ApplyColorMathToPixel(uint16_t &pixelA, uint16_t pixelB, int x, bool isInsideWindow) +void Ppu::ApplyColorMathToPixel(uint16_t& pixelA, uint16_t pixelB, int x, bool isInsideWindow) { uint8_t halfShift = (uint8_t)_state.ColorMathHalveResult; //Set color to black as needed based on clip mode - switch(_state.ColorMathClipMode) { - default: - case ColorWindowMode::Never: break; + switch (_state.ColorMathClipMode) + { + default: + case ColorWindowMode::Never: break; - case ColorWindowMode::OutsideWindow: - if(!isInsideWindow) { - pixelA = 0; - halfShift = 0; - } - break; + case ColorWindowMode::OutsideWindow: + if (!isInsideWindow) + { + pixelA = 0; + halfShift = 0; + } + break; - case ColorWindowMode::InsideWindow: - if(isInsideWindow) { - pixelA = 0; - halfShift = 0; - } - break; + case ColorWindowMode::InsideWindow: + if (isInsideWindow) + { + pixelA = 0; + halfShift = 0; + } + break; - case ColorWindowMode::Always: pixelA = 0; break; + case ColorWindowMode::Always: pixelA = 0; + break; } - if(!(_mainScreenFlags[x] & PixelFlags::AllowColorMath)) { + if (!(_mainScreenFlags[x] & PixelFlags::AllowColorMath)) + { //Color math doesn't apply to this pixel return; } //Prevent color math as needed based on mode - switch(_state.ColorMathPreventMode) { - default: - case ColorWindowMode::Never: break; + switch (_state.ColorMathPreventMode) + { + default: + case ColorWindowMode::Never: break; - case ColorWindowMode::OutsideWindow: - if(!isInsideWindow) { - return; - } - break; + case ColorWindowMode::OutsideWindow: + if (!isInsideWindow) + { + return; + } + break; - case ColorWindowMode::InsideWindow: - if(isInsideWindow) { - return; - } - break; + case ColorWindowMode::InsideWindow: + if (isInsideWindow) + { + return; + } + break; - case ColorWindowMode::Always: return; + case ColorWindowMode::Always: return; } uint16_t otherPixel; - if(_state.ColorMathAddSubscreen) { - if(_subScreenPriority[x] > 0) { + if (_state.ColorMathAddSubscreen) + { + if (_subScreenPriority[x] > 0) + { otherPixel = pixelB; - } else { + } + else + { //there's nothing in the subscreen at this pixel, use the fixed color and disable halve operation otherPixel = _state.FixedColor; halfShift = 0; } - } else { + } + else + { otherPixel = _state.FixedColor; } constexpr unsigned int mask = 0x1F; - if(_state.ColorMathSubstractMode) { + if (_state.ColorMathSubstractMode) + { uint16_t r = std::max((int)((pixelA & mask) - (otherPixel & mask)), 0) >> halfShift; uint16_t g = std::max((int)(((pixelA >> 5U) & mask) - ((otherPixel >> 5U) & mask)), 0) >> halfShift; uint16_t b = std::max((int)(((pixelA >> 10U) & mask) - ((otherPixel >> 10U) & mask)), 0) >> halfShift; pixelA = r | (g << 5U) | (b << 10U); - } else { + } + else + { uint16_t r = std::min(((pixelA & mask) + (otherPixel & mask)) >> halfShift, mask); uint16_t g = std::min((((pixelA >> 5U) & mask) + ((otherPixel >> 5U) & mask)) >> halfShift, mask); uint16_t b = std::min((((pixelA >> 10U) & mask) + ((otherPixel >> 10U) & mask)) >> halfShift, mask); @@ -1323,12 +1645,14 @@ void Ppu::ApplyColorMathToPixel(uint16_t &pixelA, uint16_t pixelB, int x, bool i } } -template +template void Ppu::ApplyBrightness() { - if(_state.ScreenBrightness != 15) { - for(int x = _drawStartX; x <= _drawEndX; x++) { - uint16_t &pixel = (forMainScreen ? _mainScreenBuffer : _subScreenBuffer)[x]; + if (_state.ScreenBrightness != 15) + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { + uint16_t& pixel = (forMainScreen ? _mainScreenBuffer : _subScreenBuffer)[x]; uint16_t r = (pixel & 0x1F) * _state.ScreenBrightness / 15; uint16_t g = ((pixel >> 5) & 0x1F) * _state.ScreenBrightness / 15; uint16_t b = ((pixel >> 10) & 0x1F) * _state.ScreenBrightness / 15; @@ -1340,7 +1664,9 @@ void Ppu::ApplyBrightness() void Ppu::ConvertToHiRes() { bool useHighResOutput = _useHighResOutput || IsDoubleWidth() || _state.ScreenInterlace; - if(!useHighResOutput || _useHighResOutput == useHighResOutput || _scanline >= _vblankStartScanline || _scanline == 0) { + if (!useHighResOutput || _useHighResOutput == useHighResOutput || _scanline >= _vblankStartScanline || _scanline == 0 + ) + { return; } @@ -1349,16 +1675,20 @@ void Ppu::ConvertToHiRes() uint16_t scanline = _overscanFrame ? (_scanline - 1) : (_scanline + 6); - if(_drawStartX > 0) { - for(int x = 0; x < _drawStartX; x++) { + if (_drawStartX > 0) + { + for (int x = 0; x < _drawStartX; x++) + { _currentBuffer[(scanline << 10) + (x << 1)] = _currentBuffer[(scanline << 8) + x]; _currentBuffer[(scanline << 10) + (x << 1) + 1] = _currentBuffer[(scanline << 8) + x]; } memcpy(_currentBuffer + (scanline << 10) + 512, _currentBuffer + (scanline << 10), 512 * sizeof(uint16_t)); } - for(int i = scanline - 1; i >= 0; i--) { - for(int x = 0; x < 256; x++) { + for (int i = scanline - 1; i >= 0; i--) + { + for (int x = 0; x < 256; x++) + { _currentBuffer[(i << 10) + (x << 1)] = _currentBuffer[(i << 8) + x]; _currentBuffer[(i << 10) + (x << 1) + 1] = _currentBuffer[(i << 8) + x]; } @@ -1371,27 +1701,39 @@ void Ppu::ApplyHiResMode() //When overscan mode is off, center the 224-line picture in the center of the 239-line output buffer uint16_t scanline = _overscanFrame ? (_scanline - 1) : (_scanline + 6); - if(!_useHighResOutput) { - memcpy(_currentBuffer + (scanline << 8) + _drawStartX, _mainScreenBuffer + _drawStartX, (_drawEndX - _drawStartX + 1) << 1); - } else { + if (!_useHighResOutput) + { + memcpy(_currentBuffer + (scanline << 8) + _drawStartX, _mainScreenBuffer + _drawStartX, + (_drawEndX - _drawStartX + 1) << 1); + } + else + { _interlacedFrame |= _state.ScreenInterlace; - uint32_t screenY = _state.ScreenInterlace ? (_oddFrame ? ((scanline << 1) + 1) : (scanline << 1)) : (scanline << 1); + uint32_t screenY = _state.ScreenInterlace + ? (_oddFrame ? ((scanline << 1) + 1) : (scanline << 1)) + : (scanline << 1); uint32_t baseAddr = (screenY << 9); - if(IsDoubleWidth()) { + if (IsDoubleWidth()) + { ApplyBrightness(); - for(int x = _drawStartX; x <= _drawEndX; x++) { + for (int x = _drawStartX; x <= _drawEndX; x++) + { _currentBuffer[baseAddr + (x << 1)] = _subScreenBuffer[x]; _currentBuffer[baseAddr + (x << 1) + 1] = _mainScreenBuffer[x]; } - } else { - for(int x = _drawStartX; x <= _drawEndX; x++) { + } + else + { + for (int x = _drawStartX; x <= _drawEndX; x++) + { _currentBuffer[baseAddr + (x << 1)] = _mainScreenBuffer[x]; _currentBuffer[baseAddr + (x << 1) + 1] = _mainScreenBuffer[x]; } } - if(!_state.ScreenInterlace) { + if (!_state.ScreenInterlace) + { //Copy this line's content to the next line (between the current start & end bounds) memcpy( _currentBuffer + baseAddr + 512 + (_drawStartX << 1), @@ -1402,24 +1744,31 @@ void Ppu::ApplyHiResMode() } } -template +template bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x) { - switch(activeWindowCount) { - case 1: - if(_state.Window[0].ActiveLayers[layerIndex]) { - return _state.Window[0].PixelNeedsMasking(x); - } - return _state.Window[1].PixelNeedsMasking(x); + switch (activeWindowCount) + { + case 1: + if (_state.Window[0].ActiveLayers[layerIndex]) + { + return _state.Window[0].PixelNeedsMasking(x); + } + return _state.Window[1].PixelNeedsMasking(x); - case 2: - switch(_state.MaskLogic[layerIndex]) { - default: - case WindowMaskLogic::Or: return _state.Window[0].PixelNeedsMasking(x) | _state.Window[1].PixelNeedsMasking(x); - case WindowMaskLogic::And: return _state.Window[0].PixelNeedsMasking(x) & _state.Window[1].PixelNeedsMasking(x); - case WindowMaskLogic::Xor: return _state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1].PixelNeedsMasking(x); - case WindowMaskLogic::Xnor: return !(_state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1].PixelNeedsMasking(x)); - } + case 2: + switch (_state.MaskLogic[layerIndex]) + { + default: + case WindowMaskLogic::Or: return _state.Window[0].PixelNeedsMasking(x) | _state.Window[1]. + PixelNeedsMasking(x); + case WindowMaskLogic::And: return _state.Window[0].PixelNeedsMasking(x) & _state.Window[1]. + PixelNeedsMasking(x); + case WindowMaskLogic::Xor: return _state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1]. + PixelNeedsMasking(x); + case WindowMaskLogic::Xnor: return !(_state.Window[0].PixelNeedsMasking(x) ^ _state.Window[1]. + PixelNeedsMasking(x)); + } } return false; } @@ -1442,7 +1791,8 @@ void Ppu::SendFrame() uint16_t width = _useHighResOutput ? 512 : 256; uint16_t height = _useHighResOutput ? 478 : 239; - if(!_overscanFrame) { + if (!_overscanFrame) + { //Clear the top 7 and bottom 8 rows int top = (_useHighResOutput ? 14 : 7); int bottom = (_useHighResOutput ? 16 : 8); @@ -1457,14 +1807,18 @@ void Ppu::SendFrame() #ifdef LIBRETRO _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount, isRewinding); #else - if(isRewinding || _interlacedFrame) { + if (isRewinding || _interlacedFrame) + { _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount, isRewinding); - } else { + } + else + { _console->GetVideoDecoder()->UpdateFrame(_currentBuffer, width, height, _frameCount); } #endif - if(!_skipRender) { + if (!_skipRender) + { _frameSkipTimer.Reset(); } } @@ -1521,10 +1875,12 @@ void Ppu::SetLocationLatchRequest(uint16_t x, uint16_t y) void Ppu::ProcessLocationLatchRequest() { //Used by super scope - if(_latchRequest) { + if (_latchRequest) + { uint16_t cycle = GetCycle(); uint16_t scanline = GetRealScanline(); - if(scanline > _latchRequestY || (_latchRequestY == scanline && cycle >= _latchRequestX)) { + if (scanline > _latchRequestY || (_latchRequestY == scanline && cycle >= _latchRequestX)) + { _latchRequest = false; _horizontalLocation = _latchRequestX; _verticalLocation = _latchRequestY; @@ -1547,12 +1903,18 @@ void Ppu::UpdateOamAddress() uint16_t Ppu::GetOamAddress() { - if(_state.ForcedVblank || _scanline >= _vblankStartScanline) { + if (_state.ForcedVblank || _scanline >= _vblankStartScanline) + { return _internalOamAddress; - } else { - if(_memoryManager->GetHClock() <= 255 * 4) { + } + else + { + if (_memoryManager->GetHClock() <= 255 * 4) + { return _oamEvaluationIndex << 2; - } else { + } + else + { return _oamTimeIndex << 2; } } @@ -1567,66 +1929,76 @@ void Ppu::UpdateVramReadBuffer() uint16_t Ppu::GetVramAddress() { uint16_t addr = _state.VramAddress; - switch(_state.VramAddressRemapping) { - default: - case 0: return addr; - case 1: return (addr & 0xFF00) | ((addr & 0xE0) >> 5) | ((addr & 0x1F) << 3); - case 2: return (addr & 0xFE00) | ((addr & 0x1C0) >> 6) | ((addr & 0x3F) << 3); - case 3: return (addr & 0xFC00) | ((addr & 0x380) >> 7) | ((addr & 0x7F) << 3); + switch (_state.VramAddressRemapping) + { + default: + case 0: return addr; + case 1: return (addr & 0xFF00) | ((addr & 0xE0) >> 5) | ((addr & 0x1F) << 3); + case 2: return (addr & 0xFE00) | ((addr & 0x1C0) >> 6) | ((addr & 0x3F) << 3); + case 3: return (addr & 0xFC00) | ((addr & 0x380) >> 7) | ((addr & 0x7F) << 3); } } uint8_t Ppu::Read(uint16_t addr) { - if(_scanline < _vblankStartScanline) { + if (_scanline < _vblankStartScanline) + { RenderScanline(); } - switch(addr) { - case 0x2134: - _state.Ppu1OpenBus = ((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) & 0xFF; - return _state.Ppu1OpenBus; + switch (addr) + { + case 0x2134: + _state.Ppu1OpenBus = ((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) & 0xFF; + return _state.Ppu1OpenBus; - case 0x2135: - _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 8) & 0xFF; - return _state.Ppu1OpenBus; + case 0x2135: + _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 8) & 0xFF; + return _state.Ppu1OpenBus; - case 0x2136: - _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 16) & 0xFF; - return _state.Ppu1OpenBus; + case 0x2136: + _state.Ppu1OpenBus = (((int16_t)_state.Mode7.Matrix[0] * ((int16_t)_state.Mode7.Matrix[1] >> 8)) >> 16) & 0xFF; + return _state.Ppu1OpenBus; - case 0x2137: - //SLHV - Software Latch for H/V Counter - //Latch values on read, and return open bus - if(_regs->GetIoPortOutput() & 0x80) { - //Only latch H/V counters if bit 7 of $4201 is set. - LatchLocationValues(); - } - break; - - case 0x2138: { + case 0x2137: + //SLHV - Software Latch for H/V Counter + //Latch values on read, and return open bus + if (_regs->GetIoPortOutput() & 0x80) + { + //Only latch H/V counters if bit 7 of $4201 is set. + LatchLocationValues(); + } + break; + + case 0x2138: + { //OAMDATAREAD - Data for OAM read //When trying to read/write during rendering, the internal address used by the PPU's sprite rendering is used uint16_t oamAddr = GetOamAddress(); uint8_t value; - if(oamAddr < 512) { + if (oamAddr < 512) + { value = _oamRam[oamAddr]; _console->ProcessPpuRead(oamAddr, value, SnesMemoryType::SpriteRam); - } else { + } + else + { value = _oamRam[0x200 | (oamAddr & 0x1F)]; _console->ProcessPpuRead(0x200 | (oamAddr & 0x1F), value, SnesMemoryType::SpriteRam); } - + _internalOamAddress = (_internalOamAddress + 1) & 0x3FF; _state.Ppu1OpenBus = value; return value; } - case 0x2139: { + case 0x2139: + { //VMDATALREAD - VRAM Data Read low byte uint8_t returnValue = (uint8_t)_state.VramReadBuffer; _console->ProcessPpuRead(GetVramAddress(), returnValue, SnesMemoryType::VideoRam); - if(!_state.VramAddrIncrementOnSecondReg) { + if (!_state.VramAddrIncrementOnSecondReg) + { UpdateVramReadBuffer(); _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; } @@ -1634,11 +2006,13 @@ uint8_t Ppu::Read(uint16_t addr) return returnValue; } - case 0x213A: { + case 0x213A: + { //VMDATAHREAD - VRAM Data Read high byte uint8_t returnValue = (uint8_t)(_state.VramReadBuffer >> 8); _console->ProcessPpuRead(GetVramAddress() + 1, returnValue, SnesMemoryType::VideoRam); - if(_state.VramAddrIncrementOnSecondReg) { + if (_state.VramAddrIncrementOnSecondReg) + { UpdateVramReadBuffer(); _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; } @@ -1646,33 +2020,41 @@ uint8_t Ppu::Read(uint16_t addr) return returnValue; } - case 0x213B: { + case 0x213B: + { //CGDATAREAD - CGRAM Data read uint8_t value; - if(_state.CgramAddressLatch){ + if (_state.CgramAddressLatch) + { value = ((_cgram[_state.CgramAddress] >> 8) & 0x7F) | (_state.Ppu2OpenBus & 0x80); _state.CgramAddress++; - + _console->ProcessPpuRead((_state.CgramAddress >> 1) + 1, value, SnesMemoryType::CGRam); - } else { + } + else + { value = (uint8_t)_cgram[_state.CgramAddress]; _console->ProcessPpuRead(_state.CgramAddress >> 1, value, SnesMemoryType::CGRam); } _state.CgramAddressLatch = !_state.CgramAddressLatch; - + _state.Ppu2OpenBus = value; return value; } - case 0x213C: { + case 0x213C: + { //OPHCT - Horizontal Scanline Location ProcessLocationLatchRequest(); uint8_t value; - if(_horizontalLocToggle) { + if (_horizontalLocToggle) + { //"Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus." value = ((_horizontalLocation & 0x100) >> 8) | (_state.Ppu2OpenBus & 0xFE); - } else { + } + else + { value = _horizontalLocation & 0xFF; } _state.Ppu2OpenBus = value; @@ -1680,15 +2062,19 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - case 0x213D: { + case 0x213D: + { //OPVCT - Vertical Scanline Location ProcessLocationLatchRequest(); uint8_t value; - if(_verticalLocationToggle) { + if (_verticalLocationToggle) + { //"Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus." value = ((_verticalLocation & 0x100) >> 8) | (_state.Ppu2OpenBus & 0xFE); - } else { + } + else + { value = _verticalLocation & 0xFF; } _state.Ppu2OpenBus = value; @@ -1696,7 +2082,8 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - case 0x213E: { + case 0x213E: + { //STAT77 - PPU Status Flag and Version uint8_t value = ( (_timeOver ? 0x80 : 0) | @@ -1708,7 +2095,8 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - case 0x213F: { + case 0x213F: + { //STAT78 - PPU Status Flag and Version ProcessLocationLatchRequest(); @@ -1720,7 +2108,8 @@ uint8_t Ppu::Read(uint16_t addr) 0x03 //PPU (5c78) chip version ); - if(_regs->GetIoPortOutput() & 0x80) { + if (_regs->GetIoPortOutput() & 0x80) + { _locationLatched = false; //"The high/low selector is reset to ?elow?f when $213F is read" (the selector is NOT reset when the counter is latched) @@ -1731,13 +2120,14 @@ uint8_t Ppu::Read(uint16_t addr) return value; } - default: - LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); - break; + default: + LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr)); + break; } - + uint16_t reg = addr & 0x210F; - if((reg >= 0x2104 && reg <= 0x2106) || (reg >= 0x2108 && reg <= 0x210A)) { + if ((reg >= 0x2104 && reg <= 0x2106) || (reg >= 0x2108 && reg <= 0x210A)) + { //Registers matching $21x4-6 or $21x8-A (where x is 0-2) return the last value read from any of the PPU1 registers $2134-6, $2138-A, or $213E. return _state.Ppu1OpenBus; } @@ -1746,63 +2136,74 @@ uint8_t Ppu::Read(uint16_t addr) void Ppu::Write(uint32_t addr, uint8_t value) { - if(_scanline < _vblankStartScanline) { + if (_scanline < _vblankStartScanline) + { RenderScanline(); } - switch(addr) { - case 0x2100: - if(_state.ForcedVblank && _scanline == _nmiScanline) { - //"writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur." - UpdateOamAddress(); - } - - _state.ForcedVblank = (value & 0x80) != 0; - _state.ScreenBrightness = value & 0x0F; - break; - - case 0x2101: - _state.OamMode = (value & 0xE0) >> 5; - _state.OamBaseAddress = (value & 0x07) << 13; - _state.OamAddressOffset = (((value & 0x18) >> 3) + 1) << 12; - break; - - case 0x2102: - _state.OamRamAddress = (_state.OamRamAddress & 0x100) | value; + switch (addr) + { + case 0x2100: + if (_state.ForcedVblank && _scanline == _nmiScanline) + { + //"writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur." UpdateOamAddress(); - break; + } - case 0x2103: - _state.OamRamAddress = (_state.OamRamAddress & 0xFF) | ((value & 0x01) << 8); - UpdateOamAddress(); - _state.EnableOamPriority = (value & 0x80) != 0; - break; + _state.ForcedVblank = (value & 0x80) != 0; + _state.ScreenBrightness = value & 0x0F; + break; - case 0x2104: { + case 0x2101: + _state.OamMode = (value & 0xE0) >> 5; + _state.OamBaseAddress = (value & 0x07) << 13; + _state.OamAddressOffset = (((value & 0x18) >> 3) + 1) << 12; + break; + + case 0x2102: + _state.OamRamAddress = (_state.OamRamAddress & 0x100) | value; + UpdateOamAddress(); + break; + + case 0x2103: + _state.OamRamAddress = (_state.OamRamAddress & 0xFF) | ((value & 0x01) << 8); + UpdateOamAddress(); + _state.EnableOamPriority = (value & 0x80) != 0; + break; + + case 0x2104: + { //When trying to read/write during rendering, the internal address used by the PPU's sprite rendering is used //This is approximated by _oamRenderAddress (but is not cycle accurate) - needed for Uniracers uint16_t oamAddr = GetOamAddress(); - - if(oamAddr < 512) { - if(oamAddr & 0x01) { + + if (oamAddr < 512) + { + if (oamAddr & 0x01) + { _console->ProcessPpuWrite(oamAddr - 1, _oamWriteBuffer, SnesMemoryType::SpriteRam); _oamRam[oamAddr - 1] = _oamWriteBuffer; - + _console->ProcessPpuWrite(oamAddr, value, SnesMemoryType::SpriteRam); _oamRam[oamAddr] = value; - } else { + } + else + { _oamWriteBuffer = value; } - } + } - if(!_state.ForcedVblank && _scanline < _nmiScanline) { + if (!_state.ForcedVblank && _scanline < _nmiScanline) + { //During rendering the high table is also written to when writing to OAM oamAddr = 0x200 | ((oamAddr & 0x1F0) >> 4); } - - if(oamAddr >= 512) { + + if (oamAddr >= 512) + { uint16_t address = 0x200 | (oamAddr & 0x1F); - if((oamAddr & 0x01) == 0) { + if ((oamAddr & 0x01) == 0) + { _oamWriteBuffer = value; } _console->ProcessPpuWrite(address, value, SnesMemoryType::SpriteRam); @@ -1812,26 +2213,30 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; } - case 0x2105: - if(_state.BgMode != (value & 0x07)) { - LogDebug("[Debug] Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")"); - } - _state.BgMode = value & 0x07; - ConvertToHiRes(); + case 0x2105: + if (_state.BgMode != (value & 0x07)) + { + LogDebug( + "[Debug] Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")"); + } + _state.BgMode = value & 0x07; + ConvertToHiRes(); - _state.Mode1Bg3Priority = (value & 0x08) != 0; + _state.Mode1Bg3Priority = (value & 0x08) != 0; - _state.Layers[0].LargeTiles = (value & 0x10) != 0; - _state.Layers[1].LargeTiles = (value & 0x20) != 0; - _state.Layers[2].LargeTiles = (value & 0x40) != 0; - _state.Layers[3].LargeTiles = (value & 0x80) != 0; - break; + _state.Layers[0].LargeTiles = (value & 0x10) != 0; + _state.Layers[1].LargeTiles = (value & 0x20) != 0; + _state.Layers[2].LargeTiles = (value & 0x40) != 0; + _state.Layers[3].LargeTiles = (value & 0x80) != 0; + break; - case 0x2106: { + case 0x2106: + { //MOSAIC - Screen Pixelation _state.MosaicSize = ((value & 0xF0) >> 4) + 1; uint8_t mosaicEnabled = value & 0x0F; - if(!_state.MosaicEnabled && mosaicEnabled) { + if (!_state.MosaicEnabled && mosaicEnabled) + { //"If this register is set during the frame, the ?starting scanline is the current scanline, otherwise it is the first visible scanline of the frame." //This is only done when mosaic is turned on from an off state (FF6 mosaic effect looks wrong otherwise) //FF6's mosaic effect is broken on some screens without this. @@ -1841,249 +2246,281 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; } - case 0x2107: case 0x2108: case 0x2109: case 0x210A: - //BG 1-4 Tilemap Address and Size (BG1SC, BG2SC, BG3SC, BG4SC) - _state.Layers[addr - 0x2107].TilemapAddress = (value & 0x7C) << 8; - _state.Layers[addr - 0x2107].DoubleWidth = (value & 0x01) != 0; - _state.Layers[addr - 0x2107].DoubleHeight = (value & 0x02) != 0; + case 0x2107: + case 0x2108: + case 0x2109: + case 0x210A: + //BG 1-4 Tilemap Address and Size (BG1SC, BG2SC, BG3SC, BG4SC) + _state.Layers[addr - 0x2107].TilemapAddress = (value & 0x7C) << 8; + _state.Layers[addr - 0x2107].DoubleWidth = (value & 0x01) != 0; + _state.Layers[addr - 0x2107].DoubleHeight = (value & 0x02) != 0; + break; + + case 0x210B: + case 0x210C: + //BG1+2 / BG3+4 Chr Address (BG12NBA / BG34NBA) + _state.Layers[(addr - 0x210B) * 2].ChrAddress = (value & 0x07) << 12; + _state.Layers[(addr - 0x210B) * 2 + 1].ChrAddress = (value & 0x70) << 8; + break; + + case 0x210D: + //M7HOFS - Mode 7 BG Horizontal Scroll + //BG1HOFS - BG1 Horizontal Scroll + _state.Mode7.HScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; + _state.Mode7.ValueLatch = value; + //no break, keep executing to set the matching BG1 HScroll register, too + + case 0x210F: + case 0x2111: + case 0x2113: + //BGXHOFS - BG1/2/3/4 Horizontal Scroll + _state.Layers[(addr - 0x210D) >> 1].HScroll = ((value << 8) | (_hvScrollLatchValue & ~0x07) | (_hScrollLatchValue + & 0x07)) & 0x3FF; + _hvScrollLatchValue = value; + _hScrollLatchValue = value; + break; + + case 0x210E: + //M7VOFS - Mode 7 BG Vertical Scroll + //BG1VOFS - BG1 Vertical Scroll + _state.Mode7.VScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; + _state.Mode7.ValueLatch = value; + //no break, keep executing to set the matching BG1 HScroll register, too + + case 0x2110: + case 0x2112: + case 0x2114: + //BGXVOFS - BG1/2/3/4 Vertical Scroll + _state.Layers[(addr - 0x210E) >> 1].VScroll = ((value << 8) | _hvScrollLatchValue) & 0x3FF; + _hvScrollLatchValue = value; + break; + + case 0x2115: + //VMAIN - Video Port Control + switch (value & 0x03) + { + case 0: _state.VramIncrementValue = 1; + break; + case 1: _state.VramIncrementValue = 32; break; - case 0x210B: case 0x210C: - //BG1+2 / BG3+4 Chr Address (BG12NBA / BG34NBA) - _state.Layers[(addr - 0x210B) * 2].ChrAddress = (value & 0x07) << 12; - _state.Layers[(addr - 0x210B) * 2 + 1].ChrAddress = (value & 0x70) << 8; + case 2: + case 3: _state.VramIncrementValue = 128; break; - - case 0x210D: - //M7HOFS - Mode 7 BG Horizontal Scroll - //BG1HOFS - BG1 Horizontal Scroll - _state.Mode7.HScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; - _state.Mode7.ValueLatch = value; - //no break, keep executing to set the matching BG1 HScroll register, too + } - case 0x210F: case 0x2111: case 0x2113: - //BGXHOFS - BG1/2/3/4 Horizontal Scroll - _state.Layers[(addr - 0x210D) >> 1].HScroll = ((value << 8) | (_hvScrollLatchValue & ~0x07) | (_hScrollLatchValue & 0x07)) & 0x3FF; - _hvScrollLatchValue = value; - _hScrollLatchValue = value; - break; + _state.VramAddressRemapping = (value & 0x0C) >> 2; + _state.VramAddrIncrementOnSecondReg = (value & 0x80) != 0; + break; - case 0x210E: - //M7VOFS - Mode 7 BG Vertical Scroll - //BG1VOFS - BG1 Vertical Scroll - _state.Mode7.VScroll = ((value << 8) | (_state.Mode7.ValueLatch)) & 0x1FFF; - _state.Mode7.ValueLatch = value; - //no break, keep executing to set the matching BG1 HScroll register, too + case 0x2116: + //VMADDL - VRAM Address low byte + _state.VramAddress = (_state.VramAddress & 0x7F00) | value; + UpdateVramReadBuffer(); + break; - case 0x2110: case 0x2112: case 0x2114: - //BGXVOFS - BG1/2/3/4 Vertical Scroll - _state.Layers[(addr - 0x210E) >> 1].VScroll = ((value << 8) | _hvScrollLatchValue) & 0x3FF; - _hvScrollLatchValue = value; - break; + case 0x2117: + //VMADDH - VRAM Address high byte + _state.VramAddress = (_state.VramAddress & 0x00FF) | ((value & 0x7F) << 8); + UpdateVramReadBuffer(); + break; - case 0x2115: - //VMAIN - Video Port Control - switch(value & 0x03) { - case 0: _state.VramIncrementValue = 1; break; - case 1: _state.VramIncrementValue = 32; break; - - case 2: - case 3: _state.VramIncrementValue = 128; break; - } + case 0x2118: + //VMDATAL - VRAM Data Write low byte + if (_scanline >= _nmiScanline || _state.ForcedVblank) + { + //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) + _console->ProcessPpuWrite(GetVramAddress() << 1, value, SnesMemoryType::VideoRam); + _vram[GetVramAddress()] = value | (_vram[GetVramAddress()] & 0xFF00); + } - _state.VramAddressRemapping = (value & 0x0C) >> 2; - _state.VramAddrIncrementOnSecondReg = (value & 0x80) != 0; - break; + //The VRAM address is incremented even outside of vblank/forced blank + if (!_state.VramAddrIncrementOnSecondReg) + { + _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; + } + break; - case 0x2116: - //VMADDL - VRAM Address low byte - _state.VramAddress = (_state.VramAddress & 0x7F00) | value; - UpdateVramReadBuffer(); - break; + case 0x2119: + //VMDATAH - VRAM Data Write high byte + if (_scanline >= _nmiScanline || _state.ForcedVblank) + { + //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) + _console->ProcessPpuWrite((GetVramAddress() << 1) + 1, value, SnesMemoryType::VideoRam); + _vram[GetVramAddress()] = (value << 8) | (_vram[GetVramAddress()] & 0xFF); + } - case 0x2117: - //VMADDH - VRAM Address high byte - _state.VramAddress = (_state.VramAddress & 0x00FF) | ((value & 0x7F) << 8); - UpdateVramReadBuffer(); - break; + //The VRAM address is incremented even outside of vblank/forced blank + if (_state.VramAddrIncrementOnSecondReg) + { + _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; + } + break; - case 0x2118: - //VMDATAL - VRAM Data Write low byte - if(_scanline >= _nmiScanline || _state.ForcedVblank) { - //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) - _console->ProcessPpuWrite(GetVramAddress() << 1, value, SnesMemoryType::VideoRam); - _vram[GetVramAddress()] = value | (_vram[GetVramAddress()] & 0xFF00); - } + case 0x211A: + //M7SEL - Mode 7 Settings + _state.Mode7.LargeMap = (value & 0x80) != 0; + _state.Mode7.FillWithTile0 = (value & 0x40) != 0; + _state.Mode7.HorizontalMirroring = (value & 0x01) != 0; + _state.Mode7.VerticalMirroring = (value & 0x02) != 0; + break; - //The VRAM address is incremented even outside of vblank/forced blank - if(!_state.VramAddrIncrementOnSecondReg) { - _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; - } - break; + case 0x211B: + case 0x211C: + case 0x211D: + case 0x211E: + //M7A/B/C/D - Mode 7 Matrix A/B/C/D (A/B are also used with $2134/6) + _state.Mode7.Matrix[addr - 0x211B] = (value << 8) | _state.Mode7.ValueLatch; + _state.Mode7.ValueLatch = value; + break; - case 0x2119: - //VMDATAH - VRAM Data Write high byte - if(_scanline >= _nmiScanline || _state.ForcedVblank) { - //Only write the value if in vblank or forced blank (writes to VRAM outside vblank/forced blank are not allowed) - _console->ProcessPpuWrite((GetVramAddress() << 1) + 1, value, SnesMemoryType::VideoRam); - _vram[GetVramAddress()] = (value << 8) | (_vram[GetVramAddress()] & 0xFF); - } - - //The VRAM address is incremented even outside of vblank/forced blank - if(_state.VramAddrIncrementOnSecondReg) { - _state.VramAddress = (_state.VramAddress + _state.VramIncrementValue) & 0x7FFF; - } - break; + case 0x211F: + //M7X - Mode 7 Center X + _state.Mode7.CenterX = ((value << 8) | _state.Mode7.ValueLatch); + _state.Mode7.ValueLatch = value; + break; - case 0x211A: - //M7SEL - Mode 7 Settings - _state.Mode7.LargeMap = (value & 0x80) != 0; - _state.Mode7.FillWithTile0 = (value & 0x40) != 0; - _state.Mode7.HorizontalMirroring = (value & 0x01) != 0; - _state.Mode7.VerticalMirroring = (value & 0x02) != 0; - break; + case 0x2120: + //M7Y - Mode 7 Center Y + _state.Mode7.CenterY = ((value << 8) | _state.Mode7.ValueLatch); + _state.Mode7.ValueLatch = value; + break; - case 0x211B: case 0x211C: case 0x211D: case 0x211E: - //M7A/B/C/D - Mode 7 Matrix A/B/C/D (A/B are also used with $2134/6) - _state.Mode7.Matrix[addr - 0x211B] = (value << 8) | _state.Mode7.ValueLatch; - _state.Mode7.ValueLatch = value; - break; - - case 0x211F: - //M7X - Mode 7 Center X - _state.Mode7.CenterX = ((value << 8) | _state.Mode7.ValueLatch); - _state.Mode7.ValueLatch = value; - break; + case 0x2121: + //CGRAM Address(CGADD) + _state.CgramAddress = value; + _state.CgramAddressLatch = false; + break; - case 0x2120: - //M7Y - Mode 7 Center Y - _state.Mode7.CenterY = ((value << 8) | _state.Mode7.ValueLatch); - _state.Mode7.ValueLatch = value; - break; + case 0x2122: + //CGRAM Data write (CGDATA) + if (_state.CgramAddressLatch) + { + //MSB ignores the 7th bit (colors are 15-bit only) + _console->ProcessPpuWrite(_state.CgramAddress >> 1, _state.CgramWriteBuffer, SnesMemoryType::CGRam); + _console->ProcessPpuWrite((_state.CgramAddress >> 1) + 1, value & 0x7F, SnesMemoryType::CGRam); - case 0x2121: - //CGRAM Address(CGADD) - _state.CgramAddress = value; - _state.CgramAddressLatch = false; - break; + _cgram[_state.CgramAddress] = _state.CgramWriteBuffer | ((value & 0x7F) << 8); + _state.CgramAddress++; + } + else + { + _state.CgramWriteBuffer = value; + } + _state.CgramAddressLatch = !_state.CgramAddressLatch; + break; - case 0x2122: - //CGRAM Data write (CGDATA) - if(_state.CgramAddressLatch) { - //MSB ignores the 7th bit (colors are 15-bit only) - _console->ProcessPpuWrite(_state.CgramAddress >> 1, _state.CgramWriteBuffer, SnesMemoryType::CGRam); - _console->ProcessPpuWrite((_state.CgramAddress >> 1) + 1, value & 0x7F, SnesMemoryType::CGRam); + case 0x2123: + //W12SEL - Window Mask Settings for BG1 and BG2 + ProcessWindowMaskSettings(value, 0); + break; - _cgram[_state.CgramAddress] = _state.CgramWriteBuffer | ((value & 0x7F) << 8); - _state.CgramAddress++; - } else { - _state.CgramWriteBuffer = value; - } - _state.CgramAddressLatch = !_state.CgramAddressLatch; - break; + case 0x2124: + //W34SEL - Window Mask Settings for BG3 and BG4 + ProcessWindowMaskSettings(value, 2); + break; - case 0x2123: - //W12SEL - Window Mask Settings for BG1 and BG2 - ProcessWindowMaskSettings(value, 0); - break; + case 0x2125: + //WOBJSEL - Window Mask Settings for OBJ and Color Window + ProcessWindowMaskSettings(value, 4); + break; - case 0x2124: - //W34SEL - Window Mask Settings for BG3 and BG4 - ProcessWindowMaskSettings(value, 2); - break; + case 0x2126: + //WH0 - Window 1 Left Position + _state.Window[0].Left = value; + break; - case 0x2125: - //WOBJSEL - Window Mask Settings for OBJ and Color Window - ProcessWindowMaskSettings(value, 4); - break; + case 0x2127: + //WH1 - Window 1 Right Position + _state.Window[0].Right = value; + break; - case 0x2126: - //WH0 - Window 1 Left Position - _state.Window[0].Left = value; - break; - - case 0x2127: - //WH1 - Window 1 Right Position - _state.Window[0].Right = value; - break; + case 0x2128: + //WH2 - Window 2 Left Position + _state.Window[1].Left = value; + break; - case 0x2128: - //WH2 - Window 2 Left Position - _state.Window[1].Left = value; - break; + case 0x2129: + //WH3 - Window 2 Right Position + _state.Window[1].Right = value; + break; - case 0x2129: - //WH3 - Window 2 Right Position - _state.Window[1].Right = value; - break; + case 0x212A: + //WBGLOG - Window mask logic for BG + _state.MaskLogic[0] = (WindowMaskLogic)(value & 0x03); + _state.MaskLogic[1] = (WindowMaskLogic)((value >> 2) & 0x03); + _state.MaskLogic[2] = (WindowMaskLogic)((value >> 4) & 0x03); + _state.MaskLogic[3] = (WindowMaskLogic)((value >> 6) & 0x03); + break; - case 0x212A: - //WBGLOG - Window mask logic for BG - _state.MaskLogic[0] = (WindowMaskLogic)(value & 0x03); - _state.MaskLogic[1] = (WindowMaskLogic)((value >> 2) & 0x03); - _state.MaskLogic[2] = (WindowMaskLogic)((value >> 4) & 0x03); - _state.MaskLogic[3] = (WindowMaskLogic)((value >> 6) & 0x03); - break; + case 0x212B: + //WOBJLOG - Window mask logic for OBJs and Color Window + _state.MaskLogic[4] = (WindowMaskLogic)((value >> 0) & 0x03); + _state.MaskLogic[5] = (WindowMaskLogic)((value >> 2) & 0x03); + break; - case 0x212B: - //WOBJLOG - Window mask logic for OBJs and Color Window - _state.MaskLogic[4] = (WindowMaskLogic)((value >> 0) & 0x03); - _state.MaskLogic[5] = (WindowMaskLogic)((value >> 2) & 0x03); - break; + case 0x212C: + //TM - Main Screen Designation + _state.MainScreenLayers = value & 0x1F; + break; - case 0x212C: - //TM - Main Screen Designation - _state.MainScreenLayers = value & 0x1F; - break; + case 0x212D: + //TS - Subscreen Designation + _state.SubScreenLayers = value & 0x1F; + break; - case 0x212D: - //TS - Subscreen Designation - _state.SubScreenLayers = value & 0x1F; - break; + case 0x212E: + //TMW - Window Mask Designation for the Main Screen + for (int i = 0; i < 5; i++) + { + _state.WindowMaskMain[i] = ((value >> i) & 0x01) != 0; + } + break; - case 0x212E: - //TMW - Window Mask Designation for the Main Screen - for(int i = 0; i < 5; i++) { - _state.WindowMaskMain[i] = ((value >> i) & 0x01) != 0; - } - break; + case 0x212F: + //TSW - Window Mask Designation for the Subscreen + for (int i = 0; i < 5; i++) + { + _state.WindowMaskSub[i] = ((value >> i) & 0x01) != 0; + } + break; - case 0x212F: - //TSW - Window Mask Designation for the Subscreen - for(int i = 0; i < 5; i++) { - _state.WindowMaskSub[i] = ((value >> i) & 0x01) != 0; - } - break; - - case 0x2130: - //CGWSEL - Color Addition Select - _state.ColorMathClipMode = (ColorWindowMode)((value >> 6) & 0x03); - _state.ColorMathPreventMode = (ColorWindowMode)((value >> 4) & 0x03); - _state.ColorMathAddSubscreen = (value & 0x02) != 0; - _state.DirectColorMode = (value & 0x01) != 0; - break; + case 0x2130: + //CGWSEL - Color Addition Select + _state.ColorMathClipMode = (ColorWindowMode)((value >> 6) & 0x03); + _state.ColorMathPreventMode = (ColorWindowMode)((value >> 4) & 0x03); + _state.ColorMathAddSubscreen = (value & 0x02) != 0; + _state.DirectColorMode = (value & 0x01) != 0; + break; - case 0x2131: - //CGADSUB - Color math designation - _state.ColorMathEnabled = value & 0x3F; - _state.ColorMathSubstractMode = (value & 0x80) != 0; - _state.ColorMathHalveResult = (value & 0x40) != 0; - break; + case 0x2131: + //CGADSUB - Color math designation + _state.ColorMathEnabled = value & 0x3F; + _state.ColorMathSubstractMode = (value & 0x80) != 0; + _state.ColorMathHalveResult = (value & 0x40) != 0; + break; - case 0x2132: - //COLDATA - Fixed Color Data - if(value & 0x80) { //B - _state.FixedColor = (_state.FixedColor & ~0x7C00) | ((value & 0x1F) << 10); - } - if(value & 0x40) { //G - _state.FixedColor = (_state.FixedColor & ~0x3E0) | ((value & 0x1F) << 5); - } - if(value & 0x20) { //R - _state.FixedColor = (_state.FixedColor & ~0x1F) | (value & 0x1F); - } - break; + case 0x2132: + //COLDATA - Fixed Color Data + if (value & 0x80) + { + //B + _state.FixedColor = (_state.FixedColor & ~0x7C00) | ((value & 0x1F) << 10); + } + if (value & 0x40) + { + //G + _state.FixedColor = (_state.FixedColor & ~0x3E0) | ((value & 0x1F) << 5); + } + if (value & 0x20) + { + //R + _state.FixedColor = (_state.FixedColor & ~0x1F) | (value & 0x1F); + } + break; - case 0x2133: { + case 0x2133: + { //SETINI - Screen Mode/Video Select //_externalSync = (value & 0x80) != 0; //NOT USED _state.ExtBgEnabled = (value & 0x40) != 0; @@ -2092,9 +2529,11 @@ void Ppu::Write(uint32_t addr, uint8_t value) _state.ObjInterlace = (value & 0x02) != 0; bool interlace = (value & 0x01) != 0; - if(_state.ScreenInterlace != interlace) { + if (_state.ScreenInterlace != interlace) + { _state.ScreenInterlace = interlace; - if(_scanline >= _vblankStartScanline && interlace) { + if (_scanline >= _vblankStartScanline && interlace) + { //Clear buffer when turning on interlace mode during vblank memset(GetPreviousScreenBuffer(), 0, 512 * 478 * sizeof(uint16_t)); } @@ -2103,45 +2542,64 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; } - default: - LogDebug("[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); - break; + default: + LogDebug( + "[Debug] Unimplemented register write: " + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); + break; } } -void Ppu::Serialize(Serializer &s) +void Ppu::Serialize(Serializer& s) { uint16_t unused_oamRenderAddress = 0; s.Stream( _state.ForcedVblank, _state.ScreenBrightness, _scanline, _frameCount, _drawStartX, _drawEndX, _state.BgMode, - _state.Mode1Bg3Priority, _state.MainScreenLayers, _state.SubScreenLayers, _state.VramAddress, _state.VramIncrementValue, _state.VramAddressRemapping, - _state.VramAddrIncrementOnSecondReg, _state.VramReadBuffer, _state.Ppu1OpenBus, _state.Ppu2OpenBus, _state.CgramAddress, _state.MosaicSize, _state.MosaicEnabled, - _mosaicScanlineCounter, _state.OamMode, _state.OamBaseAddress, _state.OamAddressOffset, _state.OamRamAddress, _state.EnableOamPriority, - _internalOamAddress, _oamWriteBuffer, _timeOver, _rangeOver, _state.HiResMode, _state.ScreenInterlace, _state.ObjInterlace, - _state.OverscanMode, _state.DirectColorMode, _state.ColorMathClipMode, _state.ColorMathPreventMode, _state.ColorMathAddSubscreen, _state.ColorMathEnabled, - _state.ColorMathSubstractMode, _state.ColorMathHalveResult, _state.FixedColor, _hvScrollLatchValue, _hScrollLatchValue, + _state.Mode1Bg3Priority, _state.MainScreenLayers, _state.SubScreenLayers, _state.VramAddress, + _state.VramIncrementValue, _state.VramAddressRemapping, + _state.VramAddrIncrementOnSecondReg, _state.VramReadBuffer, _state.Ppu1OpenBus, _state.Ppu2OpenBus, + _state.CgramAddress, _state.MosaicSize, _state.MosaicEnabled, + _mosaicScanlineCounter, _state.OamMode, _state.OamBaseAddress, _state.OamAddressOffset, _state.OamRamAddress, + _state.EnableOamPriority, + _internalOamAddress, _oamWriteBuffer, _timeOver, _rangeOver, _state.HiResMode, _state.ScreenInterlace, + _state.ObjInterlace, + _state.OverscanMode, _state.DirectColorMode, _state.ColorMathClipMode, _state.ColorMathPreventMode, + _state.ColorMathAddSubscreen, _state.ColorMathEnabled, + _state.ColorMathSubstractMode, _state.ColorMathHalveResult, _state.FixedColor, _hvScrollLatchValue, + _hScrollLatchValue, _horizontalLocation, _horizontalLocToggle, _verticalLocation, _verticalLocationToggle, _locationLatched, - _state.MaskLogic[0], _state.MaskLogic[1], _state.MaskLogic[2], _state.MaskLogic[3], _state.MaskLogic[4], _state.MaskLogic[5], - _state.WindowMaskMain[0], _state.WindowMaskMain[1], _state.WindowMaskMain[2], _state.WindowMaskMain[3], _state.WindowMaskMain[4], - _state.WindowMaskSub[0], _state.WindowMaskSub[1], _state.WindowMaskSub[2], _state.WindowMaskSub[3], _state.WindowMaskSub[4], - _state.Mode7.CenterX, _state.Mode7.CenterY, _state.ExtBgEnabled, _state.Mode7.FillWithTile0, _state.Mode7.HorizontalMirroring, - _state.Mode7.HScroll, _state.Mode7.LargeMap, _state.Mode7.Matrix[0], _state.Mode7.Matrix[1], _state.Mode7.Matrix[2], _state.Mode7.Matrix[3], - _state.Mode7.ValueLatch, _state.Mode7.VerticalMirroring, _state.Mode7.VScroll, unused_oamRenderAddress, _oddFrame, _vblankStartScanline, - _state.CgramAddressLatch, _state.CgramWriteBuffer, _nmiScanline, _vblankEndScanline, _adjustedVblankEndScanline, _baseVblankEndScanline, + _state.MaskLogic[0], _state.MaskLogic[1], _state.MaskLogic[2], _state.MaskLogic[3], _state.MaskLogic[4], + _state.MaskLogic[5], + _state.WindowMaskMain[0], _state.WindowMaskMain[1], _state.WindowMaskMain[2], _state.WindowMaskMain[3], + _state.WindowMaskMain[4], + _state.WindowMaskSub[0], _state.WindowMaskSub[1], _state.WindowMaskSub[2], _state.WindowMaskSub[3], + _state.WindowMaskSub[4], + _state.Mode7.CenterX, _state.Mode7.CenterY, _state.ExtBgEnabled, _state.Mode7.FillWithTile0, + _state.Mode7.HorizontalMirroring, + _state.Mode7.HScroll, _state.Mode7.LargeMap, _state.Mode7.Matrix[0], _state.Mode7.Matrix[1], + _state.Mode7.Matrix[2], _state.Mode7.Matrix[3], + _state.Mode7.ValueLatch, _state.Mode7.VerticalMirroring, _state.Mode7.VScroll, unused_oamRenderAddress, _oddFrame, + _vblankStartScanline, + _state.CgramAddressLatch, _state.CgramWriteBuffer, _nmiScanline, _vblankEndScanline, _adjustedVblankEndScanline, + _baseVblankEndScanline, _overclockEnabled ); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { s.Stream( - _state.Layers[i].ChrAddress, _state.Layers[i].DoubleHeight, _state.Layers[i].DoubleWidth, _state.Layers[i].HScroll, + _state.Layers[i].ChrAddress, _state.Layers[i].DoubleHeight, _state.Layers[i].DoubleWidth, + _state.Layers[i].HScroll, _state.Layers[i].LargeTiles, _state.Layers[i].TilemapAddress, _state.Layers[i].VScroll ); } - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { s.Stream( - _state.Window[i].ActiveLayers[0], _state.Window[i].ActiveLayers[1], _state.Window[i].ActiveLayers[2], _state.Window[i].ActiveLayers[3], _state.Window[i].ActiveLayers[4], _state.Window[i].ActiveLayers[5], - _state.Window[i].InvertedLayers[0], _state.Window[i].InvertedLayers[1], _state.Window[i].InvertedLayers[2], _state.Window[i].InvertedLayers[3], _state.Window[i].InvertedLayers[4], _state.Window[i].InvertedLayers[5], + _state.Window[i].ActiveLayers[0], _state.Window[i].ActiveLayers[1], _state.Window[i].ActiveLayers[2], + _state.Window[i].ActiveLayers[3], _state.Window[i].ActiveLayers[4], _state.Window[i].ActiveLayers[5], + _state.Window[i].InvertedLayers[0], _state.Window[i].InvertedLayers[1], _state.Window[i].InvertedLayers[2], + _state.Window[i].InvertedLayers[3], _state.Window[i].InvertedLayers[4], _state.Window[i].InvertedLayers[5], _state.Window[i].Left, _state.Window[i].Right ); } @@ -2149,11 +2607,14 @@ void Ppu::Serialize(Serializer &s) s.StreamArray(_vram, Ppu::VideoRamSize >> 1); s.StreamArray(_oamRam, Ppu::SpriteRamSize); s.StreamArray(_cgram, Ppu::CgRamSize >> 1); - - for(int i = 0; i < 4; i++) { - for(int j = 0; j < 33; j++) { + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 33; j++) + { s.Stream( - _layerData[i].Tiles[j].ChrData[0], _layerData[i].Tiles[j].ChrData[1], _layerData[i].Tiles[j].ChrData[2], _layerData[i].Tiles[j].ChrData[3], + _layerData[i].Tiles[j].ChrData[0], _layerData[i].Tiles[j].ChrData[1], _layerData[i].Tiles[j].ChrData[2], + _layerData[i].Tiles[j].ChrData[3], _layerData[i].Tiles[j].TilemapData, _layerData[i].Tiles[j].VScroll ); } @@ -2185,7 +2646,8 @@ void Ppu::RandomizeState() _state.MainScreenLayers = _settings->GetRandomValue(0x1F); _state.SubScreenLayers = _settings->GetRandomValue(0x1F); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _state.Layers[i].TilemapAddress = _settings->GetRandomValue(0x1F) << 10; _state.Layers[i].ChrAddress = _settings->GetRandomValue(0x07) << 12; _state.Layers[i].HScroll = _settings->GetRandomValue(0x1FFF); @@ -2195,29 +2657,38 @@ void Ppu::RandomizeState() _state.Layers[i].LargeTiles = _settings->GetRandomBool(); } - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { _state.Window[i].Left = _settings->GetRandomValue(0xFF); _state.Window[i].Right = _settings->GetRandomValue(0xFF); - for(int j = 0; j < 6; j++) { + for (int j = 0; j < 6; j++) + { _state.Window[i].ActiveLayers[j] = _settings->GetRandomBool(); _state.Window[i].InvertedLayers[j] = _settings->GetRandomBool(); } } - for(int i = 0; i < 6; i++) { + for (int i = 0; i < 6; i++) + { _state.MaskLogic[i] = (WindowMaskLogic)_settings->GetRandomValue(3); } - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { _state.WindowMaskMain[i] = _settings->GetRandomBool(); _state.WindowMaskSub[i] = _settings->GetRandomBool(); } _state.VramAddress = _settings->GetRandomValue(0x7FFF); - switch(_settings->GetRandomValue(0x03)) { - case 0: _state.VramIncrementValue = 1; break; - case 1: _state.VramIncrementValue = 32; break; - case 2: case 3: _state.VramIncrementValue = 128; break; + switch (_settings->GetRandomValue(0x03)) + { + case 0: _state.VramIncrementValue = 1; + break; + case 1: _state.VramIncrementValue = 32; + break; + case 2: + case 3: _state.VramIncrementValue = 128; + break; } _state.VramAddressRemapping = _settings->GetRandomValue(0x03); @@ -2257,64 +2728,84 @@ void Ppu::RandomizeState() } /* Everything below this point is used to select the proper arguments for templates */ -template +template void Ppu::RenderTilemap() { - if(_state.DirectColorMode) { + if (_state.DirectColorMode) + { RenderTilemap(); - } else { + } + else + { RenderTilemap(); } } -template +template void Ppu::RenderTilemap() { - bool applyMosaic = ((_state.MosaicEnabled >> layerIndex) & 0x01) != 0 && (_state.MosaicSize > 1 || _state.BgMode == 5 || _state.BgMode == 6); + bool applyMosaic = ((_state.MosaicEnabled >> layerIndex) & 0x01) != 0 && (_state.MosaicSize > 1 || _state.BgMode == 5 + || _state.BgMode == 6); - if(applyMosaic) { + if (applyMosaic) + { RenderTilemap(); - } else { + } + else + { RenderTilemap(); } } -template +template void Ppu::RenderTilemap() { - if(!IsRenderRequired(layerIndex)) { + if (!IsRenderRequired(layerIndex)) + { return; } - if(_state.BgMode == 5 || _state.BgMode == 6) { + if (_state.BgMode == 5 || _state.BgMode == 6) + { RenderTilemap(); - } else { + } + else + { RenderTilemap(); } } -template +template void Ppu::RenderTilemapMode7() { - if(!IsRenderRequired(layerIndex)) { + if (!IsRenderRequired(layerIndex)) + { return; } bool applyMosaic = ((_state.MosaicEnabled >> layerIndex) & 0x01) != 0; - if(applyMosaic) { + if (applyMosaic) + { RenderTilemapMode7(); - } else { + } + else + { RenderTilemapMode7(); } } -template +template void Ppu::RenderTilemapMode7() { - if(_state.DirectColorMode) { + if (_state.DirectColorMode) + { RenderTilemapMode7(); - } else { + } + else + { RenderTilemapMode7(); } -} \ No newline at end of file +} diff --git a/Core/Ppu.h b/Core/Ppu.h index eb2d446..5f410dc 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -64,13 +64,13 @@ private: uint16_t _drawStartX = 0; uint16_t _drawEndX = 0; - - uint16_t *_vram = nullptr; + + uint16_t* _vram = nullptr; uint16_t _cgram[Ppu::CgRamSize >> 1] = {}; uint8_t _oamRam[Ppu::SpriteRamSize] = {}; - uint16_t *_outputBuffers[2] = {}; - uint16_t *_currentBuffer = nullptr; + uint16_t* _outputBuffers[2] = {}; + uint16_t* _currentBuffer = nullptr; bool _useHighResOutput = false; bool _interlacedFrame = false; bool _overscanFrame = false; @@ -84,7 +84,7 @@ private: uint32_t _mosaicColor[4] = {}; uint32_t _mosaicPriority[4] = {}; uint16_t _mosaicScanlineCounter = 0; - + uint16_t _internalOamAddress = 0; uint8_t _oamWriteBuffer = 0; @@ -116,10 +116,10 @@ private: void RenderSprites(const uint8_t priorities[4]); - template + template void GetTilemapData(uint8_t layerIndex, uint8_t columnIndex); - template + template void GetChrData(uint8_t layerIndex, uint8_t column, uint8_t plane); void GetHorizontalOffsetByte(uint8_t columnIndex); @@ -137,48 +137,52 @@ private: void RenderBgColor(); - template - __forceinline void RenderTilemap(); - - template + template __forceinline void RenderTilemap(); - template + template __forceinline void RenderTilemap(); - template + template + __forceinline void RenderTilemap(); + + template void RenderTilemap(); - template + template __forceinline uint16_t GetRgbColor(uint8_t paletteIndex, uint8_t colorIndex); __forceinline bool IsRenderRequired(uint8_t layerIndex); - template + template __forceinline uint8_t GetTilePixelColor(const uint16_t chrData[4], const uint8_t shift); - template + template __forceinline void RenderTilemapMode7(); - template + template __forceinline void RenderTilemapMode7(); - template + template void RenderTilemapMode7(); __forceinline void DrawMainPixel(uint8_t x, uint16_t color, uint8_t flags); __forceinline void DrawSubPixel(uint8_t x, uint16_t color, uint8_t priority); void ApplyColorMath(); - void ApplyColorMathToPixel(uint16_t &pixelA, uint16_t pixelB, int x, bool isInsideWindow); - - template + void ApplyColorMathToPixel(uint16_t& pixelA, uint16_t pixelB, int x, bool isInsideWindow); + + template void ApplyBrightness(); void ConvertToHiRes(); void ApplyHiResMode(); - template + template bool ProcessMaskWindow(uint8_t activeWindowCount, int x); void ProcessWindowMaskSettings(uint8_t value, uint8_t offset); @@ -199,7 +203,7 @@ private: void UpdateOamAddress(); uint16_t GetOamAddress(); - + void RandomizeState(); public: @@ -220,7 +224,7 @@ public: uint16_t GetVblankStart(); PpuState GetState(); - void GetState(PpuState &state, bool returnPartialState); + void GetState(PpuState& state, bool returnPartialState); bool ProcessEndOfScanline(uint16_t hClock); void UpdateSpcState(); @@ -237,9 +241,9 @@ public: void SetLocationLatchRequest(uint16_t x, uint16_t y); void ProcessLocationLatchRequest(); void LatchLocationValues(); - + uint8_t Read(uint16_t addr); void Write(uint32_t addr, uint8_t value); - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/PpuTools.cpp b/Core/PpuTools.cpp index ec20c0c..93a746d 100644 --- a/Core/PpuTools.cpp +++ b/Core/PpuTools.cpp @@ -9,24 +9,30 @@ #include "DefaultVideoFilter.h" #include "GbTypes.h" -PpuTools::PpuTools(Console *console, Ppu *ppu) +PpuTools::PpuTools(Console* console, Ppu* ppu) { _console = console; _ppu = ppu; } -uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift) +uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, + const uint32_t pixelStart, const uint8_t shift) { uint8_t color; - if(bpp == 2) { + if (bpp == 2) + { color = (((ram[(pixelStart + 0) & ramMask] >> shift) & 0x01) << 0); color |= (((ram[(pixelStart + 1) & ramMask] >> shift) & 0x01) << 1); - } else if(bpp == 4) { + } + else if (bpp == 4) + { color = (((ram[(pixelStart + 0) & ramMask] >> shift) & 0x01) << 0); color |= (((ram[(pixelStart + 1) & ramMask] >> shift) & 0x01) << 1); color |= (((ram[(pixelStart + 16) & ramMask] >> shift) & 0x01) << 2); color |= (((ram[(pixelStart + 17) & ramMask] >> shift) & 0x01) << 3); - } else if(bpp == 8) { + } + else if (bpp == 8) + { color = (((ram[(pixelStart + 0) & ramMask] >> shift) & 0x01) << 0); color |= (((ram[(pixelStart + 1) & ramMask] >> shift) & 0x01) << 1); color |= (((ram[(pixelStart + 16) & ramMask] >> shift) & 0x01) << 2); @@ -35,7 +41,9 @@ uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, color |= (((ram[(pixelStart + 33) & ramMask] >> shift) & 0x01) << 5); color |= (((ram[(pixelStart + 48) & ramMask] >> shift) & 0x01) << 6); color |= (((ram[(pixelStart + 49) & ramMask] >> shift) & 0x01) << 7); - } else { + } + else + { throw std::runtime_error("unsupported bpp"); } return color; @@ -51,23 +59,28 @@ void PpuTools::BlendColors(uint8_t output[4], uint8_t input[4]) output[3] = 0xFF; } -uint32_t PpuTools::GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, uint16_t basePaletteOffset) +uint32_t PpuTools::GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, + bool directColorMode, uint16_t basePaletteOffset) { uint16_t paletteColor; - if(bpp == 8 && directColorMode) { + if (bpp == 8 && directColorMode) + { paletteColor = ( ((((colorIndex & 0x07) << 1) | (palette & 0x01)) << 1) | (((colorIndex & 0x38) | ((palette & 0x02) << 1)) << 4) | (((colorIndex & 0xC0) | ((palette & 0x04) << 3)) << 7) ); - } else { + } + else + { uint16_t paletteRamOffset = basePaletteOffset + (palette * (1 << bpp) + colorIndex) * 2; paletteColor = cgram[paletteRamOffset] | (cgram[paletteRamOffset + 1] << 8); } return DefaultVideoFilter::ToArgb(paletteColor); } -void PpuTools::GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, uint8_t *cgram, uint32_t *outBuffer) +void PpuTools::GetTileView(GetTileViewOptions options, uint8_t* source, uint32_t srcSize, uint8_t* cgram, + uint32_t* outBuffer) { constexpr uint32_t inputSize = 0x40000; constexpr uint32_t outputSize = 0x400000; @@ -77,77 +90,115 @@ void PpuTools::GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t uint8_t bpp; bool directColor = false; - switch(options.Format) { - case TileFormat::Bpp2: bpp = 2; break; - case TileFormat::Bpp4: bpp = 4; break; - case TileFormat::DirectColor: directColor = true; bpp = 8; break; - case TileFormat::Mode7: bpp = 16; break; - case TileFormat::Mode7DirectColor: directColor = true; bpp = 16; break; - default: bpp = 8; break; + switch (options.Format) + { + case TileFormat::Bpp2: bpp = 2; + break; + case TileFormat::Bpp4: bpp = 4; + break; + case TileFormat::DirectColor: directColor = true; + bpp = 8; + break; + case TileFormat::Mode7: bpp = 16; + break; + case TileFormat::Mode7DirectColor: directColor = true; + bpp = 16; + break; + default: bpp = 8; + break; } int bytesPerTile = 64 * bpp / 8; int tileCount = options.PageSize / bytesPerTile; uint32_t bgColor = 0; - switch(options.Background) { - case TileBackground::Default: bgColor = DefaultVideoFilter::ToArgb((cgram[1] << 8) | cgram[0]); break; - case TileBackground::PaletteColor: bgColor = DefaultVideoFilter::ToArgb(0); break; - case TileBackground::Black: bgColor = DefaultVideoFilter::ToArgb(0); break; - case TileBackground::White: bgColor = DefaultVideoFilter::ToArgb(0x7FFF); break; - case TileBackground::Magenta: bgColor = DefaultVideoFilter::ToArgb(0x7C1F); break; + switch (options.Background) + { + case TileBackground::Default: bgColor = DefaultVideoFilter::ToArgb((cgram[1] << 8) | cgram[0]); + break; + case TileBackground::PaletteColor: bgColor = DefaultVideoFilter::ToArgb(0); + break; + case TileBackground::Black: bgColor = DefaultVideoFilter::ToArgb(0); + break; + case TileBackground::White: bgColor = DefaultVideoFilter::ToArgb(0x7FFF); + break; + case TileBackground::Magenta: bgColor = DefaultVideoFilter::ToArgb(0x7C1F); + break; } - for(uint32_t i = 0; i < outputSize / sizeof(uint32_t); i++) { + for (uint32_t i = 0; i < outputSize / sizeof(uint32_t); i++) + { outBuffer[i] = bgColor; } int rowCount = (int)std::ceil((double)tileCount / options.Width); - for(int row = 0; row < rowCount; row++) { + for (int row = 0; row < rowCount; row++) + { uint32_t baseOffset = row * bytesPerTile * options.Width; - for(int column = 0; column < options.Width; column++) { + for (int column = 0; column < options.Width; column++) + { uint32_t addr = baseOffset + bytesPerTile * column; - int baseOutputOffset; - if(options.Layout == TileLayout::SingleLine8x16) { - int displayColumn = column / 2 + ((row & 0x01) ? options.Width/2 : 0); + int baseOutputOffset; + if (options.Layout == TileLayout::SingleLine8x16) + { + int displayColumn = column / 2 + ((row & 0x01) ? options.Width / 2 : 0); int displayRow = (row & ~0x01) + ((column & 0x01) ? 1 : 0); baseOutputOffset = displayRow * options.Width * 64 + displayColumn * 8; - } else if(options.Layout == TileLayout::SingleLine16x16) { - int displayColumn = (column / 2) + (column & 0x01) + ((row & 0x01) ? options.Width/2 : 0) + ((column & 0x02) ? -1 : 0); + } + else if (options.Layout == TileLayout::SingleLine16x16) + { + int displayColumn = (column / 2) + (column & 0x01) + ((row & 0x01) ? options.Width / 2 : 0) + ( + (column & 0x02) ? -1 : 0); int displayRow = (row & ~0x01) + ((column & 0x02) ? 1 : 0); baseOutputOffset = displayRow * options.Width * 64 + displayColumn * 8; - } else { + } + else + { baseOutputOffset = row * options.Width * 64 + column * 8; } - if(options.Format == TileFormat::Mode7 || options.Format == TileFormat::Mode7DirectColor) { - for(int y = 0; y < 8; y++) { + if (options.Format == TileFormat::Mode7 || options.Format == TileFormat::Mode7DirectColor) + { + for (int y = 0; y < 8; y++) + { uint32_t pixelStart = addr + y * 16; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t color = ram[(pixelStart + x * 2 + 1) & ramMask]; - if(color != 0 || options.Background == TileBackground::PaletteColor) { + if (color != 0 || options.Background == TileBackground::PaletteColor) + { uint32_t rgbColor; - if(directColor) { - rgbColor = DefaultVideoFilter::ToArgb(((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); - } else { + if (directColor) + { + rgbColor = DefaultVideoFilter::ToArgb( + ((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); + } + else + { rgbColor = GetRgbPixelColor(cgram, color, 0, 8, false, 0); } - outBuffer[baseOutputOffset + (y*options.Width*8) + x] = rgbColor; + outBuffer[baseOutputOffset + (y * options.Width * 8) + x] = rgbColor; } } } - } else { - for(int y = 0; y < 8; y++) { + } + else + { + for (int y = 0; y < 8; y++) + { uint32_t pixelStart = addr + y * 2; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t color = GetTilePixelColor(ram, ramMask, bpp, pixelStart, 7 - x); - if(color != 0 || options.Background == TileBackground::PaletteColor) { - outBuffer[baseOutputOffset + (y*options.Width*8) + x] = GetRgbPixelColor(cgram, color, options.Palette, bpp, directColor, 0); + if (color != 0 || options.Background == TileBackground::PaletteColor) + { + outBuffer[baseOutputOffset + (y * options.Width * 8) + x] = GetRgbPixelColor( + cgram, color, options.Palette, bpp, directColor, 0); } } } @@ -159,46 +210,58 @@ void PpuTools::GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t* outBuffer) { static constexpr uint8_t layerBpp[8][4] = { - { 2,2,2,2 }, { 4,4,2,0 }, { 4,4,0,0 }, { 8,4,0,0 }, { 8,2,0,0 }, { 4,2,0,0 }, { 4,0,0,0 }, { 8,0,0,0 } + {2, 2, 2, 2}, {4, 4, 2, 0}, {4, 4, 0, 0}, {8, 4, 0, 0}, {8, 2, 0, 0}, {4, 2, 0, 0}, {4, 0, 0, 0}, {8, 0, 0, 0} }; bool directColor = state.DirectColorMode && (state.BgMode == 3 || state.BgMode == 4 || state.BgMode == 7); uint16_t basePaletteOffset = 0; - if(state.BgMode == 0) { + if (state.BgMode == 0) + { basePaletteOffset = options.Layer * 64; } LayerConfig layer = state.Layers[options.Layer]; uint32_t bgColor = DefaultVideoFilter::ToArgb((cgram[1] << 8) | cgram[0]); - std::fill(outBuffer, outBuffer + 1024*1024, bgColor); + std::fill(outBuffer, outBuffer + 1024 * 1024, bgColor); uint8_t bpp = layerBpp[state.BgMode][options.Layer]; - if(bpp == 0) { + if (bpp == 0) + { return; } bool largeTileWidth = layer.LargeTiles || state.BgMode == 5 || state.BgMode == 6; bool largeTileHeight = layer.LargeTiles; - if(state.BgMode == 7) { - for(int row = 0; row < 128; row++) { - for(int column = 0; column < 128; column++) { + if (state.BgMode == 7) + { + for (int row = 0; row < 128; row++) + { + for (int column = 0; column < 128; column++) + { uint32_t tileIndex = vram[row * 256 + column * 2]; uint32_t tileAddr = tileIndex * 128; - for(int y = 0; y < 8; y++) { + for (int y = 0; y < 8; y++) + { uint32_t pixelStart = tileAddr + y * 16; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t color = vram[pixelStart + x * 2 + 1]; - if(color != 0) { + if (color != 0) + { uint32_t rgbColor; - if(directColor) { - rgbColor = DefaultVideoFilter::ToArgb(((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); - } else { + if (directColor) + { + rgbColor = DefaultVideoFilter::ToArgb( + ((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); + } + else + { rgbColor = GetRgbPixelColor(cgram, color, 0, 8, false, 0); } outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = rgbColor; @@ -207,24 +270,30 @@ void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vr } } } - } else { + } + else + { int tileHeight = largeTileHeight ? 16 : 8; int tileWidth = largeTileWidth ? 16 : 8; - for(int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) { + for (int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) + { uint16_t addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0; uint16_t baseOffset = layer.TilemapAddress + addrVerticalScrollingOffset + ((row & 0x1F) << 5); - for(int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) { + for (int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) + { uint16_t addr = (baseOffset + (column & 0x1F) + (layer.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1; bool vMirror = (vram[addr + 1] & 0x80) != 0; bool hMirror = (vram[addr + 1] & 0x40) != 0; uint16_t tileIndex = ((vram[addr + 1] & 0x03) << 8) | vram[addr]; - for(int y = 0; y < tileHeight; y++) { + for (int y = 0; y < tileHeight; y++) + { uint8_t yOffset = vMirror ? (7 - (y & 0x07)) : (y & 0x07); - for(int x = 0; x < tileWidth; x++) { + for (int x = 0; x < tileWidth; x++) + { uint16_t tileOffset = ( (largeTileHeight ? ((y & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + (largeTileWidth ? ((x & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) @@ -235,9 +304,11 @@ void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vr uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, bpp, pixelStart, shift); - if(color != 0) { + if (color != 0) + { uint8_t palette = bpp == 8 ? 0 : (vram[addr + 1] >> 2) & 0x07; - outBuffer[((row * tileHeight) + y) * 1024 + column * tileWidth + x] = GetRgbPixelColor(cgram, color, palette, bpp, directColor, basePaletteOffset); + outBuffer[((row * tileHeight) + y) * 1024 + column * tileWidth + x] = GetRgbPixelColor( + cgram, color, palette, bpp, directColor, basePaletteOffset); } } } @@ -247,17 +318,18 @@ void PpuTools::GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vr } static constexpr uint8_t _oamSizes[8][2][2] = { - { { 1, 1 }, { 2, 2 } }, //8x8 + 16x16 - { { 1, 1 }, { 4, 4 } }, //8x8 + 32x32 - { { 1, 1 }, { 8, 8 } }, //8x8 + 64x64 - { { 2, 2 }, { 4, 4 } }, //16x16 + 32x32 - { { 2, 2 }, { 8, 8 } }, //16x16 + 64x64 - { { 4, 4 }, { 8, 8 } }, //32x32 + 64x64 - { { 2, 4 }, { 4, 8 } }, //16x32 + 32x64 - { { 2, 4 }, { 4, 4 } } //16x32 + 32x32 + {{1, 1}, {2, 2}}, //8x8 + 16x16 + {{1, 1}, {4, 4}}, //8x8 + 32x32 + {{1, 1}, {8, 8}}, //8x8 + 64x64 + {{2, 2}, {4, 4}}, //16x16 + 32x32 + {{2, 2}, {8, 8}}, //16x16 + 64x64 + {{4, 4}, {8, 8}}, //32x32 + 64x64 + {{2, 4}, {4, 8}}, //16x32 + 32x64 + {{2, 4}, {4, 4}} //16x32 + 32x32 }; -void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t *vram, uint8_t *oamRam, uint8_t *cgram, uint32_t *outBuffer) +void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, + uint8_t* cgram, uint32_t* outBuffer) { //TODO //uint16_t baseAddr = state.EnableOamPriority ? (_internalOamAddress & 0x1FC) : 0; @@ -268,8 +340,10 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, std::fill(outBuffer, outBuffer + 256 * lastScanline, 0xFF888888); std::fill(outBuffer + 256 * lastScanline, outBuffer + 256 * 240, 0xFF000000); - for(int screenY = 0; screenY < lastScanline; screenY++) { - for(int i = 508; i >= 0; i -= 4) { + for (int screenY = 0; screenY < lastScanline; screenY++) + { + for (int i = 508; i >= 0; i -= 4) + { uint16_t addr = (baseAddr + i) & 0x1FF; uint8_t y = oamRam[addr + 1]; @@ -279,10 +353,11 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t largeSprite = (highTableValue & 0x02) >> 1; uint8_t height = _oamSizes[state.OamMode][largeSprite][1] << 3; - uint8_t endY = (y + (state.ObjInterlace ? (height >> 1): height)) & 0xFF; + uint8_t endY = (y + (state.ObjInterlace ? (height >> 1) : height)) & 0xFF; bool visible = (screenY >= y && screenY < endY) || (endY < y && screenY < endY); - if(!visible) { + if (!visible) + { //Not visible on this scanline continue; } @@ -291,7 +366,8 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint16_t sign = (highTableValue & 0x01) << 8; int16_t x = (int16_t)((sign | oamRam[addr]) << 7) >> 7; - if(x != -256 && (x + width <= 0 || x > 255)) { + if (x != -256 && (x + width <= 0 || x > 255)) + { //Sprite is not visible (and must be ignored for time/range flag calculations) //Sprites at X=-256 are always used when considering Time/Range flag calculations, but not actually drawn. continue; @@ -306,49 +382,62 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, //uint8_t priority = (flags >> 4) & 0x03; bool horizontalMirror = (flags & 0x40) != 0; bool verticalMirror = (flags & 0x80) != 0; - + uint8_t yOffset; int rowOffset; int yGap = (screenY - y); - if(state.ObjInterlace) { + if (state.ObjInterlace) + { yGap <<= 1; yGap |= (state.FrameCount & 0x01); } - if(verticalMirror) { + if (verticalMirror) + { yOffset = (height - 1 - yGap) & 0x07; rowOffset = (height - 1 - yGap) >> 3; - } else { + } + else + { yOffset = yGap & 0x07; rowOffset = yGap >> 3; } uint8_t row = (tileRow + rowOffset) & 0x0F; - for(int j = std::max(x, 0); j < x + width && j < 256; j++) { + for (int j = std::max(x, 0); j < x + width && j < 256; j++) + { uint32_t outOffset = screenY * 256 + j; - if(filled[outOffset]) { + if (filled[outOffset]) + { continue; } uint8_t xOffset; int columnOffset; - if(horizontalMirror) { + if (horizontalMirror) + { xOffset = (width - (j - x) - 1) & 0x07; columnOffset = (width - (j - x) - 1) >> 3; - } else { + } + else + { xOffset = (j - x) & 0x07; columnOffset = (j - x) >> 3; } uint8_t column = (tileColumn + columnOffset) & 0x0F; uint8_t tileIndex = (row << 4) | column; - uint16_t tileStart = ((state.OamBaseAddress + (tileIndex << 4) + (useSecondTable ? state.OamAddressOffset : 0)) & 0x7FFF) << 1; + uint16_t tileStart = ((state.OamBaseAddress + (tileIndex << 4) + (useSecondTable + ? state.OamAddressOffset + : 0)) & 0x7FFF) << 1; uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, 4, tileStart + yOffset * 2, 7 - xOffset); - if(color != 0) { - if(options.SelectedSprite == i / 4) { + if (color != 0) + { + if (options.SelectedSprite == i / 4) + { filled[outOffset] = true; } outBuffer[outOffset] = GetRgbPixelColor(cgram, color, palette, 4, false, 256); @@ -380,14 +469,16 @@ void PpuTools::GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offs uint16_t baseTile = state.BgTileSelect ? 0 : 0x1000; - std::fill(outBuffer, outBuffer + 1024*256, 0xFFFFFFFF); + std::fill(outBuffer, outBuffer + 1024 * 256, 0xFFFFFFFF); uint16_t vramMask = isCgb ? 0x3FFF : 0x1FFF; - for(int row = 0; row < 32; row++) { + for (int row = 0; row < 32; row++) + { uint16_t baseOffset = offset + ((row & 0x1F) << 5); - for(int column = 0; column < 32; column++) { + for (int column = 0; column < 32; column++) + { uint16_t addr = (baseOffset + column); uint8_t tileIndex = vram[addr]; @@ -399,26 +490,31 @@ void PpuTools::GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offs bool vMirror = (attributes & 0x40) != 0; //bool bgPriority = (attributes & 0x80) != 0; - uint16_t tileStart = baseTile + (baseTile ? (int8_t)tileIndex*16 : tileIndex*16); + uint16_t tileStart = baseTile + (baseTile ? (int8_t)tileIndex * 16 : tileIndex * 16); tileStart |= tileBank; - for(int y = 0; y < 8; y++) { + for (int y = 0; y < 8; y++) + { uint16_t pixelStart = tileStart + (vMirror ? (7 - y) : y) * 2; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, vramMask, 2, pixelStart, shift); - outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = DefaultVideoFilter::ToArgb(state.CgbBgPalettes[bgPalette + color]); + outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = DefaultVideoFilter::ToArgb( + state.CgbBgPalettes[bgPalette + color]); } } } } } -void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, uint32_t* outBuffer) +void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, + uint8_t* oamRam, uint32_t* outBuffer) { std::fill(outBuffer, outBuffer + 256 * 256, 0xFF333311); - for(int i = 16; i < 16 + 144; i++) { + for (int i = 16; i < 16 + 144; i++) + { std::fill(outBuffer + i * 256 + 8, outBuffer + i * 256 + 168, 0xFF888866); } @@ -428,12 +524,15 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta constexpr uint8_t width = 8; uint8_t filled[256]; - for(int row = 0; row < 256; row++) { + for (int row = 0; row < 256; row++) + { std::fill(filled, filled + 256, 0xFF); - for(int i = 0; i < 0xA0; i += 4) { + for (int i = 0; i < 0xA0; i += 4) + { uint8_t sprY = oamRam[i]; - if(sprY > row || sprY + height <= row) { + if (sprY > row || sprY + height <= row) + { continue; } @@ -447,7 +546,8 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta bool hMirror = (attributes & 0x20) != 0; bool vMirror = (attributes & 0x40) != 0; - if(largeSprites) { + if (largeSprites) + { tileIndex &= 0xFE; } @@ -455,18 +555,24 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta tileStart |= tileBank; uint16_t pixelStart = tileStart + (vMirror ? (height - 1 - y) : y) * 2; - for(int x = 0; x < width; x++) { - if(sprX + x >= 256) { + for (int x = 0; x < width; x++) + { + if (sprX + x >= 256) + { break; - } else if(filled[sprX + x] < sprX) { + } + else if (filled[sprX + x] < sprX) + { continue; } uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, 0x3FFF, 2, pixelStart, shift); - if(color > 0) { - if(!isCgb) { + if (color > 0) + { + if (!isCgb) + { color = (((attributes & 0x10) ? state.ObjPalette1 : state.ObjPalette0) >> (color * 2)) & 0x03; } @@ -477,4 +583,4 @@ void PpuTools::GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuSta } } } -} \ No newline at end of file +} diff --git a/Core/PpuTools.h b/Core/PpuTools.h index bf0a59a..b9da4e4 100644 --- a/Core/PpuTools.h +++ b/Core/PpuTools.h @@ -17,38 +17,46 @@ struct ViewerRefreshConfig class PpuTools { private: - Ppu *_ppu; - Console *_console; + Ppu* _ppu; + Console* _console; unordered_map _updateTimings; - uint8_t GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift); + uint8_t GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, + const uint8_t shift); void BlendColors(uint8_t output[4], uint8_t input[4]); - uint32_t GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, uint16_t basePaletteOffset); + uint32_t GetRgbPixelColor(uint8_t* cgram, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, + uint16_t basePaletteOffset); public: - PpuTools(Console *console, Ppu *ppu); + PpuTools(Console* console, Ppu* ppu); - void GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, uint8_t *cgram, uint32_t *outBuffer); - void GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t *outBuffer); - void GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, uint8_t* cgram, uint32_t *outBuffer); + void GetTileView(GetTileViewOptions options, uint8_t* source, uint32_t srcSize, uint8_t* cgram, uint32_t* outBuffer); + void GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t* outBuffer); + void GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, + uint8_t* cgram, uint32_t* outBuffer); void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType); void RemoveViewer(uint32_t viewerId); - + __forceinline void UpdateViewers(uint16_t scanline, uint16_t cycle, CpuType cpuType) { - if(_updateTimings.size() > 0) { - for(auto updateTiming : _updateTimings) { + if (_updateTimings.size() > 0) + { + for (auto updateTiming : _updateTimings) + { ViewerRefreshConfig cfg = updateTiming.second; - if(cfg.Cycle == cycle && cfg.Scanline == scanline && cfg.Type == cpuType) { - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first); + if (cfg.Cycle == cycle && cfg.Scanline == scanline && cfg.Type == cpuType) + { + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, + (void*)(uint64_t)updateTiming.first); } } } } void GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offset, uint32_t* outBuffer); - void GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, uint32_t* outBuffer); -}; \ No newline at end of file + void GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, + uint32_t* outBuffer); +}; diff --git a/Core/PpuTypes.h b/Core/PpuTypes.h index 9c85bb1..1a96bd9 100644 --- a/Core/PpuTypes.h +++ b/Core/PpuTypes.h @@ -1,7 +1,7 @@ #pragma once #include "stdafx.h" -enum class WindowMaskLogic +enum class WindowMaskLogic { Or = 0, And = 1, @@ -36,7 +36,8 @@ struct SpriteInfo bool IsVisible(uint16_t scanline, bool interlace) { - if(X != -256 && (X + Width <= 0 || X > 255)) { + if (X != -256 && (X + Width <= 0 || X > 255)) + { //Sprite is not visible (and must be ignored for time/range flag calculations) //Sprites at X=-256 are always used when considering Time/Range flag calculations, but not actually drawn. return false; @@ -83,7 +84,7 @@ struct Mode7Config int16_t CenterY; uint8_t ValueLatch; - + bool LargeMap; bool FillWithTile0; bool HorizontalMirroring; @@ -101,19 +102,28 @@ struct WindowConfig uint8_t Left; uint8_t Right; - template + template bool PixelNeedsMasking(int x) { - if(InvertedLayers[layerIndex]) { - if(Left > Right) { + if (InvertedLayers[layerIndex]) + { + if (Left > Right) + { return true; - } else { + } + else + { return x < Left || x > Right; } - } else { - if(Left > Right) { + } + else + { + if (Left > Right) + { return false; - } else { + } + else + { return x >= Left && x <= Right; } } @@ -187,4 +197,4 @@ struct PpuState enum PixelFlags { AllowColorMath = 0x80, -}; \ No newline at end of file +}; diff --git a/Core/Profiler.cpp b/Core/Profiler.cpp index bcd2a3e..0d09e4f 100644 --- a/Core/Profiler.cpp +++ b/Core/Profiler.cpp @@ -20,11 +20,13 @@ Profiler::~Profiler() { } -void Profiler::StackFunction(AddressInfo &addr, StackFrameFlags stackFlag) +void Profiler::StackFunction(AddressInfo& addr, StackFrameFlags stackFlag) { - if(addr.Address >= 0) { + if (addr.Address >= 0) + { uint32_t key = addr.Address | ((uint8_t)addr.Type << 24); - if(_functions.find(key) == _functions.end()) { + if (_functions.find(key) == _functions.end()) + { _functions[key] = ProfiledFunction(); _functions[key].Address = addr; } @@ -46,16 +48,18 @@ void Profiler::StackFunction(AddressInfo &addr, StackFrameFlags stackFlag) void Profiler::UpdateCycles() { uint64_t masterClock = _console->GetMasterClock(); - + ProfiledFunction& func = _functions[_currentFunction]; uint64_t clockGap = masterClock - _prevMasterClock; func.ExclusiveCycles += clockGap; func.InclusiveCycles += clockGap; - + int32_t len = (int32_t)_functionStack.size(); - for(int32_t i = len - 1; i >= 0; i--) { + for (int32_t i = len - 1; i >= 0; i--) + { _functions[_functionStack[i]].InclusiveCycles += clockGap; - if(_stackFlags[i] != StackFrameFlags::None) { + if (_stackFlags[i] != StackFrameFlags::None) + { //Don't apply inclusive times to stack frames before an IRQ/NMI break; } @@ -67,7 +71,8 @@ void Profiler::UpdateCycles() void Profiler::UnstackFunction() { - if(!_functionStack.empty()) { + if (!_functionStack.empty()) + { UpdateCycles(); //Return to the previous function @@ -99,24 +104,26 @@ void Profiler::InternalReset() _functionStack.clear(); _stackFlags.clear(); _cycleCountStack.clear(); - + _functions.clear(); _functions[ResetFunctionIndex] = ProfiledFunction(); - _functions[ResetFunctionIndex].Address = { ResetFunctionIndex, SnesMemoryType::Register }; + _functions[ResetFunctionIndex].Address = {ResetFunctionIndex, SnesMemoryType::Register}; } void Profiler::GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount) { DebugBreakHelper helper(_debugger); - + UpdateCycles(); functionCount = 0; - for(auto func : _functions) { + for (auto func : _functions) + { profilerData[functionCount] = func.second; functionCount++; - if(functionCount >= 100000) { + if (functionCount >= 100000) + { break; } } diff --git a/Core/Profiler.h b/Core/Profiler.h index 4cbb0cb..da86bee 100644 --- a/Core/Profiler.h +++ b/Core/Profiler.h @@ -22,7 +22,7 @@ private: Console* _console; unordered_map _functions; - + deque _functionStack; deque _stackFlags; deque _cycleCountStack; @@ -43,4 +43,4 @@ public: void Reset(); void GetProfilerData(ProfiledFunction* profilerData, uint32_t& functionCount); -}; \ No newline at end of file +}; diff --git a/Core/RamHandler.h b/Core/RamHandler.h index 2c694e2..9f165df 100644 --- a/Core/RamHandler.h +++ b/Core/RamHandler.h @@ -6,21 +6,24 @@ class RamHandler : public IMemoryHandler { private: - uint8_t * _ram; + uint8_t* _ram; uint32_t _mask; protected: uint32_t _offset; public: - RamHandler(uint8_t *ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType) : IMemoryHandler(memoryType) + RamHandler(uint8_t* ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType) : IMemoryHandler(memoryType) { _ram = ram + offset; _offset = offset; - if(size - offset < 0x1000) { + if (size - offset < 0x1000) + { _mask = size - offset - 1; - } else { + } + else + { _mask = 0xFFF; } _memoryType = memoryType; @@ -36,13 +39,17 @@ public: return _ram[addr & _mask]; } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - if(_mask != 0xFFF) { - for(int i = 0; i < 0x1000; i++) { + if (_mask != 0xFFF) + { + for (int i = 0; i < 0x1000; i++) + { output[i] = _ram[i & _mask]; } - } else { + } + else + { memcpy(output, _ram, 0x1000); } } @@ -59,4 +66,4 @@ public: info.Type = _memoryType; return info; } -}; \ No newline at end of file +}; diff --git a/Core/RecordedRomTest.cpp b/Core/RecordedRomTest.cpp index 030930a..8521cc5 100644 --- a/Core/RecordedRomTest.cpp +++ b/Core/RecordedRomTest.cpp @@ -17,9 +17,12 @@ RecordedRomTest::RecordedRomTest(shared_ptr console) { - if(console) { + if (console) + { _console = console; - } else { + } + else + { _console.reset(new Console()); _console->Initialize(); } @@ -39,15 +42,19 @@ void RecordedRomTest::SaveFrame() uint16_t* ppuFrameBuffer = _ppu->GetScreenBuffer(); uint8_t md5Hash[16]; - GetMd5Sum(md5Hash, ppuFrameBuffer, width*height*sizeof(uint16_t)); + GetMd5Sum(md5Hash, ppuFrameBuffer, width * height * sizeof(uint16_t)); - if(memcmp(_previousHash, md5Hash, 16) == 0 && _currentCount < 255) { + if (memcmp(_previousHash, md5Hash, 16) == 0 && _currentCount < 255) + { _currentCount++; - } else { + } + else + { uint8_t* hash = new uint8_t[16]; memcpy(hash, md5Hash, 16); _screenshotHashes.push_back(hash); - if(_currentCount > 0) { + if (_currentCount > 0) + { _repetitionCount.push_back(_currentCount); } _currentCount = 1; @@ -68,19 +75,22 @@ void RecordedRomTest::ValidateFrame() uint8_t md5Hash[16]; GetMd5Sum(md5Hash, ppuFrameBuffer, width * height * sizeof(uint16_t)); - if(_currentCount == 0) { + if (_currentCount == 0) + { _currentCount = _repetitionCount.front(); _repetitionCount.pop_front(); _screenshotHashes.pop_front(); } _currentCount--; - if(memcmp(_screenshotHashes.front(), md5Hash, 16) != 0) { + if (memcmp(_screenshotHashes.front(), md5Hash, 16) != 0) + { _badFrameCount++; //_console->BreakIfDebugging(); - } - - if(_currentCount == 0 && _repetitionCount.empty()) { + } + + if (_currentCount == 0 && _repetitionCount.empty()) + { //End of test _runningTest = false; _signal.Signal(); @@ -89,28 +99,33 @@ void RecordedRomTest::ValidateFrame() void RecordedRomTest::ProcessNotification(ConsoleNotificationType type, void* parameter) { - switch(type) { - case ConsoleNotificationType::PpuFrameDone: - if(_recording) { - SaveFrame(); - } else if(_runningTest) { - ValidateFrame(); - } - break; - - default: - break; + switch (type) + { + case ConsoleNotificationType::PpuFrameDone: + if (_recording) + { + SaveFrame(); + } + else if (_runningTest) + { + ValidateFrame(); + } + break; + + default: + break; } } void RecordedRomTest::Reset() { memset(_previousHash, 0xFF, 16); - + _currentCount = 0; _repetitionCount.clear(); - for(uint8_t* hash : _screenshotHashes) { + for (uint8_t* hash : _screenshotHashes) + { delete[] hash; } _screenshotHashes.clear(); @@ -125,10 +140,12 @@ void RecordedRomTest::Record(string filename, bool reset) _console->GetNotificationManager()->RegisterNotificationListener(shared_from_this()); _filename = filename; - string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), FolderUtilities::GetFilename(filename, false) + ".mrt"); + string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), + FolderUtilities::GetFilename(filename, false) + ".mrt"); _file.open(mrtFilename, ios::out | ios::binary); - if(_file) { + if (_file) + { _console->Lock(); Reset(); @@ -139,10 +156,11 @@ void RecordedRomTest::Record(string filename, bool reset) EmulationConfig emuCfg = _console->GetSettings()->GetEmulationConfig(); emuCfg.RamPowerOnState = RamState::AllZeros; _console->GetSettings()->SetEmulationConfig(emuCfg); - + //Start recording movie alongside with screenshots RecordMovieOptions options; - string movieFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), FolderUtilities::GetFilename(filename, false) + ".mmo"); + string movieFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(filename), + FolderUtilities::GetFilename(filename, false) + ".mmo"); memcpy(options.Filename, movieFilename.c_str(), std::max(1000, (int)movieFilename.size())); options.RecordFrom = reset ? RecordMovieFrom::StartWithSaveData : RecordMovieFrom::CurrentState; _console->GetMovieManager()->Record(options); @@ -159,30 +177,33 @@ int32_t RecordedRomTest::Run(string filename) EmuSettings* settings = _console->GetSettings().get(); string testName = FolderUtilities::GetFilename(filename, false); - + VirtualFile testMovie(filename, "TestMovie.msm"); VirtualFile testRom(filename, "TestRom.sfc"); ZipReader zipReader; zipReader.LoadArchive(filename); - + stringstream testData; zipReader.GetStream("TestData.mrt", testData); - if(testData && testMovie.IsValid() && testRom.IsValid()) { + if (testData && testMovie.IsValid() && testRom.IsValid()) + { char header[3]; testData.read((char*)&header, 3); - if(memcmp((char*)&header, "MRT", 3) != 0) { + if (memcmp((char*)&header, "MRT", 3) != 0) + { //Invalid test file return false; } - + Reset(); uint32_t hashCount; testData.read((char*)&hashCount, sizeof(uint32_t)); - - for(uint32_t i = 0; i < hashCount; i++) { + + for (uint32_t i = 0; i < hashCount; i++) + { uint8_t repeatCount = 0; testData.read((char*)&repeatCount, sizeof(uint8_t)); _repetitionCount.push_back(repeatCount); @@ -205,18 +226,21 @@ int32_t RecordedRomTest::Run(string filename) _console->Lock(); //Start playing movie - if(_console->LoadRom(testRom, VirtualFile(""))) { + if (_console->LoadRom(testRom, VirtualFile(""))) + { settings->SetFlag(EmulationFlags::MaximumSpeed); _console->GetMovieManager()->Play(testMovie, true); _ppu = _console->GetPpu().get(); - + _runningTest = true; _console->Unlock(); _signal.Wait(); _console->Stop(false); _runningTest = false; - } else { + } + else + { //Something went wrong when loading the rom _console->Unlock(); return -2; @@ -232,7 +256,8 @@ int32_t RecordedRomTest::Run(string filename) void RecordedRomTest::Stop() { - if(_recording) { + if (_recording) + { Save(); } Reset(); @@ -252,8 +277,9 @@ void RecordedRomTest::Save() uint32_t hashCount = (uint32_t)_screenshotHashes.size(); _file.write((char*)&hashCount, sizeof(uint32_t)); - - for(uint32_t i = 0; i < hashCount; i++) { + + for (uint32_t i = 0; i < hashCount; i++) + { _file.write((char*)&_repetitionCount[i], sizeof(uint8_t)); _file.write((char*)&_screenshotHashes[i][0], 16); } @@ -263,17 +289,19 @@ void RecordedRomTest::Save() ZipWriter writer; writer.Initialize(_filename); - string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), FolderUtilities::GetFilename(_filename, false) + ".mrt"); + string mrtFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), + FolderUtilities::GetFilename(_filename, false) + ".mrt"); writer.AddFile(mrtFilename, "TestData.mrt"); std::remove(mrtFilename.c_str()); - string mmoFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), FolderUtilities::GetFilename(_filename, false) + ".mmo"); + string mmoFilename = FolderUtilities::CombinePath(FolderUtilities::GetFolderName(_filename), + FolderUtilities::GetFilename(_filename, false) + ".mmo"); writer.AddFile(mmoFilename, "TestMovie.msm"); std::remove(mmoFilename.c_str()); writer.AddFile(_console->GetCartridge()->GetRomInfo().RomFile.GetFilePath(), "TestRom.sfc"); - + writer.Save(); MessageManager::DisplayMessage("Test", "TestFileSavedTo", FolderUtilities::GetFilename(_filename, true)); -} \ No newline at end of file +} diff --git a/Core/RecordedRomTest.h b/Core/RecordedRomTest.h index 59fc28a..ca8b15a 100644 --- a/Core/RecordedRomTest.h +++ b/Core/RecordedRomTest.h @@ -23,7 +23,7 @@ private: std::deque _screenshotHashes; std::deque _repetitionCount; uint8_t _currentCount = 0; - + string _filename; ofstream _file; @@ -43,4 +43,4 @@ public: void Record(string filename, bool reset); int32_t Run(string filename); void Stop(); -}; \ No newline at end of file +}; diff --git a/Core/RegisterHandlerA.h b/Core/RegisterHandlerA.h index 68978b8..d4406ca 100644 --- a/Core/RegisterHandlerA.h +++ b/Core/RegisterHandlerA.h @@ -8,12 +8,13 @@ class RegisterHandlerA : public IMemoryHandler { private: - DmaController *_dmaController; - InternalRegisters *_regs; - ControlManager *_controlManager; + DmaController* _dmaController; + InternalRegisters* _regs; + ControlManager* _controlManager; public: - RegisterHandlerA(DmaController *dmaController, InternalRegisters *regs, ControlManager *controlManager) : IMemoryHandler(SnesMemoryType::Register) + RegisterHandlerA(DmaController* dmaController, InternalRegisters* regs, + ControlManager* controlManager) : IMemoryHandler(SnesMemoryType::Register) { _regs = regs; _dmaController = dmaController; @@ -23,11 +24,16 @@ public: uint8_t Read(uint32_t addr) override { addr &= 0xFFFF; - if(addr == 0x4016 || addr == 0x4017) { + if (addr == 0x4016 || addr == 0x4017) + { return _controlManager->Read(addr); - } else if(addr >= 0x4300) { + } + else if (addr >= 0x4300) + { return _dmaController->Read(addr); - } else { + } + else + { return _regs->Read(addr); } } @@ -35,17 +41,22 @@ public: uint8_t Peek(uint32_t addr) override { addr &= 0xFFFF; - if(addr == 0x4016 || addr == 0x4017) { + if (addr == 0x4016 || addr == 0x4017) + { //Avoid side effects for now return 0; - } else if(addr >= 0x4300) { + } + else if (addr >= 0x4300) + { return _dmaController->Read(addr); - } else { + } + else + { return _regs->Peek(addr); } } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { //Avoid side effects for now memset(output, 0, 0x1000); @@ -54,17 +65,22 @@ public: void Write(uint32_t addr, uint8_t value) override { addr &= 0xFFFF; - if(addr == 0x4016) { + if (addr == 0x4016) + { return _controlManager->Write(addr, value); - } else if(addr == 0x420B || addr == 0x420C || addr >= 0x4300) { + } + else if (addr == 0x420B || addr == 0x420C || addr >= 0x4300) + { _dmaController->Write(addr, value); - } else { + } + else + { _regs->Write(addr, value); } } AddressInfo GetAbsoluteAddress(uint32_t address) override { - return { -1, SnesMemoryType::CpuMemory }; + return {-1, SnesMemoryType::CpuMemory}; } }; diff --git a/Core/RegisterHandlerB.cpp b/Core/RegisterHandlerB.cpp index 3344585..77ed3e2 100644 --- a/Core/RegisterHandlerB.cpp +++ b/Core/RegisterHandlerB.cpp @@ -9,7 +9,8 @@ #include "CheatManager.h" #include "../Utilities/Serializer.h" -RegisterHandlerB::RegisterHandlerB(Console *console, Ppu * ppu, Spc * spc, uint8_t * workRam) : IMemoryHandler(SnesMemoryType::Register) +RegisterHandlerB::RegisterHandlerB(Console* console, Ppu* ppu, Spc* spc, uint8_t* workRam) : IMemoryHandler( + SnesMemoryType::Register) { _console = console; _cheatManager = console->GetCheatManager().get(); @@ -24,19 +25,28 @@ RegisterHandlerB::RegisterHandlerB(Console *console, Ppu * ppu, Spc * spc, uint8 uint8_t RegisterHandlerB::Read(uint32_t addr) { addr &= 0xFFFF; - if(addr >= 0x2140 && addr <= 0x217F) { + if (addr >= 0x2140 && addr <= 0x217F) + { return _spc->CpuReadRegister(addr & 0x03); - } else if(addr == 0x2180) { + } + else if (addr == 0x2180) + { uint8_t value = _workRam[_wramPosition]; _console->ProcessWorkRamRead(_wramPosition, value); _console->GetCheatManager()->ApplyCheat(0x7E0000 | _wramPosition, value); _wramPosition = (_wramPosition + 1) & 0x1FFFF; return value; - } else if(addr >= 0x2300 && addr <= 0x23FF && _console->GetCartridge()->GetSa1()) { + } + else if (addr >= 0x2300 && addr <= 0x23FF && _console->GetCartridge()->GetSa1()) + { return _console->GetCartridge()->GetSa1()->CpuRegisterRead(addr); - } else if(_msu1 && addr <= 0x2007) { + } + else if (_msu1 && addr <= 0x2007) + { return _msu1->Read(addr); - } else { + } + else + { return _ppu->Read(addr); } } @@ -47,7 +57,7 @@ uint8_t RegisterHandlerB::Peek(uint32_t addr) return 0; } -void RegisterHandlerB::PeekBlock(uint32_t addr, uint8_t *output) +void RegisterHandlerB::PeekBlock(uint32_t addr, uint8_t* output) { //Avoid side effects for now memset(output, 0, 0x1000); @@ -56,35 +66,48 @@ void RegisterHandlerB::PeekBlock(uint32_t addr, uint8_t *output) void RegisterHandlerB::Write(uint32_t addr, uint8_t value) { addr &= 0xFFFF; - if(addr >= 0x2140 && addr <= 0x217F) { + if (addr >= 0x2140 && addr <= 0x217F) + { return _spc->CpuWriteRegister(addr & 0x03, value); - } if(addr >= 0x2180 && addr <= 0x2183) { - switch(addr & 0xFFFF) { - case 0x2180: - _console->ProcessWorkRamWrite(_wramPosition, value); - _workRam[_wramPosition] = value; - _wramPosition = (_wramPosition + 1) & 0x1FFFF; - break; + } + if (addr >= 0x2180 && addr <= 0x2183) + { + switch (addr & 0xFFFF) + { + case 0x2180: + _console->ProcessWorkRamWrite(_wramPosition, value); + _workRam[_wramPosition] = value; + _wramPosition = (_wramPosition + 1) & 0x1FFFF; + break; - case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; break; - case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); break; - case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); break; + case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; + break; + case 0x2182: _wramPosition = (_wramPosition & 0x100FF) | (value << 8); + break; + case 0x2183: _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); + break; } - } else if(addr >= 0x2200 && addr <= 0x22FF && _console->GetCartridge()->GetSa1()) { + } + else if (addr >= 0x2200 && addr <= 0x22FF && _console->GetCartridge()->GetSa1()) + { _console->GetCartridge()->GetSa1()->CpuRegisterWrite(addr, value); - } else if(_msu1 && addr <= 0x2007) { + } + else if (_msu1 && addr <= 0x2007) + { return _msu1->Write(addr, value); - } else { + } + else + { _ppu->Write(addr, value); } } AddressInfo RegisterHandlerB::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::CpuMemory }; + return {-1, SnesMemoryType::CpuMemory}; } -void RegisterHandlerB::Serialize(Serializer &s) +void RegisterHandlerB::Serialize(Serializer& s) { s.Stream(_wramPosition); } diff --git a/Core/RegisterHandlerB.h b/Core/RegisterHandlerB.h index ba48b6f..33e41ac 100644 --- a/Core/RegisterHandlerB.h +++ b/Core/RegisterHandlerB.h @@ -13,25 +13,25 @@ class CheatManager; class RegisterHandlerB : public IMemoryHandler, public ISerializable { private: - Console *_console; - CheatManager *_cheatManager; - Ppu *_ppu; - Spc *_spc; - Sa1 *_sa1; - Msu1 *_msu1; + Console* _console; + CheatManager* _cheatManager; + Ppu* _ppu; + Spc* _spc; + Sa1* _sa1; + Msu1* _msu1; - uint8_t *_workRam; + uint8_t* _workRam; uint32_t _wramPosition; public: - RegisterHandlerB(Console *console, Ppu *ppu, Spc *spc, uint8_t *workRam); + RegisterHandlerB(Console* console, Ppu* ppu, Spc* spc, uint8_t* workRam); uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t *output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/RewindData.cpp b/Core/RewindData.cpp index 61527f7..73453f7 100644 --- a/Core/RewindData.cpp +++ b/Core/RewindData.cpp @@ -4,14 +4,15 @@ #include "SaveStateManager.h" #include "../Utilities/miniz.h" -void RewindData::GetStateData(stringstream &stateData) +void RewindData::GetStateData(stringstream& stateData) { stateData.write((char*)SaveStateData.data(), SaveStateData.size()); } -void RewindData::LoadState(shared_ptr &console) +void RewindData::LoadState(shared_ptr& console) { - if(SaveStateData.size() > 0) { + if (SaveStateData.size() > 0) + { stringstream stream; stream.write((char*)SaveStateData.data(), SaveStateData.size()); stream.seekg(0, ios::beg); @@ -20,12 +21,12 @@ void RewindData::LoadState(shared_ptr &console) } } -void RewindData::SaveState(shared_ptr &console) +void RewindData::SaveState(shared_ptr& console) { std::stringstream state; console->Serialize(state); string data = state.str(); - SaveStateData = vector(data.c_str(), data.c_str()+data.size()); + SaveStateData = vector(data.c_str(), data.c_str() + data.size()); FrameCount = 0; } diff --git a/Core/RewindData.h b/Core/RewindData.h index a66db76..afc1718 100644 --- a/Core/RewindData.h +++ b/Core/RewindData.h @@ -15,8 +15,8 @@ public: int32_t FrameCount = 0; bool EndOfSegment = false; - void GetStateData(stringstream &stateData); + void GetStateData(stringstream& stateData); - void LoadState(shared_ptr &console); - void SaveState(shared_ptr &console); + void LoadState(shared_ptr& console); + void SaveState(shared_ptr& console); }; diff --git a/Core/RewindManager.cpp b/Core/RewindManager.cpp index 05a1613..186d128 100644 --- a/Core/RewindManager.cpp +++ b/Core/RewindManager.cpp @@ -42,49 +42,61 @@ void RewindManager::ClearBuffer() _currentHistory = RewindData(); } -void RewindManager::ProcessNotification(ConsoleNotificationType type, void * parameter) +void RewindManager::ProcessNotification(ConsoleNotificationType type, void* parameter) { - if(_console->IsRunAheadFrame()) { + if (_console->IsRunAheadFrame()) + { return; } - if(type == ConsoleNotificationType::PpuFrameDone) { + if (type == ConsoleNotificationType::PpuFrameDone) + { _hasHistory = _history.size() >= 2; - if(_settings->GetRewindBufferSize() > 0) { - switch(_rewindState) { - case RewindState::Starting: - case RewindState::Started: - case RewindState::Debugging: - _currentHistory.FrameCount--; - break; + if (_settings->GetRewindBufferSize() > 0) + { + switch (_rewindState) + { + case RewindState::Starting: + case RewindState::Started: + case RewindState::Debugging: + _currentHistory.FrameCount--; + break; - case RewindState::Stopping: - _framesToFastForward--; - _currentHistory.FrameCount++; - if(_framesToFastForward == 0) { - for(int i = 0; i < 4; i++) { - size_t numberToRemove = _currentHistory.InputLogs[i].size(); - _currentHistory.InputLogs[i] = _historyBackup.front().InputLogs[i]; - for(size_t j = 0; j < numberToRemove; j++) { - _currentHistory.InputLogs[i].pop_back(); - } + case RewindState::Stopping: + _framesToFastForward--; + _currentHistory.FrameCount++; + if (_framesToFastForward == 0) + { + for (int i = 0; i < 4; i++) + { + size_t numberToRemove = _currentHistory.InputLogs[i].size(); + _currentHistory.InputLogs[i] = _historyBackup.front().InputLogs[i]; + for (size_t j = 0; j < numberToRemove; j++) + { + _currentHistory.InputLogs[i].pop_back(); } - _historyBackup.clear(); - _rewindState = RewindState::Stopped; - _settings->ClearFlag(EmulationFlags::Rewind); - _settings->ClearFlag(EmulationFlags::MaximumSpeed); } - break; - - case RewindState::Stopped: - _currentHistory.FrameCount++; - break; + _historyBackup.clear(); + _rewindState = RewindState::Stopped; + _settings->ClearFlag(EmulationFlags::Rewind); + _settings->ClearFlag(EmulationFlags::MaximumSpeed); + } + break; + + case RewindState::Stopped: + _currentHistory.FrameCount++; + break; } - } else { + } + else + { ClearBuffer(); } - } else if(type == ConsoleNotificationType::StateLoaded) { - if(_rewindState == RewindState::Stopped) { + } + else if (type == ConsoleNotificationType::StateLoaded) + { + if (_rewindState == RewindState::Stopped) + { //A save state was loaded by the user, mark as the end of the current "segment" (for history viewer) _currentHistory.EndOfSegment = true; } @@ -94,12 +106,15 @@ void RewindManager::ProcessNotification(ConsoleNotificationType type, void * par void RewindManager::AddHistoryBlock() { uint32_t maxHistorySize = _settings->GetRewindBufferSize() * 60 * RewindManager::BufferSize / 60; - if(maxHistorySize > 0) { - while(_history.size() > maxHistorySize) { + if (maxHistorySize > 0) + { + while (_history.size() > maxHistorySize) + { _history.pop_front(); } - if(_currentHistory.FrameCount > 0) { + if (_currentHistory.FrameCount > 0) + { _history.push_back(_currentHistory); } _currentHistory = RewindData(); @@ -109,17 +124,22 @@ void RewindManager::AddHistoryBlock() void RewindManager::PopHistory() { - if(_history.empty() && _currentHistory.FrameCount <= 0) { + if (_history.empty() && _currentHistory.FrameCount <= 0) + { StopRewinding(); - } else { - if(_currentHistory.FrameCount <= 0) { + } + else + { + if (_currentHistory.FrameCount <= 0) + { _currentHistory = _history.back(); _history.pop_back(); } _historyBackup.push_front(_currentHistory); _currentHistory.LoadState(_console); - if(!_audioHistoryBuilder.empty()) { + if (!_audioHistoryBuilder.empty()) + { _audioHistory.insert(_audioHistory.begin(), _audioHistoryBuilder.begin(), _audioHistoryBuilder.end()); _audioHistoryBuilder.clear(); } @@ -128,7 +148,8 @@ void RewindManager::PopHistory() void RewindManager::Start(bool forDebugger) { - if(_rewindState == RewindState::Stopped && _settings->GetRewindBufferSize() > 0) { + if (_rewindState == RewindState::Stopped && _settings->GetRewindBufferSize() > 0) + { auto lock = _console->AcquireLock(); _rewindState = forDebugger ? RewindState::Debugging : RewindState::Starting; @@ -137,7 +158,7 @@ void RewindManager::Start(bool forDebugger) _audioHistoryBuilder.clear(); _audioHistory.clear(); _historyBackup.clear(); - + PopHistory(); _console->GetSoundMixer()->StopAudio(true); _settings->SetFlag(EmulationFlags::MaximumSpeed); @@ -147,8 +168,10 @@ void RewindManager::Start(bool forDebugger) void RewindManager::ForceStop() { - if(_rewindState != RewindState::Stopped) { - while(_historyBackup.size() > 1) { + if (_rewindState != RewindState::Stopped) + { + while (_historyBackup.size() > 1) + { _history.push_back(_historyBackup.front()); _historyBackup.pop_front(); } @@ -162,25 +185,32 @@ void RewindManager::ForceStop() void RewindManager::Stop() { - if(_rewindState >= RewindState::Starting) { + if (_rewindState >= RewindState::Starting) + { auto lock = _console->AcquireLock(); - if(_rewindState == RewindState::Started) { + if (_rewindState == RewindState::Started) + { //Move back to the save state containing the frame currently shown on the screen - if(_historyBackup.size() > 1) { + if (_historyBackup.size() > 1) + { _framesToFastForward = (uint32_t)_videoHistory.size() + _historyBackup.front().FrameCount; - do { + do + { _history.push_back(_historyBackup.front()); _framesToFastForward -= _historyBackup.front().FrameCount; _historyBackup.pop_front(); _currentHistory = _historyBackup.front(); } - while(_framesToFastForward > RewindManager::BufferSize && _historyBackup.size() > 1); + while (_framesToFastForward > RewindManager::BufferSize && _historyBackup.size() > 1); } - } else { + } + else + { //We started rewinding, but didn't actually visually rewind anything yet //Move back to the save state containing the frame currently shown on the screen - while(_historyBackup.size() > 1) { + while (_historyBackup.size() > 1) + { _history.push_back(_historyBackup.front()); _historyBackup.pop_front(); } @@ -189,11 +219,14 @@ void RewindManager::Stop() } _currentHistory.LoadState(_console); - if(_framesToFastForward > 0) { + if (_framesToFastForward > 0) + { _rewindState = RewindState::Stopping; _currentHistory.FrameCount = 0; _settings->SetFlag(EmulationFlags::MaximumSpeed); - } else { + } + else + { _rewindState = RewindState::Stopped; _historyBackup.clear(); _settings->ClearFlag(EmulationFlags::MaximumSpeed); @@ -209,21 +242,27 @@ void RewindManager::Stop() void RewindManager::ProcessEndOfFrame() { - if(_rewindState >= RewindState::Starting) { - if(_currentHistory.FrameCount <= 0 && _rewindState != RewindState::Debugging) { + if (_rewindState >= RewindState::Starting) + { + if (_currentHistory.FrameCount <= 0 && _rewindState != RewindState::Debugging) + { //If we're debugging, we want to keep running the emulation to the end of the next frame (even if it's incomplete) //Otherwise the emulation might diverge due to missing inputs. PopHistory(); } - } else if(_currentHistory.FrameCount >= RewindManager::BufferSize) { + } + else if (_currentHistory.FrameCount >= RewindManager::BufferSize) + { AddHistoryBlock(); } } -void RewindManager::ProcessFrame(void * frameBuffer, uint32_t width, uint32_t height, bool forRewind) +void RewindManager::ProcessFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind) { - if(_rewindState == RewindState::Starting || _rewindState == RewindState::Started) { - if(!forRewind) { + if (_rewindState == RewindState::Starting || _rewindState == RewindState::Started) + { + if (!forRewind) + { //Ignore any frames that occur between start of rewind process & first rewinded frame completed //These are caused by the fact that VideoDecoder is asynchronous - a previous (extra) frame can end up //in the rewind queue, which causes display glitches @@ -236,71 +275,93 @@ void RewindManager::ProcessFrame(void * frameBuffer, uint32_t width, uint32_t he newFrame.Height = height; _videoHistoryBuilder.push_back(newFrame); - if(_videoHistoryBuilder.size() == (size_t)_historyBackup.front().FrameCount) { - for(int i = (int)_videoHistoryBuilder.size() - 1; i >= 0; i--) { + if (_videoHistoryBuilder.size() == (size_t)_historyBackup.front().FrameCount) + { + for (int i = (int)_videoHistoryBuilder.size() - 1; i >= 0; i--) + { _videoHistory.push_front(_videoHistoryBuilder[i]); } _videoHistoryBuilder.clear(); } - if(_rewindState == RewindState::Started || _videoHistory.size() >= RewindManager::BufferSize) { + if (_rewindState == RewindState::Started || _videoHistory.size() >= RewindManager::BufferSize) + { _rewindState = RewindState::Started; _settings->ClearFlag(EmulationFlags::MaximumSpeed); - if(!_videoHistory.empty()) { - VideoFrame &frameData = _videoHistory.back(); + if (!_videoHistory.empty()) + { + VideoFrame& frameData = _videoHistory.back(); _console->GetVideoRenderer()->UpdateFrame(frameData.Data.data(), frameData.Width, frameData.Height); _videoHistory.pop_back(); } } - } else if(_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) { + } + else if (_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) + { //Display nothing while resyncing - } else { + } + else + { _console->GetVideoRenderer()->UpdateFrame(frameBuffer, width, height); } } -bool RewindManager::ProcessAudio(int16_t * soundBuffer, uint32_t sampleCount) +bool RewindManager::ProcessAudio(int16_t* soundBuffer, uint32_t sampleCount) { - if(_rewindState == RewindState::Starting || _rewindState == RewindState::Started) { + if (_rewindState == RewindState::Starting || _rewindState == RewindState::Started) + { _audioHistoryBuilder.insert(_audioHistoryBuilder.end(), soundBuffer, soundBuffer + sampleCount * 2); - if(_rewindState == RewindState::Started && _audioHistory.size() > sampleCount * 2) { - for(uint32_t i = 0; i < sampleCount * 2; i++) { + if (_rewindState == RewindState::Started && _audioHistory.size() > sampleCount * 2) + { + for (uint32_t i = 0; i < sampleCount * 2; i++) + { soundBuffer[i] = _audioHistory.back(); _audioHistory.pop_back(); } return true; - } else { + } + else + { //Mute while we prepare to rewind return false; } - } else if(_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) { + } + else if (_rewindState == RewindState::Stopping || _rewindState == RewindState::Debugging) + { //Mute while we resync return false; - } else { + } + else + { return true; } } void RewindManager::RecordInput(vector> devices) { - if(_settings->GetRewindBufferSize() > 0 && _rewindState == RewindState::Stopped) { - for(shared_ptr &device : devices) { + if (_settings->GetRewindBufferSize() > 0 && _rewindState == RewindState::Stopped) + { + for (shared_ptr& device : devices) + { _currentHistory.InputLogs[device->GetPort()].push_back(device->GetRawState()); } } } -bool RewindManager::SetInput(BaseControlDevice *device) +bool RewindManager::SetInput(BaseControlDevice* device) { uint8_t port = device->GetPort(); - if(!_currentHistory.InputLogs[port].empty() && IsRewinding()) { + if (!_currentHistory.InputLogs[port].empty() && IsRewinding()) + { ControlDeviceState state = _currentHistory.InputLogs[port].front(); _currentHistory.InputLogs[port].pop_front(); device->SetRawState(state); return true; - } else { + } + else + { return false; } } @@ -312,9 +373,12 @@ void RewindManager::StartRewinding(bool forDebugger) void RewindManager::StopRewinding(bool forDebugger) { - if(forDebugger) { + if (forDebugger) + { ForceStop(); - } else { + } + else + { Stop(); } } @@ -331,15 +395,20 @@ bool RewindManager::IsStepBack() void RewindManager::RewindSeconds(uint32_t seconds) { - if(_rewindState == RewindState::Stopped) { + if (_rewindState == RewindState::Stopped) + { uint32_t removeCount = (seconds * 60 / RewindManager::BufferSize) + 1; auto lock = _console->AcquireLock(); - for(uint32_t i = 0; i < removeCount; i++) { - if(!_history.empty()) { + for (uint32_t i = 0; i < removeCount; i++) + { + if (!_history.empty()) + { _currentHistory = _history.back(); _history.pop_back(); - } else { + } + else + { break; } } @@ -352,12 +421,12 @@ bool RewindManager::HasHistory() return _hasHistory; } -void RewindManager::SendFrame(void * frameBuffer, uint32_t width, uint32_t height, bool forRewind) +void RewindManager::SendFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind) { ProcessFrame(frameBuffer, width, height, forRewind); } -bool RewindManager::SendAudio(int16_t * soundBuffer, uint32_t sampleCount) +bool RewindManager::SendAudio(int16_t* soundBuffer, uint32_t sampleCount) { return ProcessAudio(soundBuffer, sampleCount); } diff --git a/Core/RewindManager.h b/Core/RewindManager.h index c186ec0..bcf1696 100644 --- a/Core/RewindManager.h +++ b/Core/RewindManager.h @@ -33,7 +33,7 @@ private: shared_ptr _console; shared_ptr _settings; - + bool _hasHistory; std::deque _history; @@ -55,9 +55,9 @@ private: void Stop(); void ForceStop(); - void ProcessFrame(void *frameBuffer, uint32_t width, uint32_t height, bool forRewind); - bool ProcessAudio(int16_t *soundBuffer, uint32_t sampleCount); - + void ProcessFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind); + bool ProcessAudio(int16_t* soundBuffer, uint32_t sampleCount); + void ClearBuffer(); public: @@ -68,7 +68,7 @@ public: void ProcessEndOfFrame(); void RecordInput(vector> devices) override; - bool SetInput(BaseControlDevice *device) override; + bool SetInput(BaseControlDevice* device) override; void StartRewinding(bool forDebugger = false); void StopRewinding(bool forDebugger = false); @@ -78,7 +78,7 @@ public: bool HasHistory(); - void SendFrame(void *frameBuffer, uint32_t width, uint32_t height, bool forRewind); - bool SendAudio(int16_t *soundBuffer, uint32_t sampleCount); + void SendFrame(void* frameBuffer, uint32_t width, uint32_t height, bool forRewind); + bool SendAudio(int16_t* soundBuffer, uint32_t sampleCount); void CopyHistory(shared_ptr destHistoryViewer); -}; \ No newline at end of file +}; diff --git a/Core/RomFinder.h b/Core/RomFinder.h index 61f7593..b36d7af 100644 --- a/Core/RomFinder.h +++ b/Core/RomFinder.h @@ -10,13 +10,15 @@ class RomFinder public: static bool LoadMatchingRom(Console* console, string romName, string sha1Hash) { - if(console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) { + if (console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) + { //Current game matches return true; } string match = FindMatchingRom(console, romName, sha1Hash); - if(!match.empty()) { + if (!match.empty()) + { return console->LoadRom(match, VirtualFile("")); } return false; @@ -24,7 +26,8 @@ public: static string FindMatchingRom(Console* console, string romName, string sha1Hash) { - if(console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) { + if (console->IsRunning() && console->GetCartridge()->GetSha1Hash() == sha1Hash) + { //Current game matches return console->GetRomInfo().RomFile; } @@ -34,11 +37,15 @@ public: std::transform(romName.begin(), romName.end(), romName.begin(), ::tolower); vector romFiles; - for(string folder : FolderUtilities::GetKnownGameFolders()) { - for(string romFilename : FolderUtilities::GetFilesInFolder(folder, VirtualFile::RomExtensions, true)) { + for (string folder : FolderUtilities::GetKnownGameFolders()) + { + for (string romFilename : FolderUtilities::GetFilesInFolder(folder, VirtualFile::RomExtensions, true)) + { string lcRomFile = romFilename; std::transform(lcRomFile.begin(), lcRomFile.end(), lcRomFile.begin(), ::tolower); - if(FolderUtilities::GetFilename(romName, false) == FolderUtilities::GetFilename(lcRomFile, false) && VirtualFile(romFilename).GetSha1Hash() == sha1Hash) { + if (FolderUtilities::GetFilename(romName, false) == FolderUtilities::GetFilename(lcRomFile, false) && + VirtualFile(romFilename).GetSha1Hash() == sha1Hash) + { return romFilename; } } @@ -46,4 +53,4 @@ public: return ""; } -}; \ No newline at end of file +}; diff --git a/Core/RomHandler.h b/Core/RomHandler.h index 822d0d2..b6d6064 100644 --- a/Core/RomHandler.h +++ b/Core/RomHandler.h @@ -10,4 +10,4 @@ public: void Write(uint32_t addr, uint8_t value) override { } -}; \ No newline at end of file +}; diff --git a/Core/Rtc4513.cpp b/Core/Rtc4513.cpp index 61fd6dc..a7d1988 100644 --- a/Core/Rtc4513.cpp +++ b/Core/Rtc4513.cpp @@ -21,17 +21,22 @@ Rtc4513::~Rtc4513() void Rtc4513::LoadBattery() { vector rtcData = _console->GetBatteryManager()->LoadBattery(".rtc"); - - if(rtcData.size() == sizeof(_regs) + sizeof(uint64_t)) { + + if (rtcData.size() == sizeof(_regs) + sizeof(uint64_t)) + { memcpy(_regs, rtcData.data(), sizeof(_regs)); uint64_t time = 0; - for(uint32_t i = 0; i < sizeof(uint64_t); i++) { + for (uint32_t i = 0; i < sizeof(uint64_t); i++) + { time <<= 8; time |= rtcData[sizeof(_regs) + i]; } _lastTime = time; - } else { - _lastTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + else + { + _lastTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()). + count(); } } @@ -42,7 +47,8 @@ void Rtc4513::SaveBattery() memcpy(rtcData.data(), _regs, sizeof(_regs)); uint64_t time = _lastTime; - for(uint32_t i = 0; i < sizeof(uint64_t); i++) { + for (uint32_t i = 0; i < sizeof(uint64_t); i++) + { rtcData[sizeof(_regs) + i] = (time >> 56) & 0xFF; time <<= 8; } @@ -52,24 +58,28 @@ void Rtc4513::SaveBattery() void Rtc4513::UpdateTime() { - if(IsReset()) { + if (IsReset()) + { //Reset seconds to 0 _regs[0] = 0; _regs[1] = 0; } - uint64_t currentTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + uint64_t currentTime = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); uint32_t elapsedSeconds = (uint32_t)(currentTime - _lastTime); - if(elapsedSeconds <= 0) { + if (elapsedSeconds <= 0) + { return; } - if(IsStop() || IsReset() || IsHold()) { + if (IsStop() || IsReset() || IsHold()) + { _lastTime = currentTime; return; } - std::tm tm = { }; + std::tm tm = {}; tm.tm_sec = GetSeconds(); tm.tm_min = GetMinutes(); tm.tm_hour = GetHours(); @@ -78,13 +88,15 @@ void Rtc4513::UpdateTime() tm.tm_year = (GetYear() >= 90 ? 0 : 100) + GetYear(); std::time_t tt = mktime(&tm); - if(tt == -1 || GetMonth() == 0) { + if (tt == -1 || GetMonth() == 0) + { _lastTime = currentTime; return; } int8_t dowGap = 0; - if(tm.tm_wday != GetDoW()) { + if (tm.tm_wday != GetDoW()) + { //The DoW on the RTC can be set to any arbitrary value for a specific date //Check the gap between the value set by the game & the real dow for that date dowGap = (int8_t)tm.tm_wday - (int8_t)GetDoW(); @@ -121,7 +133,7 @@ void Rtc4513::UpdateTime() _regs[10] = year % 10; _regs[11] = year / 10; - + _regs[12] = (newTm.tm_wday - dowGap) % 7; _lastTime = currentTime; @@ -131,22 +143,24 @@ uint8_t Rtc4513::Read(uint16_t addr) { UpdateTime(); - switch(addr) { - case 0x4840: break; - - case 0x4841: - if(_mode == 0x0C) { - //Read mode - //LogDebug("Read: " + HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(_regs[_index])); - uint8_t index = _index; - _index = (_index + 1) & 0x0F; - return _regs[index]; - } - break; - - case 0x4842: - //Ready - return 0x80; + switch (addr) + { + case 0x4840: break; + + case 0x4841: + if (_mode == 0x0C) + { + //Read mode + //LogDebug("Read: " + HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(_regs[_index])); + uint8_t index = _index; + _index = (_index + 1) & 0x0F; + return _regs[index]; + } + break; + + case 0x4842: + //Ready + return 0x80; } return 0; @@ -156,37 +170,44 @@ void Rtc4513::Write(uint16_t addr, uint8_t value) { UpdateTime(); - switch(addr) { - case 0x4840: - _enabled = value; - if(!(_enabled & 0x01)) { - _mode = -1; - _index = -1; + switch (addr) + { + case 0x4840: + _enabled = value; + if (!(_enabled & 0x01)) + { + _mode = -1; + _index = -1; - //Turn off reset ($01) and test ($08) bits when disabled - _regs[0x0F] &= 0x06; - } - break; + //Turn off reset ($01) and test ($08) bits when disabled + _regs[0x0F] &= 0x06; + } + break; - case 0x4841: - if(_mode == -1) { - _mode = value & 0x0F; - } else if(_index == -1) { - _index = value & 0x0F; - } else if(_mode == 0x03) { - //Write mode - //LogDebug(HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(value & 0x0F)); - uint8_t index = _index; - _index = (_index + 1) & 0x0F; - _regs[index] = value & 0x0F; - } - - case 0x4842: break; + case 0x4841: + if (_mode == -1) + { + _mode = value & 0x0F; + } + else if (_index == -1) + { + _index = value & 0x0F; + } + else if (_mode == 0x03) + { + //Write mode + //LogDebug(HexUtilities::ToHex(_index) + " = " + HexUtilities::ToHex(value & 0x0F)); + uint8_t index = _index; + _index = (_index + 1) & 0x0F; + _regs[index] = value & 0x0F; + } + + case 0x4842: break; } } void Rtc4513::Serialize(Serializer& s) { - ArrayInfo regs = { _regs, 0x10 }; + ArrayInfo regs = {_regs, 0x10}; s.Stream(_lastTime, _enabled, _mode, _index, regs); } diff --git a/Core/Rtc4513.h b/Core/Rtc4513.h index 1eb071c..e09e54f 100644 --- a/Core/Rtc4513.h +++ b/Core/Rtc4513.h @@ -22,12 +22,12 @@ private: uint8_t GetSeconds() { return _regs[0] + ((_regs[1] & 0x07) * 10); } uint8_t GetMinutes() { return _regs[2] + ((_regs[3] & 0x07) * 10); } uint8_t GetHours() { return _regs[4] + ((_regs[5] & 0x03) * 10); } - + uint8_t GetDay() { return _regs[6] + ((_regs[7] & 0x03) * 10); } uint8_t GetMonth() { return _regs[8] + ((_regs[9] & 0x01) * 10); } uint8_t GetYear() { return _regs[10] + (_regs[11] * 10); } uint8_t GetDoW() { return _regs[12] & 0x07; } - + void UpdateTime(); public: @@ -41,4 +41,4 @@ public: void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/SPC_DSP.cpp b/Core/SPC_DSP.cpp index c0f6889..996a4b5 100644 --- a/Core/SPC_DSP.cpp +++ b/Core/SPC_DSP.cpp @@ -37,16 +37,16 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //KOF ($5C) must be initialized to $00, some games (Chester Cheetah, King of Dragons) do not initialize its value //This causes missing sound effects in both games. -static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = +static BOOST::uint8_t const initial_regs[SPC_DSP::register_count] = { - 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, - 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, - 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, - 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, - 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, - 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x00,0x4E,0x7B,0xFF, - 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, - 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF + 0x45, 0x8B, 0x5A, 0x9A, 0xE4, 0x82, 0x1B, 0x78, 0x00, 0x00, 0xAA, 0x96, 0x89, 0x0E, 0xE0, 0x80, + 0x2A, 0x49, 0x3D, 0xBA, 0x14, 0xA0, 0xAC, 0xC5, 0x00, 0x00, 0x51, 0xBB, 0x9C, 0x4E, 0x7B, 0xFF, + 0xF4, 0xFD, 0x57, 0x32, 0x37, 0xD9, 0x42, 0x22, 0x00, 0x00, 0x5B, 0x3C, 0x9F, 0x1B, 0x87, 0x9A, + 0x6F, 0x27, 0xAF, 0x7B, 0xE5, 0x68, 0x0A, 0xD9, 0x00, 0x00, 0x9A, 0xC5, 0x9C, 0x4E, 0x7B, 0xFF, + 0xEA, 0x21, 0x78, 0x4F, 0xDD, 0xED, 0x24, 0x14, 0x00, 0x00, 0x77, 0xB1, 0xD1, 0x36, 0xC1, 0x67, + 0x52, 0x57, 0x46, 0x3D, 0x59, 0xF4, 0x87, 0xA4, 0x00, 0x00, 0x7E, 0x44, 0x00, 0x4E, 0x7B, 0xFF, + 0x75, 0xF5, 0x06, 0x97, 0x10, 0xC3, 0x24, 0xBB, 0x00, 0x00, 0x7B, 0x7A, 0xE0, 0x60, 0x12, 0x0F, + 0xF7, 0x74, 0x1C, 0xE5, 0x39, 0x3D, 0x73, 0xC1, 0x00, 0x00, 0x7A, 0xB3, 0xFF, 0x4E, 0x7B, 0xFF }; // if ( io < -32768 ) io = -32768; @@ -76,19 +76,19 @@ static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = out = m.extra;\ m.out_end = &m.extra [extra_size];\ }\ -}\ +} -void SPC_DSP::set_output( sample_t* out, int size ) +void SPC_DSP::set_output(sample_t* out, int size) { - require( (size & 1) == 0 ); // must be even - if ( !out ) + require((size & 1) == 0); // must be even + if (!out) { - out = m.extra; + out = m.extra; size = extra_size; } m.out_begin = out; - m.out = out; - m.out_end = out + size; + m.out = out; + m.out_end = out + size; } // Volume registers and efb are signed! Easy to forget int8_t cast. @@ -96,40 +96,40 @@ void SPC_DSP::set_output( sample_t* out, int size ) // Gaussian interpolation -static short const gauss [512] = +static short const gauss[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, - 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, - 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, - 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, - 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, - 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, - 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, - 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, - 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, - 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, - 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, - 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, - 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, - 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, - 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, - 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, - 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, - 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, - 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, -1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, -1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, -1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, -1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, -1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, -1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, -1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, + 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, + 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, + 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, + 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, + 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, + 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, + 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305, }; inline int SPC_DSP::interpolate_cubic(voice_t const* v) @@ -145,28 +145,28 @@ inline int SPC_DSP::interpolate_cubic(voice_t const* v) float b = (v0 - v1) - a; float c = v2 - v0; float d = v1; - + float ratio = (float)(v->interp_pos & 0xFFF) / 0x1000; return (int)((d + ratio * (c + ratio * (b + ratio * a))) * 32768); } -inline int SPC_DSP::interpolate( voice_t const* v ) +inline int SPC_DSP::interpolate(voice_t const* v) { // Make pointers into gaussian based on fractional position between samples int offset = v->interp_pos >> 4 & 0xFF; short const* fwd = gauss + 255 - offset; - short const* rev = gauss + offset; // mirror left half of gaussian - - int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + short const* rev = gauss + offset; // mirror left half of gaussian + + int const* in = &v->buf[(v->interp_pos >> 12) + v->buf_pos]; int out; - out = (fwd [ 0] * in [0]) >> 11; - out += (fwd [256] * in [1]) >> 11; - out += (rev [256] * in [2]) >> 11; - out = (int16_t) out; - out += (rev [ 0] * in [3]) >> 11; - - CLAMP16( out ); + out = (fwd[0] * in[0]) >> 11; + out += (fwd[256] * in[1]) >> 11; + out += (rev[256] * in[2]) >> 11; + out = (int16_t)out; + out += (rev[0] * in[3]) >> 11; + + CLAMP16(out); out &= ~1; return out; } @@ -176,26 +176,26 @@ inline int SPC_DSP::interpolate( voice_t const* v ) int const simple_counter_range = 2048 * 5 * 3; // 30720 -static unsigned const counter_rates [32] = +static unsigned const counter_rates[32] = { - simple_counter_range + 1, // never fires - 2048, 1536, - 1280, 1024, 768, - 640, 512, 384, - 320, 256, 192, - 160, 128, 96, - 80, 64, 48, - 40, 32, 24, - 20, 16, 12, - 10, 8, 6, - 5, 4, 3, - 2, - 1 + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 }; -static unsigned const counter_offsets [32] = +static unsigned const counter_offsets[32] = { - 1, 0, 1040, + 1, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, @@ -205,8 +205,8 @@ static unsigned const counter_offsets [32] = 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, - 0, - 0 + 0, + 0 }; inline void SPC_DSP::init_counter() @@ -216,39 +216,39 @@ inline void SPC_DSP::init_counter() inline void SPC_DSP::run_counters() { - if ( --m.counter < 0 ) + if (--m.counter < 0) m.counter = simple_counter_range - 1; } -inline unsigned SPC_DSP::read_counter( int rate ) +inline unsigned SPC_DSP::read_counter(int rate) { - return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; + return ((unsigned)m.counter + counter_offsets[rate]) % counter_rates[rate]; } //// Envelope -inline void SPC_DSP::run_envelope( voice_t* const v ) +inline void SPC_DSP::run_envelope(voice_t* const v) { int env = v->env; - if ( v->env_mode == env_release ) // 60% + if (v->env_mode == env_release) // 60% { - if ( (env -= 0x8) < 0 ) + if ((env -= 0x8) < 0) env = 0; v->env = env; } else { int rate; - int env_data = VREG(v->regs,adsr1); - if ( m.t_adsr0 & 0x80 ) // 99% ADSR + int env_data = VREG(v->regs, adsr1); + if (m.t_adsr0 & 0x80) // 99% ADSR { - if ( v->env_mode >= env_decay ) // 99% + if (v->env_mode >= env_decay) // 99% { env--; env -= env >> 8; rate = env_data & 0x1F; - if ( v->env_mode == env_decay ) // 1% + if (v->env_mode == env_decay) // 1% rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; } else // env_attack @@ -260,9 +260,9 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) else // GAIN { int mode; - env_data = VREG(v->regs,gain); + env_data = VREG(v->regs, gain); mode = env_data >> 5; - if ( mode < 4 ) // direct + if (mode < 4) // direct { env = env_data * 0x10; rate = 31; @@ -270,11 +270,11 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) else { rate = env_data & 0x1F; - if ( mode == 4 ) // 4: linear decrease + if (mode == 4) // 4: linear decrease { env -= 0x20; } - else if ( mode < 6 ) // 5: exponential decrease + else if (mode < 6) // 5: exponential decrease { env--; env -= env >> 8; @@ -282,27 +282,27 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) else // 6,7: linear increase { env += 0x20; - if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + if (mode > 6 && (unsigned)v->hidden_env >= 0x600) env += 0x8 - 0x20; // 7: two-slope linear increase } } } - + // Sustain level - if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + if ((env >> 8) == (env_data >> 5) && v->env_mode == env_decay) v->env_mode = env_sustain; - + v->hidden_env = env; - + // unsigned cast because linear decrease going negative also triggers this - if ( (unsigned) env > 0x7FF ) + if ((unsigned)env > 0x7FF) { env = (env < 0 ? 0 : 0x7FF); - if ( v->env_mode == env_attack ) + if (v->env_mode == env_attack) v->env_mode = env_decay; } - - if ( !read_counter( rate ) ) + + if (!read_counter(rate)) v->env = env; // nothing else is controlled by the counter } } @@ -310,40 +310,40 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) //// BRR Decoding -inline void SPC_DSP::decode_brr( voice_t* v ) +inline void SPC_DSP::decode_brr(voice_t* v) { // Arrange the four input nybbles in 0xABCD order for easy decoding int nybbles = m.t_brr_byte * 0x100 + readRam(v->brr_addr + v->brr_offset + 1); - + int const header = m.t_brr_header; - + // Write to next four samples in circular buffer - int* pos = &v->buf [v->buf_pos]; + int* pos = &v->buf[v->buf_pos]; int* end; - if ( (v->buf_pos += 4) >= brr_buf_size ) + if ((v->buf_pos += 4) >= brr_buf_size) v->buf_pos = 0; - + // Decode four samples - for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) + for (end = pos + 4; pos < end; pos++, nybbles <<= 4) { // Extract nybble and sign-extend - int s = (int16_t) nybbles >> 12; - + int s = (int16_t)nybbles >> 12; + // Shift sample based on header int const shift = header >> 4; s = (s << shift) >> 1; - if ( shift >= 0xD ) // handle invalid range + if (shift >= 0xD) // handle invalid range s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) - + // Apply IIR filter (8 is the most commonly used) int const filter = header & 0x0C; - int const p1 = pos [brr_buf_size - 1]; - int const p2 = pos [brr_buf_size - 2] >> 1; - if ( filter >= 8 ) + int const p1 = pos[brr_buf_size - 1]; + int const p2 = pos[brr_buf_size - 2] >> 1; + if (filter >= 8) { s += p1; s -= p2; - if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 + if (filter == 8) // s += p1 * 0.953125 - p2 * 0.46875 { s += p2 >> 4; s += (p1 * -3) >> 6; @@ -354,16 +354,16 @@ inline void SPC_DSP::decode_brr( voice_t* v ) s += (p2 * 3) >> 4; } } - else if ( filter ) // s += p1 * 0.46875 + else if (filter) // s += p1 * 0.46875 { s += p1 >> 1; s += (-p1) >> 5; } - + // Adjust and write sample - CLAMP16( s ); - s = (int16_t) (s * 2); - pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + CLAMP16(s); + s = (int16_t)(s * 2); + pos[brr_buf_size] = pos[0] = s; // second copy simplifies wrap-around } } @@ -372,33 +372,36 @@ inline void SPC_DSP::decode_brr( voice_t* v ) #define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() -MISC_CLOCK( 27 ) +MISC_CLOCK(27) { m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON } -MISC_CLOCK( 28 ) + +MISC_CLOCK(28) { m.t_non = REG(non); m.t_eon = REG(eon); m.t_dir = REG(dir); } -MISC_CLOCK( 29 ) + +MISC_CLOCK(29) { - if ( (m.every_other_sample ^= 1) != 0 ) + if ((m.every_other_sample ^= 1) != 0) m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read } -MISC_CLOCK( 30 ) + +MISC_CLOCK(30) { - if ( m.every_other_sample ) + if (m.every_other_sample) { - m.kon = m.new_kon; - m.t_koff = REG(koff) | m.mute_mask; + m.kon = m.new_kon; + m.t_koff = REG(koff) | m.mute_mask; } - + run_counters(); - + // Noise - if ( !read_counter( REG(flg) & 0x1F ) ) + if (!read_counter(REG(flg) & 0x1F)) { int feedback = (m.noise << 13) ^ (m.noise << 14); m.noise = (feedback & 0x4000) ^ (m.noise >> 1); @@ -410,133 +413,139 @@ MISC_CLOCK( 30 ) #define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) -inline VOICE_CLOCK( V1 ) +inline VOICE_CLOCK(V1) { m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; - m.t_srcn = VREG(v->regs,srcn); + m.t_srcn = VREG(v->regs, srcn); } -inline VOICE_CLOCK( V2 ) + +inline VOICE_CLOCK(V2) { // Read sample pointer (ignored if not needed) uint16_t entry = m.t_dir_addr; - if ( !v->kon_delay ) + if (!v->kon_delay) entry += 2; - m.t_brr_next_addr = readRam(entry) | (readRam(entry+1) << 8); - - m.t_adsr0 = VREG(v->regs,adsr0); - + m.t_brr_next_addr = readRam(entry) | (readRam(entry + 1) << 8); + + m.t_adsr0 = VREG(v->regs, adsr0); + // Read pitch, spread over two clocks - m.t_pitch = VREG(v->regs,pitchl); + m.t_pitch = VREG(v->regs, pitchl); } -inline VOICE_CLOCK( V3a ) + +inline VOICE_CLOCK(V3a) { - m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; + m.t_pitch += (VREG(v->regs, pitchh) & 0x3F) << 8; } -inline VOICE_CLOCK( V3b ) + +inline VOICE_CLOCK(V3b) { // Read BRR header and byte - m.t_brr_byte = readRam(v->brr_addr + v->brr_offset); + m.t_brr_byte = readRam(v->brr_addr + v->brr_offset); m.t_brr_header = readRam(v->brr_addr); // brr_addr doesn't need masking } -VOICE_CLOCK( V3c ) + +VOICE_CLOCK(V3c) { // Pitch modulation using previous voice's output - if ( m.t_pmon & v->vbit ) + if (m.t_pmon & v->vbit) m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; - - if ( v->kon_delay ) + + if (v->kon_delay) { // Get ready to start BRR decoding on next sample - if ( v->kon_delay == 5 ) + if (v->kon_delay == 5) { - v->brr_addr = m.t_brr_next_addr; - v->brr_offset = 1; - v->buf_pos = 0; + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; m.t_brr_header = 0; // header is ignored on this sample - m.kon_check = true; + m.kon_check = true; } - + // Envelope is never run during KON - v->env = 0; + v->env = 0; v->hidden_env = 0; - + // Disable BRR decoding until last three samples v->interp_pos = 0; - if ( --v->kon_delay & 3 ) + if (--v->kon_delay & 3) v->interp_pos = 0x4000; - + // Pitch is never added during KON m.t_pitch = 0; } - + // Gaussian interpolation { - int output = _settings->GetAudioConfig().EnableCubicInterpolation ? interpolate_cubic(v) : interpolate( v ); - + int output = _settings->GetAudioConfig().EnableCubicInterpolation ? interpolate_cubic(v) : interpolate(v); + // Noise - if ( m.t_non & v->vbit ) - output = (int16_t) (m.noise * 2); - + if (m.t_non & v->vbit) + output = (int16_t)(m.noise * 2); + // Apply envelope m.t_output = (output * v->env) >> 11 & ~1; - v->t_envx_out = (uint8_t) (v->env >> 4); + v->t_envx_out = (uint8_t)(v->env >> 4); } - + // Immediate silence due to end of sample or soft reset - if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + if (REG(flg) & 0x80 || (m.t_brr_header & 3) == 1) { v->env_mode = env_release; - v->env = 0; + v->env = 0; } - - if ( m.every_other_sample ) + + if (m.every_other_sample) { // KOFF - if ( m.t_koff & v->vbit ) + if (m.t_koff & v->vbit) v->env_mode = env_release; - + // KON - if ( m.kon & v->vbit ) + if (m.kon & v->vbit) { v->kon_delay = 5; - v->env_mode = env_attack; + v->env_mode = env_attack; } } - + // Run envelope for next sample - if ( !v->kon_delay ) - run_envelope( v ); + if (!v->kon_delay) + run_envelope(v); } -inline void SPC_DSP::voice_output( voice_t const* v, int ch ) + +inline void SPC_DSP::voice_output(voice_t const* v, int ch) { // Apply left/right volume - int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; - + int amp = (m.t_output * (int8_t)VREG(v->regs, voll + ch)) >> 7; + // Add to output total - m.t_main_out [ch] += amp; - CLAMP16( m.t_main_out [ch] ); - + m.t_main_out[ch] += amp; + CLAMP16(m.t_main_out [ch]); + // Optionally add to echo total - if ( m.t_eon & v->vbit ) + if (m.t_eon & v->vbit) { - m.t_echo_out [ch] += amp; - CLAMP16( m.t_echo_out [ch] ); + m.t_echo_out[ch] += amp; + CLAMP16(m.t_echo_out [ch]); } } -VOICE_CLOCK( V4 ) + +VOICE_CLOCK(V4) { // Decode BRR m.t_looped = 0; - if ( v->interp_pos >= 0x4000 ) + if (v->interp_pos >= 0x4000) { - decode_brr( v ); - - if ( (v->brr_offset += 2) >= brr_block_size ) + decode_brr(v); + + if ((v->brr_offset += 2) >= brr_block_size) { // Start decoding next BRR block - assert( v->brr_offset == brr_block_size ); + assert(v->brr_offset == brr_block_size); v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; - if ( m.t_brr_header & 1 ) + if (m.t_brr_header & 1) { v->brr_addr = m.t_brr_next_addr; m.t_looped = v->vbit; @@ -544,66 +553,88 @@ VOICE_CLOCK( V4 ) v->brr_offset = 1; } } - + // Apply pitch v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; - + // Keep from getting too far ahead (when using pitch modulation) - if ( v->interp_pos > 0x7FFF ) + if (v->interp_pos > 0x7FFF) v->interp_pos = 0x7FFF; - + // Output left - voice_output( v, 0 ); + voice_output(v, 0); } -inline VOICE_CLOCK( V5 ) + +inline VOICE_CLOCK(V5) { // Output right - voice_output( v, 1 ); - + voice_output(v, 1); + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier int endx_buf = REG(endx) | m.t_looped; - + // Clear bit in ENDX if KON just began - if ( v->kon_delay == 5 ) + if (v->kon_delay == 5) endx_buf &= ~v->vbit; - m.endx_buf = (uint8_t) endx_buf; + m.endx_buf = (uint8_t)endx_buf; } -inline VOICE_CLOCK( V6 ) + +inline VOICE_CLOCK(V6) { - (void) v; // avoid compiler warning about unused v - m.outx_buf = (uint8_t) (m.t_output >> 8); + (void)v; // avoid compiler warning about unused v + m.outx_buf = (uint8_t)(m.t_output >> 8); } -inline VOICE_CLOCK( V7 ) + +inline VOICE_CLOCK(V7) { // Update ENDX REG(endx) = m.endx_buf; - + m.envx_buf = v->t_envx_out; } -inline VOICE_CLOCK( V8 ) + +inline VOICE_CLOCK(V8) { // Update OUTX - VREG(v->regs,outx) = m.outx_buf; + VREG(v->regs, outx) = m.outx_buf; } -inline VOICE_CLOCK( V9 ) + +inline VOICE_CLOCK(V9) { // Update ENVX - VREG(v->regs,envx) = m.envx_buf; + VREG(v->regs, envx) = m.envx_buf; } // Most voices do all these in one clock, so make a handy composite -inline VOICE_CLOCK( V3 ) +inline VOICE_CLOCK(V3) { - voice_V3a( v ); - voice_V3b( v ); - voice_V3c( v ); + voice_V3a(v); + voice_V3b(v); + voice_V3c(v); } // Common combinations of voice steps on different voices. This greatly reduces // code size and allows everything to be inlined in these functions. -VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } -VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } -VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } +VOICE_CLOCK(V7_V4_V1) +{ + voice_V7(v); + voice_V1(v + 3); + voice_V4(v + 1); +} + +VOICE_CLOCK(V8_V5_V2) +{ + voice_V8(v); + voice_V5(v + 1); + voice_V2(v + 2); +} + +VOICE_CLOCK(V9_V6_V3) +{ + voice_V9(v); + voice_V6(v + 1); + voice_V3(v + 2); +} //// Echo @@ -619,146 +650,157 @@ VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } #define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() -inline void SPC_DSP::echo_read( int ch ) +inline void SPC_DSP::echo_read(int ch) { uint16_t echoPtr = ECHO_PTR(ch); - int16_t s = readRam(echoPtr) | (readRam(echoPtr+1) << 8); + int16_t s = readRam(echoPtr) | (readRam(echoPtr + 1) << 8); // second copy simplifies wrap-around handling - ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; + ECHO_FIR(0)[ch] = ECHO_FIR(8)[ch] = s >> 1; } -ECHO_CLOCK( 22 ) +ECHO_CLOCK(22) { // History - if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) + if (++m.echo_hist_pos >= &m.echo_hist[echo_hist_size]) m.echo_hist_pos = m.echo_hist; - + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; - echo_read( 0 ); - + echo_read(0); + // FIR (using l and r temporaries below helps compiler optimize) - int l = CALC_FIR( 0, 0 ); - int r = CALC_FIR( 0, 1 ); - - m.t_echo_in [0] = l; - m.t_echo_in [1] = r; + int l = CALC_FIR(0, 0); + int r = CALC_FIR(0, 1); + + m.t_echo_in[0] = l; + m.t_echo_in[1] = r; } -ECHO_CLOCK( 23 ) + +ECHO_CLOCK(23) { - int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); - int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); - - m.t_echo_in [0] += l; - m.t_echo_in [1] += r; - - echo_read( 1 ); + int l = CALC_FIR(1, 0) + CALC_FIR(2, 0); + int r = CALC_FIR(1, 1) + CALC_FIR(2, 1); + + m.t_echo_in[0] += l; + m.t_echo_in[1] += r; + + echo_read(1); } -ECHO_CLOCK( 24 ) + +ECHO_CLOCK(24) { - int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); - int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); - - m.t_echo_in [0] += l; - m.t_echo_in [1] += r; + int l = CALC_FIR(3, 0) + CALC_FIR(4, 0) + CALC_FIR(5, 0); + int r = CALC_FIR(3, 1) + CALC_FIR(4, 1) + CALC_FIR(5, 1); + + m.t_echo_in[0] += l; + m.t_echo_in[1] += r; } -ECHO_CLOCK( 25 ) + +ECHO_CLOCK(25) { - int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); - int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); - - l = (int16_t) l; - r = (int16_t) r; - - l += (int16_t) CALC_FIR( 7, 0 ); - r += (int16_t) CALC_FIR( 7, 1 ); - - CLAMP16( l ); - CLAMP16( r ); - - m.t_echo_in [0] = l & ~1; - m.t_echo_in [1] = r & ~1; + int l = m.t_echo_in[0] + CALC_FIR(6, 0); + int r = m.t_echo_in[1] + CALC_FIR(6, 1); + + l = (int16_t)l; + r = (int16_t)r; + + l += (int16_t)CALC_FIR(7, 0); + r += (int16_t)CALC_FIR(7, 1); + + CLAMP16(l); + CLAMP16(r); + + m.t_echo_in[0] = l & ~1; + m.t_echo_in[1] = r & ~1; } -inline int SPC_DSP::echo_output( int ch ) + +inline int SPC_DSP::echo_output(int ch) { - int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + - (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); - CLAMP16( out ); + int out = (int16_t)((m.t_main_out[ch] * (int8_t)REG(mvoll + ch * 0x10)) >> 7) + + (int16_t)((m.t_echo_in[ch] * (int8_t)REG(evoll + ch * 0x10)) >> 7); + CLAMP16(out); return out; } -ECHO_CLOCK( 26 ) + +ECHO_CLOCK(26) { // Left output volumes // (save sample for next clock so we can output both together) - m.t_main_out [0] = echo_output( 0 ); - + m.t_main_out[0] = echo_output(0); + // Echo feedback - int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); - int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); - - CLAMP16( l ); - CLAMP16( r ); - - m.t_echo_out [0] = l & ~1; - m.t_echo_out [1] = r & ~1; + int l = m.t_echo_out[0] + (int16_t)((m.t_echo_in[0] * (int8_t)REG(efb)) >> 7); + int r = m.t_echo_out[1] + (int16_t)((m.t_echo_in[1] * (int8_t)REG(efb)) >> 7); + + CLAMP16(l); + CLAMP16(r); + + m.t_echo_out[0] = l & ~1; + m.t_echo_out[1] = r & ~1; } -ECHO_CLOCK( 27 ) + +ECHO_CLOCK(27) { // Output - int l = m.t_main_out [0]; - int r = echo_output( 1 ); - m.t_main_out [0] = 0; - m.t_main_out [1] = 0; - + int l = m.t_main_out[0]; + int r = echo_output(1); + m.t_main_out[0] = 0; + m.t_main_out[1] = 0; + // TODO: global muting isn't this simple (turns DAC on and off // or something, causing small ~37-sample pulse when first muted) - if ( REG(flg) & 0x40 ) + if (REG(flg) & 0x40) { l = 0; r = 0; } - + // Output sample to DAC - #ifdef SPC_DSP_OUT_HOOK +#ifdef SPC_DSP_OUT_HOOK SPC_DSP_OUT_HOOK( l, r ); - #else - sample_t* out = m.out; - WRITE_SAMPLES( l, r, out ); - m.out = out; - #endif +#else + sample_t* out = m.out; + WRITE_SAMPLES(l, r, out); + m.out = out; +#endif } -ECHO_CLOCK( 28 ) + +ECHO_CLOCK(28) { m.t_echo_enabled = REG(flg); } -inline void SPC_DSP::echo_write( int ch ) + +inline void SPC_DSP::echo_write(int ch) { - if(!(m.t_echo_enabled & 0x20)) { + if (!(m.t_echo_enabled & 0x20)) + { uint16_t echoPtr = ECHO_PTR(ch); writeRam(echoPtr, m.t_echo_out[ch]); - writeRam(echoPtr+1, m.t_echo_out[ch] >> 8); + writeRam(echoPtr + 1, m.t_echo_out[ch] >> 8); } - m.t_echo_out [ch] = 0; + m.t_echo_out[ch] = 0; } -ECHO_CLOCK( 29 ) + +ECHO_CLOCK(29) { m.t_esa = REG(esa); - - if ( !m.echo_offset ) + + if (!m.echo_offset) m.echo_length = (REG(edl) & 0x0F) * 0x800; - + m.echo_offset += 4; - if ( m.echo_offset >= m.echo_length ) + if (m.echo_offset >= m.echo_length) m.echo_offset = 0; - + // Write left echo - echo_write( 0 ); - + echo_write(0); + m.t_echo_enabled = REG(flg); } -ECHO_CLOCK( 30 ) + +ECHO_CLOCK(30) { // Write right echo - echo_write( 1 ); + echo_write(1); } @@ -808,8 +850,7 @@ PHASE(27) misc_27(); echo_27();\ PHASE(28) misc_28(); echo_28();\ PHASE(29) misc_29(); echo_29();\ PHASE(30) misc_30();V(V3c,0) echo_30();\ -PHASE(31) V(V4,0) V(V1,2)\ - +PHASE(31) V(V4,0) V(V1,2) #if !SPC_DSP_CUSTOM_RUN void SPC_DSP::run() @@ -818,9 +859,9 @@ void SPC_DSP::run() m.phase = (phase + 1) & 31; switch (phase) { - #define PHASE( n ) if ( n ) break; case n: +#define PHASE( n ) if ( n ) break; case n: GEN_DSP_TIMING - #undef PHASE +#undef PHASE } } @@ -832,42 +873,46 @@ inline void SPC_DSP::writeRam(uint16_t addr, uint8_t value) { _spc->DspWriteRam( //// Setup -void SPC_DSP::init( Spc *spc, EmuSettings *settings, void* ram_64k ) +void SPC_DSP::init(Spc* spc, EmuSettings* settings, void* ram_64k) { _spc = spc; _settings = settings; - m.ram = (uint8_t*) ram_64k; - mute_voices( 0 ); - disable_surround( false ); - set_output( 0, 0 ); + m.ram = (uint8_t*)ram_64k; + mute_voices(0); + disable_surround(false); + set_output(0, 0); reset(); - - #ifndef NDEBUG - // be sure this sign-extends - assert( (int16_t) 0x8000 == -0x8000 ); - - // be sure right shift preserves sign - assert( (-1 >> 1) == -1 ); - - // check clamp macro - int i; - i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); - i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); - - blargg_verify_byte_order(); - #endif + +#ifndef NDEBUG + // be sure this sign-extends + assert((int16_t) 0x8000 == -0x8000); + + // be sure right shift preserves sign + assert((-1 >> 1) == -1); + + // check clamp macro + int i; + i = +0x8000; + CLAMP16(i); + assert(i == +0x7FFF); + i = -0x8001; + CLAMP16(i); + assert(i == -0x8000); + + blargg_verify_byte_order(); +#endif } void SPC_DSP::soft_reset_common() { - require( m.ram ); // init() must have been called already - - m.noise = 0x4000; - m.echo_hist_pos = m.echo_hist; + require(m.ram); // init() must have been called already + + m.noise = 0x4000; + m.echo_hist_pos = m.echo_hist; m.every_other_sample = 1; - m.echo_offset = 0; - m.phase = 0; - + m.echo_offset = 0; + m.phase = 0; + init_counter(); } @@ -877,61 +922,61 @@ void SPC_DSP::soft_reset() soft_reset_common(); } -void SPC_DSP::load( uint8_t const regs [register_count] ) +void SPC_DSP::load(uint8_t const regs[register_count]) { - memcpy( m.regs, regs, sizeof m.regs ); - memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); - + memcpy(m.regs, regs, sizeof m.regs); + memset(&m.regs[register_count], 0, offsetof(state_t, ram) - register_count); + // Internal state - for ( int i = voice_count; --i >= 0; ) + for (int i = voice_count; --i >= 0;) { - voice_t* v = &m.voices [i]; + voice_t* v = &m.voices[i]; v->brr_offset = 1; - v->vbit = 1 << i; - v->regs = &m.regs [i * 0x10]; + v->vbit = 1 << i; + v->regs = &m.regs[i * 0x10]; } m.new_kon = REG(kon); - m.t_dir = REG(dir); - m.t_esa = REG(esa); - + m.t_dir = REG(dir); + m.t_esa = REG(esa); + soft_reset_common(); } -void SPC_DSP::reset() { load( initial_regs ); } +void SPC_DSP::reset() { load(initial_regs); } //// State save/load #if !SPC_NO_COPY_STATE_FUNCS -void SPC_State_Copier::copy( void* state, size_t size ) +void SPC_State_Copier::copy(void* state, size_t size) { - func( buf, state, size ); + func(buf, state, size); } -int SPC_State_Copier::copy_int( int state, int size ) +int SPC_State_Copier::copy_int(int state, int size) { - BOOST::uint8_t s [2]; - SET_LE16( s, state ); - func( buf, &s, size ); - return GET_LE16( s ); + BOOST::uint8_t s[2]; + SET_LE16(s, state); + func(buf, &s, size); + return GET_LE16(s); } -void SPC_State_Copier::skip( int count ) +void SPC_State_Copier::skip(int count) { - if ( count > 0 ) + if (count > 0) { - char temp [64]; - memset( temp, 0, sizeof temp ); + char temp[64]; + memset(temp, 0, sizeof temp); do { int n = sizeof temp; - if ( n > count ) + if (n > count) n = count; count -= n; - func( buf, temp, n ); + func(buf, temp, n); } - while ( count ); + while (count); } } @@ -939,107 +984,107 @@ void SPC_State_Copier::extra() { int n = 0; SPC_State_Copier& copier = *this; - SPC_COPY( uint8_t, n ); - skip( n ); + SPC_COPY(uint8_t, n); + skip(n); } -void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) +void SPC_DSP::copy_state(unsigned char** io, copy_func_t copy) { - SPC_State_Copier copier( io, copy ); - + SPC_State_Copier copier(io, copy); + // DSP registers - copier.copy( m.regs, register_count ); - + copier.copy(m.regs, register_count); + // Internal state - + // Voices int i; - for ( i = 0; i < voice_count; i++ ) + for (i = 0; i < voice_count; i++) { - voice_t* v = &m.voices [i]; - + voice_t* v = &m.voices[i]; + // BRR buffer int i; - for ( i = 0; i < brr_buf_size; i++ ) + for (i = 0; i < brr_buf_size; i++) { - int s = v->buf [i]; - SPC_COPY( int16_t, s ); - v->buf [i] = v->buf [i + brr_buf_size] = s; + int s = v->buf[i]; + SPC_COPY(int16_t, s); + v->buf[i] = v->buf[i + brr_buf_size] = s; } - - SPC_COPY( uint16_t, v->interp_pos ); - SPC_COPY( uint16_t, v->brr_addr ); - SPC_COPY( uint16_t, v->env ); - SPC_COPY( int16_t, v->hidden_env ); - SPC_COPY( uint8_t, v->buf_pos ); - SPC_COPY( uint8_t, v->brr_offset ); - SPC_COPY( uint8_t, v->kon_delay ); + + SPC_COPY(uint16_t, v->interp_pos); + SPC_COPY(uint16_t, v->brr_addr); + SPC_COPY(uint16_t, v->env); + SPC_COPY(int16_t, v->hidden_env); + SPC_COPY(uint8_t, v->buf_pos); + SPC_COPY(uint8_t, v->brr_offset); + SPC_COPY(uint8_t, v->kon_delay); { int m = v->env_mode; - SPC_COPY( uint8_t, m ); - v->env_mode = (enum env_mode_t) m; + SPC_COPY(uint8_t, m); + v->env_mode = (enum env_mode_t)m; } - SPC_COPY( uint8_t, v->t_envx_out ); - + SPC_COPY(uint8_t, v->t_envx_out); + copier.extra(); } - + // Echo history - for ( i = 0; i < echo_hist_size; i++ ) + for (i = 0; i < echo_hist_size; i++) { int j; - for ( j = 0; j < 2; j++ ) + for (j = 0; j < 2; j++) { - int s = m.echo_hist_pos [i] [j]; - SPC_COPY( int16_t, s ); - m.echo_hist [i] [j] = s; // write back at offset 0 + int s = m.echo_hist_pos[i][j]; + SPC_COPY(int16_t, s); + m.echo_hist[i][j] = s; // write back at offset 0 } } m.echo_hist_pos = m.echo_hist; - memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); - + memcpy(&m.echo_hist[echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist[0]); + // Misc - SPC_COPY( uint8_t, m.every_other_sample ); - SPC_COPY( uint8_t, m.kon ); - - SPC_COPY( uint16_t, m.noise ); - SPC_COPY( uint16_t, m.counter ); - SPC_COPY( uint16_t, m.echo_offset ); - SPC_COPY( uint16_t, m.echo_length ); - SPC_COPY( uint8_t, m.phase ); - - SPC_COPY( uint8_t, m.new_kon ); - SPC_COPY( uint8_t, m.endx_buf ); - SPC_COPY( uint8_t, m.envx_buf ); - SPC_COPY( uint8_t, m.outx_buf ); - - SPC_COPY( uint8_t, m.t_pmon ); - SPC_COPY( uint8_t, m.t_non ); - SPC_COPY( uint8_t, m.t_eon ); - SPC_COPY( uint8_t, m.t_dir ); - SPC_COPY( uint8_t, m.t_koff ); - - SPC_COPY( uint16_t, m.t_brr_next_addr ); - SPC_COPY( uint8_t, m.t_adsr0 ); - SPC_COPY( uint8_t, m.t_brr_header ); - SPC_COPY( uint8_t, m.t_brr_byte ); - SPC_COPY( uint8_t, m.t_srcn ); - SPC_COPY( uint8_t, m.t_esa ); - SPC_COPY( uint8_t, m.t_echo_enabled ); - - SPC_COPY( int16_t, m.t_main_out [0] ); - SPC_COPY( int16_t, m.t_main_out [1] ); - SPC_COPY( int16_t, m.t_echo_out [0] ); - SPC_COPY( int16_t, m.t_echo_out [1] ); - SPC_COPY( int16_t, m.t_echo_in [0] ); - SPC_COPY( int16_t, m.t_echo_in [1] ); - - SPC_COPY( uint16_t, m.t_dir_addr ); - SPC_COPY( uint16_t, m.t_pitch ); - SPC_COPY( int16_t, m.t_output ); - SPC_COPY( uint16_t, m.t_echo_ptr ); - SPC_COPY( uint8_t, m.t_looped ); - + SPC_COPY(uint8_t, m.every_other_sample); + SPC_COPY(uint8_t, m.kon); + + SPC_COPY(uint16_t, m.noise); + SPC_COPY(uint16_t, m.counter); + SPC_COPY(uint16_t, m.echo_offset); + SPC_COPY(uint16_t, m.echo_length); + SPC_COPY(uint8_t, m.phase); + + SPC_COPY(uint8_t, m.new_kon); + SPC_COPY(uint8_t, m.endx_buf); + SPC_COPY(uint8_t, m.envx_buf); + SPC_COPY(uint8_t, m.outx_buf); + + SPC_COPY(uint8_t, m.t_pmon); + SPC_COPY(uint8_t, m.t_non); + SPC_COPY(uint8_t, m.t_eon); + SPC_COPY(uint8_t, m.t_dir); + SPC_COPY(uint8_t, m.t_koff); + + SPC_COPY(uint16_t, m.t_brr_next_addr); + SPC_COPY(uint8_t, m.t_adsr0); + SPC_COPY(uint8_t, m.t_brr_header); + SPC_COPY(uint8_t, m.t_brr_byte); + SPC_COPY(uint8_t, m.t_srcn); + SPC_COPY(uint8_t, m.t_esa); + SPC_COPY(uint8_t, m.t_echo_enabled); + + SPC_COPY(int16_t, m.t_main_out [0]); + SPC_COPY(int16_t, m.t_main_out [1]); + SPC_COPY(int16_t, m.t_echo_out [0]); + SPC_COPY(int16_t, m.t_echo_out [1]); + SPC_COPY(int16_t, m.t_echo_in [0]); + SPC_COPY(int16_t, m.t_echo_in [1]); + + SPC_COPY(uint16_t, m.t_dir_addr); + SPC_COPY(uint16_t, m.t_pitch); + SPC_COPY(int16_t, m.t_output); + SPC_COPY(uint16_t, m.t_echo_ptr); + SPC_COPY(uint8_t, m.t_looped); + copier.extra(); } #endif diff --git a/Core/SPC_DSP.h b/Core/SPC_DSP.h index 8d80220..8641524 100644 --- a/Core/SPC_DSP.h +++ b/Core/SPC_DSP.h @@ -5,160 +5,188 @@ #define SPC_DSP_H #include "blargg_common.h" -extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } + +extern "C" { +typedef void (*dsp_copy_func_t)(unsigned char** io, void* state, size_t); +} class Spc; class EmuSettings; -class SPC_DSP { + +class SPC_DSP +{ public: typedef BOOST::uint8_t uint8_t; - -// Setup + + // Setup // Initializes DSP and has it use the 64K RAM provided - void init( Spc* spc, EmuSettings* settings, void* ram_64k ); + void init(Spc* spc, EmuSettings* settings, void* ram_64k); // Sets destination for output samples. If out is NULL or out_size is 0, // doesn't generate any. typedef short sample_t; - void set_output( sample_t* out, int out_size ); + void set_output(sample_t* out, int out_size); // Number of samples written to output since it was last set, always // a multiple of 2. Undefined if more samples were generated than // output buffer could hold. int sample_count() const; -// Emulation + // Emulation // Resets DSP to power-on state void reset(); // Emulates pressing reset switch on SNES void soft_reset(); - + // Reads/writes DSP registers. For accuracy, you must first call run() // to catch the DSP up to present. - int read ( int addr ) const; - void write( int addr, int data ); + int read(int addr) const; + void write(int addr, int data); // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks // a pair of samples is be generated. void run(); - + bool isMuted() { return (m.regs[r_flg] & 0x40) != 0; } void copyRegs(uint8_t* output) { memcpy(output, m.regs, register_count); } uint8_t readRam(uint16_t addr); void writeRam(uint16_t addr, uint8_t value); -// Sound control + // Sound control // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). // Reduces emulation accuracy. enum { voice_count = 8 }; - void mute_voices( int mask ); -// State - + void mute_voices(int mask); + + // State + // Resets DSP and uses supplied values to initialize registers enum { register_count = 128 }; - void load( uint8_t const regs [register_count] ); + + void load(uint8_t const regs[register_count]); // Saves/loads exact emulator state enum { state_size = 640 }; // maximum space needed when saving typedef dsp_copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); + void copy_state(unsigned char** io, copy_func_t); // Returns non-zero if new key-on events occurred since last call bool check_kon(); - -// DSP register addresses + + // DSP register addresses // Global registers - enum { - r_mvoll = 0x0C, r_mvolr = 0x1C, - r_evoll = 0x2C, r_evolr = 0x3C, - r_kon = 0x4C, r_koff = 0x5C, - r_flg = 0x6C, r_endx = 0x7C, - r_efb = 0x0D, r_pmon = 0x2D, - r_non = 0x3D, r_eon = 0x4D, - r_dir = 0x5D, r_esa = 0x6D, - r_edl = 0x7D, - r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F + enum + { + r_mvoll = 0x0C, + r_mvolr = 0x1C, + r_evoll = 0x2C, + r_evolr = 0x3C, + r_kon = 0x4C, + r_koff = 0x5C, + r_flg = 0x6C, + r_endx = 0x7C, + r_efb = 0x0D, + r_pmon = 0x2D, + r_non = 0x3D, + r_eon = 0x4D, + r_dir = 0x5D, + r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F }; // Voice registers - enum { - v_voll = 0x00, v_volr = 0x01, - v_pitchl = 0x02, v_pitchh = 0x03, - v_srcn = 0x04, v_adsr0 = 0x05, - v_adsr1 = 0x06, v_gain = 0x07, - v_envx = 0x08, v_outx = 0x09 + enum + { + v_voll = 0x00, + v_volr = 0x01, + v_pitchl = 0x02, + v_pitchh = 0x03, + v_srcn = 0x04, + v_adsr0 = 0x05, + v_adsr1 = 0x06, + v_gain = 0x07, + v_envx = 0x08, + v_outx = 0x09 }; public: enum { extra_size = 16 }; - sample_t* extra() { return m.extra; } + + sample_t* extra() { return m.extra; } sample_t const* out_pos() const { return m.out; } - void disable_surround( bool ) { } // not supported + + void disable_surround(bool) + { + } // not supported public: BLARGG_DISABLE_NOTHROW - - typedef BOOST::int8_t int8_t; + + typedef BOOST::int8_t int8_t; typedef BOOST::int16_t int16_t; - + enum { echo_hist_size = 8 }; - + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + enum { brr_buf_size = 12 }; + struct voice_t { - int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) - int buf_pos; // place in buffer where next samples will be decoded - int interp_pos; // relative fractional position in sample (0x1000 = 1.0) - int brr_addr; // address of current BRR block - int brr_offset; // current decoding offset in BRR block - uint8_t* regs; // pointer to voice's DSP registers - int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. - int kon_delay; // KON delay/current setup phase + int buf[brr_buf_size * 2]; // decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8_t* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase env_mode_t env_mode; - int env; // current envelope level - int hidden_env; // used by GAIN mode 7, very obscure quirk + int env; // current envelope level + int hidden_env; // used by GAIN mode 7, very obscure quirk uint8_t t_envx_out; }; + private: enum { brr_block_size = 9 }; - + struct state_t { - uint8_t regs [register_count]; - + uint8_t regs[register_count]; + // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) - int echo_hist [echo_hist_size * 2] [2]; - int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] - + int echo_hist[echo_hist_size * 2][2]; + int (*echo_hist_pos)[2]; // &echo_hist [0 to 7] + int every_other_sample; // toggles every sample - int kon; // KON value when last checked + int kon; // KON value when last checked int noise; int counter; - int echo_offset; // offset from ESA in echo buffer - int echo_length; // number of bytes that echo_offset will stop at - int phase; // next clock cycle to run (0-31) - bool kon_check; // set when a new KON occurs - + int echo_offset; // offset from ESA in echo buffer + int echo_length; // number of bytes that echo_offset will stop at + int phase; // next clock cycle to run (0-31) + bool kon_check; // set when a new KON occurs + // Hidden registers also written to when main register is written to int new_kon; uint8_t endx_buf; uint8_t envx_buf; uint8_t outx_buf; - + // Temporary state between clocks - + // read once per sample int t_pmon; int t_non; int t_eon; int t_dir; int t_koff; - + // read a few clocks ahead then used int t_brr_next_addr; int t_adsr0; @@ -167,67 +195,68 @@ private: int t_srcn; int t_esa; int t_echo_enabled; - + // internal state that is recalculated every sample uint16_t t_dir_addr; int t_pitch; int t_output; int t_looped; int t_echo_ptr; - + // left/right sums - int t_main_out [2]; - int t_echo_out [2]; - int t_echo_in [2]; - - voice_t voices [voice_count]; - + int t_main_out[2]; + int t_echo_out[2]; + int t_echo_in[2]; + + voice_t voices[voice_count]; + // non-emulation state uint8_t* ram; // 64K shared RAM between DSP and SMP int mute_mask; sample_t* out; sample_t* out_end; sample_t* out_begin; - sample_t extra [extra_size]; + sample_t extra[extra_size]; }; + state_t m; Spc* _spc; EmuSettings* _settings; - + void init_counter(); void run_counters(); - unsigned read_counter( int rate ); - + unsigned read_counter(int rate); + int interpolate_cubic(voice_t const* v); - int interpolate( voice_t const* v ); - void run_envelope( voice_t* const v ); - void decode_brr( voice_t* v ); + int interpolate(voice_t const* v); + void run_envelope(voice_t* const v); + void decode_brr(voice_t* v); void misc_27(); void misc_28(); void misc_29(); void misc_30(); - void voice_output( voice_t const* v, int ch ); - void voice_V1( voice_t* const ); - void voice_V2( voice_t* const ); - void voice_V3( voice_t* const ); - void voice_V3a( voice_t* const ); - void voice_V3b( voice_t* const ); - void voice_V3c( voice_t* const ); - void voice_V4( voice_t* const ); - void voice_V5( voice_t* const ); - void voice_V6( voice_t* const ); - void voice_V7( voice_t* const ); - void voice_V8( voice_t* const ); - void voice_V9( voice_t* const ); - void voice_V7_V4_V1( voice_t* const ); - void voice_V8_V5_V2( voice_t* const ); - void voice_V9_V6_V3( voice_t* const ); + void voice_output(voice_t const* v, int ch); + void voice_V1(voice_t* const); + void voice_V2(voice_t* const); + void voice_V3(voice_t* const); + void voice_V3a(voice_t* const); + void voice_V3b(voice_t* const); + void voice_V3c(voice_t* const); + void voice_V4(voice_t* const); + void voice_V5(voice_t* const); + void voice_V6(voice_t* const); + void voice_V7(voice_t* const); + void voice_V8(voice_t* const); + void voice_V9(voice_t* const); + void voice_V7_V4_V1(voice_t* const); + void voice_V8_V5_V2(voice_t* const); + void voice_V9_V6_V3(voice_t* const); - void echo_read( int ch ); - int echo_output( int ch ); - void echo_write( int ch ); + void echo_read(int ch); + int echo_output(int ch); + void echo_write(int ch); void echo_22(); void echo_23(); void echo_24(); @@ -237,7 +266,7 @@ private: void echo_28(); void echo_29(); void echo_30(); - + void soft_reset_common(); }; @@ -245,41 +274,41 @@ private: inline int SPC_DSP::sample_count() const { return (int)(m.out - m.out_begin); } -inline int SPC_DSP::read( int addr ) const +inline int SPC_DSP::read(int addr) const { - assert( (unsigned) addr < register_count ); - return m.regs [addr]; + assert((unsigned) addr < register_count); + return m.regs[addr]; } -inline void SPC_DSP::write( int addr, int data ) +inline void SPC_DSP::write(int addr, int data) { - assert( (unsigned) addr < register_count ); - - m.regs [addr] = (uint8_t) data; - switch ( addr & 0x0F ) + assert((unsigned) addr < register_count); + + m.regs[addr] = (uint8_t)data; + switch (addr & 0x0F) { case v_envx: - m.envx_buf = (uint8_t) data; + m.envx_buf = (uint8_t)data; break; - + case v_outx: - m.outx_buf = (uint8_t) data; + m.outx_buf = (uint8_t)data; break; - + case 0x0C: - if ( addr == r_kon ) - m.new_kon = (uint8_t) data; - - if ( addr == r_endx ) // always cleared, regardless of data written + if (addr == r_kon) + m.new_kon = (uint8_t)data; + + if (addr == r_endx) // always cleared, regardless of data written { m.endx_buf = 0; - m.regs [r_endx] = 0; + m.regs[r_endx] = 0; } break; } } -inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } +inline void SPC_DSP::mute_voices(int mask) { m.mute_mask = mask; } inline bool SPC_DSP::check_kon() { @@ -290,14 +319,20 @@ inline bool SPC_DSP::check_kon() #if !SPC_NO_COPY_STATE_FUNCS -class SPC_State_Copier { +class SPC_State_Copier +{ SPC_DSP::copy_func_t func; unsigned char** buf; public: - SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } - void copy( void* state, size_t size ); - int copy_int( int state, int size ); - void skip( int count ); + SPC_State_Copier(unsigned char** p, SPC_DSP::copy_func_t f) + { + func = f; + buf = p; + } + + void copy(void* state, size_t size); + int copy_int(int state, int size); + void skip(int count); void extra(); }; diff --git a/Core/SPC_Filter.cpp b/Core/SPC_Filter.cpp index efa190e..ebe0218 100644 --- a/Core/SPC_Filter.cpp +++ b/Core/SPC_Filter.cpp @@ -18,7 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" -void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); } +void SPC_Filter::clear() { memset(ch, 0, sizeof ch); } SPC_Filter::SPC_Filter() { @@ -27,43 +27,43 @@ SPC_Filter::SPC_Filter() clear(); } -void SPC_Filter::run( short* io, int count ) +void SPC_Filter::run(short* io, int count) { - require( (count & 1) == 0 ); // must be even - + require((count & 1) == 0); // must be even + int const gain = this->gain; int const bass = this->bass; - chan_t* c = &ch [2]; + chan_t* c = &ch[2]; do { // cache in registers int sum = (--c)->sum; int pp1 = c->pp1; - int p1 = c->p1; - - for ( int i = 0; i < count; i += 2 ) + int p1 = c->p1; + + for (int i = 0; i < count; i += 2) { // Low-pass filter (two point FIR with coeffs 0.25, 0.75) - int f = io [i] + p1; - p1 = io [i] * 3; - + int f = io[i] + p1; + p1 = io[i] * 3; + // High-pass filter ("leaky integrator") int delta = f - pp1; pp1 = f; int s = sum >> (gain_bits + 2); sum += (delta * gain) - (sum >> bass); - + // Clamp to 16 bits - if ( (short) s != s ) + if ((short)s != s) s = (s >> 31) ^ 0x7FFF; - - io [i] = (short) s; + + io[i] = (short)s; } - - c->p1 = p1; + + c->p1 = p1; c->pp1 = pp1; c->sum = sum; ++io; } - while ( c != ch ); + while (c != ch); } diff --git a/Core/SPC_Filter.h b/Core/SPC_Filter.h index d5c83cb..a9acd6a 100644 --- a/Core/SPC_Filter.h +++ b/Core/SPC_Filter.h @@ -6,14 +6,15 @@ #include "blargg_common.h" -struct SPC_Filter { +struct SPC_Filter +{ public: - + // Filters count samples of stereo sound in place. Count must be a multiple of 2. typedef short sample_t; - void run( sample_t* io, int count ); - -// Optional features + void run(sample_t* io, int count); + + // Optional features // Clears filter to silence void clear(); @@ -21,27 +22,36 @@ public: // Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit // are fine, since output is clamped to 16-bit sample range. enum { gain_unit = 0x100 }; - void set_gain( int gain ); + + void set_gain(int gain); // Sets amount of bass (logarithmic scale) - enum { bass_none = 0 }; - enum { bass_norm = 8 }; // normal amount - enum { bass_max = 31 }; - void set_bass( int bass ); - + enum { bass_none = 0 }; + + enum { bass_norm = 8 }; // normal amount + enum { bass_max = 31 }; + + void set_bass(int bass); + public: SPC_Filter(); BLARGG_DISABLE_NOTHROW private: enum { gain_bits = 8 }; + int gain; int bass; - struct chan_t { int p1, pp1, sum; }; - chan_t ch [2]; + + struct chan_t + { + int p1, pp1, sum; + }; + + chan_t ch[2]; }; -inline void SPC_Filter::set_gain( int g ) { gain = g; } +inline void SPC_Filter::set_gain(int g) { gain = g; } -inline void SPC_Filter::set_bass( int b ) { bass = b; } +inline void SPC_Filter::set_bass(int b) { bass = b; } #endif diff --git a/Core/Sa1.cpp b/Core/Sa1.cpp index 1ec9a72..28f4378 100644 --- a/Core/Sa1.cpp +++ b/Core/Sa1.cpp @@ -25,16 +25,16 @@ Sa1::Sa1(Console* console) : BaseCoprocessor(SnesMemoryType::Register) _openBus = 0; _cart = _console->GetCartridge().get(); _snesCpu = _console->GetCpu().get(); - + _iRam = new uint8_t[Sa1::InternalRamSize]; _iRamHandler.reset(new Sa1IRamHandler(_iRam)); console->GetSettings()->InitializeRam(_iRam, 0x800); - + //Register the SA1 in the CPU's memory space ($22xx-$23xx registers) MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); _mappings.RegisterHandler(0x00, 0x3F, 0x2000, 0x2FFF, this); _mappings.RegisterHandler(0x80, 0xBF, 0x2000, 0x2FFF, this); - + cpuMappings->RegisterHandler(0x00, 0x3F, 0x3000, 0x3FFF, _iRamHandler.get()); cpuMappings->RegisterHandler(0x80, 0xBF, 0x3000, 0x3FFF, _iRamHandler.get()); @@ -43,21 +43,25 @@ Sa1::Sa1(Console* console) : BaseCoprocessor(SnesMemoryType::Register) _mappings.RegisterHandler(0x00, 0x3F, 0x0000, 0x0FFF, _iRamHandler.get()); _mappings.RegisterHandler(0x80, 0xBF, 0x0000, 0x0FFF, _iRamHandler.get()); - if(_cart->DebugGetSaveRamSize() > 0) { + if (_cart->DebugGetSaveRamSize() > 0) + { _bwRamHandler.reset(new Sa1BwRamHandler(_cart->DebugGetSaveRam(), _cart->DebugGetSaveRamSize(), &_state)); - for(int i = 0; i <= 0x3F; i++) { + for (int i = 0; i <= 0x3F; i++) + { //SA-1: 00-3F:6000-7FFF + 80-BF:6000-7FFF _mappings.RegisterHandler(i, i, 0x6000, 0x7FFF, _bwRamHandler.get()); _mappings.RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, _bwRamHandler.get()); } - for(int i = 0; i <= 0x0F; i++) { + for (int i = 0; i <= 0x0F; i++) + { //SA-1: 60-6F:0000-FFFF _mappings.RegisterHandler(i + 0x60, i + 0x60, 0x0000, 0xFFFF, _bwRamHandler.get()); } } - vector> &saveRamHandlers = _cart->GetSaveRamHandlers(); - for(unique_ptr &handler : saveRamHandlers) { + vector>& saveRamHandlers = _cart->GetSaveRamHandlers(); + for (unique_ptr& handler : saveRamHandlers) + { _cpuBwRamHandlers.push_back(unique_ptr(new CpuBwRamHandler(handler.get(), &_state, this))); } cpuMappings->RegisterHandler(0x40, 0x4F, 0x0000, 0xFFFF, _cpuBwRamHandlers); @@ -75,317 +79,416 @@ Sa1::~Sa1() void Sa1::Sa1RegisterWrite(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2209: - //SCNT (SNES CPU Control) - _state.CpuMessageReceived = value & 0x0F; - _state.UseCpuNmiVector = (value & 0x10) != 0; - _state.UseCpuIrqVector = (value & 0x40) != 0; - _state.CpuIrqRequested = (value & 0x80) != 0; + switch (addr) + { + case 0x2209: + //SCNT (SNES CPU Control) + _state.CpuMessageReceived = value & 0x0F; + _state.UseCpuNmiVector = (value & 0x10) != 0; + _state.UseCpuIrqVector = (value & 0x40) != 0; + _state.CpuIrqRequested = (value & 0x80) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x220A: - //CIE (SA-1 CPU Interrupt Enable) - _state.Sa1NmiEnabled = (value & 0x10) != 0; - _state.DmaIrqEnabled = (value & 0x20) != 0; - _state.TimerIrqEnabled = (value & 0x40) != 0; - _state.Sa1IrqEnabled = (value & 0x80) != 0; + case 0x220A: + //CIE (SA-1 CPU Interrupt Enable) + _state.Sa1NmiEnabled = (value & 0x10) != 0; + _state.DmaIrqEnabled = (value & 0x20) != 0; + _state.TimerIrqEnabled = (value & 0x40) != 0; + _state.Sa1IrqEnabled = (value & 0x80) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x220B: - //CIC (SA-1 CPU Interrupt Clear) - if(value & 0x80) { - _state.Sa1IrqRequested = false; - } - if(value & 0x20) { - _state.DmaIrqFlag = false; - } - if(value & 0x10) { - _state.Sa1NmiRequested = false; - } - ProcessInterrupts(); - break; - - case 0x220C: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF00) | value; break; //SNV (SNES CPU NMI Vector - Low) - case 0x220D: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF) | (value << 8); break; //SNV (SNES CPU NMI Vector - High) + case 0x220B: + //CIC (SA-1 CPU Interrupt Clear) + if (value & 0x80) + { + _state.Sa1IrqRequested = false; + } + if (value & 0x20) + { + _state.DmaIrqFlag = false; + } + if (value & 0x10) + { + _state.Sa1NmiRequested = false; + } + ProcessInterrupts(); + break; - case 0x220E: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF00) | value; break; //SNV (SNES CPU IRQ Vector - Low) - case 0x220F: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF) | (value << 8); break; //SIV (SNES CPU IRQ Vector - High) + case 0x220C: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF00) | value; + break; //SNV (SNES CPU NMI Vector - Low) + case 0x220D: _state.CpuNmiVector = (_state.CpuNmiVector & 0xFF) | (value << 8); + break; //SNV (SNES CPU NMI Vector - High) - case 0x2210: - //TMC (H/V Timer Control) - _state.HorizontalTimerEnabled = (value & 0x01) != 0; - _state.VerticalTimerEnabled = (value & 0x02) != 0; - _state.UseLinearTimer = (value & 0x80) != 0; - if(value) { - LogDebug("Using timer"); - } - break; + case 0x220E: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF00) | value; + break; //SNV (SNES CPU IRQ Vector - Low) + case 0x220F: _state.CpuIrqVector = (_state.CpuIrqVector & 0xFF) | (value << 8); + break; //SIV (SNES CPU IRQ Vector - High) - case 0x2211: - //CTR (CPU Timer restart) - _state.LinearTimerValue = 0; - LogDebug("Reset timer"); - break; - - case 0x2212: _state.HTimer = (_state.HTimer & 0x0100) | value; LogDebug("Set timer"); break; //HCNT (Timer H-Count - Low) - case 0x2213: _state.HTimer = (_state.HTimer & 0xFF) | ((value & 0x01) << 8); LogDebug("Set timer"); break; //HCNT (Timer H-Count - High) + case 0x2210: + //TMC (H/V Timer Control) + _state.HorizontalTimerEnabled = (value & 0x01) != 0; + _state.VerticalTimerEnabled = (value & 0x02) != 0; + _state.UseLinearTimer = (value & 0x80) != 0; + if (value) + { + LogDebug("Using timer"); + } + break; - case 0x2214: _state.VTimer = (_state.VTimer & 0x0100) | value; LogDebug("Set timer"); break; //VCNT (Timer V-Count - Low) - case 0x2215: _state.VTimer = (_state.VTimer & 0xFF) | ((value & 0x01) << 8); LogDebug("Set timer"); break; //VCNT (Timer V-Count - High) + case 0x2211: + //CTR (CPU Timer restart) + _state.LinearTimerValue = 0; + LogDebug("Reset timer"); + break; - case 0x2225: - //BMAP (SA-1 BW-RAM Address Mapping) - if(_state.Sa1BwBank != (value & 0x7F) || _state.Sa1BwMode != (value & 0x80)) { - _state.Sa1BwBank = value & 0x7F; - _state.Sa1BwMode = (value & 0x80); - UpdateSaveRamMappings(); - } - break; - - case 0x2227: _state.Sa1BwWriteEnabled = (value & 0x80) != 0; break; //CBWE (SA-1 CPU BW-RAM Write Enable) - case 0x222A: _state.Sa1IRamWriteProtect = value; break; //CIWP (SA-1 CPU I-RAM Write Protection) + case 0x2212: _state.HTimer = (_state.HTimer & 0x0100) | value; + LogDebug("Set timer"); + break; //HCNT (Timer H-Count - Low) + case 0x2213: _state.HTimer = (_state.HTimer & 0xFF) | ((value & 0x01) << 8); + LogDebug("Set timer"); + break; //HCNT (Timer H-Count - High) - case 0x2230: - //DCNT (DMA Control) - _state.DmaSrcDevice = (Sa1DmaSrcDevice)(value & 0x03); - _state.DmaDestDevice = (Sa1DmaDestDevice)((value & 0x04) >> 2); - _state.DmaCharConvAuto = (value & 0x10) != 0; - _state.DmaCharConv = (value & 0x20) != 0; - _state.DmaPriority = (value & 0x40) != 0; - _state.DmaEnabled = (value & 0x80) != 0; - if(!_state.DmaEnabled) { - _state.CharConvCounter = 0; - } - break; - - case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: - WriteSharedRegisters(addr, value); - break; + case 0x2214: _state.VTimer = (_state.VTimer & 0x0100) | value; + LogDebug("Set timer"); + break; //VCNT (Timer V-Count - Low) + case 0x2215: _state.VTimer = (_state.VTimer & 0xFF) | ((value & 0x01) << 8); + LogDebug("Set timer"); + break; //VCNT (Timer V-Count - High) - case 0x2238: _state.DmaSize = (_state.DmaSize & 0xFF00) | value; break; //DTC (DMA terminal counter - Low) - case 0x2239: _state.DmaSize = (_state.DmaSize & 0x00FF) | (value << 8); break; //DTC (DMA terminal counter - High) - - case 0x223F: _state.BwRam2BppMode = (value & 0x80) != 0; break; //BBF (Bitmap format) - - case 0x2240: case 0x2241: case 0x2242: case 0x2243: - case 0x2244: case 0x2245: case 0x2246: case 0x2247: - //BRF (Bitmap register file) - _state.BitmapRegister1[addr & 0x07] = value; - if(addr == 0x2247 && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) { - RunCharConvertType2(); - } - break; + case 0x2225: + //BMAP (SA-1 BW-RAM Address Mapping) + if (_state.Sa1BwBank != (value & 0x7F) || _state.Sa1BwMode != (value & 0x80)) + { + _state.Sa1BwBank = value & 0x7F; + _state.Sa1BwMode = (value & 0x80); + UpdateSaveRamMappings(); + } + break; - case 0x2248: case 0x2249: case 0x224A: case 0x224B: - case 0x224C: case 0x224D: case 0x224E: case 0x224F: - //BRF (Bitmap register file) - _state.BitmapRegister2[addr & 0x07] = value; - if(addr == 0x224F && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) { - RunCharConvertType2(); - } - break; + case 0x2227: _state.Sa1BwWriteEnabled = (value & 0x80) != 0; + break; //CBWE (SA-1 CPU BW-RAM Write Enable) + case 0x222A: _state.Sa1IRamWriteProtect = value; + break; //CIWP (SA-1 CPU I-RAM Write Protection) - case 0x2250: - //MCNT (Arithmetic Control) - _state.MathOp = (Sa1MathOp)(value & 0x03); - if(value & 0x02) { - //"Note: Writing Bit1=1 resets the sum to zero." - _state.MathOpResult = 0; - } - break; - case 0x2251: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0xFF00) | value; break; //MA (Arithmetic parameters - Multiplicand/Dividend - Low) - case 0x2252: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0x00FF) | (value << 8); break; //MA (Arithmetic parameters - Multiplicand/Dividend - High) - case 0x2253: _state.MultiplierDivisor = (_state.MultiplierDivisor & 0xFF00) | value; break; //MB (Arithmetic parameters - Multiplier/Divisor - Low) - case 0x2254: - //MB (Arithmetic parameters - Multiplier/Divisor - High) - _state.MultiplierDivisor = (_state.MultiplierDivisor & 0x00FF) | (value << 8); + case 0x2230: + //DCNT (DMA Control) + _state.DmaSrcDevice = (Sa1DmaSrcDevice)(value & 0x03); + _state.DmaDestDevice = (Sa1DmaDestDevice)((value & 0x04) >> 2); + _state.DmaCharConvAuto = (value & 0x10) != 0; + _state.DmaCharConv = (value & 0x20) != 0; + _state.DmaPriority = (value & 0x40) != 0; + _state.DmaEnabled = (value & 0x80) != 0; + if (!_state.DmaEnabled) + { + _state.CharConvCounter = 0; + } + break; - //"Writing to 2254h starts the operation." - CalculateMathOpResult(); - break; - - case 0x2258: - //VBD (Variable length bit processing) - _state.VarLenAutoInc = (value & 0x80) != 0; - _state.VarLenBitCount = value == 0 ? 16 : (value & 0x0F); + case 0x2231: + case 0x2232: + case 0x2233: + case 0x2234: + case 0x2235: + case 0x2236: + case 0x2237: + WriteSharedRegisters(addr, value); + break; - if(!_state.VarLenAutoInc) { - IncVarLenPosition(); - } - break; + case 0x2238: _state.DmaSize = (_state.DmaSize & 0xFF00) | value; + break; //DTC (DMA terminal counter - Low) + case 0x2239: _state.DmaSize = (_state.DmaSize & 0x00FF) | (value << 8); + break; //DTC (DMA terminal counter - High) - case 0x2259: _state.VarLenAddress = (_state.VarLenAddress & 0xFFFF00) | value; break; //VDA (Variable length data address - Low) - case 0x225A: _state.VarLenAddress = (_state.VarLenAddress & 0xFF00FF) | (value << 8); break; //VDA (Variable length data address - Mid) - case 0x225B: - //VDA (Variable length data address - High) - _state.VarLenAddress = (_state.VarLenAddress & 0x00FFFF) | (value << 16); - _state.VarLenCurrentBit = 0; - break; + case 0x223F: _state.BwRam2BppMode = (value & 0x80) != 0; + break; //BBF (Bitmap format) + + case 0x2240: + case 0x2241: + case 0x2242: + case 0x2243: + case 0x2244: + case 0x2245: + case 0x2246: + case 0x2247: + //BRF (Bitmap register file) + _state.BitmapRegister1[addr & 0x07] = value; + if (addr == 0x2247 && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) + { + RunCharConvertType2(); + } + break; + + case 0x2248: + case 0x2249: + case 0x224A: + case 0x224B: + case 0x224C: + case 0x224D: + case 0x224E: + case 0x224F: + //BRF (Bitmap register file) + _state.BitmapRegister2[addr & 0x07] = value; + if (addr == 0x224F && _state.DmaEnabled && _state.DmaCharConv && !_state.DmaCharConvAuto) + { + RunCharConvertType2(); + } + break; + + case 0x2250: + //MCNT (Arithmetic Control) + _state.MathOp = (Sa1MathOp)(value & 0x03); + if (value & 0x02) + { + //"Note: Writing Bit1=1 resets the sum to zero." + _state.MathOpResult = 0; + } + break; + case 0x2251: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0xFF00) | value; + break; //MA (Arithmetic parameters - Multiplicand/Dividend - Low) + case 0x2252: _state.MultiplicandDividend = (_state.MultiplicandDividend & 0x00FF) | (value << 8); + break; //MA (Arithmetic parameters - Multiplicand/Dividend - High) + case 0x2253: _state.MultiplierDivisor = (_state.MultiplierDivisor & 0xFF00) | value; + break; //MB (Arithmetic parameters - Multiplier/Divisor - Low) + case 0x2254: + //MB (Arithmetic parameters - Multiplier/Divisor - High) + _state.MultiplierDivisor = (_state.MultiplierDivisor & 0x00FF) | (value << 8); + + //"Writing to 2254h starts the operation." + CalculateMathOpResult(); + break; + + case 0x2258: + //VBD (Variable length bit processing) + _state.VarLenAutoInc = (value & 0x80) != 0; + _state.VarLenBitCount = value == 0 ? 16 : (value & 0x0F); + + if (!_state.VarLenAutoInc) + { + IncVarLenPosition(); + } + break; + + case 0x2259: _state.VarLenAddress = (_state.VarLenAddress & 0xFFFF00) | value; + break; //VDA (Variable length data address - Low) + case 0x225A: _state.VarLenAddress = (_state.VarLenAddress & 0xFF00FF) | (value << 8); + break; //VDA (Variable length data address - Mid) + case 0x225B: + //VDA (Variable length data address - High) + _state.VarLenAddress = (_state.VarLenAddress & 0x00FFFF) | (value << 16); + _state.VarLenCurrentBit = 0; + break; } } void Sa1::CpuRegisterWrite(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2200: - //CCNT (SA-1 CPU Control) - if(!(value & 0x20) && _state.Sa1Reset) { - //Reset the CPU, and sync cycle count - _cpu->Reset(); - _cpu->IncreaseCycleCount(_memoryManager->GetMasterClock() / 2); - } + switch (addr) + { + case 0x2200: + //CCNT (SA-1 CPU Control) + if (!(value & 0x20) && _state.Sa1Reset) + { + //Reset the CPU, and sync cycle count + _cpu->Reset(); + _cpu->IncreaseCycleCount(_memoryManager->GetMasterClock() / 2); + } - _state.Sa1MessageReceived = value & 0x0F; - _state.Sa1NmiRequested = (value & 0x10) != 0; - _state.Sa1Reset = (value & 0x20) != 0; - _state.Sa1Wait = (value & 0x40) != 0; - _state.Sa1IrqRequested = (value & 0x80) != 0; + _state.Sa1MessageReceived = value & 0x0F; + _state.Sa1NmiRequested = (value & 0x10) != 0; + _state.Sa1Reset = (value & 0x20) != 0; + _state.Sa1Wait = (value & 0x40) != 0; + _state.Sa1IrqRequested = (value & 0x80) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x2201: - //SIE (SNES CPU Interrupt Enable) - _state.CpuIrqEnabled = (value & 0x80) != 0; - _state.CharConvIrqEnabled = (value & 0x20) != 0; + case 0x2201: + //SIE (SNES CPU Interrupt Enable) + _state.CpuIrqEnabled = (value & 0x80) != 0; + _state.CharConvIrqEnabled = (value & 0x20) != 0; - ProcessInterrupts(); - break; + ProcessInterrupts(); + break; - case 0x2202: - //SIC (SNES CPU Interrupt Clear) - if(value & 0x80) { - _state.CpuIrqRequested = false; - } - if(value & 0x20) { - _state.CharConvIrqFlag = false; - } - ProcessInterrupts(); - break; + case 0x2202: + //SIC (SNES CPU Interrupt Clear) + if (value & 0x80) + { + _state.CpuIrqRequested = false; + } + if (value & 0x20) + { + _state.CharConvIrqFlag = false; + } + ProcessInterrupts(); + break; - case 0x2203: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF00) | value; break; //CRV (SA-1 Reset Vector - Low) - case 0x2204: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF) | (value << 8); break; //CRV (SA-1 Reset Vector - High) + case 0x2203: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF00) | value; + break; //CRV (SA-1 Reset Vector - Low) + case 0x2204: _state.Sa1ResetVector = (_state.Sa1ResetVector & 0xFF) | (value << 8); + break; //CRV (SA-1 Reset Vector - High) - case 0x2205: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF00) | value; break; //CRV (SA-1 NMI Vector - Low) - case 0x2206: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF) | (value << 8); break; //CRV (SA-1 NMI Vector - High) + case 0x2205: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF00) | value; + break; //CRV (SA-1 NMI Vector - Low) + case 0x2206: _state.Sa1NmiVector = (_state.Sa1NmiVector & 0xFF) | (value << 8); + break; //CRV (SA-1 NMI Vector - High) - case 0x2207: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF00) | value; break; //CRV (SA-1 IRQ Vector - Low) - case 0x2208: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF) | (value << 8); break; //CRV (SA-1 IRQ Vector - High) + case 0x2207: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF00) | value; + break; //CRV (SA-1 IRQ Vector - Low) + case 0x2208: _state.Sa1IrqVector = (_state.Sa1IrqVector & 0xFF) | (value << 8); + break; //CRV (SA-1 IRQ Vector - High) - case 0x2220: UpdateBank(0, value); break; //CXB (MMC Bank C) - case 0x2221: UpdateBank(1, value); break; //DXB (MMC Bank D) - case 0x2222: UpdateBank(2, value); break; //EXB (MMC Bank E) - case 0x2223: UpdateBank(3, value); break; //FXB (MMC Bank F) + case 0x2220: UpdateBank(0, value); + break; //CXB (MMC Bank C) + case 0x2221: UpdateBank(1, value); + break; //DXB (MMC Bank D) + case 0x2222: UpdateBank(2, value); + break; //EXB (MMC Bank E) + case 0x2223: UpdateBank(3, value); + break; //FXB (MMC Bank F) - case 0x2224: - //BMAPS (SNES CPU BW-RAM Address Mapping) - if(_state.CpuBwBank != (value & 0x1F)) { - _state.CpuBwBank = value & 0x1F; - UpdateSaveRamMappings(); - } - break; + case 0x2224: + //BMAPS (SNES CPU BW-RAM Address Mapping) + if (_state.CpuBwBank != (value & 0x1F)) + { + _state.CpuBwBank = value & 0x1F; + UpdateSaveRamMappings(); + } + break; - case 0x2226: _state.CpuBwWriteEnabled = (value & 0x80) != 0; break; //SBWE (SNES CPU BW-RAM Write Enable) - - case 0x2228: _state.BwWriteProtectedArea = (value & 0x0F); break; //BWPA (SNES CPU BW-RAM Write Protected Area) + case 0x2226: _state.CpuBwWriteEnabled = (value & 0x80) != 0; + break; //SBWE (SNES CPU BW-RAM Write Enable) - case 0x2229: _state.CpuIRamWriteProtect = value; break; //SIWP (SNES CPU I-RAM Write Protection) + case 0x2228: _state.BwWriteProtectedArea = (value & 0x0F); + break; //BWPA (SNES CPU BW-RAM Write Protected Area) - case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: - WriteSharedRegisters(addr, value); - break; + case 0x2229: _state.CpuIRamWriteProtect = value; + break; //SIWP (SNES CPU I-RAM Write Protection) + + case 0x2231: + case 0x2232: + case 0x2233: + case 0x2234: + case 0x2235: + case 0x2236: + case 0x2237: + WriteSharedRegisters(addr, value); + break; } } void Sa1::WriteSharedRegisters(uint16_t addr, uint8_t value) { - switch(addr) { - case 0x2231: - //CDMA (Character conversion DMA parameters) (Shared with SNES CPU) - _state.CharConvFormat = std::min(value & 0x03, 2); - switch(_state.CharConvFormat) { - case 0: _state.CharConvBpp = 8; break; - case 1: _state.CharConvBpp = 4; break; - case 2: _state.CharConvBpp = 2; break; - } - _state.CharConvWidth = std::min((value & 0x1C) >> 2, 5); - - if(value & 0x80) { - //End of character conversion type 1 - _state.CharConvDmaActive = false; - } + switch (addr) + { + case 0x2231: + //CDMA (Character conversion DMA parameters) (Shared with SNES CPU) + _state.CharConvFormat = std::min(value & 0x03, 2); + switch (_state.CharConvFormat) + { + case 0: _state.CharConvBpp = 8; break; - - case 0x2232: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFFFF00) | value; break; //SDA (DMA source start address - Low) (Shared with SNES CPU) - case 0x2233: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFF00FF) | (value << 8); break; //SDA (DMA source start address - Mid) (Shared with SNES CPU) - case 0x2234: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0x00FFFF) | (value << 16); break; //SDA (DMA source start address - High) (Shared with SNES CPU) - - case 0x2235: _state.DmaDestAddr = (_state.DmaDestAddr & 0xFFFF00) | value; break; //DDA (DMA dest start address - Low) (Shared with SNES CPU) - case 0x2236: - //DDA (DMA dest start address - Mid) (Shared with SNES CPU) - _state.DmaDestAddr = (_state.DmaDestAddr & 0xFF00FF) | (value << 8); - if(_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) { - _state.DmaRunning = true; - } else if(_state.DmaCharConv && _state.DmaCharConvAuto) { - _state.CharConvDmaActive = true; - _state.CharConvIrqFlag = true; - ProcessInterrupts(); - } - break; - - case 0x2237: - //DDA (DMA dest start address - High) (Shared with SNES CPU) - _state.DmaDestAddr = (_state.DmaDestAddr & 0x00FFFF) | (value << 16); - if(_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) { - _state.DmaRunning = true; - } + case 1: _state.CharConvBpp = 4; break; + case 2: _state.CharConvBpp = 2; + break; + } + _state.CharConvWidth = std::min((value & 0x1C) >> 2, 5); + + if (value & 0x80) + { + //End of character conversion type 1 + _state.CharConvDmaActive = false; + } + break; + + case 0x2232: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFFFF00) | value; + break; //SDA (DMA source start address - Low) (Shared with SNES CPU) + case 0x2233: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0xFF00FF) | (value << 8); + break; //SDA (DMA source start address - Mid) (Shared with SNES CPU) + case 0x2234: _state.DmaSrcAddr = (_state.DmaSrcAddr & 0x00FFFF) | (value << 16); + break; //SDA (DMA source start address - High) (Shared with SNES CPU) + + case 0x2235: _state.DmaDestAddr = (_state.DmaDestAddr & 0xFFFF00) | value; + break; //DDA (DMA dest start address - Low) (Shared with SNES CPU) + case 0x2236: + //DDA (DMA dest start address - Mid) (Shared with SNES CPU) + _state.DmaDestAddr = (_state.DmaDestAddr & 0xFF00FF) | (value << 8); + if (_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) + { + _state.DmaRunning = true; + } + else if (_state.DmaCharConv && _state.DmaCharConvAuto) + { + _state.CharConvDmaActive = true; + _state.CharConvIrqFlag = true; + ProcessInterrupts(); + } + break; + + case 0x2237: + //DDA (DMA dest start address - High) (Shared with SNES CPU) + _state.DmaDestAddr = (_state.DmaDestAddr & 0x00FFFF) | (value << 16); + if (_state.DmaEnabled && !_state.DmaCharConv && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) + { + _state.DmaRunning = true; + } + break; } } uint8_t Sa1::Sa1RegisterRead(uint16_t addr) { - switch(addr) { - case 0x2301: - //CFR (SA-1 Status Flags) - return ( - _state.Sa1MessageReceived | - (_state.Sa1NmiRequested << 4) | - (_state.DmaIrqFlag << 5) | - //TODO: Timer irq flag - (_state.Sa1IrqRequested << 7) - ); - - case 0x2302: break; //HCR (SA-1 H Counter read - Low) - case 0x2303: break; //HCR (SA-1 H Counter read - High) - - case 0x2304: break; //VCR (SA-1 V Counter read - Low) - case 0x2305: break; //VCR (SA-1 V Counter read - High) - - case 0x2306: return _state.MathOpResult & 0xFF; //MR (Arithmetic result) - case 0x2307: return (_state.MathOpResult >> 8) & 0xFF; //MR (Arithmetic result) - case 0x2308: return (_state.MathOpResult >> 16) & 0xFF; break; //MR (Arithmetic result) - case 0x2309: return (_state.MathOpResult >> 24) & 0xFF; break; //MR (Arithmetic result) - case 0x230A: return (_state.MathOpResult >> 32) & 0xFF; break; //MR (Arithmetic result) + switch (addr) + { + case 0x2301: + //CFR (SA-1 Status Flags) + return ( + _state.Sa1MessageReceived | + (_state.Sa1NmiRequested << 4) | + (_state.DmaIrqFlag << 5) | + //TODO: Timer irq flag + (_state.Sa1IrqRequested << 7) + ); - case 0x230B: return _state.MathOverflow; break; //OF (Arithmetic overflow flag) + case 0x2302: break; //HCR (SA-1 H Counter read - Low) + case 0x2303: break; //HCR (SA-1 H Counter read - High) - case 0x230C: { + case 0x2304: break; //VCR (SA-1 V Counter read - Low) + case 0x2305: break; //VCR (SA-1 V Counter read - High) + + case 0x2306: return _state.MathOpResult & 0xFF; //MR (Arithmetic result) + case 0x2307: return (_state.MathOpResult >> 8) & 0xFF; //MR (Arithmetic result) + case 0x2308: return (_state.MathOpResult >> 16) & 0xFF; + break; //MR (Arithmetic result) + case 0x2309: return (_state.MathOpResult >> 24) & 0xFF; + break; //MR (Arithmetic result) + case 0x230A: return (_state.MathOpResult >> 32) & 0xFF; + break; //MR (Arithmetic result) + + case 0x230B: return _state.MathOverflow; + break; //OF (Arithmetic overflow flag) + + case 0x230C: + { //VDP (Variable length data port - Low) - uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1(_state.VarLenAddress + 2) << 16); + uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1( + _state.VarLenAddress + 2) << 16); return data >> _state.VarLenCurrentBit; } - case 0x230D: { + case 0x230D: + { //VDP (Variable length data port - High) - uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1(_state.VarLenAddress + 2) << 16); + uint32_t data = ReadSa1(_state.VarLenAddress) | (ReadSa1(_state.VarLenAddress + 1) << 8) | (ReadSa1( + _state.VarLenAddress + 2) << 16); uint8_t value = data >> (_state.VarLenCurrentBit + 8); - if(_state.VarLenAutoInc) { + if (_state.VarLenAutoInc) + { IncVarLenPosition(); } return value; @@ -399,18 +502,19 @@ uint8_t Sa1::Sa1RegisterRead(uint16_t addr) uint8_t Sa1::CpuRegisterRead(uint16_t addr) { - switch(addr) { - case 0x2300: - //SFR (SNES CPU Status Flags) - return ( - _state.CpuMessageReceived | - (_state.UseCpuNmiVector << 4) | - (_state.CharConvIrqFlag << 5) | - (_state.UseCpuIrqVector << 6) | - (_state.CpuIrqRequested << 7) - ); + switch (addr) + { + case 0x2300: + //SFR (SNES CPU Status Flags) + return ( + _state.CpuMessageReceived | + (_state.UseCpuNmiVector << 4) | + (_state.CharConvIrqFlag << 5) | + (_state.UseCpuIrqVector << 6) | + (_state.CpuIrqRequested << 7) + ); - case 0x230E: break; //VC (Version code register) + case 0x230E: break; //VC (Version code register) } LogDebug("[Debug] CPU - missing register: $" + HexUtilities::ToHex(addr)); @@ -420,43 +524,55 @@ uint8_t Sa1::CpuRegisterRead(uint16_t addr) void Sa1::ProcessInterrupts() { - if((_state.Sa1IrqRequested && _state.Sa1IrqEnabled) || (_state.DmaIrqFlag && _state.DmaIrqEnabled)) { + if ((_state.Sa1IrqRequested && _state.Sa1IrqEnabled) || (_state.DmaIrqFlag && _state.DmaIrqEnabled)) + { _cpu->SetIrqSource(IrqSource::Coprocessor); - } else { + } + else + { _cpu->ClearIrqSource(IrqSource::Coprocessor); } _cpu->SetNmiFlag(_state.Sa1NmiRequested && _state.Sa1NmiEnabled); - if((_state.CpuIrqRequested && _state.CpuIrqEnabled) || (_state.CharConvIrqFlag && _state.CharConvIrqEnabled)) { + if ((_state.CpuIrqRequested && _state.CpuIrqEnabled) || (_state.CharConvIrqFlag && _state.CharConvIrqEnabled)) + { _snesCpu->SetIrqSource(IrqSource::Coprocessor); - } else { + } + else + { _snesCpu->ClearIrqSource(IrqSource::Coprocessor); } } void Sa1::WriteSa1(uint32_t addr, uint8_t value, MemoryOperationType type) { - IMemoryHandler *handler = _mappings.GetHandler(addr); + IMemoryHandler* handler = _mappings.GetHandler(addr); _console->ProcessMemoryWrite(addr, value, type); - if(handler) { + if (handler) + { _lastAccessMemType = handler->GetMemoryType(); _openBus = value; handler->Write(addr, value); - } else { + } + else + { LogDebug("[Debug] Write SA1 - missing handler: $" + HexUtilities::ToHex(addr)); } } uint8_t Sa1::ReadSa1(uint32_t addr, MemoryOperationType type) { - IMemoryHandler *handler = _mappings.GetHandler(addr); + IMemoryHandler* handler = _mappings.GetHandler(addr); uint8_t value; - if(handler) { + if (handler) + { value = handler->Read(addr); _lastAccessMemType = handler->GetMemoryType(); _openBus = value; - } else { + } + else + { value = _openBus; LogDebug("[Debug] Read SA1 - missing handler: $" + HexUtilities::ToHex(addr)); } @@ -475,7 +591,7 @@ uint8_t Sa1::Peek(uint32_t addr) return 0; } -void Sa1::PeekBlock(uint32_t addr, uint8_t *output) +void Sa1::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } @@ -487,19 +603,25 @@ void Sa1::Write(uint32_t addr, uint8_t value) AddressInfo Sa1::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void Sa1::Run() { uint64_t targetCycle = _memoryManager->GetMasterClock() / 2; - while(_cpu->GetCycleCount() < targetCycle) { - if(_state.Sa1Wait || _state.Sa1Reset) { + while (_cpu->GetCycleCount() < targetCycle) + { + if (_state.Sa1Wait || _state.Sa1Reset) + { _cpu->IncreaseCycleCount<1>(); - } else if(_state.DmaRunning) { + } + else if (_state.DmaRunning) + { RunDma(); - } else { + } + else + { _cpu->Exec(); } } @@ -517,45 +639,64 @@ void Sa1::WriteBwRam(uint32_t addr, uint8_t value) void Sa1::RunDma() { - if(_state.DmaSize > 0) { + if (_state.DmaSize > 0) + { _state.DmaSize--; - - if(_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) { + + if (_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::PrgRom || GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::PrgRom || GetSnesCpuMemoryType() == + SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); } } WriteInternalRam(_state.DmaDestAddr, ReadSa1(_state.DmaSrcAddr)); - } else if(_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) { + } + else if (_state.DmaSrcDevice == Sa1DmaSrcDevice::PrgRom && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) + { _cpu->IncreaseCycleCount<2>(); - - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) { + + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) + { _cpu->IncreaseCycleCount<2>(); } WriteBwRam(_state.DmaDestAddr, ReadSa1(_state.DmaSrcAddr)); - } else if(_state.DmaSrcDevice == Sa1DmaSrcDevice::BwRam && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) { + } + else if (_state.DmaSrcDevice == Sa1DmaSrcDevice::BwRam && _state.DmaDestDevice == Sa1DmaDestDevice::InternalRam) + { _cpu->IncreaseCycleCount<2>(); - - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == + SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) + { _cpu->IncreaseCycleCount<1>(); } } - WriteInternalRam(_state.DmaDestAddr, _cart->DebugGetSaveRam()[_state.DmaSrcAddr & (_cart->DebugGetSaveRamSize() - 1)]); - } else if(_state.DmaSrcDevice == Sa1DmaSrcDevice::InternalRam && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) { + WriteInternalRam(_state.DmaDestAddr, + _cart->DebugGetSaveRam()[_state.DmaSrcAddr & (_cart->DebugGetSaveRamSize() - 1)]); + } + else if (_state.DmaSrcDevice == Sa1DmaSrcDevice::InternalRam && _state.DmaDestDevice == Sa1DmaDestDevice::BwRam) + { _cpu->IncreaseCycleCount<2>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == SnesMemoryType::Sa1InternalRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam || GetSnesCpuMemoryType() == + SnesMemoryType::Sa1InternalRam) + { _cpu->IncreaseCycleCount<1>(); - if(GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) { + if (GetSnesCpuMemoryType() == SnesMemoryType::SaveRam) + { _cpu->IncreaseCycleCount<1>(); } } @@ -567,7 +708,8 @@ void Sa1::RunDma() _state.DmaDestAddr++; } - if(_state.DmaSize == 0) { + if (_state.DmaSize == 0) + { _state.DmaRunning = false; _state.DmaIrqFlag = true; ProcessInterrupts(); @@ -576,7 +718,8 @@ void Sa1::RunDma() void Sa1::UpdateBank(uint8_t index, uint8_t value) { - if(_state.Banks[index] != value) { + if (_state.Banks[index] != value) + { _state.Banks[index] = value; UpdatePrgRomMappings(); } @@ -584,15 +727,20 @@ void Sa1::UpdateBank(uint8_t index, uint8_t value) void Sa1::UpdatePrgRomMappings() { - vector> &prgRomHandlers = _cart->GetPrgRomHandlers(); + vector>& prgRomHandlers = _cart->GetPrgRomHandlers(); MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { MemoryMappings* mappings = i == 0 ? &_mappings : cpuMappings; - mappings->RegisterHandler(0x00, 0x1F, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[0] & 0x80) ? (_state.Banks[0] & 0x07) * 256 : 0); - mappings->RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[1] & 0x80) ? (_state.Banks[1] & 0x07) * 256 : 256); - mappings->RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[2] & 0x80) ? (_state.Banks[2] & 0x07) * 256 : 512); - mappings->RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[3] & 0x80) ? (_state.Banks[3] & 0x07) * 256 : 768); + mappings->RegisterHandler(0x00, 0x1F, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[0] & 0x80) ? (_state.Banks[0] & 0x07) * 256 : 0); + mappings->RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[1] & 0x80) ? (_state.Banks[1] & 0x07) * 256 : 256); + mappings->RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[2] & 0x80) ? (_state.Banks[2] & 0x07) * 256 : 512); + mappings->RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, prgRomHandlers, 0, + (_state.Banks[3] & 0x80) ? (_state.Banks[3] & 0x07) * 256 : 768); mappings->RegisterHandler(0xC0, 0xCF, 0x0000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[0] & 0x07) * 256); mappings->RegisterHandler(0xD0, 0xDF, 0x0000, 0xFFFF, prgRomHandlers, 0, (_state.Banks[1] & 0x07) * 256); @@ -612,12 +760,14 @@ void Sa1::UpdateVectorMappings() void Sa1::UpdateSaveRamMappings() { - vector> &saveRamHandlers = _cart->GetSaveRamHandlers(); - if(saveRamHandlers.size() > 0) { + vector>& saveRamHandlers = _cart->GetSaveRamHandlers(); + if (saveRamHandlers.size() > 0) + { MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); uint32_t bank1 = (_state.CpuBwBank * 2) % saveRamHandlers.size(); uint32_t bank2 = (_state.CpuBwBank * 2 + 1) % saveRamHandlers.size(); - for(int i = 0; i <= 0x3F; i++) { + for (int i = 0; i <= 0x3F; i++) + { //S-CPU: 00-3F:6000-7FFF + 80-BF:6000-7FFF cpuMappings->RegisterHandler(i, i, 0x6000, 0x6FFF, saveRamHandlers[bank1].get()); cpuMappings->RegisterHandler(i, i, 0x7000, 0x7FFF, saveRamHandlers[bank2].get()); @@ -636,27 +786,38 @@ void Sa1::IncVarLenPosition() void Sa1::CalculateMathOpResult() { - if((int)_state.MathOp & (int)Sa1MathOp::Sum) { - uint64_t result = _state.MathOpResult + ((int16_t)_state.MultiplicandDividend * (int16_t)_state.MultiplierDivisor); + if ((int)_state.MathOp & (int)Sa1MathOp::Sum) + { + uint64_t result = _state.MathOpResult + ((int16_t)_state.MultiplicandDividend * (int16_t)_state.MultiplierDivisor + ); _state.MathOverflow = (result >> 33) & 0x80; - + //Keep 40 bits _state.MathOpResult = result & 0xFFFFFFFFFF; _state.MultiplierDivisor = 0; - } else { - if(_state.MathOp == Sa1MathOp::Mul) { + } + else + { + if (_state.MathOp == Sa1MathOp::Mul) + { _state.MathOpResult = (uint32_t)((int16_t)_state.MultiplicandDividend * (int16_t)_state.MultiplierDivisor); //"The value in this register gets destroyed after both multiplication and division." _state.MultiplierDivisor = 0; - } else { - if(_state.MultiplierDivisor == 0) { + } + else + { + if (_state.MultiplierDivisor == 0) + { //Division by 0 returns 0, remainder 0 _state.MathOpResult = 0; - } else { + } + else + { int16_t dividend = _state.MultiplicandDividend; uint16_t remainder = dividend % _state.MultiplierDivisor; - if(dividend < 0) { + if (dividend < 0) + { remainder += _state.MultiplierDivisor; } uint16_t result = (dividend - remainder) / _state.MultiplierDivisor; @@ -675,8 +836,9 @@ void Sa1::CalculateMathOpResult() uint8_t Sa1::ReadCharConvertType1(uint32_t addr) { uint8_t mask = (_state.CharConvBpp * 8) - 1; - - if((addr & mask) == 0) { + + if ((addr & mask) == 0) + { //Trying to read the first byte of a new tile, convert it and write its contents to IRAM uint8_t* bwRam = _cart->DebugGetSaveRam(); uint32_t bwRamMask = _cart->DebugGetSaveRamSize() - 1; @@ -688,25 +850,30 @@ uint8_t Sa1::ReadCharConvertType1(uint32_t addr) uint32_t tileY = (tileNumber >> _state.CharConvWidth); uint32_t srcAddr = _state.DmaSrcAddr + tileY * 8 * bytesPerLine + tileX * _state.CharConvBpp; - for(int y = 0; y < 8; y++) { + for (int y = 0; y < 8; y++) + { //For each row, get the original pixels (in a packed format, 4 pixels per byte in 2bpp, 2 pixels per byte in 4bpp, etc.) uint64_t data = 0; - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { data |= (uint64_t)bwRam[(srcAddr + i) & bwRamMask] << (i * 8); } srcAddr += bytesPerLine; uint8_t result[8] = {}; - for(int x = 0; x < 8; x++) { + for (int x = 0; x < 8; x++) + { //For each column (pixels in the tile), convert to VRAM format - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { result[i] |= (data & 0x01) << (7 - x); data >>= 1; } } //Copy all converted bytes to IRAM (in PPU VRAM format) - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { uint8_t offset = (y << 1) + ((i >> 1) << 4) + (i & 0x01); _iRam[(_state.DmaDestAddr + offset) & 0x7FF] = result[i]; } @@ -726,10 +893,12 @@ void Sa1::RunCharConvertType2() dest += (_state.CharConvCounter & 0x08) * _state.CharConvBpp; //number of bytes per tile row //Convert 1 pixel per byte format (no matter BPP) to VRAM format - for(int i = 0; i < _state.CharConvBpp; i++) { + for (int i = 0; i < _state.CharConvBpp; i++) + { //For each bitplane, grab the matching bit for all 8 pixels and convert to VRAM format uint8_t value = 0; - for(int j = 0; j < 8; j++) { + for (int j = 0; j < 8; j++) + { value |= ((bmpRegs[j] >> i) & 0x01) << (7 - j); } @@ -799,10 +968,11 @@ CpuState Sa1::GetCpuState() uint16_t Sa1::ReadVector(uint16_t vector) { - switch(vector) { - case Sa1Cpu::NmiVector: return _state.Sa1NmiVector; - case Sa1Cpu::ResetVector: return _state.Sa1ResetVector; - case Sa1Cpu::IrqVector: return _state.Sa1IrqVector; + switch (vector) + { + case Sa1Cpu::NmiVector: return _state.Sa1NmiVector; + case Sa1Cpu::ResetVector: return _state.Sa1ResetVector; + case Sa1Cpu::IrqVector: return _state.Sa1IrqVector; } //BRK/COP vectors are taken from ROM @@ -818,7 +988,8 @@ MemoryMappings* Sa1::GetMemoryMappings() void Sa1::LoadBattery() { - if(_cpuBwRamHandlers.empty()) { + if (_cpuBwRamHandlers.empty()) + { //When there is no actual save RAM and the battery flag is set, IRAM is backed up instead //Used by Pachi-Slot Monogatari - PAL Kougyou Special _console->GetBatteryManager()->LoadBattery(".srm", _iRam, Sa1::InternalRamSize); @@ -827,25 +998,34 @@ void Sa1::LoadBattery() void Sa1::SaveBattery() { - if(_cpuBwRamHandlers.empty()) { + if (_cpuBwRamHandlers.empty()) + { _console->GetBatteryManager()->SaveBattery(".srm", _iRam, Sa1::InternalRamSize); } } -void Sa1::Serialize(Serializer &s) +void Sa1::Serialize(Serializer& s) { s.Stream(_cpu.get()); s.Stream( - _state.Sa1ResetVector, _state.Sa1IrqVector, _state.Sa1NmiVector, _state.Sa1IrqRequested, _state.Sa1IrqEnabled, _state.Sa1NmiRequested, _state.Sa1NmiEnabled, - _state.Sa1Wait, _state.Sa1Reset, _state.DmaIrqEnabled, _state.TimerIrqEnabled, _state.Sa1MessageReceived, _state.CpuMessageReceived, _state.CpuIrqVector, - _state.CpuNmiVector, _state.UseCpuIrqVector, _state.UseCpuNmiVector, _state.CpuIrqRequested, _state.CpuIrqEnabled, _state.CharConvIrqFlag, _state.CharConvIrqEnabled, - _state.CpuBwBank, _state.CpuBwWriteEnabled, _state.Sa1BwBank, _state.Sa1BwMode, _state.Sa1BwWriteEnabled, _state.BwWriteProtectedArea, _state.BwRam2BppMode, - _state.CpuIRamWriteProtect, _state.Sa1IRamWriteProtect, _state.DmaSrcAddr, _state.DmaDestAddr, _state.DmaSize, _state.DmaEnabled, _state.DmaPriority, - _state.DmaCharConv, _state.DmaCharConvAuto, _state.DmaDestDevice, _state.DmaSrcDevice, _state.DmaRunning, _state.DmaIrqFlag, _state.HorizontalTimerEnabled, - _state.VerticalTimerEnabled, _state.UseLinearTimer, _state.HTimer, _state.VTimer, _state.LinearTimerValue, _state.MathOp, _state.MultiplicandDividend, - _state.MultiplierDivisor, _state.MathOpResult, _state.MathOverflow, _state.VarLenAutoInc, _state.VarLenBitCount, _state.VarLenAddress, + _state.Sa1ResetVector, _state.Sa1IrqVector, _state.Sa1NmiVector, _state.Sa1IrqRequested, _state.Sa1IrqEnabled, + _state.Sa1NmiRequested, _state.Sa1NmiEnabled, + _state.Sa1Wait, _state.Sa1Reset, _state.DmaIrqEnabled, _state.TimerIrqEnabled, _state.Sa1MessageReceived, + _state.CpuMessageReceived, _state.CpuIrqVector, + _state.CpuNmiVector, _state.UseCpuIrqVector, _state.UseCpuNmiVector, _state.CpuIrqRequested, _state.CpuIrqEnabled, + _state.CharConvIrqFlag, _state.CharConvIrqEnabled, + _state.CpuBwBank, _state.CpuBwWriteEnabled, _state.Sa1BwBank, _state.Sa1BwMode, _state.Sa1BwWriteEnabled, + _state.BwWriteProtectedArea, _state.BwRam2BppMode, + _state.CpuIRamWriteProtect, _state.Sa1IRamWriteProtect, _state.DmaSrcAddr, _state.DmaDestAddr, _state.DmaSize, + _state.DmaEnabled, _state.DmaPriority, + _state.DmaCharConv, _state.DmaCharConvAuto, _state.DmaDestDevice, _state.DmaSrcDevice, _state.DmaRunning, + _state.DmaIrqFlag, _state.HorizontalTimerEnabled, + _state.VerticalTimerEnabled, _state.UseLinearTimer, _state.HTimer, _state.VTimer, _state.LinearTimerValue, + _state.MathOp, _state.MultiplicandDividend, + _state.MultiplierDivisor, _state.MathOpResult, _state.MathOverflow, _state.VarLenAutoInc, _state.VarLenBitCount, + _state.VarLenAddress, _state.Banks[0], _state.Banks[1], _state.Banks[2], _state.Banks[3], _state.BitmapRegister1[0], _state.BitmapRegister1[1], _state.BitmapRegister1[2], _state.BitmapRegister1[3], _state.BitmapRegister1[4], _state.BitmapRegister1[5], _state.BitmapRegister1[6], _state.BitmapRegister1[7], @@ -858,7 +1038,8 @@ void Sa1::Serialize(Serializer &s) s.Stream(_lastAccessMemType, _openBus); s.StreamArray(_iRam, Sa1::InternalRamSize); - if(!s.IsSaving()) { + if (!s.IsSaving()) + { UpdatePrgRomMappings(); UpdateSaveRamMappings(); ProcessInterrupts(); diff --git a/Core/Sa1.h b/Core/Sa1.h index e709d48..415b8fd 100644 --- a/Core/Sa1.h +++ b/Core/Sa1.h @@ -26,18 +26,18 @@ private: Sa1State _state = {}; uint8_t* _iRam; - + SnesMemoryType _lastAccessMemType; uint8_t _openBus; unique_ptr _iRamHandler; unique_ptr _bwRamHandler; unique_ptr _cpuVectorHandler; - + vector> _cpuBwRamHandlers; MemoryMappings _mappings; - + void UpdateBank(uint8_t index, uint8_t value); void UpdatePrgRomMappings(); void UpdateVectorMappings(); @@ -46,7 +46,7 @@ private: void IncVarLenPosition(); void CalculateMathOpResult(); void RunCharConvertType2(); - + void ProcessInterrupts(); void RunDma(); @@ -61,7 +61,7 @@ private: public: Sa1(Console* console); virtual ~Sa1(); - + void WriteSa1(uint32_t addr, uint8_t value, MemoryOperationType type); uint8_t ReadSa1(uint32_t addr, MemoryOperationType type = MemoryOperationType::Read); @@ -71,13 +71,13 @@ public: uint8_t ReadCharConvertType1(uint32_t addr); // Inherited via BaseCoprocessor - void Serialize(Serializer & s) override; + void Serialize(Serializer& s) override; uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; - void PeekBlock(uint32_t addr, uint8_t *output) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - + void Run() override; void Reset() override; diff --git a/Core/Sa1BwRamHandler.h b/Core/Sa1BwRamHandler.h index ac6ae5c..bb80d84 100644 --- a/Core/Sa1BwRamHandler.h +++ b/Core/Sa1BwRamHandler.h @@ -11,7 +11,7 @@ class Sa1BwRamHandler : public IMemoryHandler { private: - uint8_t * _ram; + uint8_t* _ram; uint32_t _mask; Sa1State* _state; @@ -22,14 +22,20 @@ private: __forceinline uint8_t InternalRead(uint32_t addr) { - if((addr & 0x600000) == 0x600000) { + if ((addr & 0x600000) == 0x600000) + { return ReadBitmapMode(addr - 0x600000); - } else { + } + else + { addr = GetBwRamAddress(addr); - if(_state->Sa1BwMode) { + if (_state->Sa1BwMode) + { //Bitmap mode is enabled return ReadBitmapMode(addr); - } else { + } + else + { //Return regular memory content return _ram[addr & _mask]; } @@ -54,22 +60,29 @@ public: return InternalRead(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = InternalRead(addr + i); } } void Write(uint32_t addr, uint8_t value) override { - if((addr & 0x600000) == 0x600000) { + if ((addr & 0x600000) == 0x600000) + { WriteBitmapMode(addr - 0x600000, value); - } else { + } + else + { addr = GetBwRamAddress(addr); - if(_state->Sa1BwMode) { + if (_state->Sa1BwMode) + { WriteBitmapMode(addr, value); - } else { + } + else + { _ram[addr & _mask] = value; } } @@ -77,20 +90,26 @@ public: uint8_t ReadBitmapMode(uint32_t addr) { - if(_state->BwRam2BppMode) { + if (_state->BwRam2BppMode) + { return (_ram[(addr >> 2) & _mask] >> ((addr & 0x03) * 2)) & 0x03; - } else { + } + else + { return (_ram[(addr >> 1) & _mask] >> ((addr & 0x01) * 4)) & 0x0F; } } void WriteBitmapMode(uint32_t addr, uint8_t value) { - if(_state->BwRam2BppMode) { + if (_state->BwRam2BppMode) + { uint8_t shift = (addr & 0x03) * 2; addr = (addr >> 2) & _mask; _ram[addr] = (_ram[addr] & ~(0x03 << shift)) | ((value & 0x03) << shift); - } else { + } + else + { uint8_t shift = (addr & 0x01) * 4; addr = (addr >> 1) & _mask; _ram[addr] = (_ram[addr] & ~(0x0F << shift)) | ((value & 0x0F) << shift); @@ -100,12 +119,15 @@ public: AddressInfo GetAbsoluteAddress(uint32_t addr) override { AddressInfo info; - if((addr & 0x600000) == 0x600000) { + if ((addr & 0x600000) == 0x600000) + { info.Address = ((addr - 0x600000) >> (_state->BwRam2BppMode ? 2 : 1)) & _mask; - } else { + } + else + { info.Address = GetBwRamAddress(addr) & _mask; } info.Type = SnesMemoryType::SaveRam; return info; } -}; \ No newline at end of file +}; diff --git a/Core/Sa1Cpu.cpp b/Core/Sa1Cpu.cpp index 27b3b18..70d8746 100644 --- a/Core/Sa1Cpu.cpp +++ b/Core/Sa1Cpu.cpp @@ -27,30 +27,36 @@ void Sa1Cpu::Exec() { _immediateMode = false; - switch(_state.StopState) { - case CpuStopState::Running: RunOp(); break; - case CpuStopState::Stopped: - //STP was executed, CPU no longer executes any code - _state.CycleCount++; - return; + switch (_state.StopState) + { + case CpuStopState::Running: RunOp(); + break; + case CpuStopState::Stopped: + //STP was executed, CPU no longer executes any code + _state.CycleCount++; + return; - case CpuStopState::WaitingForIrq: - //WAI + case CpuStopState::WaitingForIrq: + //WAI + Idle(); + if (_state.IrqSource || _state.NeedNmi) + { Idle(); - if(_state.IrqSource || _state.NeedNmi) { - Idle(); - _state.StopState = CpuStopState::Running; - } - break; + _state.StopState = CpuStopState::Running; + } + break; } //Use the state of the IRQ/NMI flags on the previous cycle to determine if an IRQ is processed or not - if(_state.PrevNeedNmi) { + if (_state.PrevNeedNmi) + { _state.NeedNmi = false; uint32_t originalPc = GetProgramAddress(_state.PC); ProcessInterrupt(_state.EmulationMode ? Sa1Cpu::LegacyNmiVector : Sa1Cpu::NmiVector, true); _console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true); - } else if(_state.PrevIrqSource) { + } + else if (_state.PrevIrqSource) + { uint32_t originalPc = GetProgramAddress(_state.PC); ProcessInterrupt(_state.EmulationMode ? Sa1Cpu::LegacyIrqVector : Sa1Cpu::IrqVector, true); _console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false); @@ -68,10 +74,12 @@ void Sa1Cpu::Idle() void Sa1Cpu::IdleEndJump() { IMemoryHandler* handler = _sa1->GetMemoryMappings()->GetHandler(_state.PC); - if(handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) { + if (handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) + { //Jumps/returns in PRG ROM take an extra cycle _state.CycleCount++; - if(_sa1->GetSnesCpuMemoryType() == SnesMemoryType::PrgRom) { + if (_sa1->GetSnesCpuMemoryType() == SnesMemoryType::PrgRom) + { //Add an extra wait cycle if a conflict occurs at the same time _state.CycleCount++; } @@ -80,9 +88,11 @@ void Sa1Cpu::IdleEndJump() void Sa1Cpu::IdleTakeBranch() { - if(_state.PC & 0x01) { + if (_state.PC & 0x01) + { IMemoryHandler* handler = _sa1->GetMemoryMappings()->GetHandler(_state.PC); - if(handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) { + if (handler && handler->GetMemoryType() == SnesMemoryType::PrgRom) + { //Branches to an odd address take an extra cycle _state.CycleCount++; } @@ -91,23 +101,29 @@ void Sa1Cpu::IdleTakeBranch() bool Sa1Cpu::IsAccessConflict() { - return _sa1->GetSnesCpuMemoryType() == _sa1->GetSa1MemoryType() && _sa1->GetSa1MemoryType() != SnesMemoryType::Register; + return _sa1->GetSnesCpuMemoryType() == _sa1->GetSa1MemoryType() && _sa1->GetSa1MemoryType() != + SnesMemoryType::Register; } void Sa1Cpu::ProcessCpuCycle(uint32_t addr) { _state.CycleCount++; - if(_sa1->GetSa1MemoryType() == SnesMemoryType::SaveRam) { + if (_sa1->GetSa1MemoryType() == SnesMemoryType::SaveRam) + { //BWRAM (save ram) access takes 2 cycles _state.CycleCount++; - if(IsAccessConflict()) { + if (IsAccessConflict()) + { _state.CycleCount += 2; } - } else if(IsAccessConflict()) { + } + else if (IsAccessConflict()) + { //Add a wait cycle when a conflict occurs between both CPUs _state.CycleCount++; - if(_sa1->GetSa1MemoryType() == SnesMemoryType::Sa1InternalRam && _sa1->IsSnesCpuFastRomSpeed()) { + if (_sa1->GetSa1MemoryType() == SnesMemoryType::Sa1InternalRam && _sa1->IsSnesCpuFastRomSpeed()) + { //If it's an IRAM access during FastROM access (speed = 6), add another wait cycle _state.CycleCount++; } @@ -146,42 +162,52 @@ void Sa1Cpu::IncreaseCycleCount(uint64_t cycleCount) void Sa1Cpu::SetReg(CpuRegister reg, uint16_t value) { - switch (reg) { + switch (reg) + { case CpuRegister::CpuRegA: - { - _state.A = value; - } break; + { + _state.A = value; + } + break; case CpuRegister::CpuRegX: - { - _state.X = value; - } break; + { + _state.X = value; + } + break; case CpuRegister::CpuRegY: - { - _state.Y = value; - } break; + { + _state.Y = value; + } + break; case CpuRegister::CpuRegSP: - { - _state.SP = value; - } break; + { + _state.SP = value; + } + break; case CpuRegister::CpuRegD: - { - _state.D = value; - } break; + { + _state.D = value; + } + break; case CpuRegister::CpuRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case CpuRegister::CpuRegK: - { - _state.K = value & 0xFF; - } break; + { + _state.K = value & 0xFF; + } + break; case CpuRegister::CpuRegDBR: - { - _state.DBR = value & 0xFF; - } break; + { + _state.DBR = value & 0xFF; + } + break; case CpuRegister::CpuRegPS: - { - _state.PS = value & 0xFF; - } break; + { + _state.PS = value & 0xFF; + } + break; } } diff --git a/Core/Sa1Cpu.h b/Core/Sa1Cpu.h index d8c6d1c..df32b92 100644 --- a/Core/Sa1Cpu.h +++ b/Core/Sa1Cpu.h @@ -65,8 +65,8 @@ private: void SetSP(uint16_t sp); void SetPS(uint8_t ps); - void SetRegister(uint8_t ®, uint8_t value); - void SetRegister(uint16_t ®, uint16_t value, bool eightBitMode); + void SetRegister(uint8_t& reg, uint8_t value); + void SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode); void SetZeroNegativeFlags(uint16_t value); void SetZeroNegativeFlags(uint8_t value); @@ -140,7 +140,7 @@ private: void DEC_Acc(); void INC_Acc(); - void IncDecReg(uint16_t & reg, int8_t offset); + void IncDecReg(uint16_t& reg, int8_t offset); void IncDec(int8_t offset); //Compare instructions @@ -168,10 +168,14 @@ private: void EOR(); void ORA(); - template T ShiftLeft(T value); - template T RollLeft(T value); - template T ShiftRight(T value); - template T RollRight(T value); + template + T ShiftLeft(T value); + template + T RollLeft(T value); + template + T ShiftRight(T value); + template + T RollRight(T value); //Shift operations void ASL_Acc(); @@ -207,10 +211,10 @@ private: void PLY(); void PushRegister(uint16_t reg, bool eightBitMode); - void PullRegister(uint16_t ®, bool eightBitMode); + void PullRegister(uint16_t& reg, bool eightBitMode); //Store/load instructions - void LoadRegister(uint16_t ®, bool eightBitMode); + void LoadRegister(uint16_t& reg, bool eightBitMode); void StoreRegister(uint16_t val, bool eightBitMode); void LDA(); @@ -223,7 +227,8 @@ private: void STZ(); //Test bits - template void TestBits(T value, bool alterZeroFlagOnly); + template + void TestBits(T value, bool alterZeroFlagOnly); void BIT(); void TRB(); @@ -311,7 +316,7 @@ private: void RunOp(); public: - Sa1Cpu(Sa1 *sa1, Console* console); + Sa1Cpu(Sa1* sa1, Console* console); virtual ~Sa1Cpu(); void PowerOn(); @@ -322,7 +327,7 @@ public: CpuState GetState(); uint64_t GetCycleCount(); - template + template void IncreaseCycleCount(); void SetNmiFlag(bool nmiFlag); @@ -333,12 +338,12 @@ public: void IncreaseCycleCount(uint64_t cycleCount); // Inherited via ISerializable - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(CpuRegister reg, uint16_t value); }; -template +template void Sa1Cpu::IncreaseCycleCount() { _state.CycleCount += count; diff --git a/Core/Sa1IRamHandler.h b/Core/Sa1IRamHandler.h index bf7eec8..6da8e15 100644 --- a/Core/Sa1IRamHandler.h +++ b/Core/Sa1IRamHandler.h @@ -6,19 +6,22 @@ class Sa1IRamHandler : public IMemoryHandler { private: - uint8_t * _ram; + uint8_t* _ram; __forceinline uint8_t InternalRead(uint32_t addr) { - if(addr & 0x800) { + if (addr & 0x800) + { return 0; - } else { + } + else + { return _ram[addr & 0x7FF]; } } public: - Sa1IRamHandler(uint8_t *ram) : IMemoryHandler(SnesMemoryType::Sa1InternalRam) + Sa1IRamHandler(uint8_t* ram) : IMemoryHandler(SnesMemoryType::Sa1InternalRam) { _ram = ram; } @@ -33,16 +36,18 @@ public: return InternalRead(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { - for(int i = 0; i < 0x1000; i++) { + for (int i = 0; i < 0x1000; i++) + { output[i] = InternalRead(i); } } void Write(uint32_t addr, uint8_t value) override { - if(!(addr & 0x800)) { + if (!(addr & 0x800)) + { _ram[addr & 0x7FF] = value; } } @@ -50,13 +55,16 @@ public: AddressInfo GetAbsoluteAddress(uint32_t addr) override { AddressInfo info; - if(addr & 0x800) { + if (addr & 0x800) + { info.Address = -1; info.Type = SnesMemoryType::CpuMemory; - } else { + } + else + { info.Address = (addr & 0x7FF); info.Type = _memoryType; } return info; } -}; \ No newline at end of file +}; diff --git a/Core/Sa1Types.h b/Core/Sa1Types.h index b9106f1..34e69bd 100644 --- a/Core/Sa1Types.h +++ b/Core/Sa1Types.h @@ -112,4 +112,4 @@ struct DebugSa1State { CpuState Cpu; Sa1State Sa1; -}; \ No newline at end of file +}; diff --git a/Core/Sa1VectorHandler.h b/Core/Sa1VectorHandler.h index 5422885..d82a449 100644 --- a/Core/Sa1VectorHandler.h +++ b/Core/Sa1VectorHandler.h @@ -7,7 +7,7 @@ class Sa1VectorHandler : public IMemoryHandler { private: - IMemoryHandler * _handler; + IMemoryHandler* _handler; Sa1State* _state; public: @@ -19,19 +19,28 @@ public: uint8_t Read(uint32_t addr) override { - if(addr >= Sa1Cpu::NmiVector && addr <= Sa1Cpu::ResetVector + 1) { + if (addr >= Sa1Cpu::NmiVector && addr <= Sa1Cpu::ResetVector + 1) + { //Override the regular handlers - if(_state->UseCpuNmiVector) { - if(addr == Sa1Cpu::NmiVector) { + if (_state->UseCpuNmiVector) + { + if (addr == Sa1Cpu::NmiVector) + { return (uint8_t)_state->CpuNmiVector; - } else if(addr == Sa1Cpu::NmiVector + 1) { + } + else if (addr == Sa1Cpu::NmiVector + 1) + { return (uint8_t)(_state->CpuNmiVector >> 8); } } - if(_state->UseCpuIrqVector) { - if(addr == Sa1Cpu::IrqVector) { + if (_state->UseCpuIrqVector) + { + if (addr == Sa1Cpu::IrqVector) + { return (uint8_t)_state->CpuIrqVector; - } else if(addr == Sa1Cpu::IrqVector + 1) { + } + else if (addr == Sa1Cpu::IrqVector + 1) + { return (uint8_t)(_state->CpuIrqVector >> 8); } } @@ -45,7 +54,7 @@ public: return Read(addr); } - void PeekBlock(uint32_t addr, uint8_t *output) override + void PeekBlock(uint32_t addr, uint8_t* output) override { _handler->PeekBlock(addr, output); } @@ -59,4 +68,4 @@ public: { return _handler->GetAbsoluteAddress(address); } -}; \ No newline at end of file +}; diff --git a/Core/SaveStateManager.cpp b/Core/SaveStateManager.cpp index 84c6c6c..8dd8cc0 100644 --- a/Core/SaveStateManager.cpp +++ b/Core/SaveStateManager.cpp @@ -58,7 +58,7 @@ bool SaveStateManager::LoadState() return LoadState(_lastIndex); } -void SaveStateManager::GetSaveStateHeader(ostream &stream) +void SaveStateManager::GetSaveStateHeader(ostream& stream) { uint32_t emuVersion = _console->GetSettings()->GetVersion(); uint32_t formatVersion = SaveStateManager::FileFormatVersion; @@ -72,9 +72,9 @@ void SaveStateManager::GetSaveStateHeader(ostream &stream) bool isGameboyMode = _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode); stream.write((char*)&isGameboyMode, sizeof(bool)); - #ifndef LIBRETRO +#ifndef LIBRETRO SaveScreenshotData(stream); - #endif +#endif RomInfo romInfo = _console->GetCartridge()->GetRomInfo(); string romName = FolderUtilities::GetFilename(romInfo.RomFile.GetFileName(), true); @@ -83,7 +83,7 @@ void SaveStateManager::GetSaveStateHeader(ostream &stream) stream.write(romName.c_str(), romName.size()); } -void SaveStateManager::SaveState(ostream &stream) +void SaveStateManager::SaveState(ostream& stream) { GetSaveStateHeader(stream); _console->Serialize(stream); @@ -93,14 +93,16 @@ bool SaveStateManager::SaveState(string filepath) { ofstream file(filepath, ios::out | ios::binary); - if(file) { + if (file) + { _console->Lock(); SaveState(file); _console->Unlock(); file.close(); shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->ProcessEvent(EventType::StateSaved); } return true; @@ -111,8 +113,10 @@ bool SaveStateManager::SaveState(string filepath) void SaveStateManager::SaveState(int stateIndex, bool displayMessage) { string filepath = SaveStateManager::GetStateFilepath(stateIndex); - if(SaveState(filepath)) { - if(displayMessage) { + if (SaveState(filepath)) + { + if (displayMessage) + { MessageManager::DisplayMessage("SaveStates", "SaveStateSaved", std::to_string(stateIndex)); } } @@ -127,16 +131,17 @@ void SaveStateManager::SaveScreenshotData(ostream& stream) stream.write((char*)&width, sizeof(uint32_t)); stream.write((char*)&height, sizeof(uint32_t)); - unsigned long compressedSize = compressBound(512*478*2); + unsigned long compressedSize = compressBound(512 * 478 * 2); vector compressedData(compressedSize, 0); - compress2(compressedData.data(), &compressedSize, (const unsigned char*)_console->GetPpu()->GetScreenBuffer(), width*height*2, MZ_DEFAULT_LEVEL); + compress2(compressedData.data(), &compressedSize, (const unsigned char*)_console->GetPpu()->GetScreenBuffer(), + width * height * 2, MZ_DEFAULT_LEVEL); uint32_t screenshotLength = (uint32_t)compressedSize; stream.write((char*)&screenshotLength, sizeof(uint32_t)); stream.write((char*)compressedData.data(), screenshotLength); } -bool SaveStateManager::GetScreenshotData(vector& out, uint32_t &width, uint32_t &height, istream& stream) +bool SaveStateManager::GetScreenshotData(vector& out, uint32_t& width, uint32_t& height, istream& stream) { stream.read((char*)&width, sizeof(uint32_t)); stream.read((char*)&height, sizeof(uint32_t)); @@ -149,67 +154,80 @@ bool SaveStateManager::GetScreenshotData(vector& out, uint32_t &width, out = vector(width * height * 2, 0); unsigned long decompSize = width * height * 2; - if(uncompress(out.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size()) == MZ_OK) { + if (uncompress(out.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size()) == MZ_OK) + { return true; } return false; } -bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired) +bool SaveStateManager::LoadState(istream& stream, bool hashCheckRequired) { - if(GameClient::Connected()) { + if (GameClient::Connected()) + { MessageManager::DisplayMessage("Netplay", "NetplayNotAllowed"); return false; } char header[3]; stream.read(header, 3); - if(memcmp(header, "MSS", 3) == 0) { + if (memcmp(header, "MSS", 3) == 0) + { uint32_t emuVersion, fileFormatVersion; stream.read((char*)&emuVersion, sizeof(emuVersion)); - if(emuVersion > _console->GetSettings()->GetVersion()) { + if (emuVersion > _console->GetSettings()->GetVersion()) + { MessageManager::DisplayMessage("SaveStates", "SaveStateNewerVersion"); return false; } stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion)); - if(fileFormatVersion <= 5) { + if (fileFormatVersion <= 5) + { MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion"); return false; - } else { + } + else + { char hash[41] = {}; stream.read(hash, 40); - if(fileFormatVersion >= 8) { + if (fileFormatVersion >= 8) + { bool isGameboyMode = false; stream.read((char*)&isGameboyMode, sizeof(bool)); - if(isGameboyMode != _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) { - MessageManager::DisplayMessage("SaveStates", isGameboyMode ? "SaveStateWrongSystemGb" : "SaveStateWrongSystemSnes"); + if (isGameboyMode != _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) + { + MessageManager::DisplayMessage("SaveStates", + isGameboyMode ? "SaveStateWrongSystemGb" : "SaveStateWrongSystemSnes"); return false; } - } - - if(fileFormatVersion >= 7) { - #ifndef LIBRETRO + } + + if (fileFormatVersion >= 7) + { +#ifndef LIBRETRO vector frameData; uint32_t width = 0; uint32_t height = 0; - if(GetScreenshotData(frameData, width, height, stream)) { + if (GetScreenshotData(frameData, width, height, stream)) + { _console->GetVideoDecoder()->UpdateFrameSync((uint16_t*)frameData.data(), width, height, 0, true); } - #endif +#endif } uint32_t nameLength = 0; stream.read((char*)&nameLength, sizeof(uint32_t)); - + vector nameBuffer(nameLength); stream.read(nameBuffer.data(), nameBuffer.size()); string romName(nameBuffer.data(), nameLength); - + shared_ptr cartridge = _console->GetCartridge(); - if(!cartridge /*|| cartridge->GetSha1Hash() != string(hash)*/) { + if (!cartridge /*|| cartridge->GetSha1Hash() != string(hash)*/) + { //Game isn't loaded, or CRC doesn't match //TODO: Try to find and load the game return false; @@ -233,19 +251,24 @@ bool SaveStateManager::LoadState(string filepath, bool hashCheckRequired) ifstream file(filepath, ios::in | ios::binary); bool result = false; - if(file.good()) { + if (file.good()) + { _console->Lock(); result = LoadState(file, hashCheckRequired); _console->Unlock(); file.close(); - if(result) { + if (result) + { shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->ProcessEvent(EventType::StateLoaded); } } - } else { + } + else + { MessageManager::DisplayMessage("SaveStates", "SaveStateEmpty"); } @@ -255,7 +278,8 @@ bool SaveStateManager::LoadState(string filepath, bool hashCheckRequired) bool SaveStateManager::LoadState(int stateIndex) { string filepath = SaveStateManager::GetStateFilepath(stateIndex); - if(LoadState(filepath, false)) { + if (LoadState(filepath, false)) + { MessageManager::DisplayMessage("SaveStates", "SaveStateLoaded", std::to_string(stateIndex)); return true; } @@ -302,13 +326,18 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame) std::getline(romInfoStream, patchPath); _console->Lock(); - try { - if(_console->LoadRom(romPath, patchPath)) { - if(!resetGame) { + try + { + if (_console->LoadRom(romPath, patchPath)) + { + if (!resetGame) + { SaveStateManager::LoadState(stateStream, false); } } - } catch(std::exception&) { + } + catch (std::exception&) + { _console->Stop(true); } _console->Unlock(); @@ -318,23 +347,27 @@ int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* png { ifstream stream(saveStatePath, ios::binary); - if(!stream) { + if (!stream) + { return -1; } char header[3]; stream.read(header, 3); - if(memcmp(header, "MSS", 3) == 0) { + if (memcmp(header, "MSS", 3) == 0) + { uint32_t emuVersion = 0; stream.read((char*)&emuVersion, sizeof(emuVersion)); - if(emuVersion > _console->GetSettings()->GetVersion()) { + if (emuVersion > _console->GetSettings()->GetVersion()) + { return -1; } uint32_t fileFormatVersion = 0; stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion)); - if(fileFormatVersion <= 6) { + if (fileFormatVersion <= 6) + { return -1; } @@ -344,11 +377,12 @@ int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* png vector frameData; uint32_t width = 0; uint32_t height = 0; - if(GetScreenshotData(frameData, width, height, stream)) { + if (GetScreenshotData(frameData, width, height, stream)) + { FrameInfo baseFrameInfo; baseFrameInfo.Width = width; baseFrameInfo.Height = height; - + DefaultVideoFilter filter(_console); filter.SetBaseFrameInfo(baseFrameInfo); FrameInfo frameInfo = filter.GetFrameInfo(); @@ -364,4 +398,4 @@ int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* png } } return -1; -} \ No newline at end of file +} diff --git a/Core/SaveStateManager.h b/Core/SaveStateManager.h index fcb9f40..9d0a387 100644 --- a/Core/SaveStateManager.h +++ b/Core/SaveStateManager.h @@ -11,7 +11,7 @@ private: atomic _lastIndex; shared_ptr _console; - string GetStateFilepath(int stateIndex); + string GetStateFilepath(int stateIndex); void SaveScreenshotData(ostream& stream); bool GetScreenshotData(vector& out, uint32_t& width, uint32_t& height, istream& stream); @@ -23,12 +23,12 @@ public: void SaveState(); bool LoadState(); - void GetSaveStateHeader(ostream & stream); + void GetSaveStateHeader(ostream& stream); - void SaveState(ostream &stream); + void SaveState(ostream& stream); bool SaveState(string filepath); void SaveState(int stateIndex, bool displayMessage = true); - bool LoadState(istream &stream, bool hashCheckRequired = true); + bool LoadState(istream& stream, bool hashCheckRequired = true); bool LoadState(string filepath, bool hashCheckRequired = true); bool LoadState(int stateIndex); @@ -40,4 +40,4 @@ public: void SelectSaveSlot(int slotIndex); void MoveToNextSlot(); void MoveToPreviousSlot(); -}; \ No newline at end of file +}; diff --git a/Core/SaveStateMessage.h b/Core/SaveStateMessage.h index bc6e4e3..76ef655 100644 --- a/Core/SaveStateMessage.h +++ b/Core/SaveStateMessage.h @@ -11,7 +11,7 @@ class SaveStateMessage : public NetMessage private: vector _activeCheats; vector _stateData; - + ControllerType _controllerTypes[5]; ConsoleRegion _region; uint32_t _ppuExtraScanlinesAfterNmi; @@ -19,7 +19,7 @@ private: uint32_t _gsuClockSpeed; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.StreamVector(_stateData); s.Stream(_region, _ppuExtraScanlinesAfterNmi, _ppuExtraScanlinesBeforeNmi, _gsuClockSpeed); @@ -28,8 +28,10 @@ protected: } public: - SaveStateMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } - + SaveStateMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } + SaveStateMessage(shared_ptr console) : NetMessage(MessageType::SaveState) { //Used when sending state to clients @@ -45,7 +47,8 @@ public: _gsuClockSpeed = emuCfg.GsuClockSpeed; InputConfig inputCfg = console->GetSettings()->GetInputConfig(); - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { _controllerTypes[i] = inputCfg.Controllers[i].Type; } @@ -55,7 +58,7 @@ public: _stateData.resize(dataSize); state.read((char*)_stateData.data(), dataSize); } - + void LoadState(shared_ptr console) { std::stringstream ss; @@ -71,11 +74,12 @@ public: emuCfg.GsuClockSpeed = _gsuClockSpeed; InputConfig inputCfg = console->GetSettings()->GetInputConfig(); - for(int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { inputCfg.Controllers[i].Type = _controllerTypes[i]; } console->GetSettings()->SetEmulationConfig(emuCfg); console->GetSettings()->SetInputConfig(inputCfg); } -}; \ No newline at end of file +}; diff --git a/Core/ScaleFilter.cpp b/Core/ScaleFilter.cpp index 7b19303..90a66e4 100644 --- a/Core/ScaleFilter.cpp +++ b/Core/ScaleFilter.cpp @@ -12,7 +12,8 @@ ScaleFilter::ScaleFilter(ScaleFilterType scaleFilterType, uint32_t scale) _scaleFilterType = scaleFilterType; _filterScale = scale; - if(!_hqxInitDone && _scaleFilterType == ScaleFilterType::HQX) { + if (!_hqxInitDone && _scaleFilterType == ScaleFilterType::HQX) + { hqxInit(); _hqxInitDone = true; } @@ -28,60 +29,82 @@ uint32_t ScaleFilter::GetScale() return _filterScale; } -void ScaleFilter::ApplyPrescaleFilter(uint32_t *inputArgbBuffer) +void ScaleFilter::ApplyPrescaleFilter(uint32_t* inputArgbBuffer) { uint32_t* outputBuffer = _outputBuffer; - for(uint32_t y = 0; y < _height; y++) { - for(uint32_t x = 0; x < _width; x++) { - for(uint32_t i = 0; i < _filterScale; i++) { + for (uint32_t y = 0; y < _height; y++) + { + for (uint32_t x = 0; x < _width; x++) + { + for (uint32_t i = 0; i < _filterScale; i++) + { *(outputBuffer++) = *inputArgbBuffer; } inputArgbBuffer++; } - for(uint32_t i = 1; i < _filterScale; i++) { - memcpy(outputBuffer, outputBuffer - _width*_filterScale, _width*_filterScale *4); - outputBuffer += _width*_filterScale; + for (uint32_t i = 1; i < _filterScale; i++) + { + memcpy(outputBuffer, outputBuffer - _width * _filterScale, _width * _filterScale * 4); + outputBuffer += _width * _filterScale; } } } void ScaleFilter::UpdateOutputBuffer(uint32_t width, uint32_t height) { - if(!_outputBuffer || width != _width || height != _height) { + if (!_outputBuffer || width != _width || height != _height) + { delete[] _outputBuffer; _width = width; _height = height; - _outputBuffer = new uint32_t[_width*_height*_filterScale*_filterScale]; + _outputBuffer = new uint32_t[_width * _height * _filterScale * _filterScale]; } } -uint32_t* ScaleFilter::ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity) +uint32_t* ScaleFilter::ApplyFilter(uint32_t* inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity) { UpdateOutputBuffer(width, height); - if(_scaleFilterType == ScaleFilterType::xBRZ) { + if (_scaleFilterType == ScaleFilterType::xBRZ) + { xbrz::scale(_filterScale, inputArgbBuffer, _outputBuffer, width, height, xbrz::ColorFormat::ARGB); - } else if(_scaleFilterType == ScaleFilterType::HQX) { + } + else if (_scaleFilterType == ScaleFilterType::HQX) + { hqx(_filterScale, inputArgbBuffer, _outputBuffer, width, height); - } else if(_scaleFilterType == ScaleFilterType::Scale2x) { - scale(_filterScale, _outputBuffer, width*sizeof(uint32_t)*_filterScale, inputArgbBuffer, width*sizeof(uint32_t), 4, width, height); - } else if(_scaleFilterType == ScaleFilterType::_2xSai) { + } + else if (_scaleFilterType == ScaleFilterType::Scale2x) + { + scale(_filterScale, _outputBuffer, width * sizeof(uint32_t) * _filterScale, inputArgbBuffer, + width * sizeof(uint32_t), 4, width, height); + } + else if (_scaleFilterType == ScaleFilterType::_2xSai) + { twoxsai_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale); - } else if(_scaleFilterType == ScaleFilterType::Super2xSai) { + } + else if (_scaleFilterType == ScaleFilterType::Super2xSai) + { supertwoxsai_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale); - } else if(_scaleFilterType == ScaleFilterType::SuperEagle) { + } + else if (_scaleFilterType == ScaleFilterType::SuperEagle) + { supereagle_generic_xrgb8888(width, height, inputArgbBuffer, width, _outputBuffer, width * _filterScale); - } else if(_scaleFilterType == ScaleFilterType::Prescale) { + } + else if (_scaleFilterType == ScaleFilterType::Prescale) + { ApplyPrescaleFilter(inputArgbBuffer); } scanlineIntensity = 1.0 - scanlineIntensity; - if(scanlineIntensity < 1.0) { - for(int y = 1, yMax = height * _filterScale; y < yMax; y += 2) { - for(int x = 0, xMax = width * _filterScale; x < xMax; x++) { - uint32_t &color = _outputBuffer[y*xMax + x]; + if (scanlineIntensity < 1.0) + { + for (int y = 1, yMax = height * _filterScale; y < yMax; y += 2) + { + for (int x = 0, xMax = width * _filterScale; x < xMax; x++) + { + uint32_t& color = _outputBuffer[y * xMax + x]; uint8_t r = (color >> 16) & 0xFF, g = (color >> 8) & 0xFF, b = color & 0xFF; r = (uint8_t)(r * scanlineIntensity); g = (uint8_t)(g * scanlineIntensity); @@ -97,32 +120,53 @@ uint32_t* ScaleFilter::ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, ui shared_ptr ScaleFilter::GetScaleFilter(VideoFilterType filter) { shared_ptr scaleFilter; - switch(filter) { - case VideoFilterType::NTSC: - case VideoFilterType::None: - break; + switch (filter) + { + case VideoFilterType::NTSC: + case VideoFilterType::None: + break; - case VideoFilterType::xBRZ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 2)); break; - case VideoFilterType::xBRZ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 3)); break; - case VideoFilterType::xBRZ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 4)); break; - case VideoFilterType::xBRZ5x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 5)); break; - case VideoFilterType::xBRZ6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 6)); break; - case VideoFilterType::HQ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 2)); break; - case VideoFilterType::HQ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 3)); break; - case VideoFilterType::HQ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 4)); break; - case VideoFilterType::Scale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 2)); break; - case VideoFilterType::Scale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 3)); break; - case VideoFilterType::Scale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 4)); break; - case VideoFilterType::_2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::_2xSai, 2)); break; - case VideoFilterType::Super2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Super2xSai, 2)); break; - case VideoFilterType::SuperEagle: scaleFilter.reset(new ScaleFilter(ScaleFilterType::SuperEagle, 2)); break; + case VideoFilterType::xBRZ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 2)); + break; + case VideoFilterType::xBRZ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 3)); + break; + case VideoFilterType::xBRZ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 4)); + break; + case VideoFilterType::xBRZ5x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 5)); + break; + case VideoFilterType::xBRZ6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::xBRZ, 6)); + break; + case VideoFilterType::HQ2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 2)); + break; + case VideoFilterType::HQ3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 3)); + break; + case VideoFilterType::HQ4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::HQX, 4)); + break; + case VideoFilterType::Scale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 2)); + break; + case VideoFilterType::Scale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 3)); + break; + case VideoFilterType::Scale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Scale2x, 4)); + break; + case VideoFilterType::_2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::_2xSai, 2)); + break; + case VideoFilterType::Super2xSai: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Super2xSai, 2)); + break; + case VideoFilterType::SuperEagle: scaleFilter.reset(new ScaleFilter(ScaleFilterType::SuperEagle, 2)); + break; - case VideoFilterType::Prescale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 2)); break; - case VideoFilterType::Prescale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 3)); break; - case VideoFilterType::Prescale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 4)); break; - case VideoFilterType::Prescale6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 6)); break; - case VideoFilterType::Prescale8x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 8)); break; - case VideoFilterType::Prescale10x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 10)); break; + case VideoFilterType::Prescale2x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 2)); + break; + case VideoFilterType::Prescale3x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 3)); + break; + case VideoFilterType::Prescale4x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 4)); + break; + case VideoFilterType::Prescale6x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 6)); + break; + case VideoFilterType::Prescale8x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 8)); + break; + case VideoFilterType::Prescale10x: scaleFilter.reset(new ScaleFilter(ScaleFilterType::Prescale, 10)); + break; } return scaleFilter; } @@ -133,4 +177,4 @@ FrameInfo ScaleFilter::GetFrameInfo(FrameInfo baseFrameInfo) info.Height *= this->GetScale(); info.Width *= this->GetScale(); return info; -} \ No newline at end of file +} diff --git a/Core/ScaleFilter.h b/Core/ScaleFilter.h index d53de67..a102234 100644 --- a/Core/ScaleFilter.h +++ b/Core/ScaleFilter.h @@ -9,11 +9,11 @@ private: static bool _hqxInitDone; uint32_t _filterScale; ScaleFilterType _scaleFilterType; - uint32_t *_outputBuffer = nullptr; + uint32_t* _outputBuffer = nullptr; uint32_t _width = 0; uint32_t _height = 0; - void ApplyPrescaleFilter(uint32_t *inputArgbBuffer); + void ApplyPrescaleFilter(uint32_t* inputArgbBuffer); void UpdateOutputBuffer(uint32_t width, uint32_t height); public: @@ -21,8 +21,8 @@ public: ~ScaleFilter(); uint32_t GetScale(); - uint32_t* ApplyFilter(uint32_t *inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity); + uint32_t* ApplyFilter(uint32_t* inputArgbBuffer, uint32_t width, uint32_t height, double scanlineIntensity); FrameInfo GetFrameInfo(FrameInfo baseFrameInfo); static shared_ptr GetScaleFilter(VideoFilterType filter); -}; \ No newline at end of file +}; diff --git a/Core/ScriptHost.cpp b/Core/ScriptHost.cpp index 4e9e3c9..7d551b4 100644 --- a/Core/ScriptHost.cpp +++ b/Core/ScriptHost.cpp @@ -26,7 +26,8 @@ bool ScriptHost::LoadScript(string scriptName, string scriptContent, Debugger* d { #ifndef LIBRETRO _context.reset(new LuaScriptingContext(debugger)); - if(!_context->LoadScript(scriptName, scriptContent, debugger)) { + if (!_context->LoadScript(scriptName, scriptContent, debugger)) + { return false; } return true; @@ -35,28 +36,35 @@ bool ScriptHost::LoadScript(string scriptName, string scriptContent, Debugger* d #endif } -void ScriptHost::ProcessMemoryOperation(uint32_t addr, uint8_t &value, MemoryOperationType type, CpuType cpuType) +void ScriptHost::ProcessMemoryOperation(uint32_t addr, uint8_t& value, MemoryOperationType type, CpuType cpuType) { - if(_context) { - switch(type) { - case MemoryOperationType::Read: _context->CallMemoryCallback(addr, value, CallbackType::CpuRead, cpuType); break; - case MemoryOperationType::Write: _context->CallMemoryCallback(addr, value, CallbackType::CpuWrite, cpuType); break; - case MemoryOperationType::ExecOpCode: _context->CallMemoryCallback(addr, value, CallbackType::CpuExec, cpuType); break; - default: break; + if (_context) + { + switch (type) + { + case MemoryOperationType::Read: _context->CallMemoryCallback(addr, value, CallbackType::CpuRead, cpuType); + break; + case MemoryOperationType::Write: _context->CallMemoryCallback(addr, value, CallbackType::CpuWrite, cpuType); + break; + case MemoryOperationType::ExecOpCode: _context->CallMemoryCallback(addr, value, CallbackType::CpuExec, cpuType); + break; + default: break; } } } void ScriptHost::ProcessEvent(EventType eventType) { - if(_context) { + if (_context) + { _context->CallEventCallback(eventType); } } bool ScriptHost::ProcessSavestate() { - if(_context) { + if (_context) + { return _context->ProcessSavestate(); } return false; @@ -64,7 +72,8 @@ bool ScriptHost::ProcessSavestate() bool ScriptHost::CheckStateLoadedFlag() { - if(_context) { + if (_context) + { return _context->CheckStateLoadedFlag(); } return false; diff --git a/Core/ScriptHost.h b/Core/ScriptHost.h index ce52c89..2b96c74 100644 --- a/Core/ScriptHost.h +++ b/Core/ScriptHost.h @@ -20,9 +20,9 @@ public: bool LoadScript(string scriptName, string scriptContent, Debugger* debugger); - void ProcessMemoryOperation(uint32_t addr, uint8_t &value, MemoryOperationType type, CpuType cpuType); + void ProcessMemoryOperation(uint32_t addr, uint8_t& value, MemoryOperationType type, CpuType cpuType); void ProcessEvent(EventType eventType); bool ProcessSavestate(); bool CheckStateLoadedFlag(); -}; \ No newline at end of file +}; diff --git a/Core/ScriptManager.cpp b/Core/ScriptManager.cpp index c330d9c..099108e 100644 --- a/Core/ScriptManager.cpp +++ b/Core/ScriptManager.cpp @@ -19,17 +19,22 @@ int ScriptManager::LoadScript(string name, string content, int32_t scriptId) DebugBreakHelper helper(_debugger); auto lock = _scriptLock.AcquireSafe(); - if(scriptId < 0) { + if (scriptId < 0) + { shared_ptr script(new ScriptHost(_nextScriptId++)); script->LoadScript(name, content, _debugger); _scripts.push_back(script); _hasScript = true; return script->GetScriptId(); - } else { - auto result = std::find_if(_scripts.begin(), _scripts.end(), [=](shared_ptr &script) { + } + else + { + auto result = std::find_if(_scripts.begin(), _scripts.end(), [=](shared_ptr& script) + { return script->GetScriptId() == scriptId; }); - if(result != _scripts.end()) { + if (result != _scripts.end()) + { //Send a ScriptEnded event before reloading the code (*result)->ProcessEvent(EventType::ScriptEnded); @@ -45,8 +50,10 @@ void ScriptManager::RemoveScript(int32_t scriptId) { DebugBreakHelper helper(_debugger); auto lock = _scriptLock.AcquireSafe(); - _scripts.erase(std::remove_if(_scripts.begin(), _scripts.end(), [=](const shared_ptr& script) { - if(script->GetScriptId() == scriptId) { + _scripts.erase(std::remove_if(_scripts.begin(), _scripts.end(), [=](const shared_ptr& script) + { + if (script->GetScriptId() == scriptId) + { //Send a ScriptEnded event before unloading the script script->ProcessEvent(EventType::ScriptEnded); _debugger->GetConsole()->GetDebugHud()->ClearScreen(); @@ -60,8 +67,10 @@ void ScriptManager::RemoveScript(int32_t scriptId) const char* ScriptManager::GetScriptLog(int32_t scriptId) { auto lock = _scriptLock.AcquireSafe(); - for(shared_ptr &script : _scripts) { - if(script->GetScriptId() == scriptId) { + for (shared_ptr& script : _scripts) + { + if (script->GetScriptId() == scriptId) + { return script->GetLog(); } } @@ -70,17 +79,21 @@ const char* ScriptManager::GetScriptLog(int32_t scriptId) void ScriptManager::ProcessEvent(EventType type) { - if(_hasScript) { - for(shared_ptr &script : _scripts) { + if (_hasScript) + { + for (shared_ptr& script : _scripts) + { script->ProcessEvent(type); } } } -void ScriptManager::ProcessMemoryOperation(uint32_t address, uint8_t &value, MemoryOperationType type, CpuType cpuType) +void ScriptManager::ProcessMemoryOperation(uint32_t address, uint8_t& value, MemoryOperationType type, CpuType cpuType) { - if(_hasScript) { - for(shared_ptr &script : _scripts) { + if (_hasScript) + { + for (shared_ptr& script : _scripts) + { script->ProcessMemoryOperation(address, value, type, cpuType); } } diff --git a/Core/ScriptManager.h b/Core/ScriptManager.h index 88c24ef..98511f5 100644 --- a/Core/ScriptManager.h +++ b/Core/ScriptManager.h @@ -11,19 +11,19 @@ enum class MemoryOperationType; class ScriptManager { private: - Debugger *_debugger; + Debugger* _debugger; bool _hasScript; SimpleLock _scriptLock; int _nextScriptId; vector> _scripts; public: - ScriptManager(Debugger *debugger); + ScriptManager(Debugger* debugger); __forceinline bool HasScript() { return _hasScript; } int32_t LoadScript(string name, string content, int32_t scriptId); void RemoveScript(int32_t scriptId); const char* GetScriptLog(int32_t scriptId); void ProcessEvent(EventType type); - void ProcessMemoryOperation(uint32_t address, uint8_t &value, MemoryOperationType type, CpuType cpuType); -}; \ No newline at end of file + void ProcessMemoryOperation(uint32_t address, uint8_t& value, MemoryOperationType type, CpuType cpuType); +}; diff --git a/Core/ScriptingContext.cpp b/Core/ScriptingContext.cpp index f8bc5e4..5b818f2 100644 --- a/Core/ScriptingContext.cpp +++ b/Core/ScriptingContext.cpp @@ -8,7 +8,7 @@ string ScriptingContext::_log = ""; -ScriptingContext::ScriptingContext(Debugger *debugger) +ScriptingContext::ScriptingContext(Debugger* debugger) { _debugger = debugger; } @@ -17,7 +17,8 @@ void ScriptingContext::Log(string message) { auto lock = _logLock.AcquireSafe(); _logRows.push_back(message); - if(_logRows.size() > 500) { + if (_logRows.size() > 500) + { _logRows.pop_front(); } } @@ -26,7 +27,8 @@ const char* ScriptingContext::GetLog() { auto lock = _logLock.AcquireSafe(); stringstream ss; - for(string &msg : _logRows) { + for (string& msg : _logRows) + { ss << msg << "\n"; } _log = ss.str(); @@ -43,7 +45,7 @@ string ScriptingContext::GetScriptName() return _scriptName; } -void ScriptingContext::CallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) +void ScriptingContext::CallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) { _inExecOpEvent = type == CallbackType::CpuExec; InternalCallMemoryCallback(addr, value, type, cpuType); @@ -81,13 +83,16 @@ bool ScriptingContext::CheckStateLoadedFlag() return stateLoaded; } -void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) +void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) { - if(endAddr < startAddr) { + if (endAddr < startAddr) + { return; } - if(startAddr == 0 && endAddr == 0) { + if (startAddr == 0 && endAddr == 0) + { endAddr = 0xFFFFFF; } @@ -99,19 +104,25 @@ void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, _callbacks[(int)type].push_back(callback); } -void ScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference) +void ScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, + int reference) { - if(endAddr < startAddr) { + if (endAddr < startAddr) + { return; } - if(startAddr == 0 && endAddr == 0) { + if (startAddr == 0 && endAddr == 0) + { endAddr = 0xFFFFFF; } - for(size_t i = 0; i < _callbacks[(int)type].size(); i++) { - MemoryCallback &callback = _callbacks[(int)type][i]; - if(callback.Reference == reference && callback.Type == cpuType && (int)callback.StartAddress == startAddr && (int)callback.EndAddress == endAddr) { + for (size_t i = 0; i < _callbacks[(int)type].size(); i++) + { + MemoryCallback& callback = _callbacks[(int)type][i]; + if (callback.Reference == reference && callback.Type == cpuType && (int)callback.StartAddress == startAddr && (int + )callback.EndAddress == endAddr) + { _callbacks[(int)type].erase(_callbacks[(int)type].begin() + i); break; } @@ -125,27 +136,34 @@ void ScriptingContext::RegisterEventCallback(EventType type, int reference) void ScriptingContext::UnregisterEventCallback(EventType type, int reference) { - vector &callbacks = _eventCallbacks[(int)type]; + vector& callbacks = _eventCallbacks[(int)type]; callbacks.erase(std::remove(callbacks.begin(), callbacks.end(), reference), callbacks.end()); } void ScriptingContext::RequestSaveState(int slot) { _saveSlot = slot; - if(_inExecOpEvent) { + if (_inExecOpEvent) + { SaveState(); - } else { + } + else + { _saveSlotData.erase(slot); } } bool ScriptingContext::RequestLoadState(int slot) { - if(_saveSlotData.find(slot) != _saveSlotData.end()) { + if (_saveSlotData.find(slot) != _saveSlotData.end()) + { _loadSlot = slot; - if(_inExecOpEvent) { + if (_inExecOpEvent) + { return LoadState(); - } else { + } + else + { return true; } } @@ -154,7 +172,8 @@ bool ScriptingContext::RequestLoadState(int slot) void ScriptingContext::SaveState() { - if(_saveSlot >= 0) { + if (_saveSlot >= 0) + { stringstream ss; _debugger->GetConsole()->GetSaveStateManager()->SaveState(ss); _saveSlotData[_saveSlot] = ss.str(); @@ -164,12 +183,14 @@ void ScriptingContext::SaveState() bool ScriptingContext::LoadState() { - if(_loadSlot >= 0 && _saveSlotData.find(_loadSlot) != _saveSlotData.end()) { + if (_loadSlot >= 0 && _saveSlotData.find(_loadSlot) != _saveSlotData.end()) + { stringstream ss; ss << _saveSlotData[_loadSlot]; bool result = _debugger->GetConsole()->GetSaveStateManager()->LoadState(ss); _loadSlot = -1; - if(result) { + if (result) + { _stateLoaded = true; } return result; @@ -182,7 +203,8 @@ bool ScriptingContext::LoadState(string stateData) stringstream ss; ss << stateData; bool result = _debugger->GetConsole()->GetSaveStateManager()->LoadState(ss); - if(result) { + if (result) + { _stateLoaded = true; } return result; @@ -196,9 +218,11 @@ bool ScriptingContext::ProcessSavestate() string ScriptingContext::GetSavestateData(int slot) { - if(slot >= 0) { + if (slot >= 0) + { auto result = _saveSlotData.find(slot); - if(result != _saveSlotData.end()) { + if (result != _saveSlotData.end()) + { return result->second; } } @@ -208,7 +232,8 @@ string ScriptingContext::GetSavestateData(int slot) void ScriptingContext::ClearSavestateData(int slot) { - if(slot >= 0) { + if (slot >= 0) + { _saveSlotData.erase(slot); } -} \ No newline at end of file +} diff --git a/Core/ScriptingContext.h b/Core/ScriptingContext.h index 934dda9..7da9ae0 100644 --- a/Core/ScriptingContext.h +++ b/Core/ScriptingContext.h @@ -48,12 +48,16 @@ protected: vector _callbacks[3]; vector _eventCallbacks[(int)EventType::EventTypeSize]; - virtual void InternalCallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType) = 0; + virtual void InternalCallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType) = 0; virtual int InternalCallEventCallback(EventType type) = 0; public: ScriptingContext(Debugger* debugger); - virtual ~ScriptingContext() {} + + virtual ~ScriptingContext() + { + } + virtual bool LoadScript(string scriptName, string scriptContent, Debugger* debugger) = 0; void Log(string message); @@ -71,13 +75,13 @@ public: void ClearSavestateData(int slot); bool ProcessSavestate(); - void CallMemoryCallback(uint32_t addr, uint8_t &value, CallbackType type, CpuType cpuType); + void CallMemoryCallback(uint32_t addr, uint8_t& value, CallbackType type, CpuType cpuType); int CallEventCallback(EventType type); bool CheckInitDone(); bool CheckInStartFrameEvent(); bool CheckInExecOpEvent(); bool CheckStateLoadedFlag(); - + void RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference); virtual void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, CpuType cpuType, int reference); void RegisterEventCallback(EventType type, int reference); diff --git a/Core/Sdd1.cpp b/Core/Sdd1.cpp index 3b15aec..03fb12c 100644 --- a/Core/Sdd1.cpp +++ b/Core/Sdd1.cpp @@ -10,10 +10,10 @@ Sdd1::Sdd1(Console* console) : BaseCoprocessor(SnesMemoryType::Register) { //This handler is used to dynamically map the ROM based on the banking registers _sdd1Mmc.reset(new Sdd1Mmc(_state, console->GetCartridge().get())); - - MemoryMappings *cpuMappings = console->GetMemoryManager()->GetMemoryMappings(); - vector> &prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers(); - vector> &saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers(); + + MemoryMappings* cpuMappings = console->GetMemoryManager()->GetMemoryMappings(); + vector>& prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers(); + vector>& saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers(); //Regular A Bus register handler, keep a reference to it, it'll be overwritten below _cpuRegisterHandler = cpuMappings->GetHandler(0x4000); @@ -52,41 +52,62 @@ void Sdd1::Reset() uint8_t Sdd1::Read(uint32_t addr) { - if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) { - switch(addr & 0x07) { - case 0: return _state.AllowDmaProcessing; - case 1: return _state.ProcessNextDma; + if ((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) + { + switch (addr & 0x07) + { + case 0: return _state.AllowDmaProcessing; + case 1: return _state.ProcessNextDma; - case 4: case 5: case 6: case 7: - return _state.SelectedBanks[addr & 0x03]; + case 4: + case 5: + case 6: + case 7: + return _state.SelectedBanks[addr & 0x03]; } } - + return _cpuRegisterHandler->Read(addr); } void Sdd1::Write(uint32_t addr, uint8_t value) { - if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) { + if ((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) + { //S-DD1 registers - switch(addr & 0x07) { - case 0: _state.AllowDmaProcessing = value; break; - case 1: _state.ProcessNextDma = value; break; + switch (addr & 0x07) + { + case 0: _state.AllowDmaProcessing = value; + break; + case 1: _state.ProcessNextDma = value; + break; - case 4: case 5: case 6: case 7: - _state.SelectedBanks[addr & 0x03] = value; - break; + case 4: + case 5: + case 6: + case 7: + _state.SelectedBanks[addr & 0x03] = value; + break; } - } else { - if((uint16_t)addr >= 0x4300 && (uint16_t)addr <= 0x437A) { + } + else + { + if ((uint16_t)addr >= 0x4300 && (uint16_t)addr <= 0x437A) + { //Keep track of writes to the DMA controller to know which address/length the DMAs will use uint8_t ch = (addr >> 4) & 0x07; - switch(addr & 0x0F) { - case 0x02: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFFFF00) | value; break; - case 0x03: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFF00FF) | (value << 8); break; - case 0x04: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0x00FFFF) | (value << 16); break; - case 0x05: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0xFF00) | value; break; - case 0x06: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0x00FF) | (value << 8); break; + switch (addr & 0x0F) + { + case 0x02: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFFFF00) | value; + break; + case 0x03: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFF00FF) | (value << 8); + break; + case 0x04: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0x00FFFF) | (value << 16); + break; + case 0x05: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0xFF00) | value; + break; + case 0x06: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0x00FF) | (value << 8); + break; } } @@ -95,7 +116,7 @@ void Sdd1::Write(uint32_t addr, uint8_t value) } } -void Sdd1::Serialize(Serializer &s) +void Sdd1::Serialize(Serializer& s) { s.Stream(_state.AllowDmaProcessing, _state.ProcessNextDma, _state.NeedInit); s.StreamArray(_state.DmaAddress, 8); @@ -116,5 +137,5 @@ void Sdd1::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo Sdd1::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } diff --git a/Core/Sdd1.h b/Core/Sdd1.h index b2bc379..c0dea4f 100644 --- a/Core/Sdd1.h +++ b/Core/Sdd1.h @@ -14,13 +14,13 @@ private: IMemoryHandler* _cpuRegisterHandler; public: - Sdd1(Console *console); + Sdd1(Console* console); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; uint8_t Read(uint32_t addr) override; uint8_t Peek(uint32_t addr) override; void PeekBlock(uint32_t addr, uint8_t* output) override; void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; void Reset() override; -}; \ No newline at end of file +}; diff --git a/Core/Sdd1Decomp.cpp b/Core/Sdd1Decomp.cpp index d171cbb..682f593 100644 --- a/Core/Sdd1Decomp.cpp +++ b/Core/Sdd1Decomp.cpp @@ -33,7 +33,7 @@ understood. #include "Sdd1Decomp.h" #include "Sdd1Mmc.h" -void SDD1_IM::prepareDecomp(Sdd1Mmc *mmc, uint32_t readAddr) +void SDD1_IM::prepareDecomp(Sdd1Mmc* mmc, uint32_t readAddr) { _sdd1Mmc = mmc; _readAddr = readAddr; @@ -51,12 +51,14 @@ uint8_t SDD1_IM::getCodeword(uint8_t code_len) ++bit_count; - if(codeword & 0x80) { + if (codeword & 0x80) + { codeword |= _sdd1Mmc->ReadRom(_readAddr + 1) >> (9 - bit_count); bit_count += code_len; } - if(bit_count & 0x08) { + if (bit_count & 0x08) + { _readAddr++; bit_count &= 0x07; } @@ -64,12 +66,12 @@ uint8_t SDD1_IM::getCodeword(uint8_t code_len) return codeword; } -void SDD1_IM::Serialize(Serializer &s) +void SDD1_IM::Serialize(Serializer& s) { s.Stream(_readAddr, bit_count); } -SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) : +SDD1_GCD::SDD1_GCD(SDD1_IM* associatedIM) : IM(associatedIM) { } @@ -77,61 +79,61 @@ SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) : ////////////////////////////////////////////////////// -void SDD1_GCD::getRunCount(uint8_t code_num, uint8_t *MPScount, bool *LPSind) +void SDD1_GCD::getRunCount(uint8_t code_num, uint8_t* MPScount, bool* LPSind) { - const uint8_t run_count[] = { - 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, - 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, - 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, - 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, - 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, - 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, - 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, - 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, - 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, - 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, - 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, - 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, - 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, - 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, - 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, - 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, - 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, - 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, - 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, - 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, - 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, - 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, - 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, - 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, - 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, - 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, - 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, - 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, - 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, - 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, - 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, - 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, + 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, + 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, + 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, + 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, + 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, + 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, + 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, + 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, + 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, + 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, + 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, + 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, + 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, + 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, + 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, + 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, + 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, + 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, + 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, + 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, + 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, + 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, + 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, + 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, + 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, + 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, + 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, + 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, + 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, }; uint8_t codeword = IM->getCodeword(code_num); - if(codeword & 0x80) { + if (codeword & 0x80) + { *LPSind = 1; *MPScount = run_count[codeword >> (code_num ^ 0x07)]; - } else { + } + else + { *MPScount = (1 << code_num); } - } /////////////////////////////////////////////////////// -SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code) : +SDD1_BG::SDD1_BG(SDD1_GCD* associatedGCD, uint8_t code) : code_num(code), GCD(associatedGCD) { - } /////////////////////////////////////////////// @@ -139,38 +141,37 @@ SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code) : void SDD1_BG::prepareDecomp(void) { - MPScount = 0; LPSind = 0; - } ////////////////////////////////////////////// -uint8_t SDD1_BG::getBit(bool *endOfRun) +uint8_t SDD1_BG::getBit(bool* endOfRun) { - uint8_t bit; - if(!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind); + if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind); - if(MPScount) { + if (MPScount) + { bit = 0; MPScount--; - } else { + } + else + { bit = 1; LPSind = 0; } - if(MPScount || LPSind) (*endOfRun) = 0; + if (MPScount || LPSind) (*endOfRun) = 0; else (*endOfRun) = 1; return bit; - } -void SDD1_BG::Serialize(Serializer &s) +void SDD1_BG::Serialize(Serializer& s) { s.Stream(MPScount, LPSind); } @@ -178,12 +179,11 @@ void SDD1_BG::Serialize(Serializer &s) ///////////////////////////////////////////////// -SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, - SDD1_BG *associatedBG2, SDD1_BG *associatedBG3, - SDD1_BG *associatedBG4, SDD1_BG *associatedBG5, - SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) +SDD1_PEM::SDD1_PEM(SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, + SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, + SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, + SDD1_BG* associatedBG6, SDD1_BG* associatedBG7) { - BG[0] = associatedBG0; BG[1] = associatedBG1; BG[2] = associatedBG2; @@ -192,46 +192,45 @@ SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, BG[5] = associatedBG5; BG[6] = associatedBG6; BG[7] = associatedBG7; - } ///////////////////////////////////////////////////////// const SDD1_PEM::state SDD1_PEM::evolution_table[] = { - { 0,25,25}, - { 0, 2, 1}, - { 0, 3, 1}, - { 0, 4, 2}, - { 0, 5, 3}, - { 1, 6, 4}, - { 1, 7, 5}, - { 1, 8, 6}, - { 1, 9, 7}, - { 2,10, 8}, - { 2,11, 9}, - { 2,12,10}, - { 2,13,11}, - { 3,14,12}, - { 3,15,13}, - { 3,16,14}, - { 3,17,15}, - { 4,18,16}, - { 4,19,17}, - { 5,20,18}, - { 5,21,19}, - { 6,22,20}, - { 6,23,21}, - { 7,24,22}, - { 7,24,23}, - { 0,26, 1}, - { 1,27, 2}, - { 2,28, 4}, - { 3,29, 8}, - { 4,30,12}, - { 5,31,16}, - { 6,32,18}, - { 7,24,22} + {0, 25, 25}, + {0, 2, 1}, + {0, 3, 1}, + {0, 4, 2}, + {0, 5, 3}, + {1, 6, 4}, + {1, 7, 5}, + {1, 8, 6}, + {1, 9, 7}, + {2, 10, 8}, + {2, 11, 9}, + {2, 12, 10}, + {2, 13, 11}, + {3, 14, 12}, + {3, 15, 13}, + {3, 16, 14}, + {3, 17, 15}, + {4, 18, 16}, + {4, 19, 17}, + {5, 20, 18}, + {5, 21, 19}, + {6, 22, 20}, + {6, 23, 21}, + {7, 24, 22}, + {7, 24, 23}, + {0, 26, 1}, + {1, 27, 2}, + {2, 28, 4}, + {3, 29, 8}, + {4, 30, 12}, + {5, 31, 16}, + {6, 32, 18}, + {7, 24, 22} }; ////////////////////////////////////////////////////// @@ -239,12 +238,11 @@ const SDD1_PEM::state SDD1_PEM::evolution_table[] = { void SDD1_PEM::prepareDecomp(void) { - - for(uint8_t i = 0; i < 32; i++) { + for (uint8_t i = 0; i < 32; i++) + { contextInfo[i].status = 0; contextInfo[i].MPS = 0; } - } ///////////////////////////////////////////////////////// @@ -255,18 +253,22 @@ uint8_t SDD1_PEM::getBit(uint8_t context) bool endOfRun; uint8_t bit; - SDD1_ContextInfo *pContInfo = &contextInfo[context]; + SDD1_ContextInfo* pContInfo = &contextInfo[context]; uint8_t currStatus = pContInfo->status; - const state *pState = &SDD1_PEM::evolution_table[currStatus]; + const state* pState = &SDD1_PEM::evolution_table[currStatus]; uint8_t currentMPS = pContInfo->MPS; bit = (BG[pState->code_num])->getBit(&endOfRun); - if(endOfRun) { - if(bit) { - if(!(currStatus & 0xfe)) (pContInfo->MPS) ^= 0x01; + if (endOfRun) + { + if (bit) + { + if (!(currStatus & 0xfe)) (pContInfo->MPS) ^= 0x01; (pContInfo->status) = pState->nextIfLPS; - } else { + } + else + { (pContInfo->status) = pState->nextIfMPS; } } @@ -274,9 +276,10 @@ uint8_t SDD1_PEM::getBit(uint8_t context) return bit ^ currentMPS; } -void SDD1_PEM::Serialize(Serializer &s) +void SDD1_PEM::Serialize(Serializer& s) { - for(int i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) + { s.Stream(contextInfo[i].status, contextInfo[i].MPS); } } @@ -284,10 +287,9 @@ void SDD1_PEM::Serialize(Serializer &s) ////////////////////////////////////////////////////////////// -SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) : +SDD1_CM::SDD1_CM(SDD1_PEM* associatedPEM) : PEM(associatedPEM) { - } ////////////////////////////////////////////////////////////// @@ -298,16 +300,17 @@ void SDD1_CM::prepareDecomp(uint8_t firstByte) bitplanesInfo = firstByte & 0xc0; contextBitsInfo = firstByte & 0x30; bit_number = 0; - for(int i = 0; i < 8; i++) prevBitplaneBits[i] = 0; - switch(bitplanesInfo) { - case 0x00: - currBitplane = 1; - break; - case 0x40: - currBitplane = 7; - break; - case 0x80: - currBitplane = 3; + for (int i = 0; i < 8; i++) prevBitplaneBits[i] = 0; + switch (bitplanesInfo) + { + case 0x00: + currBitplane = 1; + break; + case 0x40: + currBitplane = 7; + break; + case 0x80: + currBitplane = 3; } } @@ -316,41 +319,42 @@ void SDD1_CM::prepareDecomp(uint8_t firstByte) uint8_t SDD1_CM::getBit(void) { - uint8_t currContext; - uint16_t *context_bits; + uint16_t* context_bits; - switch(bitplanesInfo) { - case 0x00: - currBitplane ^= 0x01; - break; - case 0x40: - currBitplane ^= 0x01; - if(!(bit_number & 0x7f)) currBitplane = ((currBitplane + 2) & 0x07); - break; - case 0x80: - currBitplane ^= 0x01; - if(!(bit_number & 0x7f)) currBitplane ^= 0x02; - break; - case 0xc0: - currBitplane = bit_number & 0x07; + switch (bitplanesInfo) + { + case 0x00: + currBitplane ^= 0x01; + break; + case 0x40: + currBitplane ^= 0x01; + if (!(bit_number & 0x7f)) currBitplane = ((currBitplane + 2) & 0x07); + break; + case 0x80: + currBitplane ^= 0x01; + if (!(bit_number & 0x7f)) currBitplane ^= 0x02; + break; + case 0xc0: + currBitplane = bit_number & 0x07; } context_bits = &prevBitplaneBits[currBitplane]; currContext = (currBitplane & 0x01) << 4; - switch(contextBitsInfo) { - case 0x00: - currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); - break; - case 0x10: - currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); - break; - case 0x20: - currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); - break; - case 0x30: - currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); + switch (contextBitsInfo) + { + case 0x00: + currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); + break; + case 0x10: + currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); + break; + case 0x20: + currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); + break; + case 0x30: + currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); } uint8_t bit = PEM->getBit(currContext); @@ -361,10 +365,9 @@ uint8_t SDD1_CM::getBit(void) bit_number++; return bit; - } -void SDD1_CM::Serialize(Serializer &s) +void SDD1_CM::Serialize(Serializer& s) { s.Stream(bitplanesInfo, contextBitsInfo, bit_number, currBitplane); s.StreamArray(prevBitplaneBits, 8); @@ -373,10 +376,9 @@ void SDD1_CM::Serialize(Serializer &s) ////////////////////////////////////////////////// -SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) : +SDD1_OL::SDD1_OL(SDD1_CM* associatedCM) : CM(associatedCM) { - } /////////////////////////////////////////////////// @@ -393,55 +395,64 @@ void SDD1_OL::prepareDecomp(uint8_t firstByte) uint8_t SDD1_OL::decompressByte() { - switch(bitplanesInfo) { - case 0x00: - case 0x40: - case 0x80: - if(_regs[0] == 0) { - _regs[0] = ~_regs[0]; - return _regs[2]; - } else { - _regs[1] = 0; - _regs[2] = 0; - _regs[0] = 0x80; - - while(_regs[0]) { - if(CM->getBit()) { - _regs[1] |= _regs[0]; - } - - if(CM->getBit()) { - _regs[2] |= _regs[0]; - } - - _regs[0] >>= 1; - } - return _regs[1]; - } - break; - - case 0xC0: + switch (bitplanesInfo) + { + case 0x00: + case 0x40: + case 0x80: + if (_regs[0] == 0) + { + _regs[0] = ~_regs[0]; + return _regs[2]; + } + else + { _regs[1] = 0; - _regs[0] = 0x01; - while(_regs[0]) { - if(CM->getBit()) { + _regs[2] = 0; + _regs[0] = 0x80; + + while (_regs[0]) + { + if (CM->getBit()) + { _regs[1] |= _regs[0]; } - _regs[0] <<= 1; + + if (CM->getBit()) + { + _regs[2] |= _regs[0]; + } + + _regs[0] >>= 1; } return _regs[1]; + } + break; + + case 0xC0: + _regs[1] = 0; + _regs[0] = 0x01; + while (_regs[0]) + { + if (CM->getBit()) + { + _regs[1] |= _regs[0]; + } + _regs[0] <<= 1; + } + return _regs[1]; } throw std::runtime_error("SDD1_OL::decompressByte: Unexpected value"); } -void SDD1_OL::Serialize(Serializer &s) +void SDD1_OL::Serialize(Serializer& s) { s.Stream(bitplanesInfo); s.StreamArray(_regs, 3); } -void Sdd1Decomp::Init(Sdd1Mmc *mmc, uint32_t readAddr) +void Sdd1Decomp::Init(Sdd1Mmc* mmc, uint32_t readAddr) { uint8_t firstByte = mmc->ReadRom(readAddr); IM.prepareDecomp(mmc, readAddr); @@ -463,7 +474,7 @@ uint8_t Sdd1Decomp::GetDecompressedByte() return OL.decompressByte(); } -void Sdd1Decomp::Serialize(Serializer &s) +void Sdd1Decomp::Serialize(Serializer& s) { s.Stream(&IM); s.Stream(&BG0); @@ -487,5 +498,4 @@ Sdd1Decomp::Sdd1Decomp() : CM(&PEM), OL(&CM) { - } diff --git a/Core/Sdd1Decomp.h b/Core/Sdd1Decomp.h index e927326..fd2b850 100644 --- a/Core/Sdd1Decomp.h +++ b/Core/Sdd1Decomp.h @@ -35,14 +35,18 @@ understood. class Sdd1Mmc; class SDD1_IM : public ISerializable -{ //Input Manager +{ + //Input Manager Sdd1Mmc* _sdd1Mmc; public: - SDD1_IM(void) {} - void prepareDecomp(Sdd1Mmc *mmc, uint32_t readAddr); + SDD1_IM(void) + { + } + + void prepareDecomp(Sdd1Mmc* mmc, uint32_t readAddr); uint8_t getCodeword(const uint8_t code_len); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; private: uint32_t _readAddr; @@ -53,53 +57,54 @@ private: class SDD1_GCD -{ //Golomb-Code Decoder +{ + //Golomb-Code Decoder public: - SDD1_GCD(SDD1_IM *associatedIM); - void getRunCount(uint8_t code_num, uint8_t *MPScount, bool *LPSind); - -private: - SDD1_IM * const IM; + SDD1_GCD(SDD1_IM* associatedIM); + void getRunCount(uint8_t code_num, uint8_t* MPScount, bool* LPSind); +private: + SDD1_IM* const IM; }; ////////////////////////////////////////////////////// class SDD1_BG : public ISerializable -{ // Bits Generator +{ + // Bits Generator public: - SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code); + SDD1_BG(SDD1_GCD* associatedGCD, uint8_t code); void prepareDecomp(void); - uint8_t getBit(bool *endOfRun); - - void Serialize(Serializer &s) override; + uint8_t getBit(bool* endOfRun); + + void Serialize(Serializer& s) override; private: const uint8_t code_num; uint8_t MPScount; bool LPSind; - SDD1_GCD *const GCD; - + SDD1_GCD* const GCD; }; //////////////////////////////////////////////// class SDD1_PEM : public ISerializable -{ //Probability Estimation Module +{ + //Probability Estimation Module public: - SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, - SDD1_BG *associatedBG2, SDD1_BG *associatedBG3, - SDD1_BG *associatedBG4, SDD1_BG *associatedBG5, - SDD1_BG *associatedBG6, SDD1_BG *associatedBG7); + SDD1_PEM(SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, + SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, + SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, + SDD1_BG* associatedBG6, SDD1_BG* associatedBG7); void prepareDecomp(void); uint8_t getBit(uint8_t context); - - void Serialize(Serializer &s) override; + + void Serialize(Serializer& s) override; private: struct state @@ -108,28 +113,31 @@ private: uint8_t nextIfMPS; uint8_t nextIfLPS; }; + static const state evolution_table[]; + struct SDD1_ContextInfo { uint8_t status; uint8_t MPS; } contextInfo[32]; - SDD1_BG * BG[8]; + SDD1_BG* BG[8]; }; /////////////////////////////////////////////////// class SDD1_CM : public ISerializable -{ //Context Model +{ + //Context Model public: - SDD1_CM(SDD1_PEM *associatedPEM); + SDD1_CM(SDD1_PEM* associatedPEM); void prepareDecomp(uint8_t firstByte); uint8_t getBit(void); - - void Serialize(Serializer &s) override; + + void Serialize(Serializer& s) override; private: uint8_t bitplanesInfo; @@ -137,46 +145,50 @@ private: uint8_t bit_number; uint8_t currBitplane; uint16_t prevBitplaneBits[8]; - SDD1_PEM *const PEM; - + SDD1_PEM* const PEM; }; /////////////////////////////////////////////////// class SDD1_OL : public ISerializable -{ //Output Logic +{ + //Output Logic public: - SDD1_OL(SDD1_CM *associatedCM); + SDD1_OL(SDD1_CM* associatedCM); void prepareDecomp(uint8_t firstByte); uint8_t decompressByte(); - - void Serialize(Serializer &s) override; + + void Serialize(Serializer& s) override; private: uint8_t bitplanesInfo; uint8_t _regs[3]; - SDD1_CM *const CM; - + SDD1_CM* const CM; }; class Sdd1Decomp : public ISerializable { public: Sdd1Decomp(); - void Init(Sdd1Mmc *mmc, uint32_t readAddr); + void Init(Sdd1Mmc* mmc, uint32_t readAddr); uint8_t GetDecompressedByte(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; private: SDD1_IM IM; SDD1_GCD GCD; - SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3; - SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7; + SDD1_BG BG0; + SDD1_BG BG1; + SDD1_BG BG2; + SDD1_BG BG3; + SDD1_BG BG4; + SDD1_BG BG5; + SDD1_BG BG6; + SDD1_BG BG7; SDD1_PEM PEM; SDD1_CM CM; SDD1_OL OL; - -}; \ No newline at end of file +}; diff --git a/Core/Sdd1Mmc.cpp b/Core/Sdd1Mmc.cpp index 4427d04..b14661a 100644 --- a/Core/Sdd1Mmc.cpp +++ b/Core/Sdd1Mmc.cpp @@ -3,7 +3,7 @@ #include "Sdd1Types.h" #include "BaseCartridge.h" -Sdd1Mmc::Sdd1Mmc(Sdd1State &state, BaseCartridge *cart) : IMemoryHandler(SnesMemoryType::Register) +Sdd1Mmc::Sdd1Mmc(Sdd1State& state, BaseCartridge* cart) : IMemoryHandler(SnesMemoryType::Register) { _romHandlers = &cart->GetPrgRomHandlers(); _handlerMask = (uint32_t)((*_romHandlers).size() - 1); @@ -19,18 +19,23 @@ IMemoryHandler* Sdd1Mmc::GetHandler(uint32_t addr) { uint8_t bank = (addr >> 20) - 0x0C; uint16_t handlerIndex = ((_state->SelectedBanks[bank] & 0x0F) << 8) | ((addr & 0xFF000) >> 12); - + return (*_romHandlers)[handlerIndex & _handlerMask].get(); } uint8_t Sdd1Mmc::Read(uint32_t addr) { - if(!(addr & 0x400000)) { + if (!(addr & 0x400000)) + { uint16_t handlerIndex; - if(((addr & 0x800000) && _state->SelectedBanks[3] & 0x80) || (!(addr & 0x800000) && (_state->SelectedBanks[1] & 0x80))) { + if (((addr & 0x800000) && _state->SelectedBanks[3] & 0x80) || (!(addr & 0x800000) && (_state->SelectedBanks[1] & + 0x80))) + { //Force mirroring: $20-$3F mirrors $00-$1F, $A0-$BF mirrors $80-$9F handlerIndex = (((addr & 0x1F0000) >> 1) | (addr & 0x7000)) >> 12; - } else { + } + else + { handlerIndex = (((addr & 0x3F0000) >> 1) | (addr & 0x7000)) >> 12; } return (*_romHandlers)[handlerIndex & _handlerMask]->Read(addr); @@ -38,11 +43,15 @@ uint8_t Sdd1Mmc::Read(uint32_t addr) //Banks $C0+ uint8_t activeChannels = _state->ProcessNextDma & _state->AllowDmaProcessing; - if(activeChannels) { + if (activeChannels) + { //Some DMA channels are being processed, need to check if the address being read matches one of the dma channels - for(int i = 0; i < 8; i++) { - if((activeChannels & (1 << i)) && addr == _state->DmaAddress[i]) { - if(_state->NeedInit) { + for (int i = 0; i < 8; i++) + { + if ((activeChannels & (1 << i)) && addr == _state->DmaAddress[i]) + { + if (_state->NeedInit) + { _decompressor.Init(this, addr); _state->NeedInit = false; } @@ -50,7 +59,8 @@ uint8_t Sdd1Mmc::Read(uint32_t addr) uint8_t data = _decompressor.GetDecompressedByte(); _state->DmaLength[i]--; - if(_state->DmaLength[i] == 0) { + if (_state->DmaLength[i] == 0) + { _state->NeedInit = true; _state->ProcessNextDma &= ~(1 << i); } @@ -68,7 +78,7 @@ uint8_t Sdd1Mmc::Peek(uint32_t addr) return 0; } -void Sdd1Mmc::PeekBlock(uint32_t addr, uint8_t *output) +void Sdd1Mmc::PeekBlock(uint32_t addr, uint8_t* output) { memset(output, 0, 0x1000); } @@ -83,7 +93,7 @@ AddressInfo Sdd1Mmc::GetAbsoluteAddress(uint32_t address) return GetHandler(address)->GetAbsoluteAddress(address); } -void Sdd1Mmc::Serialize(Serializer &s) +void Sdd1Mmc::Serialize(Serializer& s) { s.Stream(&_decompressor); } diff --git a/Core/Sdd1Mmc.h b/Core/Sdd1Mmc.h index 2b843de..270e6ac 100644 --- a/Core/Sdd1Mmc.h +++ b/Core/Sdd1Mmc.h @@ -11,23 +11,23 @@ class Sdd1Mmc : public IMemoryHandler, public ISerializable { private: Sdd1State* _state; - vector> *_romHandlers; + vector>* _romHandlers; uint32_t _handlerMask; Sdd1Decomp _decompressor; IMemoryHandler* GetHandler(uint32_t addr); public: - Sdd1Mmc(Sdd1State &state, BaseCartridge *cart); + Sdd1Mmc(Sdd1State& state, BaseCartridge* cart); uint8_t ReadRom(uint32_t addr); // Inherited via IMemoryHandler virtual uint8_t Read(uint32_t addr) override; virtual uint8_t Peek(uint32_t addr) override; - virtual void PeekBlock(uint32_t addr, uint8_t * output) override; + virtual void PeekBlock(uint32_t addr, uint8_t* output) override; virtual void Write(uint32_t addr, uint8_t value) override; virtual AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Serialize(Serializer &s) override; -}; \ No newline at end of file + void Serialize(Serializer& s) override; +}; diff --git a/Core/Sdd1Types.h b/Core/Sdd1Types.h index f474cf0..89f5f68 100644 --- a/Core/Sdd1Types.h +++ b/Core/Sdd1Types.h @@ -10,4 +10,4 @@ struct Sdd1State uint32_t DmaAddress[8]; uint16_t DmaLength[8]; bool NeedInit; -}; \ No newline at end of file +}; diff --git a/Core/SelectControllerMessage.h b/Core/SelectControllerMessage.h index 4e3d6e4..ff3b0b3 100644 --- a/Core/SelectControllerMessage.h +++ b/Core/SelectControllerMessage.h @@ -8,13 +8,15 @@ private: uint8_t _portNumber; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_portNumber); } public: - SelectControllerMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { } + SelectControllerMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } SelectControllerMessage(uint8_t port) : NetMessage(MessageType::SelectController) { @@ -25,4 +27,4 @@ public: { return _portNumber; } -}; \ No newline at end of file +}; diff --git a/Core/ServerInformationMessage.h b/Core/ServerInformationMessage.h index 97192c6..1fd2bcb 100644 --- a/Core/ServerInformationMessage.h +++ b/Core/ServerInformationMessage.h @@ -8,13 +8,16 @@ private: string _hashSalt; protected: - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { s.Stream(_hashSalt); } public: - ServerInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) {} + ServerInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) + { + } + ServerInformationMessage(string hashSalt) : NetMessage(MessageType::ServerInformation) { _hashSalt = hashSalt; diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 9a7ee34..6e44a3f 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -120,7 +120,7 @@ struct AudioConfig uint32_t SampleRate = 48000; uint32_t AudioLatency = 60; - bool EnableCubicInterpolation = true; + bool EnableCubicInterpolation = true; bool MuteSoundInBackground = false; bool ReduceSoundInBackground = true; @@ -186,7 +186,9 @@ struct KeyMapping bool HasKeySet() { - if(A || B || X || Y || L || R || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboX || TurboY || TurboL || TurboR || TurboStart || TurboSelect) { + if (A || B || X || Y || L || R || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboX || + TurboY || TurboL || TurboR || TurboStart || TurboSelect) + { return true; } return false; @@ -195,8 +197,10 @@ struct KeyMapping private: bool HasKeyBinding(uint32_t* buttons, uint32_t count) { - for(uint32_t i = 0; i < count; i++) { - if(buttons[i] != 0) { + for (uint32_t i = 0; i < count; i++) + { + if (buttons[i] != 0) + { return true; } } @@ -215,16 +219,20 @@ struct KeyMappingSet vector GetKeyMappingArray() { vector keyMappings; - if(Mapping1.HasKeySet()) { + if (Mapping1.HasKeySet()) + { keyMappings.push_back(Mapping1); } - if(Mapping2.HasKeySet()) { + if (Mapping2.HasKeySet()) + { keyMappings.push_back(Mapping2); } - if(Mapping3.HasKeySet()) { + if (Mapping3.HasKeySet()) + { keyMappings.push_back(Mapping3); } - if(Mapping4.HasKeySet()) { + if (Mapping4.HasKeySet()) + { keyMappings.push_back(Mapping4); } return keyMappings; @@ -252,7 +260,7 @@ struct InputConfig uint32_t MouseSensitivity = 1; InputDisplayPosition DisplayInputPosition = InputDisplayPosition::TopLeft; - bool DisplayInputPort[5] = { false, false, false, false, false}; + bool DisplayInputPort[5] = {false, false, false, false, false}; bool DisplayInputHorizontally = true; }; @@ -315,9 +323,9 @@ struct GameboyConfig bool BlendFrames = true; bool GbcAdjustColors = true; - uint32_t BgColors[4] = { 0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000 }; - uint32_t Obj0Colors[4] = { 0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000 }; - uint32_t Obj1Colors[4] = { 0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000 }; + uint32_t BgColors[4] = {0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000}; + uint32_t Obj0Colors[4] = {0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000}; + uint32_t Obj1Colors[4] = {0xFFFFFF, 0xB0B0B0, 0x686868, 0x000000}; uint32_t Square1Vol = 100; uint32_t Square2Vol = 100; @@ -423,7 +431,7 @@ enum class EmulatorShortcut ToggleOsd, ToggleAlwaysOnTop, ToggleDebugInfo, - + ToggleAudio, IncreaseVolume, DecreaseVolume, @@ -476,13 +484,16 @@ struct KeyCombination vector GetKeys() { vector result; - if(Key1) { + if (Key1) + { result.push_back(Key1); } - if(Key2) { + if (Key2) + { result.push_back(Key2); } - if(Key3) { + if (Key3) + { result.push_back(Key3); } return result; @@ -493,9 +504,12 @@ struct KeyCombination vector myKeys = GetKeys(); vector otherKeys = keyCombination.GetKeys(); - if(otherKeys.size() > myKeys.size()) { - for(size_t i = 0; i < myKeys.size(); i++) { - if(std::find(otherKeys.begin(), otherKeys.end(), myKeys[i]) == otherKeys.end()) { + if (otherKeys.size() > myKeys.size()) + { + for (size_t i = 0; i < myKeys.size(); i++) + { + if (std::find(otherKeys.begin(), otherKeys.end(), myKeys[i]) == otherKeys.end()) + { //Current key combination contains a key not found in the other combination, so it's not a subset return false; } @@ -522,13 +536,13 @@ enum class DebuggerFlags : uint32_t ShowVerifiedData = 0x100, DisassembleVerifiedData = 0x200, - + ShowUnidentifiedData = 0x400, DisassembleUnidentifiedData = 0x800, - + UseAltSpcOpNames = 0x1000, UseLowerCaseDisassembly = 0x2000, - + AutoResetCdl = 0x4000, GbBreakOnInvalidOamAccess = 0x10000, diff --git a/Core/ShortcutKeyHandler.cpp b/Core/ShortcutKeyHandler.cpp index 451ef97..90948b8 100644 --- a/Core/ShortcutKeyHandler.cpp +++ b/Core/ShortcutKeyHandler.cpp @@ -19,8 +19,10 @@ ShortcutKeyHandler::ShortcutKeyHandler(shared_ptr console) _repeatStarted = false; _stopThread = false; - _thread = std::thread([=]() { - while(!_stopThread) { + _thread = std::thread([=]() + { + while (!_stopThread) + { ProcessKeys(); std::this_thread::sleep_for(std::chrono::duration(50)); } @@ -37,8 +39,10 @@ bool ShortcutKeyHandler::IsKeyPressed(EmulatorShortcut shortcut) { KeyCombination keyComb = _console->GetSettings()->GetShortcutKey(shortcut, _keySetIndex); vector supersets = _console->GetSettings()->GetShortcutSupersets(shortcut, _keySetIndex); - for(KeyCombination &superset : supersets) { - if(IsKeyPressed(superset)) { + for (KeyCombination& superset : supersets) + { + if (IsKeyPressed(superset)) + { //A superset is pressed, ignore this subset return false; } @@ -52,7 +56,8 @@ bool ShortcutKeyHandler::IsKeyPressed(KeyCombination comb) { int keyCount = (comb.Key1 ? 1 : 0) + (comb.Key2 ? 1 : 0) + (comb.Key3 ? 1 : 0); - if(keyCount == 0 || _pressedKeys.empty()) { + if (keyCount == 0 || _pressedKeys.empty()) + { return false; } @@ -68,11 +73,13 @@ bool ShortcutKeyHandler::IsKeyPressed(uint32_t keyCode) bool ShortcutKeyHandler::DetectKeyPress(EmulatorShortcut shortcut) { - if(IsKeyPressed(shortcut)) { + if (IsKeyPressed(shortcut)) + { bool newlyPressed = _prevKeysDown[_keySetIndex].find((uint32_t)shortcut) == _prevKeysDown[_keySetIndex].end(); _keysDown[_keySetIndex].emplace((uint32_t)shortcut); - if(newlyPressed && !_isKeyUp) { + if (newlyPressed && !_isKeyUp) + { return true; } } @@ -81,8 +88,10 @@ bool ShortcutKeyHandler::DetectKeyPress(EmulatorShortcut shortcut) bool ShortcutKeyHandler::DetectKeyRelease(EmulatorShortcut shortcut) { - if(!IsKeyPressed(shortcut)) { - if(_prevKeysDown[_keySetIndex].find((uint32_t)shortcut) != _prevKeysDown[_keySetIndex].end()) { + if (!IsKeyPressed(shortcut)) + { + if (_prevKeysDown[_keySetIndex].find((uint32_t)shortcut) != _prevKeysDown[_keySetIndex].end()) + { return true; } } @@ -92,7 +101,8 @@ bool ShortcutKeyHandler::DetectKeyRelease(EmulatorShortcut shortcut) void ShortcutKeyHandler::ProcessRunSingleFrame() { shared_ptr timer = _runSingleFrameRepeatTimer; - if(!timer) { + if (!timer) + { timer.reset(new Timer()); _runSingleFrameRepeatTimer = timer; } @@ -109,80 +119,112 @@ void ShortcutKeyHandler::CheckMappedKeys() bool isMovieRecording = _console->GetMovieManager()->Recording(); //Let the UI handle these shortcuts - for(uint64_t i = (uint64_t)EmulatorShortcut::TakeScreenshot; i < (uint64_t)EmulatorShortcut::ShortcutCount; i++) { - if(DetectKeyPress((EmulatorShortcut)i)) { + for (uint64_t i = (uint64_t)EmulatorShortcut::TakeScreenshot; i < (uint64_t)EmulatorShortcut::ShortcutCount; i++) + { + if (DetectKeyPress((EmulatorShortcut)i)) + { void* param = (void*)i; _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, param); } } - if(DetectKeyPress(EmulatorShortcut::FastForward)) { + if (DetectKeyPress(EmulatorShortcut::FastForward)) + { settings->SetFlag(EmulationFlags::Turbo); - } else if(DetectKeyRelease(EmulatorShortcut::FastForward)) { + } + else if (DetectKeyRelease(EmulatorShortcut::FastForward)) + { settings->ClearFlag(EmulationFlags::Turbo); } - if(DetectKeyPress(EmulatorShortcut::ToggleFastForward)) { - if(settings->CheckFlag(EmulationFlags::Turbo)) { + if (DetectKeyPress(EmulatorShortcut::ToggleFastForward)) + { + if (settings->CheckFlag(EmulationFlags::Turbo)) + { settings->ClearFlag(EmulationFlags::Turbo); - } else { + } + else + { settings->SetFlag(EmulationFlags::Turbo); } } - for(int i = 0; i < 10; i++) { - if(DetectKeyPress((EmulatorShortcut)((int)EmulatorShortcut::SelectSaveSlot1 + i))) { + for (int i = 0; i < 10; i++) + { + if (DetectKeyPress((EmulatorShortcut)((int)EmulatorShortcut::SelectSaveSlot1 + i))) + { _console->GetSaveStateManager()->SelectSaveSlot(i + 1); } } - if(DetectKeyPress(EmulatorShortcut::MoveToNextStateSlot)) { + if (DetectKeyPress(EmulatorShortcut::MoveToNextStateSlot)) + { _console->GetSaveStateManager()->MoveToNextSlot(); } - if(DetectKeyPress(EmulatorShortcut::MoveToPreviousStateSlot)) { + if (DetectKeyPress(EmulatorShortcut::MoveToPreviousStateSlot)) + { _console->GetSaveStateManager()->MoveToPreviousSlot(); } - if(DetectKeyPress(EmulatorShortcut::SaveState)) { + if (DetectKeyPress(EmulatorShortcut::SaveState)) + { _console->GetSaveStateManager()->SaveState(); } - if(DetectKeyPress(EmulatorShortcut::LoadState)) { + if (DetectKeyPress(EmulatorShortcut::LoadState)) + { _console->GetSaveStateManager()->LoadState(); } - if(DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) { - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats); + if (DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) + { + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, + (void*)EmulatorShortcut::ToggleCheats); } - if(DetectKeyPress(EmulatorShortcut::RunSingleFrame)) { + if (DetectKeyPress(EmulatorShortcut::RunSingleFrame)) + { ProcessRunSingleFrame(); } - if(DetectKeyRelease(EmulatorShortcut::RunSingleFrame)) { + if (DetectKeyRelease(EmulatorShortcut::RunSingleFrame)) + { _runSingleFrameRepeatTimer.reset(); _repeatStarted = false; } - if(!isNetplayClient && !isMovieRecording) { + if (!isNetplayClient && !isMovieRecording) + { shared_ptr rewindManager = _console->GetRewindManager(); - if(rewindManager) { - if(DetectKeyPress(EmulatorShortcut::ToggleRewind)) { - if(rewindManager->IsRewinding()) { + if (rewindManager) + { + if (DetectKeyPress(EmulatorShortcut::ToggleRewind)) + { + if (rewindManager->IsRewinding()) + { rewindManager->StopRewinding(); - } else { + } + else + { rewindManager->StartRewinding(); } } - if(DetectKeyPress(EmulatorShortcut::Rewind)) { + if (DetectKeyPress(EmulatorShortcut::Rewind)) + { rewindManager->StartRewinding(); - } else if(DetectKeyRelease(EmulatorShortcut::Rewind)) { + } + else if (DetectKeyRelease(EmulatorShortcut::Rewind)) + { rewindManager->StopRewinding(); - } else if(DetectKeyPress(EmulatorShortcut::RewindTenSecs)) { + } + else if (DetectKeyPress(EmulatorShortcut::RewindTenSecs)) + { rewindManager->RewindSeconds(10); - } else if(DetectKeyPress(EmulatorShortcut::RewindOneMin)) { + } + else if (DetectKeyPress(EmulatorShortcut::RewindOneMin)) + { rewindManager->RewindSeconds(60); } } @@ -191,7 +233,8 @@ void ShortcutKeyHandler::CheckMappedKeys() void ShortcutKeyHandler::ProcessKeys() { - if(!_console->GetSettings()->IsInputEnabled()) { + if (!_console->GetSettings()->IsInputEnabled()) + { return; } @@ -202,19 +245,24 @@ void ShortcutKeyHandler::ProcessKeys() _isKeyUp = _pressedKeys.size() < _lastPressedKeys.size(); bool noChange = false; - if(_pressedKeys.size() == _lastPressedKeys.size()) { + if (_pressedKeys.size() == _lastPressedKeys.size()) + { noChange = true; - for(size_t i = 0; i < _pressedKeys.size(); i++) { - if(_pressedKeys[i] != _lastPressedKeys[i]) { + for (size_t i = 0; i < _pressedKeys.size(); i++) + { + if (_pressedKeys[i] != _lastPressedKeys[i]) + { noChange = false; break; } } } - if(!noChange) { + if (!noChange) + { //Only run this if the keys have changed - for(int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { _keysDown[i].clear(); _keySetIndex = i; CheckMappedKeys(); @@ -225,13 +273,15 @@ void ShortcutKeyHandler::ProcessKeys() } shared_ptr timer = _runSingleFrameRepeatTimer; - if(timer) { + if (timer) + { double elapsedMs = timer->GetElapsedMS(); - if((_repeatStarted && elapsedMs >= 50) || (!_repeatStarted && elapsedMs >= 500)) { + if ((_repeatStarted && elapsedMs >= 50) || (!_repeatStarted && elapsedMs >= 500)) + { //Over 500ms has elapsed since the key was first pressed, or over 50ms since repeat mode started (20fps) //In this case, run another frame and pause again. _repeatStarted = true; ProcessRunSingleFrame(); } } -} \ No newline at end of file +} diff --git a/Core/ShortcutKeyHandler.h b/Core/ShortcutKeyHandler.h index 0106199..7efed91 100644 --- a/Core/ShortcutKeyHandler.h +++ b/Core/ShortcutKeyHandler.h @@ -14,7 +14,7 @@ private: thread _thread; atomic _stopThread; SimpleLock _lock; - + int _keySetIndex; vector _pressedKeys; vector _lastPressedKeys; @@ -25,9 +25,9 @@ private: unordered_set _keysDown[2]; unordered_set _prevKeysDown[2]; - + void CheckMappedKeys(); - + bool IsKeyPressed(EmulatorShortcut key); bool IsKeyPressed(KeyCombination comb); bool IsKeyPressed(uint32_t keyCode); @@ -42,4 +42,4 @@ public: ~ShortcutKeyHandler(); void ProcessKeys(); -}; \ No newline at end of file +}; diff --git a/Core/SnesController.cpp b/Core/SnesController.cpp index 12a2b62..e0ba279 100644 --- a/Core/SnesController.cpp +++ b/Core/SnesController.cpp @@ -2,7 +2,8 @@ #include "SnesController.h" #include "Console.h" -SnesController::SnesController(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console, port, keyMappings) +SnesController::SnesController(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice( + console, port, keyMappings) { _turboSpeed = keyMappings.TurboSpeed; } @@ -14,7 +15,8 @@ string SnesController::GetKeyNames() void SnesController::InternalSetStateFromInput() { - for(KeyMapping keyMapping : _keyMappings) { + for (KeyMapping keyMapping : _keyMappings) + { SetPressedState(Buttons::A, keyMapping.A); SetPressedState(Buttons::B, keyMapping.B); SetPressedState(Buttons::X, keyMapping.X); @@ -30,7 +32,8 @@ void SnesController::InternalSetStateFromInput() uint8_t turboFreq = 1 << (4 - _turboSpeed); bool turboOn = (uint8_t)(_console->GetFrameCount() % turboFreq) < turboFreq / 2; - if(turboOn) { + if (turboOn) + { SetPressedState(Buttons::A, keyMapping.TurboA); SetPressedState(Buttons::B, keyMapping.TurboB); SetPressedState(Buttons::X, keyMapping.TurboX); @@ -60,7 +63,7 @@ uint16_t SnesController::ToByte() ((uint8_t)IsPressed(Buttons::R) << 11); } -void SnesController::Serialize(Serializer & s) +void SnesController::Serialize(Serializer& s) { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer); @@ -80,12 +83,16 @@ uint8_t SnesController::ReadRam(uint16_t addr) { uint8_t output = 0; - if(IsCurrentPort(addr)) { + if (IsCurrentPort(addr)) + { StrobeProcessRead(); - if(_port >= 2) { - output = (_stateBuffer & 0x01) << 1; //P3/P4 are reported in bit 2 - } else { + if (_port >= 2) + { + output = (_stateBuffer & 0x01) << 1; //P3/P4 are reported in bit 2 + } + else + { output = _stateBuffer & 0x01; } _stateBuffer >>= 1; diff --git a/Core/SnesController.h b/Core/SnesController.h index f2572de..3565693 100644 --- a/Core/SnesController.h +++ b/Core/SnesController.h @@ -13,7 +13,7 @@ protected: string GetKeyNames() override; void InternalSetStateFromInput() override; uint16_t ToByte(); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void RefreshStateBuffer() override; public: @@ -24,4 +24,4 @@ public: ControllerType GetControllerType() override; uint8_t ReadRam(uint16_t addr) override; void WriteRam(uint16_t addr, uint8_t value) override; -}; \ No newline at end of file +}; diff --git a/Core/SnesMemoryType.h b/Core/SnesMemoryType.h index 80e5f0c..7861f9f 100644 --- a/Core/SnesMemoryType.h +++ b/Core/SnesMemoryType.h @@ -33,4 +33,4 @@ enum class SnesMemoryType GbVideoRam, GbSpriteRam, Register -}; \ No newline at end of file +}; diff --git a/Core/SnesMouse.h b/Core/SnesMouse.h index 608894a..8f85ac9 100644 --- a/Core/SnesMouse.h +++ b/Core/SnesMouse.h @@ -16,7 +16,7 @@ private: protected: bool HasCoordinates() override { return true; } - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer, _sensitivity); @@ -57,14 +57,17 @@ public: uint8_t ReadRam(uint16_t addr) override { uint8_t output = 0; - if((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) { + if ((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) + { StrobeProcessRead(); - if(_strobe) { + if (_strobe) + { _sensitivity = (_sensitivity + 1) % 3; } output = (_stateBuffer & 0x80000000) >> 31; - if(_port >= 2) { + if (_port >= 2) + { output <<= 1; } _stateBuffer <<= 1; @@ -85,10 +88,11 @@ public: dy = std::min(std::abs(dy), 127); uint8_t byte1 = 0; - uint8_t byte2 = 0x01 | ((_sensitivity & 0x03) << 4) | (IsPressed(SnesMouse::Buttons::Left) ? 0x40 : 0) | (IsPressed(SnesMouse::Buttons::Right) ? 0x80 : 0); + uint8_t byte2 = 0x01 | ((_sensitivity & 0x03) << 4) | (IsPressed(SnesMouse::Buttons::Left) ? 0x40 : 0) | ( + IsPressed(SnesMouse::Buttons::Right) ? 0x80 : 0); uint8_t byte3 = dy | upFlag; uint8_t byte4 = dx | leftFlag; _stateBuffer = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; } -}; \ No newline at end of file +}; diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index 662ce15..8b68f6a 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -12,7 +12,7 @@ #include "SuperGameboy.h" #include "../Utilities/Equalizer.h" -SoundMixer::SoundMixer(Console *console) +SoundMixer::SoundMixer(Console* console) { _console = console; _audioDevice = nullptr; @@ -25,26 +25,33 @@ SoundMixer::~SoundMixer() delete[] _sampleBuffer; } -void SoundMixer::RegisterAudioDevice(IAudioDevice *audioDevice) +void SoundMixer::RegisterAudioDevice(IAudioDevice* audioDevice) { _audioDevice = audioDevice; } AudioStatistics SoundMixer::GetStatistics() { - if(_audioDevice) { + if (_audioDevice) + { return _audioDevice->GetStatistics(); - } else { + } + else + { return AudioStatistics(); } } void SoundMixer::StopAudio(bool clearBuffer) { - if(_audioDevice) { - if(clearBuffer) { + if (_audioDevice) + { + if (clearBuffer) + { _audioDevice->Stop(); - } else { + } + else + { _audioDevice->Pause(); } } @@ -54,57 +61,73 @@ void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_ { AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); - if(cfg.EnableEqualizer) { + if (cfg.EnableEqualizer) + { ProcessEqualizer(samples, sampleCount); } uint32_t masterVolume = cfg.MasterVolume; - if(_console->GetSettings()->CheckFlag(EmulationFlags::InBackground)) { - if(cfg.MuteSoundInBackground) { + if (_console->GetSettings()->CheckFlag(EmulationFlags::InBackground)) + { + if (cfg.MuteSoundInBackground) + { masterVolume = 0; - } else if(cfg.ReduceSoundInBackground) { + } + else if (cfg.ReduceSoundInBackground) + { masterVolume = cfg.VolumeReduction == 100 ? 0 : masterVolume * (100 - cfg.VolumeReduction) / 100; } - } else if(cfg.ReduceSoundInFastForward && _console->GetSettings()->CheckFlag(EmulationFlags::TurboOrRewind)) { + } + else if (cfg.ReduceSoundInFastForward && _console->GetSettings()->CheckFlag(EmulationFlags::TurboOrRewind)) + { masterVolume = cfg.VolumeReduction == 100 ? 0 : masterVolume * (100 - cfg.VolumeReduction) / 100; } _leftSample = samples[0]; _rightSample = samples[1]; - int16_t *out = _sampleBuffer; + int16_t* out = _sampleBuffer; uint32_t count = _resampler->Resample(samples, sampleCount, sourceRate, cfg.SampleRate, out); SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy(); - if(sgb) { + if (sgb) + { uint32_t targetRate = (uint32_t)(cfg.SampleRate * _resampler->GetRateAdjustment()); sgb->MixAudio(targetRate, out, count); } shared_ptr msu1 = _console->GetMsu1(); - if(msu1) { + if (msu1) + { msu1->MixAudio(out, count, cfg.SampleRate); } - - if(masterVolume < 100) { + + if (masterVolume < 100) + { //Apply volume if not using the default value - for(uint32_t i = 0; i < count * 2; i++) { + for (uint32_t i = 0; i < count * 2; i++) + { out[i] = (int32_t)out[i] * (int32_t)masterVolume / 100; } } shared_ptr rewindManager = _console->GetRewindManager(); - if(!_console->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(out, count)) { + if (!_console->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(out, count)) + { bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording(); - if(isRecording) { - if(_waveRecorder) { + if (isRecording) + { + if (_waveRecorder) + { _waveRecorder->WriteSamples(out, count, cfg.SampleRate, true); } _console->GetVideoRenderer()->AddRecordingSound(out, count, cfg.SampleRate); } - if(_audioDevice) { - if(!cfg.EnableAudio) { + if (_audioDevice) + { + if (!cfg.EnableAudio) + { _audioDevice->Stop(); return; } @@ -118,7 +141,8 @@ void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_ void SoundMixer::ProcessEqualizer(int16_t* samples, uint32_t sampleCount) { AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); - if(!_equalizer) { + if (!_equalizer) + { _equalizer.reset(new Equalizer()); } vector bandGains = { @@ -151,8 +175,8 @@ bool SoundMixer::IsRecording() return _waveRecorder.get() != nullptr; } -void SoundMixer::GetLastSamples(int16_t &left, int16_t &right) +void SoundMixer::GetLastSamples(int16_t& left, int16_t& right) { left = _leftSample; right = _rightSample; -} \ No newline at end of file +} diff --git a/Core/SoundMixer.h b/Core/SoundMixer.h index e8c2e8b..8cedd46 100644 --- a/Core/SoundMixer.h +++ b/Core/SoundMixer.h @@ -7,34 +7,34 @@ class Equalizer; class SoundResampler; class WaveRecorder; -class SoundMixer +class SoundMixer { private: - IAudioDevice *_audioDevice; - Console *_console; + IAudioDevice* _audioDevice; + Console* _console; unique_ptr _equalizer; unique_ptr _resampler; shared_ptr _waveRecorder; - int16_t *_sampleBuffer = nullptr; + int16_t* _sampleBuffer = nullptr; int16_t _leftSample = 0; int16_t _rightSample = 0; - void ProcessEqualizer(int16_t *samples, uint32_t sampleCount); + void ProcessEqualizer(int16_t* samples, uint32_t sampleCount); public: - SoundMixer(Console *console); + SoundMixer(Console* console); ~SoundMixer(); - void PlayAudioBuffer(int16_t *samples, uint32_t sampleCount, uint32_t sourceRate); + void PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_t sourceRate); void StopAudio(bool clearBuffer = false); - void RegisterAudioDevice(IAudioDevice *audioDevice); + void RegisterAudioDevice(IAudioDevice* audioDevice); AudioStatistics GetStatistics(); double GetRateAdjustment(); void StartRecording(string filepath); void StopRecording(); bool IsRecording(); - void GetLastSamples(int16_t &left, int16_t &right); + void GetLastSamples(int16_t& left, int16_t& right); }; diff --git a/Core/SoundResampler.cpp b/Core/SoundResampler.cpp index 57adcf4..e43afb9 100644 --- a/Core/SoundResampler.cpp +++ b/Core/SoundResampler.cpp @@ -7,7 +7,7 @@ #include "VideoRenderer.h" #include "../Utilities/HermiteResampler.h" -SoundResampler::SoundResampler(Console *console) +SoundResampler::SoundResampler(Console* console) { _console = console; } @@ -25,12 +25,14 @@ double SoundResampler::GetTargetRateAdjustment() { AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); bool isRecording = _console->GetSoundMixer()->IsRecording() || _console->GetVideoRenderer()->IsRecording(); - if(!isRecording && !cfg.DisableDynamicSampleRate) { + if (!isRecording && !cfg.DisableDynamicSampleRate) + { //Don't deviate from selected sample rate while recording //TODO: Have 2 output streams (one for recording, one for the speakers) AudioStatistics stats = _console->GetSoundMixer()->GetStatistics(); - if(stats.AverageLatency > 0 && _console->GetSettings()->GetEmulationSpeed() == 100) { + if (stats.AverageLatency > 0 && _console->GetSettings()->GetEmulationSpeed() == 100) + { //Try to stay within +/- 3ms of requested latency constexpr int32_t maxGap = 3; constexpr int32_t maxSubAdjustment = 3600; @@ -39,9 +41,12 @@ double SoundResampler::GetTargetRateAdjustment() double latencyGap = stats.AverageLatency - requestedLatency; double adjustment = std::min(0.0025, (std::ceil((std::abs(latencyGap) - maxGap) * 8)) * 0.00003125); - if(latencyGap < 0 && _underTarget < maxSubAdjustment) { + if (latencyGap < 0 && _underTarget < maxSubAdjustment) + { _underTarget++; - } else if(latencyGap > 0 && _underTarget > -maxSubAdjustment) { + } + else if (latencyGap > 0 && _underTarget > -maxSubAdjustment) + { _underTarget--; } @@ -49,21 +54,31 @@ double SoundResampler::GetTargetRateAdjustment() //This should slowly get us closer to the actual output rate of the sound card double subAdjustment = 0.00003125 * _underTarget / 180; - if(adjustment > 0) { - if(latencyGap > maxGap) { + if (adjustment > 0) + { + if (latencyGap > maxGap) + { _rateAdjustment = 1 - adjustment + subAdjustment; - } else if(latencyGap < -maxGap) { + } + else if (latencyGap < -maxGap) + { _rateAdjustment = 1 + adjustment + subAdjustment; } - } else if(std::abs(latencyGap) < 1) { + } + else if (std::abs(latencyGap) < 1) + { //Restore normal rate once we get within +/- 1ms _rateAdjustment = 1.0 + subAdjustment; } - } else { + } + else + { _underTarget = 0; _rateAdjustment = 1.0; } - } else { + } + else + { _underTarget = 0; _rateAdjustment = 1.0; } @@ -73,25 +88,31 @@ double SoundResampler::GetTargetRateAdjustment() void SoundResampler::UpdateTargetSampleRate(uint32_t sourceRate, uint32_t sampleRate) { double spcSampleRate = sourceRate; - if(_console->GetSettings()->GetVideoConfig().IntegerFpsMode) { + if (_console->GetSettings()->GetVideoConfig().IntegerFpsMode) + { //Adjust sample rate when running at 60.0 fps instead of 60.1 - switch(_console->GetRegion()) { - default: - case ConsoleRegion::Ntsc: spcSampleRate = sourceRate * (60.0 / _console->GetFps()); break; - case ConsoleRegion::Pal: spcSampleRate = sourceRate * (50.0 / _console->GetFps()); break; + switch (_console->GetRegion()) + { + default: + case ConsoleRegion::Ntsc: spcSampleRate = sourceRate * (60.0 / _console->GetFps()); + break; + case ConsoleRegion::Pal: spcSampleRate = sourceRate * (50.0 / _console->GetFps()); + break; } } double targetRate = sampleRate * GetTargetRateAdjustment(); - if(targetRate != _previousTargetRate || spcSampleRate != _prevSpcSampleRate) { + if (targetRate != _previousTargetRate || spcSampleRate != _prevSpcSampleRate) + { _previousTargetRate = targetRate; _prevSpcSampleRate = spcSampleRate; _resampler.SetSampleRates(spcSampleRate, targetRate); } } -uint32_t SoundResampler::Resample(int16_t *inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, int16_t *outSamples) +uint32_t SoundResampler::Resample(int16_t* inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, + int16_t* outSamples) { UpdateTargetSampleRate(sourceRate, sampleRate); return _resampler.Resample(inSamples, sampleCount, outSamples); -} \ No newline at end of file +} diff --git a/Core/SoundResampler.h b/Core/SoundResampler.h index 2c7bed8..33c7361 100644 --- a/Core/SoundResampler.h +++ b/Core/SoundResampler.h @@ -7,7 +7,7 @@ class Console; class SoundResampler { private: - Console *_console; + Console* _console; double _rateAdjustment = 1.0; double _previousTargetRate = 0; @@ -20,10 +20,11 @@ private: void UpdateTargetSampleRate(uint32_t sourceRate, uint32_t sampleRate); public: - SoundResampler(Console *console); + SoundResampler(Console* console); ~SoundResampler(); double GetRateAdjustment(); - uint32_t Resample(int16_t *inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, int16_t *outSamples); -}; \ No newline at end of file + uint32_t Resample(int16_t* inSamples, uint32_t sampleCount, uint32_t sourceRate, uint32_t sampleRate, + int16_t* outSamples); +}; diff --git a/Core/Spc.Instructions.cpp b/Core/Spc.Instructions.cpp index 3e3e2b9..8f27871 100644 --- a/Core/Spc.Instructions.cpp +++ b/Core/Spc.Instructions.cpp @@ -15,266 +15,719 @@ void Spc::EndAddr() void Spc::Exec() { - switch(_opCode) { - case 0x00: NOP(); break; - case 0x01: TCALL<0>(); break; - case 0x02: Addr_Dir(); SET1<0>(); break; - case 0x03: Addr_Dir(); BBS<0>(); break; - case 0x04: Addr_Dir(); OR_Acc(); break; - case 0x05: Addr_Abs(); OR_Acc(); break; - case 0x06: Addr_IndX(); OR_Acc(); break; - case 0x07: Addr_DirIdxXInd(); OR_Acc(); break; - case 0x08: Addr_Imm(); OR_Imm(); break; - case 0x09: Addr_DirToDir(); OR(); break; - case 0x0A: Addr_AbsBit(); OR1(); break; - case 0x0B: Addr_Dir(); ASL(); break; - case 0x0C: Addr_Abs(); ASL(); break; - case 0x0D: PHP(); break; - case 0x0E: Addr_Abs(); TSET1(); break; - case 0x0F: BRK(); break; - case 0x10: Addr_Rel(); BPL(); break; - case 0x11: TCALL<1>(); break; - case 0x12: Addr_Dir(); CLR1<0>(); break; - case 0x13: Addr_Dir(); BBC<0>(); break; - case 0x14: Addr_DirIdxX(); OR_Acc(); break; - case 0x15: Addr_AbsIdxX(); OR_Acc(); break; - case 0x16: Addr_AbsIdxY(); OR_Acc(); break; - case 0x17: Addr_DirIndIdxY(); OR_Acc(); break; - case 0x18: Addr_DirImm(); OR(); break; - case 0x19: Addr_IndXToIndY(); OR(); break; - case 0x1A: Addr_Dir(); DECW(); break; - case 0x1B: Addr_DirIdxX(); ASL(); break; - case 0x1C: ASL_Acc(); break; - case 0x1D: DEX(); break; - case 0x1E: Addr_Abs(); CPX(); break; - case 0x1F: Addr_AbsIdxXInd(); JMP(); break; - case 0x20: CLRP(); break; - case 0x21: TCALL<2>(); break; - case 0x22: Addr_Dir(); SET1<1>(); break; - case 0x23: Addr_Dir(); BBS<1>(); break; - case 0x24: Addr_Dir(); AND_Acc(); break; - case 0x25: Addr_Abs(); AND_Acc(); break; - case 0x26: Addr_IndX(); AND_Acc(); break; - case 0x27: Addr_DirIdxXInd(); AND_Acc(); break; - case 0x28: Addr_Imm(); AND_Imm(); break; - case 0x29: Addr_DirToDir(); AND(); break; - case 0x2A: Addr_AbsBit(); NOR1(); break; - case 0x2B: Addr_Dir(); ROL(); break; - case 0x2C: Addr_Abs(); ROL(); break; - case 0x2D: PHA(); break; - case 0x2E: Addr_Dir(); CBNE(); break; - case 0x2F: Addr_Rel(); BRA(); break; - case 0x30: Addr_Rel(); BMI(); break; - case 0x31: TCALL<3>(); break; - case 0x32: Addr_Dir(); CLR1<1>(); break; - case 0x33: Addr_Dir(); BBC<1>(); break; - case 0x34: Addr_DirIdxX(); AND_Acc(); break; - case 0x35: Addr_AbsIdxX(); AND_Acc(); break; - case 0x36: Addr_AbsIdxY(); AND_Acc(); break; - case 0x37: Addr_DirIndIdxY(); AND_Acc(); break; - case 0x38: Addr_DirImm(); AND(); break; - case 0x39: Addr_IndXToIndY(); AND(); break; - case 0x3A: Addr_Dir(); INCW(); break; - case 0x3B: Addr_DirIdxX(); ROL(); break; - case 0x3C: ROL_Acc(); break; - case 0x3D: INX(); break; - case 0x3E: Addr_Dir(); CPX(); break; - case 0x3F: Addr_Abs(); JSR(); break; - case 0x40: SETP(); break; - case 0x41: TCALL<4>(); break; - case 0x42: Addr_Dir(); SET1<2>(); break; - case 0x43: Addr_Dir(); BBS<2>(); break; - case 0x44: Addr_Dir(); EOR_Acc(); break; - case 0x45: Addr_Abs(); EOR_Acc(); break; - case 0x46: Addr_IndX(); EOR_Acc(); break; - case 0x47: Addr_DirIdxXInd(); EOR_Acc(); break; - case 0x48: Addr_Imm(); EOR_Imm(); break; - case 0x49: Addr_DirToDir(); EOR(); break; - case 0x4A: Addr_AbsBit(); AND1(); break; - case 0x4B: Addr_Dir(); LSR(); break; - case 0x4C: Addr_Abs(); LSR(); break; - case 0x4D: PHX(); break; - case 0x4E: Addr_Abs(); TCLR1(); break; - case 0x4F: PCALL(); break; - case 0x50: Addr_Rel(); BVC(); break; - case 0x51: TCALL<5>(); break; - case 0x52: Addr_Dir(); CLR1<2>(); break; - case 0x53: Addr_Dir(); BBC<2>(); break; - case 0x54: Addr_DirIdxX(); EOR_Acc(); break; - case 0x55: Addr_AbsIdxX(); EOR_Acc(); break; - case 0x56: Addr_AbsIdxY(); EOR_Acc(); break; - case 0x57: Addr_DirIndIdxY(); EOR_Acc(); break; - case 0x58: Addr_DirImm(); EOR(); break; - case 0x59: Addr_IndXToIndY(); EOR(); break; - case 0x5A: Addr_Dir(); CMPW(); break; - case 0x5B: Addr_DirIdxX(); LSR(); break; - case 0x5C: LSR_Acc(); break; - case 0x5D: TAX(); break; - case 0x5E: Addr_Abs(); CPY(); break; - case 0x5F: Addr_Abs(); JMP(); break; - case 0x60: CLRC(); break; - case 0x61: TCALL<6>(); break; - case 0x62: Addr_Dir(); SET1<3>(); break; - case 0x63: Addr_Dir(); BBS<3>(); break; - case 0x64: Addr_Dir(); CMP_Acc(); break; - case 0x65: Addr_Abs(); CMP_Acc(); break; - case 0x66: Addr_IndX(); CMP_Acc(); break; - case 0x67: Addr_DirIdxXInd(); CMP_Acc(); break; - case 0x68: Addr_Imm(); CMP_Imm(); break; - case 0x69: Addr_DirToDir(); CMP(); break; - case 0x6A: Addr_AbsBit(); NAND1(); break; - case 0x6B: Addr_Dir(); ROR(); break; - case 0x6C: Addr_Abs(); ROR(); break; - case 0x6D: PHY(); break; - case 0x6E: Addr_Dir(); DBNZ(); break; - case 0x6F: RTS(); break; - case 0x70: Addr_Rel(); BVS(); break; - case 0x71: TCALL<7>(); break; - case 0x72: Addr_Dir(); CLR1<3>(); break; - case 0x73: Addr_Dir(); BBC<3>(); break; - case 0x74: Addr_DirIdxX(); CMP_Acc(); break; - case 0x75: Addr_AbsIdxX(); CMP_Acc(); break; - case 0x76: Addr_AbsIdxY(); CMP_Acc(); break; - case 0x77: Addr_DirIndIdxY(); CMP_Acc(); break; - case 0x78: Addr_DirImm(); CMP(); break; - case 0x79: Addr_IndXToIndY(); CMP(); break; - case 0x7A: Addr_Dir(); ADDW(); break; - case 0x7B: Addr_DirIdxX(); ROR(); break; - case 0x7C: ROR_Acc(); break; - case 0x7D: TXA(); break; - case 0x7E: Addr_Dir(); CPY(); break; - case 0x7F: RTI(); break; - case 0x80: SETC(); break; - case 0x81: TCALL<8>(); break; - case 0x82: Addr_Dir(); SET1<4>(); break; - case 0x83: Addr_Dir(); BBS<4>(); break; - case 0x84: Addr_Dir(); ADC_Acc(); break; - case 0x85: Addr_Abs(); ADC_Acc(); break; - case 0x86: Addr_IndX(); ADC_Acc(); break; - case 0x87: Addr_DirIdxXInd(); ADC_Acc(); break; - case 0x88: Addr_Imm(); ADC_Imm(); break; - case 0x89: Addr_DirToDir(); ADC(); break; - case 0x8A: Addr_AbsBit(); EOR1(); break; - case 0x8B: Addr_Dir(); DEC(); break; - case 0x8C: Addr_Abs(); DEC(); break; - case 0x8D: Addr_Imm(); LDY_Imm(); break; - case 0x8E: PLP(); break; - case 0x8F: Addr_DirImm(); MOV_Imm(); break; - case 0x90: Addr_Rel(); BCC(); break; - case 0x91: TCALL<9>(); break; - case 0x92: Addr_Dir(); CLR1<4>(); break; - case 0x93: Addr_Dir(); BBC<4>(); break; - case 0x94: Addr_DirIdxX(); ADC_Acc(); break; - case 0x95: Addr_AbsIdxX(); ADC_Acc(); break; - case 0x96: Addr_AbsIdxY(); ADC_Acc(); break; - case 0x97: Addr_DirIndIdxY(); ADC_Acc(); break; - case 0x98: Addr_DirImm(); ADC(); break; - case 0x99: Addr_IndXToIndY(); ADC(); break; - case 0x9A: Addr_Dir(); SUBW(); break; - case 0x9B: Addr_DirIdxX(); DEC(); break; - case 0x9C: DEC_Acc(); break; - case 0x9D: TSX(); break; - case 0x9E: DIV(); break; - case 0x9F: XCN(); break; - case 0xA0: EI(); break; - case 0xA1: TCALL<10>(); break; - case 0xA2: Addr_Dir(); SET1<5>(); break; - case 0xA3: Addr_Dir(); BBS<5>(); break; - case 0xA4: Addr_Dir(); SBC_Acc(); break; - case 0xA5: Addr_Abs(); SBC_Acc(); break; - case 0xA6: Addr_IndX(); SBC_Acc(); break; - case 0xA7: Addr_DirIdxXInd(); SBC_Acc(); break; - case 0xA8: Addr_Imm(); SBC_Imm(); break; - case 0xA9: Addr_DirToDir(); SBC(); break; - case 0xAA: Addr_AbsBit(); LDC(); break; - case 0xAB: Addr_Dir(); INC(); break; - case 0xAC: Addr_Abs(); INC(); break; - case 0xAD: Addr_Imm(); CPY_Imm(); break; - case 0xAE: PLA(); break; - case 0xAF: Addr_IndX(); STA_AutoIncX(); break; - case 0xB0: Addr_Rel(); BCS(); break; - case 0xB1: TCALL<11>(); break; - case 0xB2: Addr_Dir(); CLR1<5>(); break; - case 0xB3: Addr_Dir(); BBC<5>(); break; - case 0xB4: Addr_DirIdxX(); SBC_Acc(); break; - case 0xB5: Addr_AbsIdxX(); SBC_Acc(); break; - case 0xB6: Addr_AbsIdxY(); SBC_Acc(); break; - case 0xB7: Addr_DirIndIdxY(); SBC_Acc(); break; - case 0xB8: Addr_DirImm(); SBC(); break; - case 0xB9: Addr_IndXToIndY(); SBC(); break; - case 0xBA: Addr_Dir(); LDW(); break; - case 0xBB: Addr_DirIdxX(); INC(); break; - case 0xBC: INC_Acc(); break; - case 0xBD: TXS(); break; - case 0xBE: DAS(); break; - case 0xBF: Addr_IndX(); LDA_AutoIncX(); break; - case 0xC0: DI(); break; - case 0xC1: TCALL<12>(); break; - case 0xC2: Addr_Dir(); SET1<6>(); break; - case 0xC3: Addr_Dir(); BBS<6>(); break; - case 0xC4: Addr_Dir(); STA(); break; - case 0xC5: Addr_Abs(); STA(); break; - case 0xC6: Addr_IndX(); STA(); break; - case 0xC7: Addr_DirIdxXInd(); STA(); break; - case 0xC8: Addr_Imm(); CPX_Imm(); break; - case 0xC9: Addr_Abs(); STX(); break; - case 0xCA: Addr_AbsBit(); STC(); break; - case 0xCB: Addr_Dir(); STY(); break; - case 0xCC: Addr_Abs(); STY(); break; - case 0xCD: Addr_Imm(); LDX_Imm(); break; - case 0xCE: PLX(); break; - case 0xCF: MUL(); break; - case 0xD0: Addr_Rel(); BNE(); break; - case 0xD1: TCALL<13>(); break; - case 0xD2: Addr_Dir(); CLR1<6>(); break; - case 0xD3: Addr_Dir(); BBC<6>(); break; - case 0xD4: Addr_DirIdxX(); STA(); break; - case 0xD5: Addr_AbsIdxX(); STA(); break; - case 0xD6: Addr_AbsIdxY(); STA(); break; - case 0xD7: Addr_DirIndIdxY(); STA(); break; - case 0xD8: Addr_Dir(); STX(); break; - case 0xD9: Addr_DirIdxY(); STX(); break; - case 0xDA: Addr_Dir(); STW(); break; - case 0xDB: Addr_DirIdxX(); STY(); break; - case 0xDC: DEY(); break; - case 0xDD: TYA(); break; - case 0xDE: Addr_DirIdxX(); CBNE(); break; - case 0xDF: DAA(); break; - case 0xE0: CLRV(); break; - case 0xE1: TCALL<14>(); break; - case 0xE2: Addr_Dir(); SET1<7>(); break; - case 0xE3: Addr_Dir(); BBS<7>(); break; - case 0xE4: Addr_Dir(); LDA(); break; - case 0xE5: Addr_Abs(); LDA(); break; - case 0xE6: Addr_IndX(); LDA(); break; - case 0xE7: Addr_DirIdxXInd(); LDA(); break; - case 0xE8: Addr_Imm(); LDA_Imm(); break; - case 0xE9: Addr_Abs(); LDX(); break; - case 0xEA: Addr_AbsBit(); NOT1(); break; - case 0xEB: Addr_Dir(); LDY(); break; - case 0xEC: Addr_Abs(); LDY(); break; - case 0xED: NOTC(); break; - case 0xEE: PLY(); break; - case 0xEF: SLEEP(); break; - case 0xF0: Addr_Rel(); BEQ(); break; - case 0xF1: TCALL<15>(); break; - case 0xF2: Addr_Dir(); CLR1<7>(); break; - case 0xF3: Addr_Dir(); BBC<7>(); break; - case 0xF4: Addr_DirIdxX(); LDA(); break; - case 0xF5: Addr_AbsIdxX(); LDA(); break; - case 0xF6: Addr_AbsIdxY(); LDA(); break; - case 0xF7: Addr_DirIndIdxY(); LDA(); break; - case 0xF8: Addr_Dir(); LDX(); break; - case 0xF9: Addr_DirIdxY(); LDX(); break; - case 0xFA: Addr_DirToDir(); MOV(); break; - case 0xFB: Addr_DirIdxX(); LDY(); break; - case 0xFC: INY(); break; - case 0xFD: TAY(); break; - case 0xFE: DBNZ_Y(); break; - case 0xFF: STOP(); break; + switch (_opCode) + { + case 0x00: NOP(); + break; + case 0x01: TCALL<0>(); + break; + case 0x02: Addr_Dir(); + SET1<0>(); + break; + case 0x03: Addr_Dir(); + BBS<0>(); + break; + case 0x04: Addr_Dir(); + OR_Acc(); + break; + case 0x05: Addr_Abs(); + OR_Acc(); + break; + case 0x06: Addr_IndX(); + OR_Acc(); + break; + case 0x07: Addr_DirIdxXInd(); + OR_Acc(); + break; + case 0x08: Addr_Imm(); + OR_Imm(); + break; + case 0x09: Addr_DirToDir(); + OR(); + break; + case 0x0A: Addr_AbsBit(); + OR1(); + break; + case 0x0B: Addr_Dir(); + ASL(); + break; + case 0x0C: Addr_Abs(); + ASL(); + break; + case 0x0D: PHP(); + break; + case 0x0E: Addr_Abs(); + TSET1(); + break; + case 0x0F: BRK(); + break; + case 0x10: Addr_Rel(); + BPL(); + break; + case 0x11: TCALL<1>(); + break; + case 0x12: Addr_Dir(); + CLR1<0>(); + break; + case 0x13: Addr_Dir(); + BBC<0>(); + break; + case 0x14: Addr_DirIdxX(); + OR_Acc(); + break; + case 0x15: Addr_AbsIdxX(); + OR_Acc(); + break; + case 0x16: Addr_AbsIdxY(); + OR_Acc(); + break; + case 0x17: Addr_DirIndIdxY(); + OR_Acc(); + break; + case 0x18: Addr_DirImm(); + OR(); + break; + case 0x19: Addr_IndXToIndY(); + OR(); + break; + case 0x1A: Addr_Dir(); + DECW(); + break; + case 0x1B: Addr_DirIdxX(); + ASL(); + break; + case 0x1C: ASL_Acc(); + break; + case 0x1D: DEX(); + break; + case 0x1E: Addr_Abs(); + CPX(); + break; + case 0x1F: Addr_AbsIdxXInd(); + JMP(); + break; + case 0x20: CLRP(); + break; + case 0x21: TCALL<2>(); + break; + case 0x22: Addr_Dir(); + SET1<1>(); + break; + case 0x23: Addr_Dir(); + BBS<1>(); + break; + case 0x24: Addr_Dir(); + AND_Acc(); + break; + case 0x25: Addr_Abs(); + AND_Acc(); + break; + case 0x26: Addr_IndX(); + AND_Acc(); + break; + case 0x27: Addr_DirIdxXInd(); + AND_Acc(); + break; + case 0x28: Addr_Imm(); + AND_Imm(); + break; + case 0x29: Addr_DirToDir(); + AND(); + break; + case 0x2A: Addr_AbsBit(); + NOR1(); + break; + case 0x2B: Addr_Dir(); + ROL(); + break; + case 0x2C: Addr_Abs(); + ROL(); + break; + case 0x2D: PHA(); + break; + case 0x2E: Addr_Dir(); + CBNE(); + break; + case 0x2F: Addr_Rel(); + BRA(); + break; + case 0x30: Addr_Rel(); + BMI(); + break; + case 0x31: TCALL<3>(); + break; + case 0x32: Addr_Dir(); + CLR1<1>(); + break; + case 0x33: Addr_Dir(); + BBC<1>(); + break; + case 0x34: Addr_DirIdxX(); + AND_Acc(); + break; + case 0x35: Addr_AbsIdxX(); + AND_Acc(); + break; + case 0x36: Addr_AbsIdxY(); + AND_Acc(); + break; + case 0x37: Addr_DirIndIdxY(); + AND_Acc(); + break; + case 0x38: Addr_DirImm(); + AND(); + break; + case 0x39: Addr_IndXToIndY(); + AND(); + break; + case 0x3A: Addr_Dir(); + INCW(); + break; + case 0x3B: Addr_DirIdxX(); + ROL(); + break; + case 0x3C: ROL_Acc(); + break; + case 0x3D: INX(); + break; + case 0x3E: Addr_Dir(); + CPX(); + break; + case 0x3F: Addr_Abs(); + JSR(); + break; + case 0x40: SETP(); + break; + case 0x41: TCALL<4>(); + break; + case 0x42: Addr_Dir(); + SET1<2>(); + break; + case 0x43: Addr_Dir(); + BBS<2>(); + break; + case 0x44: Addr_Dir(); + EOR_Acc(); + break; + case 0x45: Addr_Abs(); + EOR_Acc(); + break; + case 0x46: Addr_IndX(); + EOR_Acc(); + break; + case 0x47: Addr_DirIdxXInd(); + EOR_Acc(); + break; + case 0x48: Addr_Imm(); + EOR_Imm(); + break; + case 0x49: Addr_DirToDir(); + EOR(); + break; + case 0x4A: Addr_AbsBit(); + AND1(); + break; + case 0x4B: Addr_Dir(); + LSR(); + break; + case 0x4C: Addr_Abs(); + LSR(); + break; + case 0x4D: PHX(); + break; + case 0x4E: Addr_Abs(); + TCLR1(); + break; + case 0x4F: PCALL(); + break; + case 0x50: Addr_Rel(); + BVC(); + break; + case 0x51: TCALL<5>(); + break; + case 0x52: Addr_Dir(); + CLR1<2>(); + break; + case 0x53: Addr_Dir(); + BBC<2>(); + break; + case 0x54: Addr_DirIdxX(); + EOR_Acc(); + break; + case 0x55: Addr_AbsIdxX(); + EOR_Acc(); + break; + case 0x56: Addr_AbsIdxY(); + EOR_Acc(); + break; + case 0x57: Addr_DirIndIdxY(); + EOR_Acc(); + break; + case 0x58: Addr_DirImm(); + EOR(); + break; + case 0x59: Addr_IndXToIndY(); + EOR(); + break; + case 0x5A: Addr_Dir(); + CMPW(); + break; + case 0x5B: Addr_DirIdxX(); + LSR(); + break; + case 0x5C: LSR_Acc(); + break; + case 0x5D: TAX(); + break; + case 0x5E: Addr_Abs(); + CPY(); + break; + case 0x5F: Addr_Abs(); + JMP(); + break; + case 0x60: CLRC(); + break; + case 0x61: TCALL<6>(); + break; + case 0x62: Addr_Dir(); + SET1<3>(); + break; + case 0x63: Addr_Dir(); + BBS<3>(); + break; + case 0x64: Addr_Dir(); + CMP_Acc(); + break; + case 0x65: Addr_Abs(); + CMP_Acc(); + break; + case 0x66: Addr_IndX(); + CMP_Acc(); + break; + case 0x67: Addr_DirIdxXInd(); + CMP_Acc(); + break; + case 0x68: Addr_Imm(); + CMP_Imm(); + break; + case 0x69: Addr_DirToDir(); + CMP(); + break; + case 0x6A: Addr_AbsBit(); + NAND1(); + break; + case 0x6B: Addr_Dir(); + ROR(); + break; + case 0x6C: Addr_Abs(); + ROR(); + break; + case 0x6D: PHY(); + break; + case 0x6E: Addr_Dir(); + DBNZ(); + break; + case 0x6F: RTS(); + break; + case 0x70: Addr_Rel(); + BVS(); + break; + case 0x71: TCALL<7>(); + break; + case 0x72: Addr_Dir(); + CLR1<3>(); + break; + case 0x73: Addr_Dir(); + BBC<3>(); + break; + case 0x74: Addr_DirIdxX(); + CMP_Acc(); + break; + case 0x75: Addr_AbsIdxX(); + CMP_Acc(); + break; + case 0x76: Addr_AbsIdxY(); + CMP_Acc(); + break; + case 0x77: Addr_DirIndIdxY(); + CMP_Acc(); + break; + case 0x78: Addr_DirImm(); + CMP(); + break; + case 0x79: Addr_IndXToIndY(); + CMP(); + break; + case 0x7A: Addr_Dir(); + ADDW(); + break; + case 0x7B: Addr_DirIdxX(); + ROR(); + break; + case 0x7C: ROR_Acc(); + break; + case 0x7D: TXA(); + break; + case 0x7E: Addr_Dir(); + CPY(); + break; + case 0x7F: RTI(); + break; + case 0x80: SETC(); + break; + case 0x81: TCALL<8>(); + break; + case 0x82: Addr_Dir(); + SET1<4>(); + break; + case 0x83: Addr_Dir(); + BBS<4>(); + break; + case 0x84: Addr_Dir(); + ADC_Acc(); + break; + case 0x85: Addr_Abs(); + ADC_Acc(); + break; + case 0x86: Addr_IndX(); + ADC_Acc(); + break; + case 0x87: Addr_DirIdxXInd(); + ADC_Acc(); + break; + case 0x88: Addr_Imm(); + ADC_Imm(); + break; + case 0x89: Addr_DirToDir(); + ADC(); + break; + case 0x8A: Addr_AbsBit(); + EOR1(); + break; + case 0x8B: Addr_Dir(); + DEC(); + break; + case 0x8C: Addr_Abs(); + DEC(); + break; + case 0x8D: Addr_Imm(); + LDY_Imm(); + break; + case 0x8E: PLP(); + break; + case 0x8F: Addr_DirImm(); + MOV_Imm(); + break; + case 0x90: Addr_Rel(); + BCC(); + break; + case 0x91: TCALL<9>(); + break; + case 0x92: Addr_Dir(); + CLR1<4>(); + break; + case 0x93: Addr_Dir(); + BBC<4>(); + break; + case 0x94: Addr_DirIdxX(); + ADC_Acc(); + break; + case 0x95: Addr_AbsIdxX(); + ADC_Acc(); + break; + case 0x96: Addr_AbsIdxY(); + ADC_Acc(); + break; + case 0x97: Addr_DirIndIdxY(); + ADC_Acc(); + break; + case 0x98: Addr_DirImm(); + ADC(); + break; + case 0x99: Addr_IndXToIndY(); + ADC(); + break; + case 0x9A: Addr_Dir(); + SUBW(); + break; + case 0x9B: Addr_DirIdxX(); + DEC(); + break; + case 0x9C: DEC_Acc(); + break; + case 0x9D: TSX(); + break; + case 0x9E: DIV(); + break; + case 0x9F: XCN(); + break; + case 0xA0: EI(); + break; + case 0xA1: TCALL<10>(); + break; + case 0xA2: Addr_Dir(); + SET1<5>(); + break; + case 0xA3: Addr_Dir(); + BBS<5>(); + break; + case 0xA4: Addr_Dir(); + SBC_Acc(); + break; + case 0xA5: Addr_Abs(); + SBC_Acc(); + break; + case 0xA6: Addr_IndX(); + SBC_Acc(); + break; + case 0xA7: Addr_DirIdxXInd(); + SBC_Acc(); + break; + case 0xA8: Addr_Imm(); + SBC_Imm(); + break; + case 0xA9: Addr_DirToDir(); + SBC(); + break; + case 0xAA: Addr_AbsBit(); + LDC(); + break; + case 0xAB: Addr_Dir(); + INC(); + break; + case 0xAC: Addr_Abs(); + INC(); + break; + case 0xAD: Addr_Imm(); + CPY_Imm(); + break; + case 0xAE: PLA(); + break; + case 0xAF: Addr_IndX(); + STA_AutoIncX(); + break; + case 0xB0: Addr_Rel(); + BCS(); + break; + case 0xB1: TCALL<11>(); + break; + case 0xB2: Addr_Dir(); + CLR1<5>(); + break; + case 0xB3: Addr_Dir(); + BBC<5>(); + break; + case 0xB4: Addr_DirIdxX(); + SBC_Acc(); + break; + case 0xB5: Addr_AbsIdxX(); + SBC_Acc(); + break; + case 0xB6: Addr_AbsIdxY(); + SBC_Acc(); + break; + case 0xB7: Addr_DirIndIdxY(); + SBC_Acc(); + break; + case 0xB8: Addr_DirImm(); + SBC(); + break; + case 0xB9: Addr_IndXToIndY(); + SBC(); + break; + case 0xBA: Addr_Dir(); + LDW(); + break; + case 0xBB: Addr_DirIdxX(); + INC(); + break; + case 0xBC: INC_Acc(); + break; + case 0xBD: TXS(); + break; + case 0xBE: DAS(); + break; + case 0xBF: Addr_IndX(); + LDA_AutoIncX(); + break; + case 0xC0: DI(); + break; + case 0xC1: TCALL<12>(); + break; + case 0xC2: Addr_Dir(); + SET1<6>(); + break; + case 0xC3: Addr_Dir(); + BBS<6>(); + break; + case 0xC4: Addr_Dir(); + STA(); + break; + case 0xC5: Addr_Abs(); + STA(); + break; + case 0xC6: Addr_IndX(); + STA(); + break; + case 0xC7: Addr_DirIdxXInd(); + STA(); + break; + case 0xC8: Addr_Imm(); + CPX_Imm(); + break; + case 0xC9: Addr_Abs(); + STX(); + break; + case 0xCA: Addr_AbsBit(); + STC(); + break; + case 0xCB: Addr_Dir(); + STY(); + break; + case 0xCC: Addr_Abs(); + STY(); + break; + case 0xCD: Addr_Imm(); + LDX_Imm(); + break; + case 0xCE: PLX(); + break; + case 0xCF: MUL(); + break; + case 0xD0: Addr_Rel(); + BNE(); + break; + case 0xD1: TCALL<13>(); + break; + case 0xD2: Addr_Dir(); + CLR1<6>(); + break; + case 0xD3: Addr_Dir(); + BBC<6>(); + break; + case 0xD4: Addr_DirIdxX(); + STA(); + break; + case 0xD5: Addr_AbsIdxX(); + STA(); + break; + case 0xD6: Addr_AbsIdxY(); + STA(); + break; + case 0xD7: Addr_DirIndIdxY(); + STA(); + break; + case 0xD8: Addr_Dir(); + STX(); + break; + case 0xD9: Addr_DirIdxY(); + STX(); + break; + case 0xDA: Addr_Dir(); + STW(); + break; + case 0xDB: Addr_DirIdxX(); + STY(); + break; + case 0xDC: DEY(); + break; + case 0xDD: TYA(); + break; + case 0xDE: Addr_DirIdxX(); + CBNE(); + break; + case 0xDF: DAA(); + break; + case 0xE0: CLRV(); + break; + case 0xE1: TCALL<14>(); + break; + case 0xE2: Addr_Dir(); + SET1<7>(); + break; + case 0xE3: Addr_Dir(); + BBS<7>(); + break; + case 0xE4: Addr_Dir(); + LDA(); + break; + case 0xE5: Addr_Abs(); + LDA(); + break; + case 0xE6: Addr_IndX(); + LDA(); + break; + case 0xE7: Addr_DirIdxXInd(); + LDA(); + break; + case 0xE8: Addr_Imm(); + LDA_Imm(); + break; + case 0xE9: Addr_Abs(); + LDX(); + break; + case 0xEA: Addr_AbsBit(); + NOT1(); + break; + case 0xEB: Addr_Dir(); + LDY(); + break; + case 0xEC: Addr_Abs(); + LDY(); + break; + case 0xED: NOTC(); + break; + case 0xEE: PLY(); + break; + case 0xEF: SLEEP(); + break; + case 0xF0: Addr_Rel(); + BEQ(); + break; + case 0xF1: TCALL<15>(); + break; + case 0xF2: Addr_Dir(); + CLR1<7>(); + break; + case 0xF3: Addr_Dir(); + BBC<7>(); + break; + case 0xF4: Addr_DirIdxX(); + LDA(); + break; + case 0xF5: Addr_AbsIdxX(); + LDA(); + break; + case 0xF6: Addr_AbsIdxY(); + LDA(); + break; + case 0xF7: Addr_DirIndIdxY(); + LDA(); + break; + case 0xF8: Addr_Dir(); + LDX(); + break; + case 0xF9: Addr_DirIdxY(); + LDX(); + break; + case 0xFA: Addr_DirToDir(); + MOV(); + break; + case 0xFB: Addr_DirIdxX(); + LDY(); + break; + case 0xFC: INY(); + break; + case 0xFD: TAY(); + break; + case 0xFE: DBNZ_Y(); + break; + case 0xFF: STOP(); + break; } - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _opStep = SpcOpStep::Operation; } } @@ -284,7 +737,8 @@ void Spc::Exec() //***************** void Spc::Addr_Dir() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { _operandA = GetDirectAddress(ReadOperandByte()); EndAddr(); } @@ -292,80 +746,112 @@ void Spc::Addr_Dir() void Spc::Addr_DirIdxX() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.X); break; - case 1: Idle(); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.X); + break; + case 1: Idle(); + EndAddr(); + break; } } } void Spc::Addr_DirIdxY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.Y); break; - case 1: Idle(); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.Y); + break; + case 1: Idle(); + EndAddr(); + break; } } } void Spc::Addr_DirToDir() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); break; - case 1: _operandA = Read(_tmp1); break; - case 2: _operandB = GetDirectAddress(ReadOperandByte()); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); + break; + case 1: _operandA = Read(_tmp1); + break; + case 2: _operandB = GetDirectAddress(ReadOperandByte()); + EndAddr(); + break; } } } void Spc::Addr_DirImm() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _operandA = ReadOperandByte(); break; - case 1: _operandB = GetDirectAddress(ReadOperandByte()); EndAddr(); break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _operandA = ReadOperandByte(); + break; + case 1: _operandB = GetDirectAddress(ReadOperandByte()); + EndAddr(); + break; } } } void Spc::Addr_DirIdxXInd() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = GetDirectAddress(ReadOperandByte() + _state.X); break; - case 1: Idle(); break; - case 2: _tmp2 = Read(_tmp1); break; - case 3: - _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); - _operandA = (_tmp3 << 8) | _tmp2; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = GetDirectAddress(ReadOperandByte() + _state.X); + break; + case 1: Idle(); + break; + case 2: _tmp2 = Read(_tmp1); + break; + case 3: + _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); + _operandA = (_tmp3 << 8) | _tmp2; + EndAddr(); + break; } } } void Spc::Addr_DirIndIdxY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); break; - case 1: _tmp2 = Read(_tmp1); break; - case 2: _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); break; - case 4: - Idle(); - _operandA = ((_tmp3 << 8) | _tmp2) + _state.Y; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = GetDirectAddress(ReadOperandByte()); + break; + case 1: _tmp2 = Read(_tmp1); + break; + case 2: _tmp3 = Read(GetDirectAddress(_tmp1 + 1)); + break; + case 4: + Idle(); + _operandA = ((_tmp3 << 8) | _tmp2) + _state.Y; + EndAddr(); + break; } } } void Spc::Addr_IndX() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { DummyRead(); _operandA = GetDirectAddress(_state.X); EndAddr(); @@ -374,82 +860,97 @@ void Spc::Addr_IndX() void Spc::Addr_IndXToIndY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - _operandA = Read(GetDirectAddress(_state.Y)); - _operandB = GetDirectAddress(_state.X); - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + _operandA = Read(GetDirectAddress(_state.Y)); + _operandB = GetDirectAddress(_state.X); + EndAddr(); + break; } } } void Spc::Addr_Abs() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + EndAddr(); + break; } } } void Spc::Addr_AbsBit() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - _operandB = _operandA >> 13; - _operandA = _operandA & 0x1FFF; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + _operandB = _operandA >> 13; + _operandA = _operandA & 0x1FFF; + EndAddr(); + break; } } } void Spc::Addr_AbsIdxX() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + break; - case 2: - Idle(); - _operandA += _state.X; - EndAddr(); - break; + case 2: + Idle(); + _operandA += _state.X; + EndAddr(); + break; } } } void Spc::Addr_AbsIdxY() { - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: - _tmp2 = ReadOperandByte(); - _operandA = ((_tmp2 << 8) | _tmp1); - break; - - case 2: - Idle(); - _operandA += _state.Y; - EndAddr(); - break; + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: + _tmp2 = ReadOperandByte(); + _operandA = ((_tmp2 << 8) | _tmp1); + break; + + case 2: + Idle(); + _operandA += _state.Y; + EndAddr(); + break; } } } @@ -457,12 +958,17 @@ void Spc::Addr_AbsIdxY() void Spc::Addr_AbsIdxXInd() { //Used by JMP only - if(_opStep == SpcOpStep::Addressing) { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: _tmp2 = ReadOperandByte(); break; - case 2: Idle(); break; - case 3: + if (_opStep == SpcOpStep::Addressing) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: _tmp2 = ReadOperandByte(); + break; + case 2: Idle(); + break; + case 3: { uint16_t addr = ((_tmp2 << 8) | _tmp1); _tmp1 = Read(addr + _state.X); @@ -477,7 +983,8 @@ void Spc::Addr_AbsIdxXInd() void Spc::Addr_Rel() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { _operandA = ReadOperandByte(); EndAddr(); } @@ -485,7 +992,8 @@ void Spc::Addr_Rel() void Spc::Addr_Imm() { - if(_opStep == SpcOpStep::Addressing) { + if (_opStep == SpcOpStep::Addressing) + { _operandA = ReadOperandByte(); EndAddr(); } @@ -496,84 +1004,109 @@ void Spc::Addr_Imm() //***************** void Spc::STA() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Read(_operandA); break; - case 1: Write(_operandA, _state.A); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Read(_operandA); + break; + case 1: Write(_operandA, _state.A); + EndOp(); + break; } } } void Spc::STX() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Read(_operandA); break; - case 1: Write(_operandA, _state.X); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Read(_operandA); + break; + case 1: Write(_operandA, _state.X); + EndOp(); + break; } } } void Spc::STY() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Read(_operandA); break; - case 1: Write(_operandA, _state.Y); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Read(_operandA); + break; + case 1: Write(_operandA, _state.Y); + EndOp(); + break; } } } void Spc::STW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: DummyRead(_operandA); break; - case 1: Write(_operandA, _state.A); break; - case 2: - uint16_t msbAddress = GetDirectAddress(_operandA + 1); - Write(msbAddress, _state.Y); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: DummyRead(_operandA); + break; + case 1: Write(_operandA, _state.A); + break; + case 2: + uint16_t msbAddress = GetDirectAddress(_operandA + 1); + Write(msbAddress, _state.Y); + EndOp(); + break; } } } void Spc::STA_AutoIncX() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Write(_operandA, _state.A); - _state.X++; - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Write(_operandA, _state.A); + _state.X++; + EndOp(); + break; } } } void Spc::LDA_AutoIncX() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: - _state.A = Read(_operandA); - SetZeroNegativeFlags(_state.A); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: + _state.A = Read(_operandA); + SetZeroNegativeFlags(_state.A); + break; - case 1: - Idle(); - _state.X++; - EndOp(); - break; + case 1: + Idle(); + _state.X++; + EndOp(); + break; } } } void Spc::LDA() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A = GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -582,7 +1115,8 @@ void Spc::LDA() void Spc::LDA_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A = (uint8_t)_operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -591,7 +1125,8 @@ void Spc::LDA_Imm() void Spc::LDX() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.X = GetByteValue(); SetZeroNegativeFlags(_state.X); EndOp(); @@ -600,7 +1135,8 @@ void Spc::LDX() void Spc::LDX_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.X = (uint8_t)_operandA; SetZeroNegativeFlags(_state.X); EndOp(); @@ -609,7 +1145,8 @@ void Spc::LDX_Imm() void Spc::LDY() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.Y = GetByteValue(); SetZeroNegativeFlags(_state.Y); EndOp(); @@ -618,7 +1155,8 @@ void Spc::LDY() void Spc::LDY_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.Y = (uint8_t)_operandA; SetZeroNegativeFlags(_state.Y); EndOp(); @@ -627,23 +1165,27 @@ void Spc::LDY_Imm() void Spc::LDW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = (msb << 8) | _tmp1; - _state.A = (uint8_t)value; - _state.Y = (value >> 8); - SetZeroNegativeFlags16(value); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = (msb << 8) | _tmp1; + _state.A = (uint8_t)value; + _state.Y = (value >> 8); + SetZeroNegativeFlags16(value); + EndOp(); + break; } } } -void Spc::Transfer(uint8_t &dst, uint8_t src) +void Spc::Transfer(uint8_t& dst, uint8_t src) { DummyRead(); dst = src; @@ -685,7 +1227,8 @@ void Spc::TXS() void Spc::MOV() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Write(_operandB, (uint8_t)_operandA); EndOp(); } @@ -693,10 +1236,15 @@ void Spc::MOV() void Spc::MOV_Imm() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: DummyRead(_operandB); break; - case 1: Write(_operandB, (uint8_t)_operandA); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: DummyRead(_operandB); + break; + case 1: Write(_operandB, (uint8_t)_operandA); + EndOp(); + break; } } } @@ -708,13 +1256,16 @@ uint8_t Spc::Add(uint8_t a, uint8_t b) ClearFlags(SpcFlags::Carry | SpcFlags::Negative | SpcFlags::Zero | SpcFlags::Overflow | SpcFlags::HalfCarry); - if(~(a ^ b) & (a ^ result) & 0x80) { + if (~(a ^ b) & (a ^ result) & 0x80) + { SetFlags(SpcFlags::Overflow); } - if(result > 0xFF) { + if (result > 0xFF) + { SetFlags(SpcFlags::Carry); } - if(((result & 0x0F) - subResult) & 0x10) { + if (((result & 0x0F) - subResult) & 0x10) + { SetFlags(SpcFlags::HalfCarry); } SetZeroNegativeFlags((uint8_t)result); @@ -727,9 +1278,12 @@ uint8_t Spc::Sub(uint8_t a, uint8_t b) uint32_t carryCalc = a - b - ((_state.PS & SpcFlags::Carry) ^ 0x01); uint8_t result = Add(a, ~b); - if(carryCalc <= 0xFF) { + if (carryCalc <= 0xFF) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } @@ -738,24 +1292,27 @@ uint8_t Spc::Sub(uint8_t a, uint8_t b) void Spc::ADC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: - _tmp1 = (uint8_t)_operandA; - _tmp2 = Read(_operandB); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: + _tmp1 = (uint8_t)_operandA; + _tmp2 = Read(_operandB); + break; - case 1: - Write(_operandB, Add((uint8_t)_tmp2, (uint8_t)_tmp1)); - EndOp(); - break; + case 1: + Write(_operandB, Add((uint8_t)_tmp2, (uint8_t)_tmp1)); + EndOp(); + break; } } } void Spc::ADC_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A = Add(_state.A, GetByteValue()); EndOp(); } @@ -763,7 +1320,8 @@ void Spc::ADC_Acc() void Spc::ADC_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A = Add(_state.A, (uint8_t)_operandA); EndOp(); } @@ -771,59 +1329,69 @@ void Spc::ADC_Imm() void Spc::ADDW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = ((msb << 8) | _tmp1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = ((msb << 8) | _tmp1); - uint8_t lowCarry = (_tmp1 + _state.A) > 0xFF ? 1 : 0; - ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); - if(((_state.Y & 0x0F) + (msb & 0x0F) + lowCarry) & 0x10) { - SetFlags(SpcFlags::HalfCarry); - } + uint8_t lowCarry = (_tmp1 + _state.A) > 0xFF ? 1 : 0; + ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); + if (((_state.Y & 0x0F) + (msb & 0x0F) + lowCarry) & 0x10) + { + SetFlags(SpcFlags::HalfCarry); + } - uint16_t ya = (_state.Y << 8) | _state.A; - uint32_t result = ya + value; - if(result > 0xFFFF) { - SetFlags(SpcFlags::Carry); - } - SetZeroNegativeFlags16(result); + uint16_t ya = (_state.Y << 8) | _state.A; + uint32_t result = ya + value; + if (result > 0xFFFF) + { + SetFlags(SpcFlags::Carry); + } + SetZeroNegativeFlags16(result); - if(~(ya ^ value) & (ya ^ result) & 0x8000) { - SetFlags(SpcFlags::Overflow); - } + if (~(ya ^ value) & (ya ^ result) & 0x8000) + { + SetFlags(SpcFlags::Overflow); + } - _state.Y = result >> 8; - _state.A = (uint8_t)result; + _state.Y = result >> 8; + _state.A = (uint8_t)result; - EndOp(); + EndOp(); } } } void Spc::SBC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: - _tmp1 = (uint8_t)_operandA; - _tmp2 = Read(_operandB); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: + _tmp1 = (uint8_t)_operandA; + _tmp2 = Read(_operandB); + break; - case 1: - Write(_operandB, Sub((uint8_t)_tmp2, (uint8_t)_tmp1)); - EndOp(); - break; + case 1: + Write(_operandB, Sub((uint8_t)_tmp2, (uint8_t)_tmp1)); + EndOp(); + break; } } } void Spc::SBC_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A = Sub(_state.A, GetByteValue()); EndOp(); } @@ -831,7 +1399,8 @@ void Spc::SBC_Acc() void Spc::SBC_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A = Sub(_state.A, (uint8_t)_operandA); EndOp(); } @@ -839,49 +1408,59 @@ void Spc::SBC_Imm() void Spc::SUBW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = ((msb << 8) | _tmp1); - uint16_t ya = (_state.Y << 8) | _state.A; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = ((msb << 8) | _tmp1); + uint16_t ya = (_state.Y << 8) | _state.A; - uint32_t l = _state.A - _tmp1; - uint8_t carry = l > 0xFF ? 1 : 0; - uint32_t h = _state.Y - msb - carry; + uint32_t l = _state.A - _tmp1; + uint8_t carry = l > 0xFF ? 1 : 0; + uint32_t h = _state.Y - msb - carry; - ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); - if(h <= 0xFF) { - SetFlags(SpcFlags::Carry); - } + ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow); + if (h <= 0xFF) + { + SetFlags(SpcFlags::Carry); + } - if((((_state.Y & 0x0F) - (msb & 0x0F) - carry) & 0x10) == 0) { - SetFlags(SpcFlags::HalfCarry); - } + if ((((_state.Y & 0x0F) - (msb & 0x0F) - carry) & 0x10) == 0) + { + SetFlags(SpcFlags::HalfCarry); + } - _state.Y = h; - _state.A = l; + _state.Y = h; + _state.A = l; - uint16_t result = (_state.Y << 8) | _state.A; + uint16_t result = (_state.Y << 8) | _state.A; - if((ya ^ value) & (ya ^ result) & 0x8000) { - SetFlags(SpcFlags::Overflow); - } + if ((ya ^ value) & (ya ^ result) & 0x8000) + { + SetFlags(SpcFlags::Overflow); + } - SetZeroNegativeFlags16(result); - EndOp(); - break; + SetZeroNegativeFlags16(result); + EndOp(); + break; } } } void Spc::Compare(uint8_t a, uint8_t b) { - if(a >= b) { + if (a >= b) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } @@ -891,17 +1470,23 @@ void Spc::Compare(uint8_t a, uint8_t b) void Spc::CMP() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Compare(Read(_operandB), (uint8_t)_operandA); break; - case 1: Idle(); EndOp(); break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Compare(Read(_operandB), (uint8_t)_operandA); + break; + case 1: Idle(); + EndOp(); + break; } } } void Spc::CMP_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Compare(_state.A, GetByteValue()); EndOp(); } @@ -909,7 +1494,8 @@ void Spc::CMP_Acc() void Spc::CMP_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { Compare(_state.A, (uint8_t)_operandA); EndOp(); } @@ -917,7 +1503,8 @@ void Spc::CMP_Imm() void Spc::CPX() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Compare(_state.X, GetByteValue()); EndOp(); } @@ -925,7 +1512,8 @@ void Spc::CPX() void Spc::CPX_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { Compare(_state.X, (uint8_t)_operandA); EndOp(); } @@ -933,7 +1521,8 @@ void Spc::CPX_Imm() void Spc::CPY() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Compare(_state.Y, GetByteValue()); EndOp(); } @@ -941,7 +1530,8 @@ void Spc::CPY() void Spc::CPY_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { Compare(_state.Y, (uint8_t)_operandA); EndOp(); } @@ -949,39 +1539,48 @@ void Spc::CPY_Imm() void Spc::CMPW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - uint8_t msb = Read(GetDirectAddress(_operandA + 1)); - uint16_t value = ((msb << 8) | _tmp1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + uint8_t msb = Read(GetDirectAddress(_operandA + 1)); + uint16_t value = ((msb << 8) | _tmp1); - uint16_t ya = (_state.Y << 8) | _state.A; + uint16_t ya = (_state.Y << 8) | _state.A; - if(ya >= value) { - SetFlags(SpcFlags::Carry); - } else { - ClearFlags(SpcFlags::Carry); - } + if (ya >= value) + { + SetFlags(SpcFlags::Carry); + } + else + { + ClearFlags(SpcFlags::Carry); + } - uint16_t result = ya - value; - SetZeroNegativeFlags16(result); - EndOp(); - break; + uint16_t result = ya - value; + SetZeroNegativeFlags16(result); + EndOp(); + break; } } } void Spc::INC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA) + 1; break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA) + 1; + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1012,33 +1611,39 @@ void Spc::INY() void Spc::INCW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 + 1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 + 1); - uint16_t msbAddress = GetDirectAddress(_operandA + 1); - uint8_t msb = Read(msbAddress); - uint16_t value = ((msb << 8) | _tmp1) + 1; - Write(msbAddress, value >> 8); - SetZeroNegativeFlags16(value); - EndOp(); - break; + uint16_t msbAddress = GetDirectAddress(_operandA + 1); + uint8_t msb = Read(msbAddress); + uint16_t value = ((msb << 8) | _tmp1) + 1; + Write(msbAddress, value >> 8); + SetZeroNegativeFlags16(value); + EndOp(); + break; } } } void Spc::DEC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA) - 1; break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA) - 1; + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1069,160 +1674,206 @@ void Spc::DEY() void Spc::DECW() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 - 1); + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 - 1); - uint16_t msbAddress = GetDirectAddress(_operandA + 1); - uint8_t msb = Read(msbAddress); - uint16_t value = ((msb << 8) | _tmp1) - 1; - Write(msbAddress, value >> 8); - SetZeroNegativeFlags16(value); - EndOp(); - break; + uint16_t msbAddress = GetDirectAddress(_operandA + 1); + uint8_t msb = Read(msbAddress); + uint16_t value = ((msb << 8) | _tmp1) - 1; + Write(msbAddress, value >> 8); + SetZeroNegativeFlags16(value); + EndOp(); + break; } } } void Spc::MUL() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Idle(); break; - case 3: Idle(); break; - case 4: Idle(); break; - case 5: Idle(); break; - case 6: Idle(); break; - case 7: - Idle(); - uint16_t result = _state.Y * _state.A; - _state.Y = result >> 8; - _state.A = (uint8_t)result; - SetZeroNegativeFlags(_state.Y); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Idle(); + break; + case 3: Idle(); + break; + case 4: Idle(); + break; + case 5: Idle(); + break; + case 6: Idle(); + break; + case 7: + Idle(); + uint16_t result = _state.Y * _state.A; + _state.Y = result >> 8; + _state.A = (uint8_t)result; + SetZeroNegativeFlags(_state.Y); + EndOp(); + break; } } void Spc::DIV() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Idle(); break; - case 3: Idle(); break; - case 4: Idle(); break; - case 5: Idle(); break; - case 6: Idle(); break; - case 7: Idle(); break; - case 8: Idle(); break; - case 9: Idle(); break; - case 11: - Idle(); - uint32_t ya = (_state.Y << 8) | _state.A; - uint32_t sub = _state.X << 9; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Idle(); + break; + case 3: Idle(); + break; + case 4: Idle(); + break; + case 5: Idle(); + break; + case 6: Idle(); + break; + case 7: Idle(); + break; + case 8: Idle(); + break; + case 9: Idle(); + break; + case 11: + Idle(); + uint32_t ya = (_state.Y << 8) | _state.A; + uint32_t sub = _state.X << 9; - for(int i = 0; i < 9; i++) { - if(ya & 0x10000) { - ya = ((ya << 1) | 0x01) & 0x1FFFF; - } else { - ya = (ya << 1) & 0x1FFFF; - } - - if(ya >= sub) { - ya ^= 0x01; - } - - if(ya & 0x01) { - ya = (ya - sub) & 0x1FFFF; - } + for (int i = 0; i < 9; i++) + { + if (ya & 0x10000) + { + ya = ((ya << 1) | 0x01) & 0x1FFFF; + } + else + { + ya = (ya << 1) & 0x1FFFF; } - - if((_state.Y & 0x0F) >= (_state.X & 0x0F)) { - SetFlags(SpcFlags::HalfCarry); - } else { - ClearFlags(SpcFlags::HalfCarry); + if (ya >= sub) + { + ya ^= 0x01; } - _state.A = (uint8_t)ya; - _state.Y = ya >> 9; - - if(ya & 0x100) { - SetFlags(SpcFlags::Overflow); - } else { - ClearFlags(SpcFlags::Overflow); + if (ya & 0x01) + { + ya = (ya - sub) & 0x1FFFF; } + } - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + + if ((_state.Y & 0x0F) >= (_state.X & 0x0F)) + { + SetFlags(SpcFlags::HalfCarry); + } + else + { + ClearFlags(SpcFlags::HalfCarry); + } + + _state.A = (uint8_t)ya; + _state.Y = ya >> 9; + + if (ya & 0x100) + { + SetFlags(SpcFlags::Overflow); + } + else + { + ClearFlags(SpcFlags::Overflow); + } + + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::DAA() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Idle(); - if(CheckFlag(SpcFlags::Carry) || _state.A > 0x99) { - _state.A += 0x60; - SetFlags(SpcFlags::Carry); - } + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Idle(); + if (CheckFlag(SpcFlags::Carry) || _state.A > 0x99) + { + _state.A += 0x60; + SetFlags(SpcFlags::Carry); + } - if(CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) { - _state.A += 6; - } + if (CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) + { + _state.A += 6; + } - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::DAS() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Idle(); + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Idle(); - if(!CheckFlag(SpcFlags::Carry) || _state.A > 0x99) { - _state.A -= 0x60; - ClearFlags(SpcFlags::Carry); - } + if (!CheckFlag(SpcFlags::Carry) || _state.A > 0x99) + { + _state.A -= 0x60; + ClearFlags(SpcFlags::Carry); + } - if(!CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) { - _state.A -= 6; - } + if (!CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9)) + { + _state.A -= 6; + } - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::AND() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = _operandA & Read(_operandB); break; - case 1: - Write(_operandB, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = _operandA & Read(_operandB); + break; + case 1: + Write(_operandB, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } void Spc::AND_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A &= GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -1231,7 +1882,8 @@ void Spc::AND_Acc() void Spc::AND_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A &= _operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -1240,21 +1892,25 @@ void Spc::AND_Imm() void Spc::OR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = _operandA | Read(_operandB); break; - case 1: - Write(_operandB, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = _operandA | Read(_operandB); + break; + case 1: + Write(_operandB, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } void Spc::OR_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A |= GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -1263,7 +1919,8 @@ void Spc::OR_Acc() void Spc::OR_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A |= _operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -1272,21 +1929,25 @@ void Spc::OR_Imm() void Spc::EOR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = _operandA ^ Read(_operandB); break; - case 1: - Write(_operandB, (uint8_t)_tmp1); - SetZeroNegativeFlags((uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = _operandA ^ Read(_operandB); + break; + case 1: + Write(_operandB, (uint8_t)_tmp1); + SetZeroNegativeFlags((uint8_t)_tmp1); + EndOp(); + break; } } } void Spc::EOR_Acc() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { _state.A ^= GetByteValue(); SetZeroNegativeFlags(_state.A); EndOp(); @@ -1295,7 +1956,8 @@ void Spc::EOR_Acc() void Spc::EOR_Imm() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.A ^= _operandA; SetZeroNegativeFlags(_state.A); EndOp(); @@ -1309,9 +1971,11 @@ void Spc::SetCarry(uint8_t carry) void Spc::OR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: { uint8_t carry = _state.PS & SpcFlags::Carry; carry |= (Read(_operandA) >> _operandB) & 0x01; @@ -1319,19 +1983,21 @@ void Spc::OR1() break; } - case 1: - Idle(); - EndOp(); - break; + case 1: + Idle(); + EndOp(); + break; } } } void Spc::NOR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: { uint8_t carry = _state.PS & SpcFlags::Carry; carry |= ~((Read(_operandA) >> _operandB)) & 0x01; @@ -1339,17 +2005,18 @@ void Spc::NOR1() break; } - case 1: - Idle(); - EndOp(); - break; + case 1: + Idle(); + EndOp(); + break; } } } void Spc::AND1() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { uint8_t carry = _state.PS & SpcFlags::Carry; carry &= (Read(_operandA) >> _operandB) & 0x01; SetCarry(carry); @@ -1359,7 +2026,8 @@ void Spc::AND1() void Spc::NAND1() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { uint8_t carry = _state.PS & SpcFlags::Carry; carry &= ~((Read(_operandA) >> _operandB)) & 0x01; SetCarry(carry); @@ -1369,9 +2037,11 @@ void Spc::NAND1() void Spc::EOR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: { uint8_t carry = _state.PS & SpcFlags::Carry; carry ^= (Read(_operandA) >> _operandB) & 0x01; @@ -1379,47 +2049,55 @@ void Spc::EOR1() break; } - case 1: - Idle(); - EndOp(); - break; + case 1: + Idle(); + EndOp(); + break; } } } void Spc::NOT1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - uint8_t mask = (1 << _operandB); - Write(_operandA, _tmp1 ^ mask); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + uint8_t mask = (1 << _operandB); + Write(_operandA, _tmp1 ^ mask); + EndOp(); + break; } } } void Spc::STC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - uint8_t mask = (1 << _operandB); - uint8_t carry = (_state.PS & SpcFlags::Carry) << _operandB; - Write(_operandA, (_tmp1 & ~mask) | carry); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + uint8_t mask = (1 << _operandB); + uint8_t carry = (_state.PS & SpcFlags::Carry) << _operandB; + Write(_operandA, (_tmp1 & ~mask) | carry); + EndOp(); + break; } } } void Spc::LDC() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { uint8_t carry = (Read(_operandA) >> _operandB) & 0x01; SetCarry(carry); EndOp(); @@ -1429,9 +2107,12 @@ void Spc::LDC() uint8_t Spc::ShiftLeft(uint8_t value) { uint8_t result = value << 1; - if(value & (1 << 7)) { + if (value & (1 << 7)) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1441,9 +2122,12 @@ uint8_t Spc::ShiftLeft(uint8_t value) uint8_t Spc::RollLeft(uint8_t value) { uint8_t result = value << 1 | (_state.PS & SpcFlags::Carry); - if(value & (1 << 7)) { + if (value & (1 << 7)) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1453,9 +2137,12 @@ uint8_t Spc::RollLeft(uint8_t value) uint8_t Spc::ShiftRight(uint8_t value) { uint8_t result = value >> 1; - if(value & 0x01) { + if (value & 0x01) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1465,9 +2152,12 @@ uint8_t Spc::ShiftRight(uint8_t value) uint8_t Spc::RollRight(uint8_t value) { uint8_t result = value >> 1 | ((_state.PS & 0x01) << 7); - if(value & 0x01) { + if (value & 0x01) + { SetFlags(SpcFlags::Carry); - } else { + } + else + { ClearFlags(SpcFlags::Carry); } SetZeroNegativeFlags(result); @@ -1476,13 +2166,16 @@ uint8_t Spc::RollRight(uint8_t value) void Spc::ASL() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = ShiftLeft(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ShiftLeft(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1496,13 +2189,16 @@ void Spc::ASL_Acc() void Spc::LSR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = ShiftRight(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = ShiftRight(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1516,13 +2212,16 @@ void Spc::LSR_Acc() void Spc::ROL() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = RollLeft(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = RollLeft(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1536,13 +2235,16 @@ void Spc::ROL_Acc() void Spc::ROR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = RollRight(Read(_operandA)); break; - case 1: - Write(_operandA, (uint8_t)_tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = RollRight(Read(_operandA)); + break; + case 1: + Write(_operandA, (uint8_t)_tmp1); + EndOp(); + break; } } } @@ -1556,45 +2258,56 @@ void Spc::ROR_Acc() void Spc::XCN() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Idle(); break; - case 3: - Idle(); - _state.A = (_state.A >> 4) | (_state.A << 4); - SetZeroNegativeFlags(_state.A); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Idle(); + break; + case 3: + Idle(); + _state.A = (_state.A >> 4) | (_state.A << 4); + SetZeroNegativeFlags(_state.A); + EndOp(); + break; } } void Spc::Branch() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: - Idle(); - int8_t offset = (int8_t)_operandA; - _state.PC = _state.PC + offset; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: + Idle(); + int8_t offset = (int8_t)_operandA; + _state.PC = _state.PC + offset; + EndOp(); + break; } } void Spc::BRA() { - if(_opStep == SpcOpStep::Operation) { + if (_opStep == SpcOpStep::Operation) + { Branch(); } } void Spc::BEQ() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Zero)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Zero)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1602,10 +2315,14 @@ void Spc::BEQ() void Spc::BNE() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Zero)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Zero)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1613,10 +2330,14 @@ void Spc::BNE() void Spc::BCS() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Carry)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Carry)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1624,10 +2345,14 @@ void Spc::BCS() void Spc::BCC() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Carry)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Carry)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1635,10 +2360,14 @@ void Spc::BCC() void Spc::BVS() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Overflow)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Overflow)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1646,10 +2375,14 @@ void Spc::BVS() void Spc::BVC() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Overflow)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Overflow)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1657,10 +2390,14 @@ void Spc::BVC() void Spc::BMI() { - if(_opStep == SpcOpStep::Operation) { - if(CheckFlag(SpcFlags::Negative)) { + if (_opStep == SpcOpStep::Operation) + { + if (CheckFlag(SpcFlags::Negative)) + { Branch(); - } else { + } + else + { EndOp(); } } @@ -1668,163 +2405,203 @@ void Spc::BMI() void Spc::BPL() { - if(_opStep == SpcOpStep::Operation) { - if(!CheckFlag(SpcFlags::Negative)) { + if (_opStep == SpcOpStep::Operation) + { + if (!CheckFlag(SpcFlags::Negative)) + { Branch(); - } else { + } + else + { EndOp(); } } } -template +template void Spc::SET1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 | (1 << bit)); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 | (1 << bit)); + EndOp(); + break; } } } -template +template void Spc::CLR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: - Write(_operandA, _tmp1 & ~(1 << bit)); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: + Write(_operandA, _tmp1 & ~(1 << bit)); + EndOp(); + break; } } } -template +template void Spc::BBS() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - _tmp2 = ReadOperandByte(); - if(!(_tmp1 & (1 << bit))) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (!(_tmp1 & (1 << bit))) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } -template +template void Spc::BBC() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - _tmp2 = ReadOperandByte(); - if(_tmp1 & (1 << bit)) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (_tmp1 & (1 << bit)) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } void Spc::CBNE() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: Idle(); break; - case 2: - _tmp2 = ReadOperandByte(); - if(_state.A == _tmp1) { - EndOp(); - } - break; - - case 3: Idle(); break; - - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: Idle(); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (_state.A == _tmp1) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } void Spc::DBNZ() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA) - 1; break; - case 1: Write(_operandA, (uint8_t)_tmp1); break; - case 2: - _tmp2 = ReadOperandByte(); - if(!_tmp1) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA) - 1; + break; + case 1: Write(_operandA, (uint8_t)_tmp1); + break; + case 2: + _tmp2 = ReadOperandByte(); + if (!_tmp1) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } } void Spc::DBNZ_Y() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: - _state.Y--; - _tmp2 = ReadOperandByte(); - if(!_state.Y) { - EndOp(); - } - break; - - case 3: Idle(); break; - case 4: - Idle(); - _state.PC += (int8_t)_tmp2; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: + _state.Y--; + _tmp2 = ReadOperandByte(); + if (!_state.Y) + { EndOp(); - break; + } + break; + + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC += (int8_t)_tmp2; + EndOp(); + break; } } void Spc::JMP() { - if(_opStep == SpcOpStep::AfterAddressing) { + if (_opStep == SpcOpStep::AfterAddressing) + { _state.PC = _operandA; EndOp(); } @@ -1832,17 +2609,22 @@ void Spc::JMP() void Spc::NOTC() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - Idle(); - if(CheckFlag(SpcFlags::Carry)) { - ClearFlags(SpcFlags::Carry); - } else { - SetFlags(SpcFlags::Carry); - } - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + Idle(); + if (CheckFlag(SpcFlags::Carry)) + { + ClearFlags(SpcFlags::Carry); + } + else + { + SetFlags(SpcFlags::Carry); + } + EndOp(); + break; } } @@ -1883,176 +2665,228 @@ void Spc::SETP() void Spc::EI() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - SetFlags(SpcFlags::IrqEnable); - Idle(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + SetFlags(SpcFlags::IrqEnable); + Idle(); + EndOp(); + break; } } void Spc::DI() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: - ClearFlags(SpcFlags::IrqEnable); - Idle(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: + ClearFlags(SpcFlags::IrqEnable); + Idle(); + EndOp(); + break; } } void Spc::TSET1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: DummyRead(_operandA); break; - case 2: - Write(_operandA, _tmp1 | _state.A); - SetZeroNegativeFlags(_state.A - _tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: DummyRead(_operandA); + break; + case 2: + Write(_operandA, _tmp1 | _state.A); + SetZeroNegativeFlags(_state.A - _tmp1); + EndOp(); + break; } } } void Spc::TCLR1() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: _tmp1 = Read(_operandA); break; - case 1: DummyRead(_operandA); break; - case 2: - Write(_operandA, _tmp1 & ~_state.A); - SetZeroNegativeFlags(_state.A - _tmp1); - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: _tmp1 = Read(_operandA); + break; + case 1: DummyRead(_operandA); + break; + case 2: + Write(_operandA, _tmp1 & ~_state.A); + SetZeroNegativeFlags(_state.A - _tmp1); + EndOp(); + break; } } } -template +template void Spc::TCALL() { constexpr uint16_t vectorAddr = 0xFFDE - (offset * 2); - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: Push(_state.PC >> 8); break; - case 3: Push((uint8_t)_state.PC); break; - case 4: Idle(); break; - case 5: _tmp1 = Read(vectorAddr); break; - case 6: - _state.PC = (Read(vectorAddr + 1) << 8) | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: Push(_state.PC >> 8); + break; + case 3: Push((uint8_t)_state.PC); + break; + case 4: Idle(); + break; + case 5: _tmp1 = Read(vectorAddr); + break; + case 6: + _state.PC = (Read(vectorAddr + 1) << 8) | _tmp1; + EndOp(); + break; } } void Spc::PCALL() { - switch(_opSubStep++) { - case 0: _tmp1 = ReadOperandByte(); break; - case 1: Idle(); break; - case 2: Push(_state.PC >> 8); break; - case 3: Push((uint8_t)_state.PC); break; - case 4: - Idle(); - _state.PC = 0xFF00 | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: _tmp1 = ReadOperandByte(); + break; + case 1: Idle(); + break; + case 2: Push(_state.PC >> 8); + break; + case 3: Push((uint8_t)_state.PC); + break; + case 4: + Idle(); + _state.PC = 0xFF00 | _tmp1; + EndOp(); + break; } } void Spc::JSR() { - if(_opStep == SpcOpStep::Operation) { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: Push(_state.PC >> 8); break; - case 2: Push((uint8_t)_state.PC); break; - case 3: Idle(); break; - case 4: - Idle(); - _state.PC = _operandA; - EndOp(); - break; + if (_opStep == SpcOpStep::Operation) + { + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: Push(_state.PC >> 8); + break; + case 2: Push((uint8_t)_state.PC); + break; + case 3: Idle(); + break; + case 4: + Idle(); + _state.PC = _operandA; + EndOp(); + break; } } } void Spc::RTS() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: _tmp1 = Pop(); break; - case 3: - _state.PC = (Pop() << 8) | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: _tmp1 = Pop(); + break; + case 3: + _state.PC = (Pop() << 8) | _tmp1; + EndOp(); + break; } } void Spc::RTI() { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: _state.PS = Pop(); break; - case 3: _tmp1 = Pop(); break; - case 4: - _state.PC = (Pop() << 8) | _tmp1; - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: _state.PS = Pop(); + break; + case 3: _tmp1 = Pop(); + break; + case 4: + _state.PC = (Pop() << 8) | _tmp1; + EndOp(); + break; } } void Spc::BRK() { - switch(_opSubStep++) { - case 0: Idle(); break; - case 1: Push(_state.PC >> 8); break; - case 2: Push((uint8_t)_state.PC); break; - case 3: Push(_state.PS); break; - case 4: Idle(); break; - case 5: _tmp1 = Read(0xFFDE); break; - case 6: - uint8_t msb = Read(0xFFDF); - _state.PC = (msb << 8) | _tmp1; + switch (_opSubStep++) + { + case 0: Idle(); + break; + case 1: Push(_state.PC >> 8); + break; + case 2: Push((uint8_t)_state.PC); + break; + case 3: Push(_state.PS); + break; + case 4: Idle(); + break; + case 5: _tmp1 = Read(0xFFDE); + break; + case 6: + uint8_t msb = Read(0xFFDF); + _state.PC = (msb << 8) | _tmp1; - SetFlags(SpcFlags::Break); - ClearFlags(SpcFlags::IrqEnable); - EndOp(); - break; + SetFlags(SpcFlags::Break); + ClearFlags(SpcFlags::IrqEnable); + EndOp(); + break; } } void Spc::PushOperation(uint8_t value) { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Push(value); break; - case 2: - Idle(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Push(value); + break; + case 2: + Idle(); + EndOp(); + break; } } -void Spc::PullOperation(uint8_t &dst) +void Spc::PullOperation(uint8_t& dst) { - switch(_opSubStep++) { - case 0: DummyRead(); break; - case 1: Idle(); break; - case 2: - dst = Pop(); - EndOp(); - break; + switch (_opSubStep++) + { + case 0: DummyRead(); + break; + case 1: Idle(); + break; + case 2: + dst = Pop(); + EndOp(); + break; } } diff --git a/Core/Spc.cpp b/Core/Spc.cpp index 06126ae..6dda552 100644 --- a/Core/Spc.cpp +++ b/Core/Spc.cpp @@ -24,9 +24,9 @@ Spc::Spc(Console* console) _console->GetSettings()->InitializeRam(_ram, Spc::SpcRamSize); _dsp.reset(new SPC_DSP()); - #ifndef DUMMYSPC +#ifndef DUMMYSPC _dsp->init(this, _console->GetSettings().get(), _ram); - #endif +#endif _dsp->reset(); _dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); @@ -76,7 +76,7 @@ void Spc::Reset() _state.RomEnabled = true; _state.Cycle = 0; _state.PC = ReadWord(Spc::ResetVector); - + _opCode = 0; _opStep = SpcOpStep::ReadOpCode; _opSubStep = 0; @@ -93,11 +93,15 @@ void Spc::Reset() void Spc::SetSpcState(bool enabled) { //Used by overclocking logic to disable SPC during the extra scanlines added to the PPU - if(_enabled != enabled) { - if(enabled) { + if (_enabled != enabled) + { + if (enabled) + { //When re-enabling, adjust the cycle counter to prevent running extra cycles UpdateClockRatio(); - } else { + } + else + { //Catch up SPC before disabling it Run(); } @@ -113,7 +117,8 @@ void Spc::UpdateClockRatio() //This can happen due to overclocking (which disables the SPC for some scanlines) or if the SPC's //internal sample rate is changed between versions (e.g 32000hz -> 32040hz) uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); - if(std::abs((int64_t)targetCycle - (int64_t)_state.Cycle) > 10) { + if (std::abs((int64_t)targetCycle - (int64_t)_state.Cycle) > 10) + { _state.Cycle = targetCycle; } } @@ -135,14 +140,17 @@ void Spc::DummyRead(uint16_t addr) void Spc::IncCycleCount(int32_t addr) { - static constexpr uint8_t cpuWait[4] = { 2, 4, 10, 20 }; - static constexpr uint8_t timerMultiplier[4] = { 2, 4, 8, 16 }; + static constexpr uint8_t cpuWait[4] = {2, 4, 10, 20}; + static constexpr uint8_t timerMultiplier[4] = {2, 4, 8, 16}; uint8_t speedSelect; - if(addr < 0 || ((addr & 0xFFF0) == 0x00F0) || (addr >= 0xFFC0 && _state.RomEnabled)) { + if (addr < 0 || ((addr & 0xFFF0) == 0x00F0) || (addr >= 0xFFC0 && _state.RomEnabled)) + { //Use internal speed (bits 4-5) for idle cycles, register access or IPL rom access speedSelect = _state.InternalSpeed; - } else { + } + else + { speedSelect = _state.ExternalSpeed; } @@ -159,34 +167,36 @@ void Spc::IncCycleCount(int32_t addr) uint8_t Spc::DebugRead(uint16_t addr) { - if(addr >= 0xFFC0 && _state.RomEnabled) { + if (addr >= 0xFFC0 && _state.RomEnabled) + { return _spcBios[addr & 0x3F]; } - switch(addr) { - case 0xF0: return 0; - case 0xF1: return 0; + switch (addr) + { + case 0xF0: return 0; + case 0xF1: return 0; - case 0xF2: return _state.DspReg; - case 0xF3: return _dsp->read(_state.DspReg & 0x7F); + case 0xF2: return _state.DspReg; + case 0xF3: return _dsp->read(_state.DspReg & 0x7F); - case 0xF4: return _state.CpuRegs[0]; - case 0xF5: return _state.CpuRegs[1]; - case 0xF6: return _state.CpuRegs[2]; - case 0xF7: return _state.CpuRegs[3]; + case 0xF4: return _state.CpuRegs[0]; + case 0xF5: return _state.CpuRegs[1]; + case 0xF6: return _state.CpuRegs[2]; + case 0xF7: return _state.CpuRegs[3]; - case 0xF8: return _state.RamReg[0]; - case 0xF9: return _state.RamReg[1]; + case 0xF8: return _state.RamReg[0]; + case 0xF9: return _state.RamReg[1]; - case 0xFA: return 0; - case 0xFB: return 0; - case 0xFC: return 0; + case 0xFA: return 0; + case 0xFB: return 0; + case 0xFC: return 0; - case 0xFD: return _state.Timer0.DebugRead(); - case 0xFE: return _state.Timer1.DebugRead(); - case 0xFF: return _state.Timer2.DebugRead(); + case 0xFD: return _state.Timer0.DebugRead(); + case 0xFE: return _state.Timer1.DebugRead(); + case 0xFF: return _state.Timer2.DebugRead(); - default: return _ram[addr]; + default: return _ram[addr]; } } @@ -200,45 +210,65 @@ uint8_t Spc::Read(uint16_t addr, MemoryOperationType type) IncCycleCount(addr); uint8_t value; - if(addr >= 0xFFC0 && _state.RomEnabled) { + if (addr >= 0xFFC0 && _state.RomEnabled) + { value = _spcBios[addr & 0x3F]; - } else { - switch(addr) { - case 0xF0: value = 0; break; - case 0xF1: value = 0; break; + } + else + { + switch (addr) + { + case 0xF0: value = 0; + break; + case 0xF1: value = 0; + break; - case 0xF2: value = _state.DspReg; break; - case 0xF3: - #ifndef DUMMYSPC + case 0xF2: value = _state.DspReg; + break; + case 0xF3: +#ifndef DUMMYSPC value = _dsp->read(_state.DspReg & 0x7F); - #else - value = 0; - #endif - break; +#else + value = 0; +#endif + break; - case 0xF4: value = _state.CpuRegs[0]; break; - case 0xF5: value = _state.CpuRegs[1]; break; - case 0xF6: value = _state.CpuRegs[2]; break; - case 0xF7: value = _state.CpuRegs[3]; break; + case 0xF4: value = _state.CpuRegs[0]; + break; + case 0xF5: value = _state.CpuRegs[1]; + break; + case 0xF6: value = _state.CpuRegs[2]; + break; + case 0xF7: value = _state.CpuRegs[3]; + break; - case 0xF8: value = _state.RamReg[0]; break; - case 0xF9: value = _state.RamReg[1]; break; + case 0xF8: value = _state.RamReg[0]; + break; + case 0xF9: value = _state.RamReg[1]; + break; - case 0xFA: value = 0; break; - case 0xFB: value = 0; break; - case 0xFC: value = 0; break; + case 0xFA: value = 0; + break; + case 0xFB: value = 0; + break; + case 0xFC: value = 0; + break; - case 0xFD: value = _state.Timer0.GetOutput(); break; - case 0xFE: value = _state.Timer1.GetOutput(); break; - case 0xFF: value = _state.Timer2.GetOutput(); break; + case 0xFD: value = _state.Timer0.GetOutput(); + break; + case 0xFE: value = _state.Timer1.GetOutput(); + break; + case 0xFF: value = _state.Timer2.GetOutput(); + break; - default: value = _ram[addr]; break; + default: value = _ram[addr]; + break; } } #ifndef DUMMYSPC _console->ProcessMemoryRead(addr, value, type); -#else +#else LogRead(addr, value); #endif @@ -346,24 +376,29 @@ void Spc::DspWriteRam(uint16_t addr, uint8_t value) void Spc::Run() { - if(!_enabled || _state.StopState != CpuStopState::Running) { + if (!_enabled || _state.StopState != CpuStopState::Running) + { //STOP or SLEEP were executed - execution is stopped forever. return; } uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); - while(_state.Cycle < targetCycle) { + while (_state.Cycle < targetCycle) + { ProcessCycle(); } } void Spc::ProcessCycle() { - if(_opStep == SpcOpStep::ReadOpCode) { + if (_opStep == SpcOpStep::ReadOpCode) + { _opCode = GetOpCode(); _opStep = SpcOpStep::Addressing; _opSubStep = 0; - } else { + } + else + { Exec(); } } @@ -375,7 +410,8 @@ void Spc::ProcessEndFrame() UpdateClockRatio(); int sampleCount = _dsp->sample_count(); - if(sampleCount != 0) { + if (sampleCount != 0) + { _console->GetSoundMixer()->PlayAudioBuffer(_soundBuffer, sampleCount / 2, Spc::SpcSampleRate); } _dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); @@ -400,20 +436,26 @@ bool Spc::IsMuted() AddressInfo Spc::GetAbsoluteAddress(uint16_t addr) { - if(addr < 0xFFC0 || !_state.RomEnabled) { - return AddressInfo { addr, SnesMemoryType::SpcRam }; + if (addr < 0xFFC0 || !_state.RomEnabled) + { + return AddressInfo{addr, SnesMemoryType::SpcRam}; } - return AddressInfo { addr & 0x3F, SnesMemoryType::SpcRom }; + return AddressInfo{addr & 0x3F, SnesMemoryType::SpcRom}; } -int Spc::GetRelativeAddress(AddressInfo &absAddress) +int Spc::GetRelativeAddress(AddressInfo& absAddress) { - if(absAddress.Type == SnesMemoryType::SpcRom) { - if(_state.RomEnabled) { + if (absAddress.Type == SnesMemoryType::SpcRom) + { + if (_state.RomEnabled) + { return 0xFFC0 | (absAddress.Address & 0x3F); } - } else { - if(absAddress.Address < 0xFFC0 || !_state.RomEnabled) { + } + else + { + if (absAddress.Address < 0xFFC0 || !_state.RomEnabled) + { return absAddress.Address; } } @@ -430,7 +472,7 @@ uint8_t* Spc::GetSpcRom() return _spcBios; } -void Spc::Serialize(Serializer &s) +void Spc::Serialize(Serializer& s) { s.Stream(_state.A, _state.Cycle, _state.PC, _state.PS, _state.SP, _state.X, _state.Y); s.Stream(_state.CpuRegs[0], _state.CpuRegs[1], _state.CpuRegs[2], _state.CpuRegs[3]); @@ -443,26 +485,31 @@ void Spc::Serialize(Serializer &s) _state.Timer1.Serialize(s); _state.Timer2.Serialize(s); - ArrayInfo ram { _ram, Spc::SpcRamSize }; + ArrayInfo ram{_ram, Spc::SpcRamSize}; s.Stream(ram); uint8_t dspState[SPC_DSP::state_size]; memset(dspState, 0, SPC_DSP::state_size); - if(s.IsSaving()) { - uint8_t *out = dspState; - _dsp->copy_state(&out, [](uint8_t** output, void* in, size_t size) { + if (s.IsSaving()) + { + uint8_t* out = dspState; + _dsp->copy_state(&out, [](uint8_t** output, void* in, size_t size) + { memcpy(*output, in, size); *output += size; }); s.StreamArray(dspState, SPC_DSP::state_size); - } else { + } + else + { s.StreamArray(dspState, SPC_DSP::state_size); UpdateClockRatio(); - uint8_t *in = dspState; - _dsp->copy_state(&in, [](uint8_t** input, void* output, size_t size) { + uint8_t* in = dspState; + _dsp->copy_state(&in, [](uint8_t** input, void* output, size_t size) + { memcpy(output, *input, size); *input += size; }); @@ -512,9 +559,12 @@ bool Spc::CheckFlag(uint8_t flag) void Spc::SetZeroNegativeFlags(uint8_t value) { ClearFlags(SpcFlags::Zero | SpcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(SpcFlags::Zero); - } else if(value & 0x80) { + } + else if (value & 0x80) + { SetFlags(SpcFlags::Negative); } } @@ -522,9 +572,12 @@ void Spc::SetZeroNegativeFlags(uint8_t value) void Spc::SetZeroNegativeFlags16(uint16_t value) { ClearFlags(SpcFlags::Zero | SpcFlags::Negative); - if(value == 0) { + if (value == 0) + { SetFlags(SpcFlags::Zero); - } else if(value & 0x8000) { + } + else if (value & 0x8000) + { SetFlags(SpcFlags::Negative); } } @@ -571,7 +624,7 @@ void Spc::LoadSpcFile(SpcFileData* data) _state.CpuRegs[1] = data->CpuRegs[1]; _state.CpuRegs[2] = data->CpuRegs[2]; _state.CpuRegs[3] = data->CpuRegs[3]; - + _state.RamReg[0] = data->RamRegs[0]; _state.RamReg[1] = data->RamRegs[1]; @@ -589,28 +642,34 @@ void Spc::SetReg(SpcRegister reg, uint16_t value) switch (reg) { case SpcRegister::SpcRegPC: - { - _state.PC = value; - } break; + { + _state.PC = value; + } + break; case SpcRegister::SpcRegA: - { - _state.A = value & 0xFF; - } break; + { + _state.A = value & 0xFF; + } + break; case SpcRegister::SpcRegX: - { - _state.X = value & 0xFF; - } break; + { + _state.X = value & 0xFF; + } + break; case SpcRegister::SpcRegY: - { - _state.Y = value & 0xFF; - } break; + { + _state.Y = value & 0xFF; + } + break; case SpcRegister::SpcRegSP: - { - _state.SP = value & 0xFF; - } break; + { + _state.SP = value & 0xFF; + } + break; case SpcRegister::SpcRegPS: - { - _state.PS = value & 0xFF; - } break; + { + _state.PS = value & 0xFF; + } + break; } } diff --git a/Core/Spc.h b/Core/Spc.h index 1d745dc..f572d69 100644 --- a/Core/Spc.h +++ b/Core/Spc.h @@ -49,7 +49,7 @@ private: SpcState _state; uint8_t* _ram; - uint8_t _spcBios[64] { + uint8_t _spcBios[64]{ 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, @@ -60,7 +60,7 @@ private: 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF }; - int16_t *_soundBuffer; + int16_t* _soundBuffer; //Store operations void STA(); @@ -81,7 +81,7 @@ private: void LDW(); //Transfer - void Transfer(uint8_t & dst, uint8_t src); + void Transfer(uint8_t& dst, uint8_t src); void TXA(); void TYA(); void TAX(); @@ -203,10 +203,14 @@ private: void TSET1(); void TCLR1(); - template void SET1(); - template void CLR1(); - template void BBS(); - template void BBC(); + template + void SET1(); + template + void CLR1(); + template + void BBS(); + template + void BBC(); //Subroutine operations void PCALL(); @@ -215,11 +219,12 @@ private: void BRK(); void RTI(); - template void TCALL(); + template + void TCALL(); //Stack operations void PushOperation(uint8_t value); - void PullOperation(uint8_t & dst); + void PullOperation(uint8_t& dst); void PHA(); void PHX(); @@ -235,7 +240,7 @@ private: void NOP(); void SLEEP(); void STOP(); - + void Idle(); void DummyRead(); void DummyRead(uint16_t addr); @@ -281,7 +286,7 @@ private: void EndAddr(); void ProcessCycle(); void Exec(); - + void UpdateClockRatio(); public: @@ -309,14 +314,14 @@ public: bool IsMuted(); AddressInfo GetAbsoluteAddress(uint16_t addr); - int GetRelativeAddress(AddressInfo & absAddress); + int GetRelativeAddress(AddressInfo& absAddress); uint8_t* GetSpcRam(); uint8_t* GetSpcRom(); void LoadSpcFile(SpcFileData* spcData); - void Serialize(Serializer &s) override; + void Serialize(Serializer& s) override; void SetReg(SpcRegister reg, uint16_t value); @@ -348,4 +353,4 @@ public: #endif }; -#endif \ No newline at end of file +#endif diff --git a/Core/Spc7110.cpp b/Core/Spc7110.cpp index c7dd233..74039d9 100644 --- a/Core/Spc7110.cpp +++ b/Core/Spc7110.cpp @@ -39,10 +39,13 @@ Spc7110::Spc7110(Console* console, bool useRtc) : BaseCoprocessor(SnesMemoryType bool enableStrictBoardMappings = console->GetSettings()->GetEmulationConfig().EnableStrictBoardMappings; uint32_t romSize = _cart->DebugGetPrgRomSize(); - if(!enableStrictBoardMappings && _cart->DebugGetPrgRomSize() >= 0x600000) { + if (!enableStrictBoardMappings && _cart->DebugGetPrgRomSize() >= 0x600000) + { mappings->RegisterHandler(0x40, 0x4F, 0x0000, 0xFFFF, prgRomHandlers, 0, 0x600); _realDataRomSize = romSize - 0x200000; - } else { + } + else + { _realDataRomSize = romSize - 0x100000; } mappings->RegisterHandler(0xC0, 0xCF, 0x0000, 0xFFFF, prgRomHandlers); @@ -52,212 +55,258 @@ Spc7110::Spc7110(Console* console, bool useRtc) : BaseCoprocessor(SnesMemoryType void Spc7110::Serialize(Serializer& s) { - ArrayInfo decompBuffer = { _decompBuffer, 32 }; - ArrayInfo dataRomBanks = { _dataRomBanks, 3 }; + ArrayInfo decompBuffer = {_decompBuffer, 32}; + ArrayInfo dataRomBanks = {_dataRomBanks, 3}; s.Stream( - _directoryBase, _directoryIndex, _targetOffset, _dataLengthCounter, _skipBytes, _decompFlags, _decompMode, _srcAddress, _decompOffset, _decompStatus, - decompBuffer, _dividend = 0, _multiplier, _divisor, _multDivResult, _remainder, _aluState, _aluFlags, _sramEnabled, dataRomBanks, _dataRomSize, _readBase, + _directoryBase, _directoryIndex, _targetOffset, _dataLengthCounter, _skipBytes, _decompFlags, _decompMode, + _srcAddress, _decompOffset, _decompStatus, + decompBuffer, _dividend = 0, _multiplier, _divisor, _multDivResult, _remainder, _aluState, _aluFlags, + _sramEnabled, dataRomBanks, _dataRomSize, _readBase, _readOffset, _readStep, _readMode, _readBuffer ); s.Stream(_decomp.get()); - if(_rtc) { + if (_rtc) + { s.Stream(_rtc.get()); } } uint8_t Spc7110::Read(uint32_t addr) { - if((addr & 0xFF0000) == 0x500000) { + if ((addr & 0xFF0000) == 0x500000) + { addr = 0x4800; - } else if((addr & 0xFF0000) == 0x580000) { + } + else if ((addr & 0xFF0000) == 0x580000) + { addr = 0x4808; } - switch(addr & 0xFFFF) { + switch (addr & 0xFFFF) + { //Decompression - case 0x4800: - _dataLengthCounter--; - return ReadDecompressedByte(); + case 0x4800: + _dataLengthCounter--; + return ReadDecompressedByte(); - case 0x4801: return (_directoryBase) & 0xFF; - case 0x4802: return (_directoryBase >> 8) & 0xFF; - case 0x4803: return (_directoryBase >> 16) & 0xFF; - case 0x4804: return _directoryIndex; - case 0x4805: return (_targetOffset) & 0xFF; - case 0x4806: return (_targetOffset >> 8) & 0xFF; - case 0x4807: return _skipBytes; - case 0x4808: return 0; - case 0x4809: return (_dataLengthCounter & 0xFF); - case 0x480A: return (_dataLengthCounter >> 8) & 0xFF; - case 0x480B: return _decompFlags; - case 0x480C: return _decompStatus; + case 0x4801: return (_directoryBase) & 0xFF; + case 0x4802: return (_directoryBase >> 8) & 0xFF; + case 0x4803: return (_directoryBase >> 16) & 0xFF; + case 0x4804: return _directoryIndex; + case 0x4805: return (_targetOffset) & 0xFF; + case 0x4806: return (_targetOffset >> 8) & 0xFF; + case 0x4807: return _skipBytes; + case 0x4808: return 0; + case 0x4809: return (_dataLengthCounter & 0xFF); + case 0x480A: return (_dataLengthCounter >> 8) & 0xFF; + case 0x480B: return _decompFlags; + case 0x480C: return _decompStatus; //Data read - case 0x4810: { + case 0x4810: + { uint8_t value = _readBuffer; IncrementPosition4810(); return value; } - case 0x4811: return _readBase & 0xFF; - case 0x4812: return (_readBase >> 8) & 0xFF; - case 0x4813: return (_readBase >> 16) & 0xFF; - case 0x4814: return _readOffset & 0xFF; - case 0x4815: return (_readOffset >> 8) & 0xFF; - case 0x4816: return _readStep & 0xFF; - case 0x4817: return (_readStep >> 8) & 0xFF; - case 0x4818: return _readMode; + case 0x4811: return _readBase & 0xFF; + case 0x4812: return (_readBase >> 8) & 0xFF; + case 0x4813: return (_readBase >> 16) & 0xFF; + case 0x4814: return _readOffset & 0xFF; + case 0x4815: return (_readOffset >> 8) & 0xFF; + case 0x4816: return _readStep & 0xFF; + case 0x4817: return (_readStep >> 8) & 0xFF; + case 0x4818: return _readMode; - case 0x481A: - if((_readMode & 0x60) == 0x60) { - IncrementPosition(); - } - return 0; + case 0x481A: + if ((_readMode & 0x60) == 0x60) + { + IncrementPosition(); + } + return 0; //ALU - case 0x4820: return _dividend & 0xFF; - case 0x4821: return (_dividend >> 8) & 0xFF; - case 0x4822: return (_dividend >> 16) & 0xFF; - case 0x4823: return (_dividend >> 24) & 0xFF; - case 0x4824: return _multiplier & 0xFF; - case 0x4825: return (_multiplier >> 8) & 0xFF; - case 0x4826: return _divisor & 0xFF; - case 0x4827: return (_divisor >> 8) & 0xFF; - case 0x4828: return _multDivResult & 0xFF; - case 0x4829: return (_multDivResult >> 8) & 0xFF; - case 0x482A: return (_multDivResult >> 16) & 0xFF; - case 0x482B: return (_multDivResult >> 24) & 0xFF; - case 0x482C: return _remainder & 0xFF; - case 0x482D: return (_remainder >> 8) & 0xFF; - case 0x482E: return _aluFlags; - case 0x482F: return _aluState; + case 0x4820: return _dividend & 0xFF; + case 0x4821: return (_dividend >> 8) & 0xFF; + case 0x4822: return (_dividend >> 16) & 0xFF; + case 0x4823: return (_dividend >> 24) & 0xFF; + case 0x4824: return _multiplier & 0xFF; + case 0x4825: return (_multiplier >> 8) & 0xFF; + case 0x4826: return _divisor & 0xFF; + case 0x4827: return (_divisor >> 8) & 0xFF; + case 0x4828: return _multDivResult & 0xFF; + case 0x4829: return (_multDivResult >> 8) & 0xFF; + case 0x482A: return (_multDivResult >> 16) & 0xFF; + case 0x482B: return (_multDivResult >> 24) & 0xFF; + case 0x482C: return _remainder & 0xFF; + case 0x482D: return (_remainder >> 8) & 0xFF; + case 0x482E: return _aluFlags; + case 0x482F: return _aluState; - case 0x4830: return _sramEnabled; - case 0x4831: return _dataRomBanks[0]; - case 0x4832: return _dataRomBanks[1]; - case 0x4833: return _dataRomBanks[2]; - case 0x4834: return _dataRomSize; + case 0x4830: return _sramEnabled; + case 0x4831: return _dataRomBanks[0]; + case 0x4832: return _dataRomBanks[1]; + case 0x4833: return _dataRomBanks[2]; + case 0x4834: return _dataRomSize; - case 0x4840: - case 0x4841: - case 0x4842: - return _rtc ? _rtc->Read(addr) : 0; + case 0x4840: + case 0x4841: + case 0x4842: + return _rtc ? _rtc->Read(addr) : 0; - default: - if((addr & 0xFFFF) >= 0x4800) { - LogDebug("[Debug] Missing read handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); - } - return _cpuRegisterHandler->Read(addr); + default: + if ((addr & 0xFFFF) >= 0x4800) + { + LogDebug("[Debug] Missing read handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); + } + return _cpuRegisterHandler->Read(addr); } } void Spc7110::Write(uint32_t addr, uint8_t value) { - if((addr & 0xFF0000) == 0x500000) { + if ((addr & 0xFF0000) == 0x500000) + { addr = 0x4800; - } else if((addr & 0xFF0000) == 0x580000) { + } + else if ((addr & 0xFF0000) == 0x580000) + { addr = 0x4808; } - switch(addr & 0xFFFF) { + switch (addr & 0xFFFF) + { //Data ROM Decompression (4800-480C) - case 0x4801: _directoryBase = (_directoryBase & 0xFFFF00) | value; break; - case 0x4802: _directoryBase = (_directoryBase & 0xFF00FF) | (value << 8); break; - case 0x4803: _directoryBase = (_directoryBase & 0x00FFFF) | (value << 16); break; - case 0x4804: - _directoryIndex = value; - LoadEntryHeader(); - break; + case 0x4801: _directoryBase = (_directoryBase & 0xFFFF00) | value; + break; + case 0x4802: _directoryBase = (_directoryBase & 0xFF00FF) | (value << 8); + break; + case 0x4803: _directoryBase = (_directoryBase & 0x00FFFF) | (value << 16); + break; + case 0x4804: + _directoryIndex = value; + LoadEntryHeader(); + break; - case 0x4805: _targetOffset = (_targetOffset & 0xFF00) | value; break; - case 0x4806: - _targetOffset = (_targetOffset & 0x00FF) | (value << 8); - BeginDecompression(); - break; + case 0x4805: _targetOffset = (_targetOffset & 0xFF00) | value; + break; + case 0x4806: + _targetOffset = (_targetOffset & 0x00FF) | (value << 8); + BeginDecompression(); + break; - case 0x4807: _skipBytes = value; break; - case 0x4808: break; + case 0x4807: _skipBytes = value; + break; + case 0x4808: break; - case 0x4809: _dataLengthCounter = (_dataLengthCounter & 0xFF00) | value; break; - case 0x480A: _dataLengthCounter = (_dataLengthCounter & 0x00FF) | (value << 8); break; - case 0x480B: _decompFlags = value & 0x03; break; + case 0x4809: _dataLengthCounter = (_dataLengthCounter & 0xFF00) | value; + break; + case 0x480A: _dataLengthCounter = (_dataLengthCounter & 0x00FF) | (value << 8); + break; + case 0x480B: _decompFlags = value & 0x03; + break; //Direct Data ROM Access (4810-481A) - case 0x4811: _readBase = (_readBase & 0xFFFF00) | value; break; - case 0x4812: _readBase = (_readBase & 0xFF00FF) | (value << 8); break; - case 0x4813: - _readBase = (_readBase & 0x00FFFF) | (value << 16); + case 0x4811: _readBase = (_readBase & 0xFFFF00) | value; + break; + case 0x4812: _readBase = (_readBase & 0xFF00FF) | (value << 8); + break; + case 0x4813: + _readBase = (_readBase & 0x00FFFF) | (value << 16); + FillReadBuffer(); + break; + + case 0x4814: + _readOffset = (_readOffset & 0xFF00) | value; + if ((_readMode & 0x60) == 0x20) + { + IncrementPosition(); + } + break; + + case 0x4815: + _readOffset = (_readOffset & 0x00FF) | (value << 8); + if (_readMode & 0x02) + { FillReadBuffer(); - break; + } + if ((_readMode & 0x60) == 0x40) + { + IncrementPosition(); + } + break; - case 0x4814: - _readOffset = (_readOffset & 0xFF00) | value; - if((_readMode & 0x60) == 0x20) { - IncrementPosition(); - } - break; + case 0x4816: _readStep = (_readStep & 0xFF00) | value; + break; + case 0x4817: _readStep = (_readStep & 0x00FF) | (value << 8); + break; - case 0x4815: - _readOffset = (_readOffset & 0x00FF) | (value << 8); - if(_readMode & 0x02) { - FillReadBuffer(); - } - if((_readMode & 0x60) == 0x40) { - IncrementPosition(); - } - break; - - case 0x4816: _readStep = (_readStep & 0xFF00) | value; break; - case 0x4817: _readStep = (_readStep & 0x00FF) | (value << 8); break; - - case 0x4818: - _readMode = value & 0x7F; - FillReadBuffer(); - break; + case 0x4818: + _readMode = value & 0x7F; + FillReadBuffer(); + break; //ALU (4820-482F) - case 0x4820: _dividend = (_dividend & 0xFFFFFF00) | value; break; - case 0x4821: _dividend = (_dividend & 0xFFFF00FF) | (value << 8); break; - case 0x4822: _dividend = (_dividend & 0xFF00FFFF) | (value << 16); break; - case 0x4823: _dividend = (_dividend & 0x00FFFFFF) | (value << 24); break; - case 0x4824: _multiplier = (_multiplier & 0xFF00) | value; break; - case 0x4825: - _multiplier = (_multiplier & 0x00FF) | (value << 8); - ProcessMultiplication(); - break; + case 0x4820: _dividend = (_dividend & 0xFFFFFF00) | value; + break; + case 0x4821: _dividend = (_dividend & 0xFFFF00FF) | (value << 8); + break; + case 0x4822: _dividend = (_dividend & 0xFF00FFFF) | (value << 16); + break; + case 0x4823: _dividend = (_dividend & 0x00FFFFFF) | (value << 24); + break; + case 0x4824: _multiplier = (_multiplier & 0xFF00) | value; + break; + case 0x4825: + _multiplier = (_multiplier & 0x00FF) | (value << 8); + ProcessMultiplication(); + break; - case 0x4826: _divisor = (_divisor & 0xFF00) | value; break; - case 0x4827: - _divisor = (_divisor & 0x00FF) | (value << 8); - ProcessDivision(); - break; + case 0x4826: _divisor = (_divisor & 0xFF00) | value; + break; + case 0x4827: + _divisor = (_divisor & 0x00FF) | (value << 8); + ProcessDivision(); + break; - case 0x482E: _aluFlags = value & 0x01; break; + case 0x482E: _aluFlags = value & 0x01; + break; //Memory mapping (4830-4834) - case 0x4830: _sramEnabled = value & 0x87; break; - case 0x4831: _dataRomBanks[0] = value & 0x07; UpdateMappings(); break; - case 0x4832: _dataRomBanks[1] = value & 0x07; UpdateMappings(); break; - case 0x4833: _dataRomBanks[2] = value & 0x07; UpdateMappings(); break; - case 0x4834: _dataRomSize = value & 0x07; break; + case 0x4830: _sramEnabled = value & 0x87; + break; + case 0x4831: _dataRomBanks[0] = value & 0x07; + UpdateMappings(); + break; + case 0x4832: _dataRomBanks[1] = value & 0x07; + UpdateMappings(); + break; + case 0x4833: _dataRomBanks[2] = value & 0x07; + UpdateMappings(); + break; + case 0x4834: _dataRomSize = value & 0x07; + break; //RTC (4840-4842) - case 0x4840: - case 0x4841: - case 0x4842: - if(_rtc) { - _rtc->Write(addr, value); - } - break; + case 0x4840: + case 0x4841: + case 0x4842: + if (_rtc) + { + _rtc->Write(addr, value); + } + break; - default: - if((addr & 0xFFFF) >= 0x4800) { - LogDebug("[Debug] Missing write handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); - } - _cpuRegisterHandler->Write(addr, value); - break; + default: + if ((addr & 0xFFFF) >= 0x4800) + { + LogDebug("[Debug] Missing write handler: $" + HexUtilities::ToHex(addr & 0xFFFF)); + } + _cpuRegisterHandler->Write(addr, value); + break; } } @@ -267,17 +316,22 @@ void Spc7110::UpdateMappings() vector>& prgRomHandlers = _cart->GetPrgRomHandlers(); uint32_t dataRomSize = _realDataRomSize >> 12; - for(int i = 0; i < 3; i++) { - mappings->RegisterHandler(0xD0 + (i * 0x10), 0xDF + (i * 0x10), 0x0000, 0xFFFF, prgRomHandlers, 0, 0x100 + ((_dataRomBanks[i] * 0x100) % dataRomSize)); + for (int i = 0; i < 3; i++) + { + mappings->RegisterHandler(0xD0 + (i * 0x10), 0xDF + (i * 0x10), 0x0000, 0xFFFF, prgRomHandlers, 0, + 0x100 + ((_dataRomBanks[i] * 0x100) % dataRomSize)); } } void Spc7110::ProcessMultiplication() { - if(_aluFlags & 0x01) { + if (_aluFlags & 0x01) + { //Signed multiplication (16x16=32) _multDivResult = (int32_t)((int16_t)_dividend * (int16_t)_multiplier); - } else { + } + else + { //Unsigned multiplication (16x16=32) _multDivResult = (uint32_t)(_dividend * _multiplier); } @@ -288,24 +342,33 @@ void Spc7110::ProcessMultiplication() void Spc7110::ProcessDivision() { - if(_aluFlags & 0x01) { + if (_aluFlags & 0x01) + { //Signed division (32 / 16 = 32 + 16) int32_t dividend = (int32_t)_dividend; int16_t divisor = (int16_t)_divisor; - if(divisor != 0) { + if (divisor != 0) + { _multDivResult = (int32_t)(dividend / divisor); _remainder = ((int32_t)(dividend % divisor)) & 0xFFFF; - } else { + } + else + { _multDivResult = 0; _remainder = dividend & 0xFFFF; } - } else { + } + else + { //Unsigned division (32 / 16 = 32 + 16) - if(_divisor != 0) { + if (_divisor != 0) + { _multDivResult = _dividend / _divisor; _remainder = (uint16_t)(_dividend % _divisor); - } else { + } + else + { _multDivResult = 0; _remainder = _dividend & 0xffff; } @@ -318,7 +381,8 @@ uint8_t Spc7110::ReadDataRom(uint32_t addr) { uint32_t configSize = 0x100000 * (1 << (_dataRomSize & 0x03)); uint32_t dataRomSize = std::min(configSize, _realDataRomSize); - if(addr >= dataRomSize) { + if (addr >= dataRomSize) + { return 0x00; } @@ -328,7 +392,8 @@ uint8_t Spc7110::ReadDataRom(uint32_t addr) void Spc7110::FillReadBuffer() { int32_t offset = _readMode & 0x02 ? _readOffset : 0; - if(_readMode & 0x08) { + if (_readMode & 0x08) + { offset = (int16_t)offset; } _readBuffer = ReadDataRom(_readBase + offset); @@ -343,13 +408,17 @@ void Spc7110::IncrementPosition() void Spc7110::IncrementPosition4810() { int32_t step = _readMode & 0x01 ? _readStep : 1; - if(_readMode & 0x04) { + if (_readMode & 0x04) + { step = (int16_t)step; } - if(_readMode & 0x10) { + if (_readMode & 0x10) + { _readOffset += step; - } else { + } + else + { _readBase = (_readBase + step) & 0xFFFFFF; } @@ -365,7 +434,8 @@ void Spc7110::LoadEntryHeader() void Spc7110::BeginDecompression() { - if(_decompMode == 3) { + if (_decompMode == 3) + { return; } @@ -373,7 +443,8 @@ void Spc7110::BeginDecompression() _decomp->Decode(); uint32_t seek = _decompFlags & 0x02 ? _targetOffset : 0; - while(seek--) { + while (seek--) + { _decomp->Decode(); } @@ -383,32 +454,37 @@ void Spc7110::BeginDecompression() uint8_t Spc7110::ReadDecompressedByte() { - if((_decompStatus & 0x80) == 0) { + if ((_decompStatus & 0x80) == 0) + { return 0x00; } uint8_t bpp = _decomp->GetBpp(); - if(_decompOffset == 0) { - for(int i = 0; i < 8; i++) { + if (_decompOffset == 0) + { + for (int i = 0; i < 8; i++) + { uint32_t result = _decomp->GetResult(); - switch(bpp) { - case 1: - _decompBuffer[i] = result; - break; - case 2: - _decompBuffer[i * 2 + 0] = result >> 0; - _decompBuffer[i * 2 + 1] = result >> 8; - break; - case 4: - _decompBuffer[i * 2 + 0] = result >> 0; - _decompBuffer[i * 2 + 1] = result >> 8; - _decompBuffer[i * 2 + 16] = result >> 16; - _decompBuffer[i * 2 + 17] = result >> 24; - break; + switch (bpp) + { + case 1: + _decompBuffer[i] = result; + break; + case 2: + _decompBuffer[i * 2 + 0] = result >> 0; + _decompBuffer[i * 2 + 1] = result >> 8; + break; + case 4: + _decompBuffer[i * 2 + 0] = result >> 0; + _decompBuffer[i * 2 + 1] = result >> 8; + _decompBuffer[i * 2 + 16] = result >> 16; + _decompBuffer[i * 2 + 17] = result >> 24; + break; } uint32_t seek = (_decompFlags & 0x01) ? _skipBytes : 1; - while(seek--) { + while (seek--) + { _decomp->Decode(); } } @@ -431,7 +507,7 @@ void Spc7110::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo Spc7110::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void Spc7110::Reset() @@ -471,21 +547,24 @@ void Spc7110::Reset() UpdateMappings(); _decomp.reset(new Spc7110Decomp(this)); - if(_useRtc) { + if (_useRtc) + { _rtc.reset(new Rtc4513(_console)); } } void Spc7110::LoadBattery() { - if(_rtc) { + if (_rtc) + { _rtc->LoadBattery(); } } void Spc7110::SaveBattery() { - if(_rtc) { + if (_rtc) + { _rtc->SaveBattery(); } } diff --git a/Core/Spc7110.h b/Core/Spc7110.h index 027bf8f..9aac623 100644 --- a/Core/Spc7110.h +++ b/Core/Spc7110.h @@ -45,7 +45,7 @@ private: //Memory mappings uint8_t _sramEnabled = 0; - uint8_t _dataRomBanks[3] = { 0, 1, 2 }; + uint8_t _dataRomBanks[3] = {0, 1, 2}; uint8_t _dataRomSize = 0; //Data rom @@ -68,7 +68,7 @@ private: public: Spc7110(Console* console, bool useRtc); - + uint8_t ReadDataRom(uint32_t addr); void Serialize(Serializer& s) override; @@ -82,4 +82,4 @@ public: void LoadBattery() override; void SaveBattery() override; -}; \ No newline at end of file +}; diff --git a/Core/Spc7110Decomp.cpp b/Core/Spc7110Decomp.cpp index 3abaeb5..4063ab6 100644 --- a/Core/Spc7110Decomp.cpp +++ b/Core/Spc7110Decomp.cpp @@ -36,8 +36,10 @@ uint32_t Spc7110Decomp::Deinterleave(uint64_t data, uint32_t bits) //extract a nibble and move it to the low four bits uint64_t Spc7110Decomp::MoveToFront(uint64_t list, uint32_t nibble) { - for(uint64_t n = 0, mask = ~15; n < 64; n += 4, mask <<= 4) { - if((list >> n & 15) != nibble) { + for (uint64_t n = 0, mask = ~15; n < 64; n += 4, mask <<= 4) + { + if ((list >> n & 15) != nibble) + { continue; } return (list & mask) + (list << 4 & ~mask) + nibble; @@ -62,21 +64,24 @@ void Spc7110Decomp::Initialize(uint32_t mode, uint32_t origin) void Spc7110Decomp::Decode() { - for(uint32_t pixel = 0; pixel < 8; pixel++) { + for (uint32_t pixel = 0; pixel < 8; pixel++) + { uint64_t map = _colormap; uint32_t diff = 0; - if(_bpp > 1) { + if (_bpp > 1) + { uint32_t pa = (_bpp == 2 ? (_pixels >> 2) & 3 : (_pixels >> 0) & 15); uint32_t pb = (_bpp == 2 ? (_pixels >> 14) & 3 : (_pixels >> 28) & 15); uint32_t pc = (_bpp == 2 ? (_pixels >> 16) & 3 : (_pixels >> 32) & 15); - if(pa != pb || pb != pc) { + if (pa != pb || pb != pc) + { uint32_t match = pa ^ pb ^ pc; - diff = 4; //no match; all pixels differ - if((match ^ pc) == 0) diff = 3; //a == b; pixel c differs - if((match ^ pb) == 0) diff = 2; //c == a; pixel b differs - if((match ^ pa) == 0) diff = 1; //b == c; pixel a differs + diff = 4; //no match; all pixels differ + if ((match ^ pc) == 0) diff = 3; //a == b; pixel c differs + if ((match ^ pb) == 0) diff = 2; //c == a; pixel b differs + if ((match ^ pa) == 0) diff = 1; //b == c; pixel a differs } _colormap = MoveToFront(_colormap, pa); @@ -86,65 +91,85 @@ void Spc7110Decomp::Decode() map = MoveToFront(map, pa); } - for(uint32_t plane = 0; plane < _bpp; plane++) { + for (uint32_t plane = 0; plane < _bpp; plane++) + { uint32_t bit = _bpp > 1 ? 1 << plane : 1 << (pixel & 3); uint32_t history = (bit - 1) & _output; uint32_t set = 0; - if(_bpp == 1) { + if (_bpp == 1) + { set = pixel >= 4; - } else if(_bpp == 2) { + } + else if (_bpp == 2) + { set = diff; } - if(plane >= 2 && history <= 1) { + if (plane >= 2 && history <= 1) + { set = diff; } auto& ctx = _context[set][bit + history - 1]; auto& model = evolution[ctx.prediction]; uint8_t lps_offset = _range - model.probability; - bool symbol = _input >= (lps_offset << 8); //test only the MSB + bool symbol = _input >= (lps_offset << 8); //test only the MSB _output = _output << 1 | ((uint8_t)symbol ^ ctx.swap); - if(symbol == MPS) { //[0 ... range-p] - _range = lps_offset; //range = range-p - } else { //[range-p+1 ... range] - _range -= lps_offset; //range = p-1, with p < 0.75 - _input -= lps_offset << 8; //therefore, always rescale + if (symbol == MPS) + { + //[0 ... range-p] + _range = lps_offset; //range = range-p + } + else + { + //[range-p+1 ... range] + _range -= lps_offset; //range = p-1, with p < 0.75 + _input -= lps_offset << 8; //therefore, always rescale } - while(_range <= Max / 2) { //scale back into [0.75 ... 1.5] + while (_range <= Max / 2) + { + //scale back into [0.75 ... 1.5] ctx.prediction = model.next[symbol]; _range <<= 1; _input <<= 1; - if(--_bits == 0) { + if (--_bits == 0) + { _bits = 8; _input += ReadByte(); } } - if(symbol == LPS && model.probability > Half) { + if (symbol == LPS && model.probability > Half) + { ctx.swap ^= 1; } } uint32_t index = _output & ((1 << _bpp) - 1); - if(_bpp == 1) { + if (_bpp == 1) + { index ^= _pixels >> 15 & 1; } _pixels = _pixels << _bpp | (map >> 4 * index & 15); } - if(_bpp == 1) { + if (_bpp == 1) + { _result = (uint32_t)_pixels; - } else if(_bpp == 2) { + } + else if (_bpp == 2) + { _result = Deinterleave(_pixels, 16); - } else if(_bpp == 4) { + } + else if (_bpp == 4) + { _result = Deinterleave(Deinterleave(_pixels, 32), 32); } } @@ -162,35 +187,37 @@ uint8_t Spc7110Decomp::GetBpp() void Spc7110Decomp::Serialize(Serializer& s) { s.Stream(_bpp, _offset, _bits, _range, _input, _output, _pixels, _colormap, _result); - for(int i = 0; i < 5; i++) { - for(int j = 0; j < 15; j++) { + for (int i = 0; i < 5; i++) + { + for (int j = 0; j < 15; j++) + { s.Stream(_context[i][j].swap, _context[i][j].prediction); } } } Spc7110Decomp::ModelState Spc7110Decomp::evolution[53] = { - {0x5a, { 1, 1}}, {0x25, { 2, 6}}, {0x11, { 3, 8}}, - {0x08, { 4,10}}, {0x03, { 5,12}}, {0x01, { 5,15}}, + {0x5a, {1, 1}}, {0x25, {2, 6}}, {0x11, {3, 8}}, + {0x08, {4, 10}}, {0x03, {5, 12}}, {0x01, {5, 15}}, - {0x5a, { 7, 7}}, {0x3f, { 8,19}}, {0x2c, { 9,21}}, - {0x20, {10,22}}, {0x17, {11,23}}, {0x11, {12,25}}, - {0x0c, {13,26}}, {0x09, {14,28}}, {0x07, {15,29}}, - {0x05, {16,31}}, {0x04, {17,32}}, {0x03, {18,34}}, - {0x02, { 5,35}}, + {0x5a, {7, 7}}, {0x3f, {8, 19}}, {0x2c, {9, 21}}, + {0x20, {10, 22}}, {0x17, {11, 23}}, {0x11, {12, 25}}, + {0x0c, {13, 26}}, {0x09, {14, 28}}, {0x07, {15, 29}}, + {0x05, {16, 31}}, {0x04, {17, 32}}, {0x03, {18, 34}}, + {0x02, {5, 35}}, - {0x5a, {20,20}}, {0x48, {21,39}}, {0x3a, {22,40}}, - {0x2e, {23,42}}, {0x26, {24,44}}, {0x1f, {25,45}}, - {0x19, {26,46}}, {0x15, {27,25}}, {0x11, {28,26}}, - {0x0e, {29,26}}, {0x0b, {30,27}}, {0x09, {31,28}}, - {0x08, {32,29}}, {0x07, {33,30}}, {0x05, {34,31}}, - {0x04, {35,33}}, {0x04, {36,33}}, {0x03, {37,34}}, - {0x02, {38,35}}, {0x02, { 5,36}}, + {0x5a, {20, 20}}, {0x48, {21, 39}}, {0x3a, {22, 40}}, + {0x2e, {23, 42}}, {0x26, {24, 44}}, {0x1f, {25, 45}}, + {0x19, {26, 46}}, {0x15, {27, 25}}, {0x11, {28, 26}}, + {0x0e, {29, 26}}, {0x0b, {30, 27}}, {0x09, {31, 28}}, + {0x08, {32, 29}}, {0x07, {33, 30}}, {0x05, {34, 31}}, + {0x04, {35, 33}}, {0x04, {36, 33}}, {0x03, {37, 34}}, + {0x02, {38, 35}}, {0x02, {5, 36}}, - {0x58, {40,39}}, {0x4d, {41,47}}, {0x43, {42,48}}, - {0x3b, {43,49}}, {0x34, {44,50}}, {0x2e, {45,51}}, - {0x29, {46,44}}, {0x25, {24,45}}, + {0x58, {40, 39}}, {0x4d, {41, 47}}, {0x43, {42, 48}}, + {0x3b, {43, 49}}, {0x34, {44, 50}}, {0x2e, {45, 51}}, + {0x29, {46, 44}}, {0x25, {24, 45}}, - {0x56, {48,47}}, {0x4f, {49,47}}, {0x47, {50,48}}, - {0x41, {51,49}}, {0x3c, {52,50}}, {0x37, {43,51}}, -}; \ No newline at end of file + {0x56, {48, 47}}, {0x4f, {49, 47}}, {0x47, {50, 48}}, + {0x41, {51, 49}}, {0x3c, {52, 50}}, {0x37, {43, 51}}, +}; diff --git a/Core/Spc7110Decomp.h b/Core/Spc7110Decomp.h index 50a0629..04e31a9 100644 --- a/Core/Spc7110Decomp.h +++ b/Core/Spc7110Decomp.h @@ -12,33 +12,36 @@ class Spc7110Decomp : public ISerializable { private: enum : uint32_t { MPS = 0, LPS = 1 }; + enum : uint32_t { One = 0xAA, Half = 0x55, Max = 0xFF }; struct ModelState { - uint8_t probability; //of the more probable symbol (MPS) - uint8_t next[2]; //next state after output {MPS, LPS} + uint8_t probability; //of the more probable symbol (MPS) + uint8_t next[2]; //next state after output {MPS, LPS} }; + static ModelState evolution[53]; struct Context { - uint8_t prediction; //current model state - uint8_t swap; //if 1, exchange the role of MPS and LPS - }; - Context _context[5][15]; //not all 75 contexts exists; this simplifies the code + uint8_t prediction; //current model state + uint8_t swap; //if 1, exchange the role of MPS and LPS + }; + + Context _context[5][15]; //not all 75 contexts exists; this simplifies the code Spc7110* _spc; - uint32_t _bpp; //bits per pixel (1bpp = 1; 2bpp = 2; 4bpp = 4) - uint32_t _offset; //SPC7110 data ROM read offset - uint32_t _bits; //bits remaining in input - uint16_t _range; //arithmetic range: technically 8-bits, but Max+1 = 256 - uint16_t _input; //input data from SPC7110 data ROM + uint32_t _bpp; //bits per pixel (1bpp = 1; 2bpp = 2; 4bpp = 4) + uint32_t _offset; //SPC7110 data ROM read offset + uint32_t _bits; //bits remaining in input + uint16_t _range; //arithmetic range: technically 8-bits, but Max+1 = 256 + uint16_t _input; //input data from SPC7110 data ROM uint8_t _output; uint64_t _pixels; - uint64_t _colormap; //most recently used list - uint32_t _result; //decompressed word after calling decode() + uint64_t _colormap; //most recently used list + uint32_t _result; //decompressed word after calling decode() private: uint8_t ReadByte(); @@ -55,4 +58,4 @@ public: uint8_t GetBpp(); void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/SpcDebugger.cpp b/Core/SpcDebugger.cpp index 65790d4..b26f166 100644 --- a/Core/SpcDebugger.cpp +++ b/Core/SpcDebugger.cpp @@ -36,22 +36,26 @@ void SpcDebugger::Reset() void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType type) { - if(type == MemoryOperationType::DummyRead) { + if (type == MemoryOperationType::DummyRead) + { //Ignore all dummy reads for now return; } AddressInfo addressInfo = _spc->GetAbsoluteAddress(addr); - MemoryOperationInfo operation { addr, value, type }; + MemoryOperationInfo operation{addr, value, type}; BreakSource breakSource = BreakSource::Unspecified; - if(type == MemoryOperationType::ExecOpCode) { + if (type == MemoryOperationType::ExecOpCode) + { SpcState spcState = _spc->GetState(); - if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { + if (_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) + { _disassembler->BuildCache(addressInfo, 0, CpuType::Spc); - if(_traceLogger->IsCpuLogged(CpuType::Spc)) { + if (_traceLogger->IsCpuLogged(CpuType::Spc)) + { _debugger->GetState(_debugState, true); DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Spc); @@ -59,19 +63,24 @@ void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType } } - if(_prevOpCode == 0x3F || _prevOpCode == 0x0F) { + if (_prevOpCode == 0x3F || _prevOpCode == 0x0F) + { //JSR, BRK uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc); uint16_t returnPc = _prevProgramCounter + opSize; AddressInfo src = _spc->GetAbsoluteAddress(_prevProgramCounter); AddressInfo ret = _spc->GetAbsoluteAddress(returnPc); - _callstackManager->Push(src, _prevProgramCounter, addressInfo, spcState.PC, ret, returnPc, StackFrameFlags::None); - } else if(_prevOpCode == 0x6F || _prevOpCode == 0x7F) { + _callstackManager->Push(src, _prevProgramCounter, addressInfo, spcState.PC, ret, returnPc, + StackFrameFlags::None); + } + else if (_prevOpCode == 0x6F || _prevOpCode == 0x7F) + { //RTS, RTI _callstackManager->Pop(addressInfo, spcState.PC); } - if(_step->BreakAddress == (int32_t)spcState.PC && (_prevOpCode == 0x6F || _prevOpCode == 0x7F)) { + if (_step->BreakAddress == (int32_t)spcState.PC && (_prevOpCode == 0x6F || _prevOpCode == 0x7F)) + { //RTS/RTI found, if we're on the expected return address, break immediately (for step over/step out) _step->StepCount = 0; } @@ -79,34 +88,44 @@ void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType _prevOpCode = value; _prevProgramCounter = spcState.PC; - if(_step->StepCount > 0) { + if (_step->StepCount > 0) + { _step->StepCount--; } - if(_settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { + if (_settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) + { //Break on BRK/STP - if(value == 0x0F && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) { + if (value == 0x0F && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) + { breakSource = BreakSource::BreakOnBrk; _step->StepCount = 0; - } else if(value == 0xFF && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) { + } + else if (value == 0xFF && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) + { breakSource = BreakSource::BreakOnStp; _step->StepCount = 0; } } _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else if(type == MemoryOperationType::ExecOperand) { + } + else if (type == MemoryOperationType::ExecOperand) + { _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); - } else { + } + else + { _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); } - _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource); + _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, + breakSource); } void SpcDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { - AddressInfo addressInfo { addr, SnesMemoryType::SpcRam }; //Writes never affect the SPC ROM - MemoryOperationInfo operation { addr, value, type }; + AddressInfo addressInfo{addr, SnesMemoryType::SpcRam}; //Writes never affect the SPC ROM + MemoryOperationInfo operation{addr, value, type}; _debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo); _disassembler->InvalidateCache(addressInfo, CpuType::Spc); @@ -123,22 +142,28 @@ void SpcDebugger::Step(int32_t stepCount, StepType type) { StepRequest step; - switch(type) { - case StepType::Step: step.StepCount = stepCount; break; - case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); break; - case StepType::StepOver: - if(_prevOpCode == 0x3F || _prevOpCode == 0x0F) { - //JSR, BRK - step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc); - } else { - //For any other instruction, step over is the same as step into - step.StepCount = 1; - } - break; - - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + switch (type) + { + case StepType::Step: step.StepCount = stepCount; + break; + case StepType::StepOut: step.BreakAddress = _callstackManager->GetReturnAddress(); + break; + case StepType::StepOver: + if (_prevOpCode == 0x3F || _prevOpCode == 0x0F) + { + //JSR, BRK + step.BreakAddress = _prevProgramCounter + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc); + } + else + { + //For any other instruction, step over is the same as step into + step.StepCount = 1; + } + break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; } _step.reset(new StepRequest(step)); @@ -152,4 +177,4 @@ shared_ptr SpcDebugger::GetCallstackManager() BreakpointManager* SpcDebugger::GetBreakpointManager() { return _breakpointManager.get(); -} \ No newline at end of file +} diff --git a/Core/SpcDebugger.h b/Core/SpcDebugger.h index 908f3c5..7c412df 100644 --- a/Core/SpcDebugger.h +++ b/Core/SpcDebugger.h @@ -29,7 +29,7 @@ class SpcDebugger final : public IDebugger uint8_t _prevOpCode = 0xFF; uint32_t _prevProgramCounter = 0; - + DebugState _debugState; public: @@ -43,4 +43,4 @@ public: void Step(int32_t stepCount, StepType type); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); -}; \ No newline at end of file +}; diff --git a/Core/SpcDisUtils.cpp b/Core/SpcDisUtils.cpp index 791baf9..2839532 100644 --- a/Core/SpcDisUtils.cpp +++ b/Core/SpcDisUtils.cpp @@ -9,41 +9,73 @@ #include "../Utilities/HexUtilities.h" constexpr const char* _altOpTemplate[256] = { - "NOP", "TCALL 0", "SET1 d.0", "BBS d.0,q", "OR A,d", "OR A,!a", "OR A,(X)", "OR A,[d+X]", "OR A,#i", "OR t,s", "OR1 C,m.b", "ASL d", "ASL !a", "PUSH PSW", "TSET1 !a", "BRK", - "BPL r", "TCALL 1", "CLR1 d.0", "BBC d.0,q", "OR A,d+X", "OR A,!a+X", "OR A,!a+Y", "OR A,[d]+Y", "OR e,#i", "OR (X),(Y)", "DECW d", "ASL d+X", "ASL A", "DEC X", "CMP X,!a", "JMP [!a+X]", - "CLRP", "TCALL 2", "SET1 d.1", "BBS d.1,q", "AND A,d", "AND A,!a", "AND A,(X)", "AND A,[d+X]", "AND A,#i", "AND t,s", "OR1 C,/m.b", "ROL d", "ROL !a", "PUSH A", "CBNE d,q", "BRA r", - "BMI r", "TCALL 3", "CLR1 d.1", "BBC d.1,q", "AND A,d+X", "AND A,!a+X", "AND A,!a+Y", "AND A,[d]+Y", "AND e,#i", "AND (X),(Y)", "INCW d", "ROL d+X", "ROL A", "INC X", "CMP X,d", "CALL !a", - "SETP", "TCALL 4", "SET1 d.2", "BBS d.2,q", "EOR A,d", "EOR A,!a", "EOR A,(X)", "EOR A,[d+X]", "EOR A,#i", "EOR t,s", "AND1 C,m.b", "LSR d", "LSR !a", "PUSH X", "TCLR1 !a", "PCALL u", - "BVC r", "TCALL 5", "CLR1 d.2", "BBC d.2,q", "EOR A,d+X", "EOR A,!a+X", "EOR A,!a+Y", "EOR A,[d]+Y", "EOR e,#i", "EOR (X),(Y)", "CMPW YA,d", "LSR d+X", "LSR A", "MOV X,A", "CMP Y,!a", "JMP !a", - "CLRC", "TCALL 6", "SET1 d.3", "BBS d.3,q", "CMP A,d", "CMP A,!a", "CMP A,(X)", "CMP A,[d+X]", "CMP A,#i", "CMP t,s", "AND1 C,/m.b", "ROR d", "ROR !a", "PUSH Y", "DBNZ d,q", "RET", - "BVS r", "TCALL 7", "CLR1 d.3", "BBC d.3,q", "CMP A,d+X", "CMP A,!a+X", "CMP A,!a+Y", "CMP A,[d]+Y", "CMP e,#i", "CMP (X),(Y)", "ADDW YA,d", "ROR d+X", "ROR A", "MOV A,X", "CMP Y,d", "RET1", - "SETC", "TCALL 8", "SET1 d.4", "BBS d.4,q", "ADC A,d", "ADC A,!a", "ADC A,(X)", "ADC A,[d+X]", "ADC A,#i", "ADC t,s", "EOR1 C,m.b", "DEC d", "DEC !a", "MOV Y,#i", "POP PSW", "MOV e,#i", - "BCC r", "TCALL 9", "CLR1 d.4", "BBC d.4,q", "ADC A,d+X", "ADC A,!a+X", "ADC A,!a+Y", "ADC A,[d]+Y", "ADC e,#i", "ADC (X),(Y)", "SUBW YA,d", "DEC d+X", "DEC A", "MOV X,SP", "DIV YA,X", "XCN A", - "EI", "TCALL 10", "SET1 d.5", "BBS d.5,q", "SBC A,d", "SBC A,!a", "SBC A,(X)", "SBC A,[d+X]", "SBC A,#i", "SBC t,s", "MOV1 C,m.b", "INC d", "INC !a", "CMP Y,#i", "POP A", "MOV (X)+,A", - "BCS r", "TCALL 11", "CLR1 d.5", "BBC d.5,q", "SBC A,d+X", "SBC A,!a+X", "SBC A,!a+Y", "SBC A,[d]+Y", "SBC e,#i", "SBC (X),(Y)", "MOVW YA,d", "INC d+X", "INC A", "MOV SP,X", "DAS A", "MOV A,(X)+", - "DI", "TCALL 12", "SET1 d.6", "BBS d.6,q", "MOV d,A", "MOV !a,A", "MOV (X),A", "MOV [d+X],A", "CMP X,#i", "MOV !a,X", "MOV1 m.b,C", "MOV d,Y", "MOV !a,Y", "MOV X,#i", "POP X", "MUL YA", - "BNE r", "TCALL 13", "CLR1 d.6", "BBC d.6,q", "MOV d+X,A", "MOV !a+X,A", "MOV !a+Y,A", "MOV [d]+Y,A", "MOV e,X", "MOV d+Y,X", "MOVW d,YA", "MOV d+X,Y", "DEC Y", "MOV A,Y", "CBNE d+X,q", "DAA A", - "CLRV", "TCALL 14", "SET1 d.7", "BBS d.7,q", "MOV A,d", "MOV A,!a", "MOV A,(X)", "MOV A,[d+X]", "MOV A,#i", "MOV X,!a", "NOT1 m.b", "MOV Y,d", "MOV Y,!a", "NOTC", "POP Y", "SLEEP", - "BEQ r", "TCALL 15", "CLR1 d.7", "BBC d.7,q", "MOV A,d+X", "MOV A,!a+X", "MOV A,!a+Y", "MOV A,[d]+Y", "MOV X,d", "MOV X,d+Y", "MOV t,s", "MOV Y,d+X", "INC Y", "MOV Y,A", "DBNZ Y,q", "STOP" + "NOP", "TCALL 0", "SET1 d.0", "BBS d.0,q", "OR A,d", "OR A,!a", "OR A,(X)", "OR A,[d+X]", "OR A,#i", "OR t,s", + "OR1 C,m.b", "ASL d", "ASL !a", "PUSH PSW", "TSET1 !a", "BRK", + "BPL r", "TCALL 1", "CLR1 d.0", "BBC d.0,q", "OR A,d+X", "OR A,!a+X", "OR A,!a+Y", "OR A,[d]+Y", "OR e,#i", + "OR (X),(Y)", "DECW d", "ASL d+X", "ASL A", "DEC X", "CMP X,!a", "JMP [!a+X]", + "CLRP", "TCALL 2", "SET1 d.1", "BBS d.1,q", "AND A,d", "AND A,!a", "AND A,(X)", "AND A,[d+X]", "AND A,#i", "AND t,s", + "OR1 C,/m.b", "ROL d", "ROL !a", "PUSH A", "CBNE d,q", "BRA r", + "BMI r", "TCALL 3", "CLR1 d.1", "BBC d.1,q", "AND A,d+X", "AND A,!a+X", "AND A,!a+Y", "AND A,[d]+Y", "AND e,#i", + "AND (X),(Y)", "INCW d", "ROL d+X", "ROL A", "INC X", "CMP X,d", "CALL !a", + "SETP", "TCALL 4", "SET1 d.2", "BBS d.2,q", "EOR A,d", "EOR A,!a", "EOR A,(X)", "EOR A,[d+X]", "EOR A,#i", "EOR t,s", + "AND1 C,m.b", "LSR d", "LSR !a", "PUSH X", "TCLR1 !a", "PCALL u", + "BVC r", "TCALL 5", "CLR1 d.2", "BBC d.2,q", "EOR A,d+X", "EOR A,!a+X", "EOR A,!a+Y", "EOR A,[d]+Y", "EOR e,#i", + "EOR (X),(Y)", "CMPW YA,d", "LSR d+X", "LSR A", "MOV X,A", "CMP Y,!a", "JMP !a", + "CLRC", "TCALL 6", "SET1 d.3", "BBS d.3,q", "CMP A,d", "CMP A,!a", "CMP A,(X)", "CMP A,[d+X]", "CMP A,#i", "CMP t,s", + "AND1 C,/m.b", "ROR d", "ROR !a", "PUSH Y", "DBNZ d,q", "RET", + "BVS r", "TCALL 7", "CLR1 d.3", "BBC d.3,q", "CMP A,d+X", "CMP A,!a+X", "CMP A,!a+Y", "CMP A,[d]+Y", "CMP e,#i", + "CMP (X),(Y)", "ADDW YA,d", "ROR d+X", "ROR A", "MOV A,X", "CMP Y,d", "RET1", + "SETC", "TCALL 8", "SET1 d.4", "BBS d.4,q", "ADC A,d", "ADC A,!a", "ADC A,(X)", "ADC A,[d+X]", "ADC A,#i", "ADC t,s", + "EOR1 C,m.b", "DEC d", "DEC !a", "MOV Y,#i", "POP PSW", "MOV e,#i", + "BCC r", "TCALL 9", "CLR1 d.4", "BBC d.4,q", "ADC A,d+X", "ADC A,!a+X", "ADC A,!a+Y", "ADC A,[d]+Y", "ADC e,#i", + "ADC (X),(Y)", "SUBW YA,d", "DEC d+X", "DEC A", "MOV X,SP", "DIV YA,X", "XCN A", + "EI", "TCALL 10", "SET1 d.5", "BBS d.5,q", "SBC A,d", "SBC A,!a", "SBC A,(X)", "SBC A,[d+X]", "SBC A,#i", "SBC t,s", + "MOV1 C,m.b", "INC d", "INC !a", "CMP Y,#i", "POP A", "MOV (X)+,A", + "BCS r", "TCALL 11", "CLR1 d.5", "BBC d.5,q", "SBC A,d+X", "SBC A,!a+X", "SBC A,!a+Y", "SBC A,[d]+Y", "SBC e,#i", + "SBC (X),(Y)", "MOVW YA,d", "INC d+X", "INC A", "MOV SP,X", "DAS A", "MOV A,(X)+", + "DI", "TCALL 12", "SET1 d.6", "BBS d.6,q", "MOV d,A", "MOV !a,A", "MOV (X),A", "MOV [d+X],A", "CMP X,#i", "MOV !a,X", + "MOV1 m.b,C", "MOV d,Y", "MOV !a,Y", "MOV X,#i", "POP X", "MUL YA", + "BNE r", "TCALL 13", "CLR1 d.6", "BBC d.6,q", "MOV d+X,A", "MOV !a+X,A", "MOV !a+Y,A", "MOV [d]+Y,A", "MOV e,X", + "MOV d+Y,X", "MOVW d,YA", "MOV d+X,Y", "DEC Y", "MOV A,Y", "CBNE d+X,q", "DAA A", + "CLRV", "TCALL 14", "SET1 d.7", "BBS d.7,q", "MOV A,d", "MOV A,!a", "MOV A,(X)", "MOV A,[d+X]", "MOV A,#i", + "MOV X,!a", "NOT1 m.b", "MOV Y,d", "MOV Y,!a", "NOTC", "POP Y", "SLEEP", + "BEQ r", "TCALL 15", "CLR1 d.7", "BBC d.7,q", "MOV A,d+X", "MOV A,!a+X", "MOV A,!a+Y", "MOV A,[d]+Y", "MOV X,d", + "MOV X,d+Y", "MOV t,s", "MOV Y,d+X", "INC Y", "MOV Y,A", "DBNZ Y,q", "STOP" }; constexpr const char* _opTemplate[256] = { - "NOP", "JST0", "SET1 d.0", "BBS d.0,q", "ORA d", "ORA a", "ORA (X)", "ORA [d,X]", "ORA #i", "OR t,s", "ORC m.b", "ASL d", "ASL a", "PHP", "SET1 a", "BRK", - "BPL r", "JST1", "CLR1 d.0", "BBC d.0,q", "ORA d,X", "ORA a,X", "ORA a,Y", "ORA [d],Y", "OR e,#i", "OR (X),(Y)", "DEW d", "ASL d,X", "ASL A", "DEX", "CPX a", "JMP [a,X]", - "CLP", "JST2", "SET1 d.1", "BBS d.1,q", "AND d", "AND a", "AND (X)", "AND [d,X]", "AND #i", "AND t,s", "ORC /m.b", "ROL d", "ROL a", "PHA", "CBNE d,q", "BRA r", - "BMI r", "JST3", "CLR1 d.1", "BBC d.1,q", "AND d,X", "AND a,X", "AND a,Y", "AND [d],Y", "AND e,#i", "AND (X),(Y)", "INW d", "ROL d,X", "ROL A", "INX", "CPX d", "JSR a", - "SEP", "JST4", "SET1 d.2", "BBS d.2,q", "EOR d", "EOR a", "EOR (X)", "EOR [d,X]", "EOR #i", "EOR t,s", "ANDC m.b", "LSR d", "LSR a", "PHX", "CLR1 a", "JSP u", - "BVC r", "JST5", "CLR1 d.2", "BBC d.2,q", "EOR d,X", "EOR a,X", "EOR a,Y", "EOR [d],Y", "EOR e,#i", "EOR (X),(Y)", "CPW d", "LSR d,X", "LSR A", "TAX", "CPY a", "JMP a", - "CLC", "JST6", "SET1 d.3", "BBS d.3,q", "CMP d", "CMP a", "CMP (X)", "CMP [d,X]", "CMP #i", "CMP t,s", "ANDC /m.b", "ROR d", "ROR a", "PHY", "DBNZ d,q", "RTS", - "BVS r", "JST7", "CLR1 d.3", "BBC d.3,q", "CMP d,X", "CMP a,X", "CMP a,Y", "CMP [d],Y", "CMP e,#i", "CMP (X),(Y)", "ADW d", "ROR d,X", "ROR A", "TXA", "CPY d", "RTI", - "SEC", "JST8", "SET1 d.4", "BBS d.4,q", "ADC d", "ADC a", "ADC (X)", "ADC [d,X]", "ADC #i", "ADC t,s", "EORC m.b", "DEC d", "DEC a", "LDY #i","PLP", "MOV e,#i", - "BCC r", "JST9", "CLR1 d.4", "BBC d.4,q", "ADC d,X", "ADC a,X", "ADC a,Y", "ADC [d],Y", "ADC e,#i", "ADC (X),(Y)", "SBW d", "DEC d,X", "DEC A", "TSX", "DIV YA,X", "XCN A", - "CLI", "JSTA", "SET1 d.5", "BBS d.5,q", "SBC d", "SBC a", "SBC (X)", "SBC [d,X]", "SBC #i", "SBC t,s", "LDC m.b", "INC d", "INC a", "CMY #i","PLA", "STA (X)+,A", - "BCS r", "JSTB", "CLR1 d.5", "BBC d.5,q", "SBC d,X", "SBC a,X", "SBC a,Y", "SBC [d],Y", "SBC e,#i", "SBC (X),(Y)", "LDW d", "INC d,X", "INC A", "TXS", "DAS A", "LDA (X)+", - "SEI", "JSTC", "SET1 d.6", "BBS d.6,q", "STA d", "STA a", "STA (X)", "STA [d,X]", "CPX #i", "STX a", "STC m.b", "STY d", "STY a", "LDX #i","PLX", "MUL YA", - "BNE r", "JSTD", "CLR1 d.6", "BBC d.6,q", "STA d,X", "STA a,X", "STA a,Y", "STA [d],Y", "STX d", "STX d,Y", "STW d", "STY d,X", "DEY", "TYA", "CBNE d,X, q", "DAA A", - "CLV", "JSTE", "SET1 d.7", "BBS d.7,q", "LDA d", "LDA a", "LDA (X)", "LDA [d,X]", "LDA #i", "LDX a", "NOT m.b", "LDY d", "LDY a", "NOTC", "PLY", "WAI", - "BEQ r", "JSTF", "CLR1 d.7", "BBC d.7,q", "LDA d,X", "LDA a,X", "LDA a,Y", "LDA [d],Y", "LDX d", "LDX d,Y", "MOV t,s", "LDY d,X", "INC Y", "TAY", "DBNZ Y,r", "STP" + "NOP", "JST0", "SET1 d.0", "BBS d.0,q", "ORA d", "ORA a", "ORA (X)", "ORA [d,X]", "ORA #i", "OR t,s", "ORC m.b", + "ASL d", "ASL a", "PHP", "SET1 a", "BRK", + "BPL r", "JST1", "CLR1 d.0", "BBC d.0,q", "ORA d,X", "ORA a,X", "ORA a,Y", "ORA [d],Y", "OR e,#i", "OR (X),(Y)", + "DEW d", "ASL d,X", "ASL A", "DEX", "CPX a", "JMP [a,X]", + "CLP", "JST2", "SET1 d.1", "BBS d.1,q", "AND d", "AND a", "AND (X)", "AND [d,X]", "AND #i", "AND t,s", "ORC /m.b", + "ROL d", "ROL a", "PHA", "CBNE d,q", "BRA r", + "BMI r", "JST3", "CLR1 d.1", "BBC d.1,q", "AND d,X", "AND a,X", "AND a,Y", "AND [d],Y", "AND e,#i", "AND (X),(Y)", + "INW d", "ROL d,X", "ROL A", "INX", "CPX d", "JSR a", + "SEP", "JST4", "SET1 d.2", "BBS d.2,q", "EOR d", "EOR a", "EOR (X)", "EOR [d,X]", "EOR #i", "EOR t,s", "ANDC m.b", + "LSR d", "LSR a", "PHX", "CLR1 a", "JSP u", + "BVC r", "JST5", "CLR1 d.2", "BBC d.2,q", "EOR d,X", "EOR a,X", "EOR a,Y", "EOR [d],Y", "EOR e,#i", "EOR (X),(Y)", + "CPW d", "LSR d,X", "LSR A", "TAX", "CPY a", "JMP a", + "CLC", "JST6", "SET1 d.3", "BBS d.3,q", "CMP d", "CMP a", "CMP (X)", "CMP [d,X]", "CMP #i", "CMP t,s", "ANDC /m.b", + "ROR d", "ROR a", "PHY", "DBNZ d,q", "RTS", + "BVS r", "JST7", "CLR1 d.3", "BBC d.3,q", "CMP d,X", "CMP a,X", "CMP a,Y", "CMP [d],Y", "CMP e,#i", "CMP (X),(Y)", + "ADW d", "ROR d,X", "ROR A", "TXA", "CPY d", "RTI", + "SEC", "JST8", "SET1 d.4", "BBS d.4,q", "ADC d", "ADC a", "ADC (X)", "ADC [d,X]", "ADC #i", "ADC t,s", "EORC m.b", + "DEC d", "DEC a", "LDY #i", "PLP", "MOV e,#i", + "BCC r", "JST9", "CLR1 d.4", "BBC d.4,q", "ADC d,X", "ADC a,X", "ADC a,Y", "ADC [d],Y", "ADC e,#i", "ADC (X),(Y)", + "SBW d", "DEC d,X", "DEC A", "TSX", "DIV YA,X", "XCN A", + "CLI", "JSTA", "SET1 d.5", "BBS d.5,q", "SBC d", "SBC a", "SBC (X)", "SBC [d,X]", "SBC #i", "SBC t,s", "LDC m.b", + "INC d", "INC a", "CMY #i", "PLA", "STA (X)+,A", + "BCS r", "JSTB", "CLR1 d.5", "BBC d.5,q", "SBC d,X", "SBC a,X", "SBC a,Y", "SBC [d],Y", "SBC e,#i", "SBC (X),(Y)", + "LDW d", "INC d,X", "INC A", "TXS", "DAS A", "LDA (X)+", + "SEI", "JSTC", "SET1 d.6", "BBS d.6,q", "STA d", "STA a", "STA (X)", "STA [d,X]", "CPX #i", "STX a", "STC m.b", + "STY d", "STY a", "LDX #i", "PLX", "MUL YA", + "BNE r", "JSTD", "CLR1 d.6", "BBC d.6,q", "STA d,X", "STA a,X", "STA a,Y", "STA [d],Y", "STX d", "STX d,Y", "STW d", + "STY d,X", "DEY", "TYA", "CBNE d,X, q", "DAA A", + "CLV", "JSTE", "SET1 d.7", "BBS d.7,q", "LDA d", "LDA a", "LDA (X)", "LDA [d,X]", "LDA #i", "LDX a", "NOT m.b", + "LDY d", "LDY a", "NOTC", "PLY", "WAI", + "BEQ r", "JSTF", "CLR1 d.7", "BBC d.7,q", "LDA d,X", "LDA a,X", "LDA a,Y", "LDA [d],Y", "LDX d", "LDX d,Y", + "MOV t,s", "LDY d,X", "INC Y", "TAY", "DBNZ Y,r", "STP" }; constexpr const uint8_t _opSize[256] = { @@ -67,60 +99,80 @@ constexpr const uint8_t _opSize[256] = { constexpr bool _needAddress[256] = { false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, false, true, true, true, true, false, true, true, false, false, false, true, false, false, true, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, true, false, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, true, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, true, - false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, + false, true, true, true, true, true, true, true, true, false, true, true, false, false, false, true, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false, + false, true, true, true, true, true, true, true, true, true, true, true, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, false, false, false, - false, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false + false, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false }; -void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings) +void SpcDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings) { FastString str(settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)); - AddressInfo addrInfo { 0, SnesMemoryType::SpcMemory }; - auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) { + AddressInfo addrInfo{0, SnesMemoryType::SpcMemory}; + auto getOperand = [&str, &addrInfo, labelManager](uint16_t addr) + { addrInfo.Address = addr; string label = labelManager ? labelManager->GetLabel(addrInfo) : ""; - if(label.empty()) { + if (label.empty()) + { str.WriteAll('$', HexUtilities::ToHex(addr)); - } else { + } + else + { str.Write(label, true); } }; uint8_t* byteCode = info.GetByteCode(); - const char* op = settings->CheckDebuggerFlag(DebuggerFlags::UseAltSpcOpNames) ? _altOpTemplate[byteCode[0]] : _opTemplate[byteCode[0]]; + const char* op = settings->CheckDebuggerFlag(DebuggerFlags::UseAltSpcOpNames) + ? _altOpTemplate[byteCode[0]] + : _opTemplate[byteCode[0]]; int i = 0; - while(op[i]) { - switch(op[i]) { - case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); break; - case 'q': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[2] + GetOpSize(byteCode[0]))); break; //relative 2nd byte + while (op[i]) + { + switch (op[i]) + { + case 'r': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); + break; + case 'q': getOperand((uint16_t)(memoryAddr + (int8_t)byteCode[2] + GetOpSize(byteCode[0]))); + break; //relative 2nd byte - case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); break; - - case 'd': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break; - case 'e': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); break; //direct 2nd byte + case 'a': getOperand((uint16_t)(byteCode[1] | (byteCode[2] << 8))); + break; - case 's': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break; - case 't': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); break; + case 'd': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); + break; + case 'e': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); + break; //direct 2nd byte - case 'i': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); break; + case 's': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); + break; + case 't': str.WriteAll('$', HexUtilities::ToHex(byteCode[2])); + break; - case 'm': getOperand((uint16_t)((byteCode[1] | (byteCode[2] << 8)) & 0x1FFF)); break; - case 'b': str.WriteAll((char)('0' + (byteCode[2] >> 5))); break; + case 'i': str.WriteAll('$', HexUtilities::ToHex(byteCode[1])); + break; - default: str.Write(op[i]); break; + case 'm': getOperand((uint16_t)((byteCode[1] | (byteCode[2] << 8)) & 0x1FFF)); + break; + case 'b': str.WriteAll((char)('0' + (byteCode[2] >> 5))); + break; + + default: str.Write(op[i]); + break; } i++; } @@ -128,18 +180,22 @@ void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me out += str.ToString(); } -int32_t SpcDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console, SpcState &state) +int32_t SpcDisUtils::GetEffectiveAddress(DisassemblyInfo& info, Console* console, SpcState& state) { - if(_needAddress[info.GetOpCode()]) { + if (_needAddress[info.GetOpCode()]) + { Spc* spc = console->GetSpc().get(); DummySpc dummySpc(spc->GetSpcRam(), state); dummySpc.Step(); uint32_t addr; uint8_t value; uint32_t writeCount = dummySpc.GetWriteCount(); - if(writeCount > 0) { + if (writeCount > 0) + { dummySpc.GetWriteInfo(writeCount - 1, addr, value); - } else { + } + else + { uint32_t readCount = dummySpc.GetReadCount(); dummySpc.GetReadInfo(readCount - 1, addr, value); } diff --git a/Core/SpcDisUtils.h b/Core/SpcDisUtils.h index f52c736..dfcf81a 100644 --- a/Core/SpcDisUtils.h +++ b/Core/SpcDisUtils.h @@ -10,7 +10,8 @@ struct SpcState; class SpcDisUtils { public: - static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings); - static int32_t GetEffectiveAddress(DisassemblyInfo &info, Console *console, SpcState &state); + static void GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, + EmuSettings* settings); + static int32_t GetEffectiveAddress(DisassemblyInfo& info, Console* console, SpcState& state); static uint8_t GetOpSize(uint8_t opCode); }; diff --git a/Core/SpcFileData.h b/Core/SpcFileData.h index a4bdb47..f2ab87b 100644 --- a/Core/SpcFileData.h +++ b/Core/SpcFileData.h @@ -66,4 +66,4 @@ public: TimerOutput[1] = spcData[0x100 + 0xFE]; TimerOutput[2] = spcData[0x100 + 0xFF]; } -}; \ No newline at end of file +}; diff --git a/Core/SpcHud.cpp b/Core/SpcHud.cpp index ddec3d1..ca5f398 100644 --- a/Core/SpcHud.cpp +++ b/Core/SpcHud.cpp @@ -5,7 +5,7 @@ #include "DebugHud.h" #include "SpcFileData.h" -SpcHud::SpcHud(Console * console, SpcFileData* spcData) +SpcHud::SpcHud(Console* console, SpcFileData* spcData) { _mixer = console->GetSoundMixer().get(); _hud = console->GetDebugHud().get(); @@ -29,8 +29,11 @@ void SpcHud::Draw(uint32_t frame) _volumesL[_volPosition] = left / 128; _volumesR[_volPosition] = right / 128; _volPosition = (_volPosition + 1) & 0x7F; - for(int i = 1; i < 128; i++) { - _hud->DrawLine((i - 1)*2, 160 + _volumesL[(_volPosition + i - 1) & 0x7F], i*2, 160 + _volumesL[(_volPosition + i) & 0x7F], 0x30FFAAAA, 1, frame); - _hud->DrawLine((i - 1)*2, 160 + _volumesR[(_volPosition + i - 1) & 0x7F], i*2, 160 + _volumesR[(_volPosition + i) & 0x7F], 0x30AAAAFF, 1, frame); + for (int i = 1; i < 128; i++) + { + _hud->DrawLine((i - 1) * 2, 160 + _volumesL[(_volPosition + i - 1) & 0x7F], i * 2, + 160 + _volumesL[(_volPosition + i) & 0x7F], 0x30FFAAAA, 1, frame); + _hud->DrawLine((i - 1) * 2, 160 + _volumesR[(_volPosition + i - 1) & 0x7F], i * 2, + 160 + _volumesR[(_volPosition + i) & 0x7F], 0x30AAAAFF, 1, frame); } } diff --git a/Core/SpcHud.h b/Core/SpcHud.h index 6f3239b..e96881d 100644 --- a/Core/SpcHud.h +++ b/Core/SpcHud.h @@ -22,4 +22,4 @@ public: SpcHud(Console* console, SpcFileData* spcData); void Draw(uint32_t frame); -}; \ No newline at end of file +}; diff --git a/Core/SpcTimer.h b/Core/SpcTimer.h index bfa9176..bf8b3f4 100644 --- a/Core/SpcTimer.h +++ b/Core/SpcTimer.h @@ -2,7 +2,7 @@ #include "stdafx.h" #include "../Utilities/Serializer.h" -template +template class SpcTimer { private: @@ -18,19 +18,22 @@ private: void ClockTimer() { uint8_t currentState = _stage1; - if(!_timersEnabled) { + if (!_timersEnabled) + { //All timers are disabled currentState = 0; } uint8_t prevState = _prevStage1; _prevStage1 = currentState; - if(!_enabled || !prevState || currentState) { + if (!_enabled || !prevState || currentState) + { //Only clock on 1->0 transitions, when the timer is enabled return; } - if(++_stage2 == _target) { + if (++_stage2 == _target) + { _stage2 = 0; _output++; } @@ -44,7 +47,8 @@ public: void SetEnabled(bool enabled) { - if(!_enabled && enabled) { + if (!_enabled && enabled) + { _stage2 = 0; _output = 0; } @@ -60,7 +64,8 @@ public: void Run(uint8_t step) { _stage0 += step; - if(_stage0 >= rate) { + if (_stage0 >= rate) + { _stage1 ^= 0x01; _stage0 -= rate; @@ -91,8 +96,8 @@ public: _output = value; } - void Serialize(Serializer &s) + void Serialize(Serializer& s) { s.Stream(_stage0, _stage1, _stage2, _output, _target, _enabled, _timersEnabled, _prevStage1); } -}; \ No newline at end of file +}; diff --git a/Core/SpcTypes.h b/Core/SpcTypes.h index 5213f03..1265867 100644 --- a/Core/SpcTypes.h +++ b/Core/SpcTypes.h @@ -36,21 +36,26 @@ struct DspState uint8_t Regs[128]; }; -namespace SpcFlags { +namespace SpcFlags +{ enum SpcFlags : uint8_t { Carry = 0x01, Zero = 0x02, - IrqEnable = 0x04, //unused + IrqEnable = 0x04, + //unused HalfCarry = 0x08, - Break = 0x10, /* Set by the BRK instruction */ - DirectPage = 0x20, /* Selects page 0 or 1 for direct mode addressing */ + Break = 0x10, + /* Set by the BRK instruction */ + DirectPage = 0x20, + /* Selects page 0 or 1 for direct mode addressing */ Overflow = 0x40, Negative = 0x80 }; } -namespace SpcControlFlags { +namespace SpcControlFlags +{ enum SpcControlFlags : uint8_t { Timer0 = 0x01, @@ -64,7 +69,8 @@ namespace SpcControlFlags { }; } -namespace SpcTestFlags { +namespace SpcTestFlags +{ enum SpcTestFlags : uint8_t { TimersDisabled = 0x01, @@ -83,4 +89,4 @@ enum class SpcOpStep : uint8_t Addressing = 1, AfterAddressing = 2, Operation = 3 -}; \ No newline at end of file +}; diff --git a/Core/SuperGameboy.cpp b/Core/SuperGameboy.cpp index 15c1533..b72722f 100644 --- a/Core/SuperGameboy.cpp +++ b/Core/SuperGameboy.cpp @@ -20,15 +20,16 @@ SuperGameboy::SuperGameboy(Console* console) : BaseCoprocessor(SnesMemoryType::R _memoryManager = console->GetMemoryManager().get(); _cart = _console->GetCartridge().get(); _spc = _console->GetSpc().get(); - + _gameboy = _cart->GetGameboy(); _ppu = _gameboy->GetPpu(); _control = 0x01; //Divider = 5, gameboy = not running UpdateClockRatio(); - + MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); - for(int i = 0; i <= 0x3F; i++) { + for (int i = 0; i <= 0x3F; i++) + { cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, this); cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, this); } @@ -66,12 +67,16 @@ void SuperGameboy::Reset() uint8_t SuperGameboy::Read(uint32_t addr) { addr &= 0xF80F; - - if(addr >= 0x7000 && addr <= 0x700F) { + + if (addr >= 0x7000 && addr <= 0x700F) + { _packetReady = false; return _packetData[addr & 0x0F]; - } else if(addr >= 0x7800 && addr <= 0x780F) { - if(_readPosition >= 320) { + } + else if (addr >= 0x7800 && addr <= 0x780F) + { + if (_readPosition >= 320) + { //Return 0xFF for 320..511 and then wrap to 0 _readPosition = (_readPosition + 1) & 0x1FF; return 0xFF; @@ -83,16 +88,20 @@ uint8_t SuperGameboy::Read(uint32_t addr) uint8_t data = 0; uint8_t shift = _readPosition & 0x01; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { data |= ((start[i] >> shift) & 0x01) << (7 - i); } _readPosition++; return data; - } else { - switch(addr & 0xFFFF) { - case 0x6000: return (GetLcdRow() << 3) | GetLcdBufferRow(); - case 0x6002: return _packetReady; - case 0x600F: return 0x21; //or 0x61 + } + else + { + switch (addr & 0xFFFF) + { + case 0x6000: return (GetLcdRow() << 3) | GetLcdBufferRow(); + case 0x6002: return _packetReady; + case 0x600F: return 0x21; //or 0x61 } } @@ -103,14 +112,17 @@ void SuperGameboy::Write(uint32_t addr, uint8_t value) { addr &= 0xF80F; - switch(addr & 0xFFFF) { - case 0x6001: - _lcdRowSelect = value & 0x03; - _readPosition = 0; - break; + switch (addr & 0xFFFF) + { + case 0x6001: + _lcdRowSelect = value & 0x03; + _readPosition = 0; + break; - case 0x6003: { - if(!(_control & 0x80) && (value & 0x80)) { + case 0x6003: + { + if (!(_control & 0x80) && (value & 0x80)) + { _resetClock = _memoryManager->GetMasterClock(); _gameboy->PowerOn(this); _ppu = _gameboy->GetPpu(); @@ -122,67 +134,94 @@ void SuperGameboy::Write(uint32_t addr, uint8_t value) break; } - case 0x6004: _input[0] = value; break; - case 0x6005: _input[1] = value; break; - case 0x6006: _input[2] = value; break; - case 0x6007: _input[3] = value; break; + case 0x6004: _input[0] = value; + break; + case 0x6005: _input[1] = value; + break; + case 0x6006: _input[2] = value; + break; + case 0x6007: _input[3] = value; + break; } } void SuperGameboy::ProcessInputPortWrite(uint8_t value) { - if(_inputValue == value) { + if (_inputValue == value) + { return; } - if(value == 0x00) { + if (value == 0x00) + { //Reset pulse _waitForHigh = true; _packetByte = 0; _packetBit = 0; - } else if(_waitForHigh) { - if(value == 0x10 || value == 0x20) { + } + else if (_waitForHigh) + { + if (value == 0x10 || value == 0x20) + { //Invalid sequence (should be 0x00 -> 0x30 -> 0x10/0x20 -> 0x30 -> 0x10/0x20, etc.) _waitForHigh = false; _listeningForPacket = false; - } else if(value == 0x30) { + } + else if (value == 0x30) + { _waitForHigh = false; _listeningForPacket = true; } - } else if(_listeningForPacket) { - if(value == 0x20) { + } + else if (_listeningForPacket) + { + if (value == 0x20) + { //0 bit - if(_packetByte >= 16 && _packetBit == 0) { + if (_packetByte >= 16 && _packetBit == 0) + { _packetReady = true; _listeningForPacket = false; - if(_console->IsDebugging()) { + if (_console->IsDebugging()) + { LogPacket(); } - } else { + } + else + { _packetData[_packetByte] &= ~(1 << _packetBit); } _packetBit++; - if(_packetBit == 8) { + if (_packetBit == 8) + { _packetBit = 0; _packetByte++; } - } else if(value == 0x10) { + } + else if (value == 0x10) + { //1 bit - if(_packetByte >= 16) { + if (_packetByte >= 16) + { //Invalid bit _listeningForPacket = false; - } else { + } + else + { _packetData[_packetByte] |= (1 << _packetBit); _packetBit++; - if(_packetBit == 8) { + if (_packetBit == 8) + { _packetBit = 0; _packetByte++; } } } _waitForHigh = _listeningForPacket; - } else if(!(_inputValue & 0x20) && (value & 0x20)) { + } + else if (!(_inputValue & 0x20) && (value & 0x20)) + { _inputIndex = (_inputIndex + 1) % GetPlayerCount(); } @@ -194,41 +233,72 @@ void SuperGameboy::LogPacket() { uint8_t commandId = _packetData[0] >> 3; string name; - switch(commandId) { - case 0: name = "PAL01"; break; //Set SGB Palette 0, 1 Data - case 1: name = "PAL23"; break; //Set SGB Palette 2, 3 Data - case 2: name = "PAL03"; break; //Set SGB Palette 0, 3 Data - case 3: name = "PAL12"; break; //Set SGB Palette 1, 2 Data - case 4: name = "ATTR_BLK"; break; //"Block" Area Designation Mode - case 5: name = "ATTR_LIN"; break; //"Line" Area Designation Mode - case 6: name = "ATTR_DIV"; break; //"Divide" Area Designation Mode - case 7: name = "ATTR_CHR"; break; //"1CHR" Area Designation Mode - case 8: name = "SOUND"; break; //Sound On / Off - case 9: name = "SOU_TRN"; break; //Transfer Sound PRG / DATA - case 0xA: name = "PAL_SET"; break; //Set SGB Palette Indirect - case 0xB: name = "PAL_TRN"; break; //Set System Color Palette Data - case 0xC: name = "ATRC_EN"; break; //Enable / disable Attraction Mode - case 0xD: name = "TEST_EN"; break; //Speed Function - case 0xE: name = "ICON_EN"; break; //SGB Function - case 0xF: name = "DATA_SND"; break; //SUPER NES WRAM Transfer 1 - case 0x10: name = "DATA_TRN"; break; //SUPER NES WRAM Transfer 2 - case 0x11: name = "MLT_REG"; break; //Controller 2 Request - case 0x12: name = "JUMP"; break; //Set SNES Program Counter - case 0x13: name = "CHR_TRN"; break; //Transfer Character Font Data - case 0x14: name = "PCT_TRN"; break; //Set Screen Data Color Data - case 0x15: name = "ATTR_TRN"; break; //Set Attribute from ATF - case 0x16: name = "ATTR_SET"; break; //Set Data to ATF - case 0x17: name = "MASK_EN"; break; //Game Boy Window Mask - case 0x18: name = "OBJ_TRN"; break; //Super NES OBJ Mode - - case 0x1E: name = "Header Data"; break; - case 0x1F: name = "Header Data"; break; + switch (commandId) + { + case 0: name = "PAL01"; + break; //Set SGB Palette 0, 1 Data + case 1: name = "PAL23"; + break; //Set SGB Palette 2, 3 Data + case 2: name = "PAL03"; + break; //Set SGB Palette 0, 3 Data + case 3: name = "PAL12"; + break; //Set SGB Palette 1, 2 Data + case 4: name = "ATTR_BLK"; + break; //"Block" Area Designation Mode + case 5: name = "ATTR_LIN"; + break; //"Line" Area Designation Mode + case 6: name = "ATTR_DIV"; + break; //"Divide" Area Designation Mode + case 7: name = "ATTR_CHR"; + break; //"1CHR" Area Designation Mode + case 8: name = "SOUND"; + break; //Sound On / Off + case 9: name = "SOU_TRN"; + break; //Transfer Sound PRG / DATA + case 0xA: name = "PAL_SET"; + break; //Set SGB Palette Indirect + case 0xB: name = "PAL_TRN"; + break; //Set System Color Palette Data + case 0xC: name = "ATRC_EN"; + break; //Enable / disable Attraction Mode + case 0xD: name = "TEST_EN"; + break; //Speed Function + case 0xE: name = "ICON_EN"; + break; //SGB Function + case 0xF: name = "DATA_SND"; + break; //SUPER NES WRAM Transfer 1 + case 0x10: name = "DATA_TRN"; + break; //SUPER NES WRAM Transfer 2 + case 0x11: name = "MLT_REG"; + break; //Controller 2 Request + case 0x12: name = "JUMP"; + break; //Set SNES Program Counter + case 0x13: name = "CHR_TRN"; + break; //Transfer Character Font Data + case 0x14: name = "PCT_TRN"; + break; //Set Screen Data Color Data + case 0x15: name = "ATTR_TRN"; + break; //Set Attribute from ATF + case 0x16: name = "ATTR_SET"; + break; //Set Data to ATF + case 0x17: name = "MASK_EN"; + break; //Game Boy Window Mask + case 0x18: name = "OBJ_TRN"; + break; //Super NES OBJ Mode - default: name = "Unknown"; break; + case 0x1E: name = "Header Data"; + break; + case 0x1F: name = "Header Data"; + break; + + default: name = "Unknown"; + break; } - string log = "SGB Command: " + HexUtilities::ToHex(commandId) + " - " + name + " (Len: " + std::to_string(_packetData[0] & 0x07) + ") - "; - for(int i = 0; i < 16; i++) { + string log = "SGB Command: " + HexUtilities::ToHex(commandId) + " - " + name + " (Len: " + std::to_string( + _packetData[0] & 0x07) + ") - "; + for (int i = 0; i < 16; i++) + { log += HexUtilities::ToHex(_packetData[i]) + " "; } _console->DebugLog(log); @@ -243,7 +313,8 @@ uint8_t SuperGameboy::GetLcdRow() { uint8_t scanline = _ppu->GetScanline(); uint8_t row = scanline / 8; - if(row >= 18) { + if (row >= 18) + { row = 0; } return row; @@ -257,7 +328,8 @@ uint8_t SuperGameboy::GetLcdBufferRow() uint8_t SuperGameboy::GetPlayerCount() { uint8_t playerCount = ((_control >> 4) & 0x03) + 1; - if(playerCount >= 3) { + if (playerCount >= 3) + { //Unknown: 2 and 3 both mean 4 players? return 4; } @@ -270,29 +342,35 @@ void SuperGameboy::MixAudio(uint32_t targetRate, int16_t* soundSamples, uint32_t uint32_t gbSampleCount = 0; _gameboy->GetSoundSamples(gbSamples, gbSampleCount); _resampler.SetSampleRates(GbApu::SampleRate, targetRate); - + int32_t outCount = (int32_t)_resampler.Resample(gbSamples, gbSampleCount, _mixBuffer + _mixSampleCount) * 2; _mixSampleCount += outCount; - int32_t copyCount = (int32_t)std::min(_mixSampleCount, sampleCount*2); - if(!_spc->IsMuted()) { - for(int32_t i = 0; i < copyCount; i++) { + int32_t copyCount = (int32_t)std::min(_mixSampleCount, sampleCount * 2); + if (!_spc->IsMuted()) + { + for (int32_t i = 0; i < copyCount; i++) + { soundSamples[i] += _mixBuffer[i]; } } int32_t remainingSamples = (int32_t)_mixSampleCount - copyCount; - if(remainingSamples > 0) { - memmove(_mixBuffer, _mixBuffer + copyCount, remainingSamples*sizeof(int16_t)); + if (remainingSamples > 0) + { + memmove(_mixBuffer, _mixBuffer + copyCount, remainingSamples * sizeof(int16_t)); _mixSampleCount = remainingSamples; - } else { + } + else + { _mixSampleCount = 0; } } void SuperGameboy::Run() { - if(!(_control & 0x80)) { + if (!(_control & 0x80)) + { return; } @@ -306,11 +384,16 @@ void SuperGameboy::UpdateClockRatio() uint8_t divider = 5; //TODO: This doesn't actually work properly if the speed is changed while the SGB is running (but this most likely never happens?) - switch(_control & 0x03) { - case 0: divider = 4; break; - case 1: divider = 5; break; - case 2: divider = 7; break; - case 3: divider = 9; break; + switch (_control & 0x03) + { + case 0: divider = 4; + break; + case 1: divider = 5; + break; + case 2: divider = 7; + break; + case 3: divider = 9; + break; } double effectiveRate = (double)masterRate / divider; @@ -344,7 +427,7 @@ void SuperGameboy::PeekBlock(uint32_t addr, uint8_t* output) AddressInfo SuperGameboy::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::Register }; + return {-1, SnesMemoryType::Register}; } void SuperGameboy::Serialize(Serializer& s) diff --git a/Core/SuperGameboy.h b/Core/SuperGameboy.h index f7766e9..3b89e23 100644 --- a/Core/SuperGameboy.h +++ b/Core/SuperGameboy.h @@ -23,7 +23,7 @@ private: uint8_t _control = 0; uint64_t _resetClock = 0; double _clockRatio = 0; - + uint8_t _input[4] = {}; uint8_t _inputIndex = 0; @@ -31,7 +31,7 @@ private: bool _waitForHigh = true; bool _packetReady = false; uint64_t _inputWriteClock = 0; - uint8_t _inputValue = 0; + uint8_t _inputValue = 0; uint8_t _packetData[16] = {}; uint8_t _packetByte = 0; uint8_t _packetBit = 0; @@ -39,7 +39,7 @@ private: uint8_t _lcdRowSelect = 0; uint16_t _readPosition = 0; uint8_t _lcdBuffer[4][1280] = {}; - + HermiteResampler _resampler; int16_t* _mixBuffer = nullptr; uint32_t _mixSampleCount = 0; @@ -53,7 +53,7 @@ public: ~SuperGameboy(); void Reset() override; - + uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; @@ -77,4 +77,4 @@ public: void PeekBlock(uint32_t addr, uint8_t* output) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; void Serialize(Serializer& s) override; -}; \ No newline at end of file +}; diff --git a/Core/SuperScope.h b/Core/SuperScope.h index f559a7e..0c80fcb 100644 --- a/Core/SuperScope.h +++ b/Core/SuperScope.h @@ -9,16 +9,17 @@ class SuperScope : public BaseControlDevice { private: enum Buttons { Fire = 0, Cursor = 1, Turbo = 2, Pause = 3 }; + uint32_t _stateBuffer = 0; bool _prevFireButton = false; bool _prevTurboButton = false; bool _prevPauseButton = false; bool _turbo = false; - Ppu *_ppu; + Ppu* _ppu; protected: bool HasCoordinates() override { return true; } - + string GetKeyNames() override { return "FCTP"; @@ -29,7 +30,8 @@ protected: SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton)); SetPressedState(Buttons::Cursor, KeyManager::IsMouseButtonPressed(MouseButton::RightButton)); SetPressedState(Buttons::Turbo, KeyManager::IsMouseButtonPressed(MouseButton::MiddleButton)); - for(KeyMapping keyMapping : _keyMappings) { + for (KeyMapping keyMapping : _keyMappings) + { SetPressedState(Buttons::Pause, KeyManager::IsKeyPressed(keyMapping.Start)); } @@ -42,12 +44,13 @@ protected: MousePosition pos = GetCoordinates(); //Make the PPU latch the H/V counters at the mouse's position (offset slightly to make target in the center of the mouse cursor) - if(pos.X >= 0 && pos.Y >= 0) { + if (pos.X >= 0 && pos.Y >= 0) + { _ppu->SetLocationLatchRequest(pos.X + 10, std::max(0, pos.Y - 3)); } } - void Serialize(Serializer &s) override + void Serialize(Serializer& s) override { BaseControlDevice::Serialize(s); s.Stream(_stateBuffer, _prevTurboButton, _prevFireButton, _prevPauseButton, _turbo); @@ -65,27 +68,33 @@ protected: { uint16_t output = 0xFF00; //signature bits - if(!_prevTurboButton && IsPressed(Buttons::Turbo)) { + if (!_prevTurboButton && IsPressed(Buttons::Turbo)) + { _turbo = !_turbo; } - if((_turbo || !_prevFireButton) && IsPressed(Buttons::Fire)) { + if ((_turbo || !_prevFireButton) && IsPressed(Buttons::Fire)) + { output |= 0x01; } - if(IsPressed(Buttons::Cursor)) { + if (IsPressed(Buttons::Cursor)) + { output |= 0x02; } - if(_turbo) { + if (_turbo) + { output |= 0x04; } - if(!_prevPauseButton && IsPressed(Buttons::Pause)) { + if (!_prevPauseButton && IsPressed(Buttons::Pause)) + { output |= 0x08; } - if(GetCoordinates().X < 0 || GetCoordinates().Y < 0) { + if (GetCoordinates().X < 0 || GetCoordinates().Y < 0) + { output |= 0x40; //offscreen flag } @@ -107,7 +116,8 @@ public: { uint8_t output = 0; - if(IsCurrentPort(addr)) { + if (IsCurrentPort(addr)) + { StrobeProcessRead(); output = (_stateBuffer & 0x01); @@ -123,4 +133,4 @@ public: { StrobeProcessWrite(value); } -}; \ No newline at end of file +}; diff --git a/Core/SystemActionManager.h b/Core/SystemActionManager.h index c5e42cc..6359de8 100644 --- a/Core/SystemActionManager.h +++ b/Core/SystemActionManager.h @@ -15,7 +15,7 @@ protected: { return "RP"; } - + public: enum Buttons { ResetButton = 0, PowerButton = 1 }; @@ -39,19 +39,23 @@ public: void OnAfterSetState() override { - if(_needReset) { + if (_needReset) + { SetBit(SystemActionManager::Buttons::ResetButton); } - if(_needPowerCycle) { + if (_needPowerCycle) + { SetBit(SystemActionManager::Buttons::PowerButton); } } bool Reset() { - if(!_needReset) { + if (!_needReset) + { shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); debugger->Run(); } @@ -64,9 +68,11 @@ public: bool PowerCycle() { - if(!_needPowerCycle) { + if (!_needPowerCycle) + { shared_ptr debugger = _console->GetDebugger(false); - if(debugger) { + if (debugger) + { debugger->SuspendDebugger(false); debugger->Run(); } @@ -88,4 +94,4 @@ public: _needPowerCycle = false; return IsPressed(SystemActionManager::Buttons::PowerButton); } -}; \ No newline at end of file +}; diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index dc4c827..ef1b989 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -48,21 +48,23 @@ TraceLogger::~TraceLogger() delete[] _logCpuTypeCopy; } -template -void TraceLogger::WriteValue(string &output, T value, RowPart& rowPart) +template +void TraceLogger::WriteValue(string& output, T value, RowPart& rowPart) { string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value); output += str; - if(rowPart.MinWidth > (int)str.size()) { + if (rowPart.MinWidth > (int)str.size()) + { output += std::string(rowPart.MinWidth - str.size(), ' '); } } -template<> -void TraceLogger::WriteValue(string &output, string value, RowPart& rowPart) +template <> +void TraceLogger::WriteValue(string& output, string value, RowPart& rowPart) { output += value; - if(rowPart.MinWidth > (int)value.size()) { + if (rowPart.MinWidth > (int)value.size()) + { output += std::string(rowPart.MinWidth - value.size(), ' '); } } @@ -70,7 +72,7 @@ void TraceLogger::WriteValue(string &output, string value, RowPart& rowPart) void TraceLogger::SetOptions(TraceLoggerOptions options) { _options = options; - + _logCpu[(int)CpuType::Cpu] = options.LogCpu; _logCpu[(int)CpuType::Spc] = options.LogSpc; _logCpu[(int)CpuType::NecDsp] = options.LogNecDsp; @@ -93,92 +95,157 @@ void TraceLogger::SetOptions(TraceLoggerOptions options) }*/ ParseFormatString(_rowParts, format); - ParseFormatString(_spcRowParts, "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_dspRowParts, "[PC,4h] [ByteCode,11h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_gsuRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,50] SRC:[X,2] DST:[Y,2] R0:[A,2h] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_cx4RowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] [A,2h] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_gbRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] A:[A,2h] B:[B,2h] C:[C,2h] D:[D,2h] E:[E,2h] HL:[H,2h][L,2h] F:[F,2h] SP:[SP,4h] CYC:[Cycle,3] LY:[Scanline,3]"); + ParseFormatString(_spcRowParts, + "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_dspRowParts, + "[PC,4h] [ByteCode,11h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_gsuRowParts, + "[PC,6h] [ByteCode,11h] [Disassembly] [Align,50] SRC:[X,2] DST:[Y,2] R0:[A,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_cx4RowParts, + "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] [A,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_gbRowParts, + "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] A:[A,2h] B:[B,2h] C:[C,2h] D:[D,2h] E:[E,2h] HL:[H,2h][L,2h] F:[F,2h] SP:[SP,4h] CYC:[Cycle,3] LY:[Scanline,3]"); } -void TraceLogger::ParseFormatString(vector &rowParts, string format) +void TraceLogger::ParseFormatString(vector& rowParts, string format) { rowParts.clear(); - std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", std::regex_constants::icase); + std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", + std::regex_constants::icase); std::sregex_iterator start = std::sregex_iterator(format.cbegin(), format.cend(), formatRegex); std::sregex_iterator end = std::sregex_iterator(); - for(std::sregex_iterator it = start; it != end; it++) { + for (std::sregex_iterator it = start; it != end; it++) + { const std::smatch& match = *it; - if(match.str(1) == "") { + if (match.str(1) == "") + { RowPart part = {}; part.DataType = RowDataType::Text; part.Text = match.str(6); rowParts.push_back(part); - } else { + } + else + { RowPart part = {}; string dataType = match.str(2); - if(dataType == "ByteCode") { + if (dataType == "ByteCode") + { part.DataType = RowDataType::ByteCode; - } else if(dataType == "Disassembly") { + } + else if (dataType == "Disassembly") + { part.DataType = RowDataType::Disassembly; - } else if(dataType == "EffectiveAddress") { + } + else if (dataType == "EffectiveAddress") + { part.DataType = RowDataType::EffectiveAddress; - } else if(dataType == "MemoryValue") { + } + else if (dataType == "MemoryValue") + { part.DataType = RowDataType::MemoryValue; - } else if(dataType == "Align") { + } + else if (dataType == "Align") + { part.DataType = RowDataType::Align; - } else if(dataType == "PC") { + } + else if (dataType == "PC") + { part.DataType = RowDataType::PC; - } else if(dataType == "A") { + } + else if (dataType == "A") + { part.DataType = RowDataType::A; - } else if(dataType == "B") { + } + else if (dataType == "B") + { part.DataType = RowDataType::B; - } else if(dataType == "C") { + } + else if (dataType == "C") + { part.DataType = RowDataType::C; - } else if(dataType == "D") { + } + else if (dataType == "D") + { part.DataType = RowDataType::D; - } else if(dataType == "E") { + } + else if (dataType == "E") + { part.DataType = RowDataType::E; - } else if(dataType == "F") { + } + else if (dataType == "F") + { part.DataType = RowDataType::F; - } else if(dataType == "H") { + } + else if (dataType == "H") + { part.DataType = RowDataType::H; - } else if(dataType == "L") { + } + else if (dataType == "L") + { part.DataType = RowDataType::L; - } else if(dataType == "X") { + } + else if (dataType == "X") + { part.DataType = RowDataType::X; - } else if(dataType == "Y") { + } + else if (dataType == "Y") + { part.DataType = RowDataType::Y; - } else if(dataType == "D") { + } + else if (dataType == "D") + { part.DataType = RowDataType::D; - } else if(dataType == "DB") { + } + else if (dataType == "DB") + { part.DataType = RowDataType::DB; - } else if(dataType == "P") { + } + else if (dataType == "P") + { part.DataType = RowDataType::PS; - } else if(dataType == "SP") { + } + else if (dataType == "SP") + { part.DataType = RowDataType::SP; - } else if(dataType == "Cycle") { + } + else if (dataType == "Cycle") + { part.DataType = RowDataType::Cycle; - } else if(dataType == "HClock") { + } + else if (dataType == "HClock") + { part.DataType = RowDataType::HClock; - } else if(dataType == "Scanline") { + } + else if (dataType == "Scanline") + { part.DataType = RowDataType::Scanline; - } else if(dataType == "FrameCount") { + } + else if (dataType == "FrameCount") + { part.DataType = RowDataType::FrameCount; - } else if(dataType == "CycleCount") { + } + else if (dataType == "CycleCount") + { part.DataType = RowDataType::CycleCount; - } else { + } + else + { part.DataType = RowDataType::Text; part.Text = "[Invalid tag]"; } - if(!match.str(4).empty()) { - try { + if (!match.str(4).empty()) + { + try + { part.MinWidth = std::stoi(match.str(4)); - } catch(std::exception&) { + } + catch (std::exception&) + { } } part.DisplayInHex = match.str(5) == "h"; @@ -197,10 +264,13 @@ void TraceLogger::StartLogging(string filename) void TraceLogger::StopLogging() { - if(_logToFile) { + if (_logToFile) + { _logToFile = false; - if(_outputFile) { - if(!_outputBuffer.empty()) { + if (_outputFile) + { + if (!_outputBuffer.empty()) + { _outputFile << _outputBuffer; } _outputFile.close(); @@ -208,36 +278,45 @@ void TraceLogger::StopLogging() } } -void TraceLogger::LogExtraInfo(const char *log, uint32_t cycleCount) +void TraceLogger::LogExtraInfo(const char* log, uint32_t cycleCount) { - if(_logToFile && _options.ShowExtraInfo) { + if (_logToFile && _options.ShowExtraInfo) + { //Flush current buffer _outputFile << _outputBuffer; _outputBuffer.clear(); - _outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << (_options.UseWindowsEol ? "\r\n" : "\n"); + _outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << ( + _options.UseWindowsEol ? "\r\n" : "\n"); } } -template -void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part) +template +void TraceLogger::GetStatusFlag(string& output, uint8_t ps, RowPart& part) { - constexpr char cpuActiveStatusLetters[8] = { 'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C' }; - constexpr char cpuInactiveStatusLetters[8] = { 'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c' }; + constexpr char cpuActiveStatusLetters[8] = {'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C'}; + constexpr char cpuInactiveStatusLetters[8] = {'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c'}; - constexpr char spcActiveStatusLetters[8] = { 'N', 'V', 'P', 'B', 'H', 'I', 'Z', 'C' }; - constexpr char spcInactiveStatusLetters[8] = { 'n', 'v', 'p', 'b', 'h', 'i', 'z', 'c' }; + constexpr char spcActiveStatusLetters[8] = {'N', 'V', 'P', 'B', 'H', 'I', 'Z', 'C'}; + constexpr char spcInactiveStatusLetters[8] = {'n', 'v', 'p', 'b', 'h', 'i', 'z', 'c'}; - const char *activeStatusLetters = cpuType == CpuType::Cpu ? cpuActiveStatusLetters : spcActiveStatusLetters; - const char *inactiveStatusLetters = cpuType == CpuType::Cpu ? cpuInactiveStatusLetters : spcInactiveStatusLetters; + const char* activeStatusLetters = cpuType == CpuType::Cpu ? cpuActiveStatusLetters : spcActiveStatusLetters; + const char* inactiveStatusLetters = cpuType == CpuType::Cpu ? cpuInactiveStatusLetters : spcInactiveStatusLetters; - if(part.DisplayInHex) { + if (part.DisplayInHex) + { WriteValue(output, ps, part); - } else { + } + else + { string flags; - for(int i = 0; i < 8; i++) { - if(ps & 0x80) { + for (int i = 0; i < 8; i++) + { + if (ps & 0x80) + { flags += activeStatusLetters[i]; - } else if(part.MinWidth >= 8) { + } + else if (part.MinWidth >= 8) + { flags += inactiveStatusLetters[i]; } ps <<= 1; @@ -246,23 +325,25 @@ void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part) } } -void TraceLogger::WriteByteCode(DisassemblyInfo &info, RowPart &rowPart, string &output) +void TraceLogger::WriteByteCode(DisassemblyInfo& info, RowPart& rowPart, string& output) { string byteCode; info.GetByteCode(byteCode); - if(!rowPart.DisplayInHex) { + if (!rowPart.DisplayInHex) + { //Remove $ marks if not in "hex" mode (but still display the bytes as hex) byteCode.erase(std::remove(byteCode.begin(), byteCode.end(), '$'), byteCode.end()); } WriteValue(output, byteCode, rowPart); } -void TraceLogger::WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint8_t sp, uint32_t pc, string &output) +void TraceLogger::WriteDisassembly(DisassemblyInfo& info, RowPart& rowPart, uint8_t sp, uint32_t pc, string& output) { int indentLevel = 0; string code; - if(_options.IndentCode) { + if (_options.IndentCode) + { indentLevel = 0xFF - (sp & 0xFF); code = std::string(indentLevel, ' '); } @@ -272,14 +353,18 @@ void TraceLogger::WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint WriteValue(output, code, rowPart); } -void TraceLogger::WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType cpuMemoryType, CpuType cpuType) +void TraceLogger::WriteEffectiveAddress(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType cpuMemoryType, CpuType cpuType) { int32_t effectiveAddress = info.GetEffectiveAddress(_console, cpuState, cpuType); - if(effectiveAddress >= 0) { - if(_options.UseLabels) { - AddressInfo addr { effectiveAddress, cpuMemoryType }; + if (effectiveAddress >= 0) + { + if (_options.UseLabels) + { + AddressInfo addr{effectiveAddress, cpuMemoryType}; string label = _labelManager->GetLabel(addr); - if(!label.empty()) { + if (!label.empty()) + { WriteValue(output, " [" + label + "]", rowPart); return; } @@ -288,231 +373,349 @@ void TraceLogger::WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, } } -void TraceLogger::WriteMemoryValue(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType memType, CpuType cpuType) +void TraceLogger::WriteMemoryValue(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType memType, CpuType cpuType) { int32_t address = info.GetEffectiveAddress(_console, cpuState, cpuType); - if(address >= 0) { + if (address >= 0) + { uint8_t valueSize; uint16_t value = info.GetMemoryValue(address, _memoryDumper, memType, valueSize); - if(rowPart.DisplayInHex) { + if (rowPart.DisplayInHex) + { output += "= $"; - if(valueSize == 2) { + if (valueSize == 2) + { WriteValue(output, (uint16_t)value, rowPart); - } else { + } + else + { WriteValue(output, (uint8_t)value, rowPart); } - } else { + } + else + { output += "= "; } } } -void TraceLogger::WriteAlign(int originalSize, RowPart &rowPart, string &output) +void TraceLogger::WriteAlign(int originalSize, RowPart& rowPart, string& output) { - if((int)output.size() - originalSize < rowPart.MinWidth) { + if ((int)output.size() - originalSize < rowPart.MinWidth) + { output += std::string(rowPart.MinWidth - (output.size() - originalSize), ' '); } } -void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType, CpuType cpuType) +void TraceLogger::GetTraceRow(string& output, CpuState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo, + SnesMemoryType memType, CpuType cpuType) { int originalSize = (int)output.size(); uint32_t pcAddress = (cpuState.K << 16) | cpuState.PC; - for(RowPart& rowPart : _rowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); break; - case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); break; - case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _rowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: + WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); + break; + case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, memType, + cpuType); + break; + case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; - case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break; - case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break; - case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break; - case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break; - case RowDataType::DB: WriteValue(output, cpuState.DBR, rowPart); break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - case RowDataType::CycleCount: WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart); break; - default: break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); + break; + case RowDataType::A: WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::X: WriteValue(output, cpuState.X, rowPart); + break; + case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); + break; + case RowDataType::D: WriteValue(output, cpuState.D, rowPart); + break; + case RowDataType::DB: WriteValue(output, cpuState.DBR, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + case RowDataType::CycleCount: WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, SpcState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = cpuState.PC; - for(RowPart& rowPart : _spcRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break; - case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::SpcMemory, CpuType::Spc); break; - case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::SpcMemory, CpuType::Spc); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _spcRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); + break; + case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::SpcMemory, CpuType::Spc); + break; + case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::SpcMemory, CpuType::Spc); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break; - case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break; - case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break; - case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); + break; + case RowDataType::A: WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::X: WriteValue(output, cpuState.X, rowPart); + break; + case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; - default: break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, NecDspState& cpuState, PpuState& ppuState, + DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = cpuState.PC; - for(RowPart& rowPart : _dspRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _dspRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break; - case RowDataType::A: - output += "A:" + HexUtilities::ToHex(cpuState.A); - output += " B:" + HexUtilities::ToHex(cpuState.B); - output += " DR:" + HexUtilities::ToHex(cpuState.DR); - output += " DP:" + HexUtilities::ToHex(cpuState.DP); - output += " SR:" + HexUtilities::ToHex(cpuState.SR); - output += " K:" + HexUtilities::ToHex(cpuState.K); - output += " L:" + HexUtilities::ToHex(cpuState.L); - output += " M:" + HexUtilities::ToHex(cpuState.M); - output += " N:" + HexUtilities::ToHex(cpuState.N); - output += " RP:" + HexUtilities::ToHex(cpuState.RP); - output += " TR:" + HexUtilities::ToHex(cpuState.TR); - output += " TRB:" + HexUtilities::ToHex(cpuState.TRB) + " "; - //output += "FA=" + HexUtilities::ToHex(cpuState.FlagsA); - //output += "FB=" + HexUtilities::ToHex(cpuState.FlagsB); - WriteValue(output, cpuState.A, rowPart); - break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - default: break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); + break; + case RowDataType::A: + output += "A:" + HexUtilities::ToHex(cpuState.A); + output += " B:" + HexUtilities::ToHex(cpuState.B); + output += " DR:" + HexUtilities::ToHex(cpuState.DR); + output += " DP:" + HexUtilities::ToHex(cpuState.DP); + output += " SR:" + HexUtilities::ToHex(cpuState.SR); + output += " K:" + HexUtilities::ToHex(cpuState.K); + output += " L:" + HexUtilities::ToHex(cpuState.L); + output += " M:" + HexUtilities::ToHex(cpuState.M); + output += " N:" + HexUtilities::ToHex(cpuState.N); + output += " RP:" + HexUtilities::ToHex(cpuState.RP); + output += " TR:" + HexUtilities::ToHex(cpuState.TR); + output += " TRB:" + HexUtilities::ToHex(cpuState.TRB) + " "; + //output += "FA=" + HexUtilities::ToHex(cpuState.FlagsA); + //output += "FB=" + HexUtilities::ToHex(cpuState.FlagsB); + WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, GsuState& gsuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = (gsuState.ProgramBank << 16) | gsuState.R[15]; - for(RowPart& rowPart : _gsuRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _gsuRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; - case RowDataType::A: - WriteValue(output, gsuState.R[0], rowPart); - for(int i = 1; i < 16; i++) { - output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex(gsuState.R[i]); - } - break; - case RowDataType::X: WriteValue(output, gsuState.SrcReg, rowPart); break; - case RowDataType::Y: WriteValue(output, gsuState.DestReg, rowPart); break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); + break; + case RowDataType::A: + WriteValue(output, gsuState.R[0], rowPart); + for (int i = 1; i < 16; i++) + { + output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex(gsuState.R[i]); + } + break; + case RowDataType::X: WriteValue(output, gsuState.SrcReg, rowPart); + break; + case RowDataType::Y: WriteValue(output, gsuState.DestReg, rowPart); + break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - default: break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string &output, Cx4State &cx4State, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, Cx4State& cx4State, PpuState& ppuState, DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = (cx4State.Cache.Address[cx4State.Cache.Page] + (cx4State.PC * 2)) & 0xFFFFFF; - for(RowPart& rowPart : _cx4RowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _cx4RowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; - case RowDataType::A: - output += " A:" + HexUtilities::ToHex24(cx4State.A); - output += string(" ") + (cx4State.Carry ? "C" : "c") + (cx4State.Zero ? "Z" : "z") + (cx4State.Overflow ? "V" : "v") + (cx4State.Negative ? "N" : "n"); + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); + break; + case RowDataType::A: + output += " A:" + HexUtilities::ToHex24(cx4State.A); + output += string(" ") + (cx4State.Carry ? "C" : "c") + (cx4State.Zero ? "Z" : "z") + ( + cx4State.Overflow ? "V" : "v") + (cx4State.Negative ? "N" : "n"); - output += " PC:" + HexUtilities::ToHex(cx4State.PC); - output += " MAR:" + HexUtilities::ToHex24(cx4State.MemoryAddressReg); - output += " MDR:" + HexUtilities::ToHex24(cx4State.MemoryDataReg); - output += " DPR:" + HexUtilities::ToHex24(cx4State.DataPointerReg); - output += " ML:" + HexUtilities::ToHex24((uint32_t)cx4State.Mult & 0xFFFFFF); - output += " MH:" + HexUtilities::ToHex24((uint32_t)(cx4State.Mult >> 24) & 0xFFFFFF); - for(int i = 0; i < 16; i++) { - output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex24(cx4State.Regs[i]); - } - break; + output += " PC:" + HexUtilities::ToHex(cx4State.PC); + output += " MAR:" + HexUtilities::ToHex24(cx4State.MemoryAddressReg); + output += " MDR:" + HexUtilities::ToHex24(cx4State.MemoryDataReg); + output += " DPR:" + HexUtilities::ToHex24(cx4State.DataPointerReg); + output += " ML:" + HexUtilities::ToHex24((uint32_t)cx4State.Mult & 0xFFFFFF); + output += " MH:" + HexUtilities::ToHex24((uint32_t)(cx4State.Mult >> 24) & 0xFFFFFF); + for (int i = 0; i < 16; i++) + { + output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex24(cx4State.Regs[i]); + } + break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; - default: break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; } -void TraceLogger::GetTraceRow(string& output, GbCpuState& cpuState, GbPpuState& ppuState, DisassemblyInfo& disassemblyInfo) +void TraceLogger::GetTraceRow(string& output, GbCpuState& cpuState, GbPpuState& ppuState, + DisassemblyInfo& disassemblyInfo) { int originalSize = (int)output.size(); uint32_t pcAddress = cpuState.PC; - for(RowPart& rowPart : _gbRowParts) { - switch(rowPart.DataType) { - case RowDataType::Text: output += rowPart.Text; break; - case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; - case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); break; - case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::GameboyMemory, CpuType::Gameboy); break; - case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::GameboyMemory, CpuType::Gameboy); break; - case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + for (RowPart& rowPart : _gbRowParts) + { + switch (rowPart.DataType) + { + case RowDataType::Text: output += rowPart.Text; + break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); + break; + case RowDataType::Disassembly: + WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); + break; + case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::GameboyMemory, CpuType::Gameboy); + break; + case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, + SnesMemoryType::GameboyMemory, CpuType::Gameboy); + break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); + break; - case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break; - case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break; - case RowDataType::B: WriteValue(output, cpuState.B, rowPart); break; - case RowDataType::C: WriteValue(output, cpuState.C, rowPart); break; - case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break; - case RowDataType::E: WriteValue(output, cpuState.E, rowPart); break; - case RowDataType::F: WriteValue(output, cpuState.Flags, rowPart); break; - case RowDataType::H: WriteValue(output, cpuState.H, rowPart); break; - case RowDataType::L: WriteValue(output, cpuState.L, rowPart); break; - case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break; - case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; - case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; - case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); + break; + case RowDataType::A: WriteValue(output, cpuState.A, rowPart); + break; + case RowDataType::B: WriteValue(output, cpuState.B, rowPart); + break; + case RowDataType::C: WriteValue(output, cpuState.C, rowPart); + break; + case RowDataType::D: WriteValue(output, cpuState.D, rowPart); + break; + case RowDataType::E: WriteValue(output, cpuState.E, rowPart); + break; + case RowDataType::F: WriteValue(output, cpuState.Flags, rowPart); + break; + case RowDataType::H: WriteValue(output, cpuState.H, rowPart); + break; + case RowDataType::L: WriteValue(output, cpuState.L, rowPart); + break; + case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); + break; + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); + break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); + break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); + break; - default: break; + default: break; } } output += _options.UseWindowsEol ? "\r\n" : "\n"; @@ -537,33 +740,45 @@ bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemb } */ -void TraceLogger::GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state) +void TraceLogger::GetTraceRow(string& output, CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state) { - switch(cpuType) { - case CpuType::Cpu: GetTraceRow(output, state.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::CpuMemory, cpuType); break; - case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); break; - case CpuType::NecDsp: GetTraceRow(output, state.NecDsp, state.Ppu, disassemblyInfo); break; - case CpuType::Sa1: GetTraceRow(output, state.Sa1.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::Sa1Memory, cpuType); break; - case CpuType::Gsu: GetTraceRow(output, state.Gsu, state.Ppu, disassemblyInfo); break; - case CpuType::Cx4: GetTraceRow(output, state.Cx4, state.Ppu, disassemblyInfo); break; - case CpuType::Gameboy: GetTraceRow(output, state.Gameboy.Cpu, state.Gameboy.Ppu, disassemblyInfo); break; + switch (cpuType) + { + case CpuType::Cpu: GetTraceRow(output, state.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::CpuMemory, cpuType); + break; + case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); + break; + case CpuType::NecDsp: GetTraceRow(output, state.NecDsp, state.Ppu, disassemblyInfo); + break; + case CpuType::Sa1: GetTraceRow(output, state.Sa1.Cpu, state.Ppu, disassemblyInfo, SnesMemoryType::Sa1Memory, + cpuType); + break; + case CpuType::Gsu: GetTraceRow(output, state.Gsu, state.Ppu, disassemblyInfo); + break; + case CpuType::Cx4: GetTraceRow(output, state.Cx4, state.Ppu, disassemblyInfo); + break; + case CpuType::Gameboy: GetTraceRow(output, state.Gameboy.Cpu, state.Gameboy.Ppu, disassemblyInfo); + break; } } -void TraceLogger::AddRow(CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state) +void TraceLogger::AddRow(CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state) { _logCpuType[_currentPos] = cpuType; _disassemblyCache[_currentPos] = disassemblyInfo; _stateCache[_currentPos] = state; _pendingLog = false; - if(_logCount < ExecutionLogSize) { + if (_logCount < ExecutionLogSize) + { _logCount++; } - if(_logToFile) { + if (_logToFile) + { GetTraceRow(_outputBuffer, cpuType, _disassemblyCache[_currentPos], _stateCache[_currentPos]); - if(_outputBuffer.size() > 32768) { + if (_outputBuffer.size() > 32768) + { _outputFile << _outputBuffer; _outputBuffer.clear(); } @@ -571,6 +786,7 @@ void TraceLogger::AddRow(CpuType cpuType, DisassemblyInfo &disassemblyInfo, Debu _currentPos = (_currentPos + 1) % ExecutionLogSize; } + /* void TraceLogger::LogNonExec(OperationInfo& operationInfo) { @@ -582,13 +798,14 @@ void TraceLogger::LogNonExec(OperationInfo& operationInfo) } }*/ -void TraceLogger::Log(CpuType cpuType, DebugState &state, DisassemblyInfo &disassemblyInfo) +void TraceLogger::Log(CpuType cpuType, DebugState& state, DisassemblyInfo& disassemblyInfo) { - if(_logCpu[(int)cpuType]) { + if (_logCpu[(int)cpuType]) + { //For the sake of performance, only log data for the CPUs we're actively displaying/logging auto lock = _lock.AcquireSafe(); //if(ConditionMatches(state, disassemblyInfo, operationInfo)) { - AddRow(cpuType, disassemblyInfo, state); + AddRow(cpuType, disassemblyInfo, state); //} } } @@ -613,37 +830,55 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) } bool enabled = false; - for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) { + for (int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) + { enabled |= _logCpu[i]; } - if(enabled && lineCount > 0) { - for(int i = 0; i < TraceLogger::ExecutionLogSize; i++) { + if (enabled && lineCount > 0) + { + for (int i = 0; i < TraceLogger::ExecutionLogSize; i++) + { int index = (startPos - i); - if(index < 0) { + if (index < 0) + { index = TraceLogger::ExecutionLogSize + index; } - if((i > 0 && startPos == index) || !_disassemblyCacheCopy[index].IsInitialized()) { + if ((i > 0 && startPos == index) || !_disassemblyCacheCopy[index].IsInitialized()) + { //If the entire array was checked, or this element is not initialized, stop break; } CpuType cpuType = _logCpuTypeCopy[index]; - if(!_logCpu[(int)cpuType]) { + if (!_logCpu[(int)cpuType]) + { //This line isn't for a CPU currently being logged continue; } - DebugState &state = _stateCacheCopy[index]; - switch(cpuType) { - case CpuType::Cpu: _executionTrace += "\x2\x1" + HexUtilities::ToHex24((state.Cpu.K << 16) | state.Cpu.PC) + "\x1"; break; - case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(state.Spc.PC) + "\x1"; break; - case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.NecDsp.PC) + "\x1"; break; - case CpuType::Sa1: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Sa1.Cpu.K << 16) | state.Sa1.Cpu.PC) + "\x1"; break; - case CpuType::Gsu: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Gsu.ProgramBank << 16) | state.Gsu.R[15]) + "\x1"; break; - case CpuType::Cx4: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((state.Cx4.Cache.Address[state.Cx4.Cache.Page] + (state.Cx4.PC * 2)) & 0xFFFFFF) + "\x1"; break; - case CpuType::Gameboy: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.Gameboy.Cpu.PC) + "\x1"; break; + DebugState& state = _stateCacheCopy[index]; + switch (cpuType) + { + case CpuType::Cpu: _executionTrace += "\x2\x1" + HexUtilities::ToHex24((state.Cpu.K << 16) | state.Cpu.PC) + + "\x1"; + break; + case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(state.Spc.PC) + "\x1"; + break; + case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.NecDsp.PC) + "\x1"; + break; + case CpuType::Sa1: _executionTrace += "\x4\x1" + HexUtilities::ToHex24( + (state.Sa1.Cpu.K << 16) | state.Sa1.Cpu.PC) + "\x1"; + break; + case CpuType::Gsu: _executionTrace += "\x4\x1" + HexUtilities::ToHex24( + (state.Gsu.ProgramBank << 16) | state.Gsu.R[15]) + "\x1"; + break; + case CpuType::Cx4: _executionTrace += "\x4\x1" + HexUtilities::ToHex24( + (state.Cx4.Cache.Address[state.Cx4.Cache.Page] + (state.Cx4.PC * 2)) & 0xFFFFFF) + "\x1"; + break; + case CpuType::Gameboy: _executionTrace += "\x4\x1" + HexUtilities::ToHex(state.Gameboy.Cpu.PC) + "\x1"; + break; } string byteCode; @@ -652,10 +887,11 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) GetTraceRow(_executionTrace, cpuType, _disassemblyCacheCopy[index], _stateCacheCopy[index]); lineCount--; - if(lineCount == 0) { + if (lineCount == 0) + { break; } } } return _executionTrace.c_str(); -} \ No newline at end of file +} diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index 5558019..0269be3 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -106,37 +106,42 @@ private: bool _logToFile; uint32_t _currentPos; uint32_t _logCount; - DebugState *_stateCache = nullptr; - DisassemblyInfo *_disassemblyCache = nullptr; + DebugState* _stateCache = nullptr; + DisassemblyInfo* _disassemblyCache = nullptr; CpuType* _logCpuType = nullptr; - DebugState *_stateCacheCopy = nullptr; - DisassemblyInfo *_disassemblyCacheCopy = nullptr; + DebugState* _stateCacheCopy = nullptr; + DisassemblyInfo* _disassemblyCacheCopy = nullptr; CpuType* _logCpuTypeCopy = nullptr; SimpleLock _lock; - template void GetStatusFlag(string &output, uint8_t ps, RowPart& part); + template + void GetStatusFlag(string& output, uint8_t ps, RowPart& part); - void WriteByteCode(DisassemblyInfo &info, RowPart &rowPart, string &output); - void WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint8_t sp, uint32_t pc, string &output); - void WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType cpuMemoryType, CpuType cpuType); - void WriteMemoryValue(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType memType, CpuType cpuType); - void WriteAlign(int originalSize, RowPart &rowPart, string &output); - void AddRow(CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state); + void WriteByteCode(DisassemblyInfo& info, RowPart& rowPart, string& output); + void WriteDisassembly(DisassemblyInfo& info, RowPart& rowPart, uint8_t sp, uint32_t pc, string& output); + void WriteEffectiveAddress(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType cpuMemoryType, CpuType cpuType); + void WriteMemoryValue(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, + SnesMemoryType memType, CpuType cpuType); + void WriteAlign(int originalSize, RowPart& rowPart, string& output); + void AddRow(CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state); //bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo); - - void ParseFormatString(vector &rowParts, string format); - void GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo &disassemblyInfo, DebugState &state); - void GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType, CpuType cpuType); - void GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); - void GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); - void GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); + void ParseFormatString(vector& rowParts, string format); + + void GetTraceRow(string& output, CpuType cpuType, DisassemblyInfo& disassemblyInfo, DebugState& state); + void GetTraceRow(string& output, CpuState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo, + SnesMemoryType memType, CpuType cpuType); + void GetTraceRow(string& output, SpcState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); + void GetTraceRow(string& output, NecDspState& cpuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); + void GetTraceRow(string& output, GsuState& gsuState, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); void GetTraceRow(string& output, Cx4State& cx4State, PpuState& ppuState, DisassemblyInfo& disassemblyInfo); - void GetTraceRow(string &output, GbCpuState &gbState, GbPpuState &gbPpuState, DisassemblyInfo &disassemblyInfo); + void GetTraceRow(string& output, GbCpuState& gbState, GbPpuState& gbPpuState, DisassemblyInfo& disassemblyInfo); - template void WriteValue(string &output, T value, RowPart& rowPart); + template + void WriteValue(string& output, T value, RowPart& rowPart); public: TraceLogger(Debugger* debugger, shared_ptr console); @@ -144,14 +149,14 @@ public: __forceinline bool IsCpuLogged(CpuType type) { return _logCpu[(int)type]; } - void Log(CpuType cpuType, DebugState &state, DisassemblyInfo &disassemblyInfo); + void Log(CpuType cpuType, DebugState& state, DisassemblyInfo& disassemblyInfo); void Clear(); //void LogNonExec(OperationInfo& operationInfo); void SetOptions(TraceLoggerOptions options); void StartLogging(string filename); void StopLogging(); - void LogExtraInfo(const char *log, uint32_t cycleCount); + void LogExtraInfo(const char* log, uint32_t cycleCount); const char* GetExecutionTrace(uint32_t lineCount); }; diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index 91dbc4a..0b86dde 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -19,7 +19,7 @@ VideoDecoder::VideoDecoder(shared_ptr console) _console = console; _frameChanged = false; _stopFlag = false; - _baseFrameInfo = { 512, 478 }; + _baseFrameInfo = {512, 478}; _lastFrameInfo = _baseFrameInfo; UpdateVideoFilter(); _videoFilter->SetBaseFrameInfo(_baseFrameInfo); @@ -49,14 +49,19 @@ ScreenSize VideoDecoder::GetScreenSize(bool ignoreScale) size.Scale = scale; double aspectRatio = _console->GetSettings()->GetAspectRatio(_console->GetRegion()); - if(aspectRatio != 0.0) { + if (aspectRatio != 0.0) + { VideoAspectRatio aspect = _console->GetSettings()->GetVideoConfig().AspectRatio; - bool usePar = aspect == VideoAspectRatio::NTSC || aspect == VideoAspectRatio::PAL || aspect == VideoAspectRatio::Auto; - if(usePar) { + bool usePar = aspect == VideoAspectRatio::NTSC || aspect == VideoAspectRatio::PAL || aspect == + VideoAspectRatio::Auto; + if (usePar) + { OverscanDimensions overscan = _console->GetSettings()->GetOverscan(); uint32_t fullWidth = frameInfo.Width + (overscan.Left + overscan.Right); size.Width = (uint32_t)(256 * scale * aspectRatio * frameInfo.Width / fullWidth); - } else { + } + else + { size.Width = (uint32_t)(size.Height * aspectRatio); } } @@ -68,15 +73,19 @@ void VideoDecoder::UpdateVideoFilter() { VideoFilterType newFilter = _console->GetSettings()->GetVideoConfig().VideoFilter; - if(_videoFilterType != newFilter || _videoFilter == nullptr) { + if (_videoFilterType != newFilter || _videoFilter == nullptr) + { _videoFilterType = newFilter; _videoFilter.reset(new DefaultVideoFilter(_console)); _scaleFilter.reset(); - switch(_videoFilterType) { - case VideoFilterType::None: break; - case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); break; - default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); break; + switch (_videoFilterType) + { + case VideoFilterType::None: break; + case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); + break; + default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); + break; } } } @@ -90,18 +99,22 @@ void VideoDecoder::DecodeFrame(bool forRewind) uint32_t* outputBuffer = _videoFilter->GetOutputBuffer(); FrameInfo frameInfo = _videoFilter->GetFrameInfo(); - + _inputHud->DrawControllers(_videoFilter->GetOverscan(), _frameNumber); _console->GetDebugHud()->Draw(outputBuffer, _videoFilter->GetOverscan(), frameInfo.Width, _frameNumber); - if(_scaleFilter) { - outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetVideoConfig().ScanlineIntensity); + if (_scaleFilter) + { + outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, + _console->GetSettings()->GetVideoConfig().ScanlineIntensity); frameInfo = _scaleFilter->GetFrameInfo(frameInfo); } ScreenSize screenSize = GetScreenSize(true); VideoConfig config = _console->GetSettings()->GetVideoConfig(); - if(_previousScale != config.VideoScale || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) { + if (_previousScale != config.VideoScale || screenSize.Height != _previousScreenSize.Height || screenSize.Width != + _previousScreenSize.Width) + { _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ResolutionChanged); } _previousScale = config.VideoScale; @@ -117,11 +130,14 @@ void VideoDecoder::DecodeFrame(bool forRewind) void VideoDecoder::DecodeThread() { //This thread will decode the PPU's output (color ID to RGB, intensify r/g/b and produce a HD version of the frame if needed) - while(!_stopFlag.load()) { + while (!_stopFlag.load()) + { //DecodeFrame returns the final ARGB frame we want to display in the emulator window - while(!_frameChanged) { + while (!_frameChanged) + { _waitForFrame.Wait(); - if(_stopFlag.load()) { + if (_stopFlag.load()) + { return; } } @@ -135,20 +151,24 @@ uint32_t VideoDecoder::GetFrameCount() return _frameCount; } -void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, bool forRewind) +void VideoDecoder::UpdateFrameSync(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, + bool forRewind) { - if(_console->IsRunAheadFrame()) { + if (_console->IsRunAheadFrame()) + { return; } - if(_frameChanged) { + if (_frameChanged) + { //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay - while(_frameChanged) { + while (_frameChanged) + { //Spin until decode is done } //At this point, we are sure that the decode thread is no longer busy } - + _frameChanged = true; _baseFrameInfo.Width = width; _baseFrameInfo.Height = height; @@ -158,20 +178,23 @@ void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, ui _frameCount++; } -void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) +void VideoDecoder::UpdateFrame(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) { - if(_console->IsRunAheadFrame()) { + if (_console->IsRunAheadFrame()) + { return; } - if(_frameChanged) { + if (_frameChanged) + { //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay - while(_frameChanged) { + while (_frameChanged) + { //Spin until decode is done } //At this point, we are sure that the decode thread is no longer busy } - + _baseFrameInfo.Width = width; _baseFrameInfo.Height = height; _frameNumber = frameNumber; @@ -185,12 +208,13 @@ void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16 void VideoDecoder::StartThread() { #ifndef LIBRETRO - if(!_decodeThread) { + if (!_decodeThread) + { _stopFlag = false; _frameChanged = false; _frameCount = 0; _waitForFrame.Reset(); - + _decodeThread.reset(new thread(&VideoDecoder::DecodeThread, this)); } #endif @@ -200,14 +224,16 @@ void VideoDecoder::StopThread() { #ifndef LIBRETRO _stopFlag = true; - if(_decodeThread) { + if (_decodeThread) + { _waitForFrame.Signal(); _decodeThread->join(); _decodeThread.reset(); //Clear whole screen - if(_frameCount > 0) { + if (_frameCount > 0) + { vector outputBuffer(512 * 478, 0); _ppuOutputBuffer = outputBuffer.data(); memset(_ppuOutputBuffer, 0, 512 * 478 * 2); @@ -225,14 +251,16 @@ bool VideoDecoder::IsRunning() void VideoDecoder::TakeScreenshot() { - if(_videoFilter) { + if (_videoFilter) + { _videoFilter->TakeScreenshot(_console->GetRomInfo().RomFile.GetFileName(), _videoFilterType); } } -void VideoDecoder::TakeScreenshot(std::stringstream &stream) +void VideoDecoder::TakeScreenshot(std::stringstream& stream) { - if(_videoFilter) { + if (_videoFilter) + { _videoFilter->TakeScreenshot(_videoFilterType, "", &stream); } } diff --git a/Core/VideoDecoder.h b/Core/VideoDecoder.h index 47f10c0..66359f2 100644 --- a/Core/VideoDecoder.h +++ b/Core/VideoDecoder.h @@ -16,14 +16,14 @@ class VideoDecoder private: shared_ptr _console; - uint16_t *_ppuOutputBuffer = nullptr; + uint16_t* _ppuOutputBuffer = nullptr; uint32_t _frameNumber = 0; unique_ptr _decodeThread; unique_ptr _inputHud; AutoResetEvent _waitForFrame; - + atomic _frameChanged; atomic _stopFlag; uint32_t _frameCount = 0; @@ -48,17 +48,18 @@ public: void DecodeFrame(bool synchronous = false); void TakeScreenshot(); - void TakeScreenshot(std::stringstream &stream); + void TakeScreenshot(std::stringstream& stream); uint32_t GetFrameCount(); FrameInfo GetFrameInfo(); ScreenSize GetScreenSize(bool ignoreScale); - void UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, bool forRewind); - void UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber); + void UpdateFrameSync(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, + bool forRewind); + void UpdateFrame(uint16_t* ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber); bool IsRunning(); void StartThread(); void StopThread(); -}; \ No newline at end of file +}; diff --git a/Core/VideoRenderer.cpp b/Core/VideoRenderer.cpp index 3f11646..7ab5d7e 100644 --- a/Core/VideoRenderer.cpp +++ b/Core/VideoRenderer.cpp @@ -12,7 +12,7 @@ VideoRenderer::VideoRenderer(shared_ptr console) { _console = console; - _stopFlag = false; + _stopFlag = false; StartThread(); } @@ -25,7 +25,8 @@ VideoRenderer::~VideoRenderer() void VideoRenderer::StartThread() { #ifndef LIBRETRO - if(!_renderThread) { + if (!_renderThread) + { _stopFlag = false; _waitForRender.Reset(); @@ -38,7 +39,8 @@ void VideoRenderer::StopThread() { #ifndef LIBRETRO _stopFlag = true; - if(_renderThread) { + if (_renderThread) + { _renderThread->join(); _renderThread.reset(); } @@ -47,14 +49,17 @@ void VideoRenderer::StopThread() void VideoRenderer::RenderThread() { - if(_renderer) { + if (_renderer) + { _renderer->Reset(); } - while(!_stopFlag.load()) { + while (!_stopFlag.load()) + { //Wait until a frame is ready, or until 16ms have passed (to allow UI to run at a minimum of 60fps) _waitForRender.Wait(16); - if(_renderer) { + if (_renderer) + { _renderer->Render(); } } @@ -63,25 +68,28 @@ void VideoRenderer::RenderThread() void VideoRenderer::UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height) { shared_ptr recorder = _recorder; - if(recorder) { + if (recorder) + { recorder->AddFrame(frameBuffer, width, height, _console->GetFps()); } - if(_renderer) { + if (_renderer) + { _renderer->UpdateFrame(frameBuffer, width, height); _waitForRender.Signal(); } } -void VideoRenderer::RegisterRenderingDevice(IRenderingDevice *renderer) +void VideoRenderer::RegisterRenderingDevice(IRenderingDevice* renderer) { _renderer = renderer; StartThread(); } -void VideoRenderer::UnregisterRenderingDevice(IRenderingDevice *renderer) +void VideoRenderer::UnregisterRenderingDevice(IRenderingDevice* renderer) { - if(_renderer == renderer) { + if (_renderer == renderer) + { StopThread(); _renderer = nullptr; } @@ -92,13 +100,18 @@ void VideoRenderer::StartRecording(string filename, VideoCodec codec, uint32_t c FrameInfo frameInfo = _console->GetVideoDecoder()->GetFrameInfo(); shared_ptr recorder; - if(codec == VideoCodec::GIF) { + if (codec == VideoCodec::GIF) + { recorder.reset(new GifRecorder()); - } else { + } + else + { recorder.reset(new AviRecorder(codec, compressionLevel)); } - if(recorder->StartRecording(filename, frameInfo.Width, frameInfo.Height, 4, _console->GetSettings()->GetAudioConfig().SampleRate, _console->GetFps())) { + if (recorder->StartRecording(filename, frameInfo.Width, frameInfo.Height, 4, + _console->GetSettings()->GetAudioConfig().SampleRate, _console->GetFps())) + { _recorder = recorder; MessageManager::DisplayMessage("VideoRecorder", "VideoRecorderStarted", filename); } @@ -107,7 +120,8 @@ void VideoRenderer::StartRecording(string filename, VideoCodec codec, uint32_t c void VideoRenderer::AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate) { shared_ptr recorder = _recorder; - if(recorder) { + if (recorder) + { recorder->AddSound(soundBuffer, sampleCount, sampleRate); } } @@ -115,7 +129,8 @@ void VideoRenderer::AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount void VideoRenderer::StopRecording() { shared_ptr recorder = _recorder; - if(recorder) { + if (recorder) + { MessageManager::DisplayMessage("VideoRecorder", "VideoRecorderStopped", recorder->GetOutputFile()); } _recorder.reset(); @@ -124,4 +139,4 @@ void VideoRenderer::StopRecording() bool VideoRenderer::IsRecording() { return _recorder != nullptr && _recorder->IsRecording(); -} \ No newline at end of file +} diff --git a/Core/VideoRenderer.h b/Core/VideoRenderer.h index 6ed3504..568cc6b 100644 --- a/Core/VideoRenderer.h +++ b/Core/VideoRenderer.h @@ -30,12 +30,12 @@ public: void StartThread(); void StopThread(); - void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height); - void RegisterRenderingDevice(IRenderingDevice *renderer); - void UnregisterRenderingDevice(IRenderingDevice *renderer); + void UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height); + void RegisterRenderingDevice(IRenderingDevice* renderer); + void UnregisterRenderingDevice(IRenderingDevice* renderer); void StartRecording(string filename, VideoCodec codec, uint32_t compressionLevel); void AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate); void StopRecording(); bool IsRecording(); -}; \ No newline at end of file +}; diff --git a/Core/WaveRecorder.cpp b/Core/WaveRecorder.cpp index d628e7b..4004e0f 100644 --- a/Core/WaveRecorder.cpp +++ b/Core/WaveRecorder.cpp @@ -9,8 +9,9 @@ WaveRecorder::WaveRecorder(string outputFile, uint32_t sampleRate, bool isStereo _streamSize = 0; _sampleRate = sampleRate; _isStereo = isStereo; - - if(_stream) { + + if (_stream) + { WriteHeader(); MessageManager::DisplayMessage("SoundRecorder", "SoundRecorderStarted", _outputFile); } @@ -52,13 +53,16 @@ void WaveRecorder::WriteHeader() _stream.write((char*)&size, sizeof(size)); } -bool WaveRecorder::WriteSamples(int16_t * samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) +bool WaveRecorder::WriteSamples(int16_t* samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) { - if(_sampleRate != sampleRate || _isStereo != isStereo) { + if (_sampleRate != sampleRate || _isStereo != isStereo) + { //Format changed, stop recording CloseFile(); return false; - } else { + } + else + { uint32_t sampleBytes = sampleCount * (isStereo ? 4 : 2); _stream.write((char*)samples, sampleBytes); _streamSize += sampleBytes; @@ -78,7 +82,8 @@ void WaveRecorder::UpdateSizeValues() void WaveRecorder::CloseFile() { - if(_stream && _stream.is_open()) { + if (_stream && _stream.is_open()) + { UpdateSizeValues(); _stream.close(); diff --git a/Core/WaveRecorder.h b/Core/WaveRecorder.h index 1cb3dab..7b51f99 100644 --- a/Core/WaveRecorder.h +++ b/Core/WaveRecorder.h @@ -18,4 +18,4 @@ public: ~WaveRecorder(); bool WriteSamples(int16_t* samples, uint32_t sampleCount, uint32_t sampleRate, bool isStereo); -}; \ No newline at end of file +}; diff --git a/Core/blargg_common.h b/Core/blargg_common.h index 75edff3..d73c065 100644 --- a/Core/blargg_common.h +++ b/Core/blargg_common.h @@ -18,62 +18,75 @@ // BLARGG_RESTRICT: equivalent to restrict, where supported #if defined (__GNUC__) || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict +#define BLARGG_RESTRICT __restrict #else #define BLARGG_RESTRICT #endif // STATIC_CAST(T,expr): Used in place of static_cast (expr) #ifndef STATIC_CAST - #define STATIC_CAST(T,expr) ((T) (expr)) +#define STATIC_CAST(T,expr) ((T) (expr)) #endif // blargg_err_t (0 on success, otherwise error string) #ifndef blargg_err_t - typedef const char* blargg_err_t; +typedef const char* blargg_err_t; #endif // blargg_vector - very lightweight vector of POD types (no constructor/destructor) -template -class blargg_vector { +template +class blargg_vector +{ T* begin_; size_t size_; public: - blargg_vector() : begin_( 0 ), size_( 0 ) { } - ~blargg_vector() { free( begin_ ); } + blargg_vector() : begin_(0), size_(0) + { + } + + ~blargg_vector() { free(begin_); } size_t size() const { return size_; } T* begin() const { return begin_; } T* end() const { return begin_ + size_; } - blargg_err_t resize( size_t n ) + + blargg_err_t resize(size_t n) { // TODO: blargg_common.cpp to hold this as an outline function, ugh - void* p = realloc( begin_, n * sizeof (T) ); - if ( p ) - begin_ = (T*) p; - else if ( n > size_ ) // realloc failure only a problem if expanding + void* p = realloc(begin_, n * sizeof(T)); + if (p) + begin_ = (T*)p; + else if (n > size_) // realloc failure only a problem if expanding return "Out of memory"; size_ = n; return 0; } - void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } - T& operator [] ( size_t n ) const + + void clear() { - assert( n <= size_ ); // <= to allow past-the-end value - return begin_ [n]; + void* p = begin_; + begin_ = 0; + size_ = 0; + free(p); + } + + T& operator [](size_t n) const + { + assert(n <= size_); // <= to allow past-the-end value + return begin_[n]; } }; #ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if operator new can return NULL - #if __cplusplus >= 199711 || defined (__GNUC__) - #define BLARGG_THROWS( spec ) throw spec - #else +// throw spec mandatory in ISO C++ if operator new can return NULL +#if __cplusplus >= 199711 || defined (__GNUC__) +#define BLARGG_THROWS( spec ) throw spec +#else #define BLARGG_THROWS( spec ) - #endif - #define BLARGG_DISABLE_NOTHROW \ +#endif +#define BLARGG_DISABLE_NOTHROW \ void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ void operator delete ( void* p ) { free( p ); } - #define BLARGG_NEW new +#define BLARGG_NEW new #else #include #define BLARGG_NEW new (std::nothrow) @@ -85,34 +98,34 @@ public: // BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. #ifndef BOOST_STATIC_ASSERT - #ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified - #define BOOST_STATIC_ASSERT( expr ) \ +#ifdef _MSC_VER +// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified +#define BOOST_STATIC_ASSERT( expr ) \ void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) - #else +#else // Some other compilers fail when declaring same function multiple times in class, // so differentiate them by line #define BOOST_STATIC_ASSERT( expr ) \ void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) - #endif +#endif #endif // BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, // compiler is assumed to support bool. If undefined, availability is determined. #ifndef BLARGG_COMPILER_HAS_BOOL - #if defined (__MWERKS__) - #if !__option(bool) +#if defined (__MWERKS__) +#if !__option(bool) #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (_MSC_VER) - #if _MSC_VER < 1100 +#endif +#elif defined (_MSC_VER) +#if _MSC_VER < 1100 #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (__GNUC__) - // supports bool - #elif __cplusplus < 199711 +#endif +#elif defined (__GNUC__) +// supports bool +#elif __cplusplus < 199711 #define BLARGG_COMPILER_HAS_BOOL 0 - #endif +#endif #endif #if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL // If you get errors here, modify your blargg_config.h file @@ -124,13 +137,13 @@ public: // blargg_long/blargg_ulong = at least 32 bits, int if it's big enough #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blargg_long; +typedef long blargg_long; #else typedef int blargg_long; #endif #if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF - typedef unsigned long blargg_ulong; +typedef unsigned long blargg_ulong; #else typedef unsigned blargg_ulong; #endif @@ -148,38 +161,38 @@ public: #define BOOST #else - struct BOOST - { - #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F - typedef signed char int8_t; - typedef unsigned char uint8_t; - #else +struct BOOST +{ +#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; +#else // No suitable 8-bit type available typedef struct see_blargg_common_h int8_t; typedef struct see_blargg_common_h uint8_t; - #endif - - #if USHRT_MAX == 0xFFFF - typedef short int16_t; - typedef unsigned short uint16_t; - #else +#endif + +#if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; +#else // No suitable 16-bit type available typedef struct see_blargg_common_h int16_t; typedef struct see_blargg_common_h uint16_t; - #endif - - #if ULONG_MAX == 0xFFFFFFFF - typedef long int32_t; - typedef unsigned long uint32_t; - #elif UINT_MAX == 0xFFFFFFFF +#endif + +#if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; +#elif UINT_MAX == 0xFFFFFFFF typedef int int32_t; typedef unsigned int uint32_t; - #else +#else // No suitable 32-bit type available typedef struct see_blargg_common_h int32_t; typedef struct see_blargg_common_h uint32_t; - #endif - }; +#endif +}; #endif #endif diff --git a/Core/blargg_endian.h b/Core/blargg_endian.h index f2daca6..79f3745 100644 --- a/Core/blargg_endian.h +++ b/Core/blargg_endian.h @@ -24,11 +24,11 @@ #ifdef __GLIBC__ // GCC handles this for us #include - #if __BYTE_ORDER == __LITTLE_ENDIAN +#if __BYTE_ORDER == __LITTLE_ENDIAN #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN #define BLARGG_BIG_ENDIAN 1 - #endif +#endif #else #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ @@ -41,8 +41,8 @@ (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) #define BLARGG_BIG_ENDIAN 1 #elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 +// No endian specified; assume little-endian, since it's most common +#define BLARGG_LITTLE_ENDIAN 1 #endif #endif #endif @@ -54,132 +54,148 @@ inline void blargg_verify_byte_order() { - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN +#ifndef NDEBUG +#if BLARGG_BIG_ENDIAN volatile int i = 1; assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif +#elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert(*(volatile char*) &i != 0); +#endif +#endif } -inline unsigned get_le16( void const* p ) +inline unsigned get_le16(void const* p) { - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; + return (unsigned)((unsigned char const*)p)[1] << 8 | + (unsigned)((unsigned char const*)p)[0]; } -inline unsigned get_be16( void const* p ) +inline unsigned get_be16(void const* p) { - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; + return (unsigned)((unsigned char const*)p)[0] << 8 | + (unsigned)((unsigned char const*)p)[1]; } -inline blargg_ulong get_le32( void const* p ) +inline blargg_ulong get_le32(void const* p) { - return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | - (blargg_ulong) ((unsigned char const*) p) [2] << 16 | - (blargg_ulong) ((unsigned char const*) p) [1] << 8 | - (blargg_ulong) ((unsigned char const*) p) [0]; + return (blargg_ulong)((unsigned char const*)p)[3] << 24 | + (blargg_ulong)((unsigned char const*)p)[2] << 16 | + (blargg_ulong)((unsigned char const*)p)[1] << 8 | + (blargg_ulong)((unsigned char const*)p)[0]; } -inline blargg_ulong get_be32( void const* p ) +inline blargg_ulong get_be32(void const* p) { - return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | - (blargg_ulong) ((unsigned char const*) p) [1] << 16 | - (blargg_ulong) ((unsigned char const*) p) [2] << 8 | - (blargg_ulong) ((unsigned char const*) p) [3]; + return (blargg_ulong)((unsigned char const*)p)[0] << 24 | + (blargg_ulong)((unsigned char const*)p)[1] << 16 | + (blargg_ulong)((unsigned char const*)p)[2] << 8 | + (blargg_ulong)((unsigned char const*)p)[3]; } -inline void set_le16( void* p, unsigned n ) +inline void set_le16(void* p, unsigned n) { - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*)p)[1] = (unsigned char)(n >> 8); + ((unsigned char*)p)[0] = (unsigned char)n; } -inline void set_be16( void* p, unsigned n ) +inline void set_be16(void* p, unsigned n) { - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; + ((unsigned char*)p)[0] = (unsigned char)(n >> 8); + ((unsigned char*)p)[1] = (unsigned char)n; } -inline void set_le32( void* p, blargg_ulong n ) +inline void set_le32(void* p, blargg_ulong n) { - ((unsigned char*) p) [0] = (unsigned char) n; - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24); + ((unsigned char*)p)[0] = (unsigned char)n; + ((unsigned char*)p)[1] = (unsigned char)(n >> 8); + ((unsigned char*)p)[2] = (unsigned char)(n >> 16); + ((unsigned char*)p)[3] = (unsigned char)(n >> 24); } -inline void set_be32( void* p, blargg_ulong n ) +inline void set_be32(void* p, blargg_ulong n) { - ((unsigned char*) p) [3] = (unsigned char) n; - ((unsigned char*) p) [2] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) (n >> 16); - ((unsigned char*) p) [0] = (unsigned char) (n >> 24); + ((unsigned char*)p)[3] = (unsigned char)n; + ((unsigned char*)p)[2] = (unsigned char)(n >> 8); + ((unsigned char*)p)[1] = (unsigned char)(n >> 16); + ((unsigned char*)p)[0] = (unsigned char)(n >> 24); } #if BLARGG_NONPORTABLE - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN +// Optimized implementation if byte order is known +#if BLARGG_LITTLE_ENDIAN #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN +#elif BLARGG_BIG_ENDIAN #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) +#if BLARGG_CPU_POWERPC +// PowerPC has special byte-reversed instructions +#if defined (__MWERKS__) #define GET_LE16( addr ) (__lhbrx( addr, 0 )) #define GET_LE32( addr ) (__lwbrx( addr, 0 )) #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) +#elif defined (__GNUC__) #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) - #endif - #endif - #endif +#endif +#endif +#endif #endif #ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #define SET_LE16( addr, data ) set_le16( addr, data ) +#define GET_LE16( addr ) get_le16( addr ) +#define SET_LE16( addr, data ) set_le16( addr, data ) #endif #ifndef GET_LE32 - #define GET_LE32( addr ) get_le32( addr ) - #define SET_LE32( addr, data ) set_le32( addr, data ) +#define GET_LE32( addr ) get_le32( addr ) +#define SET_LE32( addr, data ) set_le32( addr, data ) #endif #ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #define SET_BE16( addr, data ) set_be16( addr, data ) +#define GET_BE16( addr ) get_be16( addr ) +#define SET_BE16( addr, data ) set_be16( addr, data ) #endif #ifndef GET_BE32 - #define GET_BE32( addr ) get_be32( addr ) - #define SET_BE32( addr, data ) set_be32( addr, data ) +#define GET_BE32( addr ) get_be32( addr ) +#define SET_BE32( addr, data ) set_be32( addr, data ) #endif // auto-selecting versions -inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } -inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } -inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } -inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } -inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } -inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } +inline void set_le(BOOST::uint16_t* p, unsigned n) +{ + SET_LE16(p, n); +} + +inline void set_le(BOOST::uint32_t* p, blargg_ulong n) +{ + SET_LE32(p, n); +} + +inline void set_be(BOOST::uint16_t* p, unsigned n) +{ + SET_BE16(p, n); +} + +inline void set_be(BOOST::uint32_t* p, blargg_ulong n) +{ + SET_BE32(p, n); +} + +inline unsigned get_le(BOOST::uint16_t* p) { return GET_LE16(p); } +inline blargg_ulong get_le(BOOST::uint32_t* p) { return GET_LE32(p); } +inline unsigned get_be(BOOST::uint16_t* p) { return GET_BE16(p); } +inline blargg_ulong get_be(BOOST::uint32_t* p) { return GET_BE32(p); } #endif diff --git a/Core/blargg_source.h b/Core/blargg_source.h index 5e45c4f..2b845f8 100644 --- a/Core/blargg_source.h +++ b/Core/blargg_source.h @@ -22,7 +22,9 @@ all other #include lines. */ // Like printf() except output goes to debug log file. Might be defined to do // nothing (not even evaluate its arguments). // void dprintf( const char* format, ... ); -static inline void blargg_dprintf_( const char*, ... ) { } +static inline void blargg_dprintf_(const char*, ...) +{ +} #undef dprintf #define dprintf (1) ? (void) 0 : blargg_dprintf_ @@ -51,12 +53,12 @@ static inline void blargg_dprintf_( const char*, ... ) { } static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ static inline type max( type x, type y ) { if ( y < x ) return x; return y; } -DEF_MIN_MAX( int ) -DEF_MIN_MAX( unsigned ) -DEF_MIN_MAX( long ) -DEF_MIN_MAX( unsigned long ) -DEF_MIN_MAX( float ) -DEF_MIN_MAX( double ) +DEF_MIN_MAX(int) +DEF_MIN_MAX(unsigned) +DEF_MIN_MAX(long) +DEF_MIN_MAX(unsigned long) +DEF_MIN_MAX(float) +DEF_MIN_MAX(double) #undef DEF_MIN_MAX diff --git a/Core/stdafx.h b/Core/stdafx.h index 82bd244..b2f4678 100644 --- a/Core/stdafx.h +++ b/Core/stdafx.h @@ -25,13 +25,13 @@ #include "../Utilities/UTF8Util.h" #ifndef __MINGW32__ - #ifdef __clang__ +#ifdef __clang__ #define __forceinline __attribute__((always_inline)) inline - #else - #ifdef __GNUC__ +#else +#ifdef __GNUC__ #define __forceinline __attribute__((always_inline)) inline - #endif - #endif +#endif +#endif #endif using std::vector; diff --git a/InteropDLL/ConfigApiWrapper.cpp b/InteropDLL/ConfigApiWrapper.cpp index bf7ba42..bdfdc44 100644 --- a/InteropDLL/ConfigApiWrapper.cpp +++ b/InteropDLL/ConfigApiWrapper.cpp @@ -9,60 +9,60 @@ extern unique_ptr _soundManager; static string _returnString; extern "C" { - DllExport void __stdcall SetVideoConfig(VideoConfig config) - { - _console->GetSettings()->SetVideoConfig(config); - } +DllExport void __stdcall SetVideoConfig(VideoConfig config) +{ + _console->GetSettings()->SetVideoConfig(config); +} - DllExport void __stdcall SetAudioConfig(AudioConfig config) - { - _console->GetSettings()->SetAudioConfig(config); - } +DllExport void __stdcall SetAudioConfig(AudioConfig config) +{ + _console->GetSettings()->SetAudioConfig(config); +} - DllExport void __stdcall SetInputConfig(InputConfig config) - { - _console->GetSettings()->SetInputConfig(config); - } +DllExport void __stdcall SetInputConfig(InputConfig config) +{ + _console->GetSettings()->SetInputConfig(config); +} - DllExport void __stdcall SetEmulationConfig(EmulationConfig config) - { - _console->GetSettings()->SetEmulationConfig(config); - } - - DllExport void __stdcall SetGameboyConfig(GameboyConfig config) - { - _console->GetSettings()->SetGameboyConfig(config); - } +DllExport void __stdcall SetEmulationConfig(EmulationConfig config) +{ + _console->GetSettings()->SetEmulationConfig(config); +} - DllExport void __stdcall SetPreferences(PreferencesConfig config) - { - _console->GetSettings()->SetPreferences(config); - } +DllExport void __stdcall SetGameboyConfig(GameboyConfig config) +{ + _console->GetSettings()->SetGameboyConfig(config); +} - DllExport void __stdcall SetShortcutKeys(ShortcutKeyInfo shortcuts[], uint32_t count) - { - vector shortcutList(shortcuts, shortcuts + count); - _console->GetSettings()->SetShortcutKeys(shortcutList); - } +DllExport void __stdcall SetPreferences(PreferencesConfig config) +{ + _console->GetSettings()->SetPreferences(config); +} - DllExport ControllerType __stdcall GetControllerType(int player) - { - return _console->GetSettings()->GetInputConfig().Controllers[player].Type; - } +DllExport void __stdcall SetShortcutKeys(ShortcutKeyInfo shortcuts[], uint32_t count) +{ + vector shortcutList(shortcuts, shortcuts + count); + _console->GetSettings()->SetShortcutKeys(shortcutList); +} - DllExport const char* __stdcall GetAudioDevices() - { - _returnString = _soundManager ? _soundManager->GetAvailableDevices() : ""; - return _returnString.c_str(); - } +DllExport ControllerType __stdcall GetControllerType(int player) +{ + return _console->GetSettings()->GetInputConfig().Controllers[player].Type; +} - DllExport void __stdcall SetEmulationFlag(EmulationFlags flag, bool enabled) - { - _console->GetSettings()->SetFlagState(flag, enabled); - } +DllExport const char* __stdcall GetAudioDevices() +{ + _returnString = _soundManager ? _soundManager->GetAvailableDevices() : ""; + return _returnString.c_str(); +} - DllExport void __stdcall SetDebuggerFlag(DebuggerFlags flag, bool enabled) - { - _console->GetSettings()->SetDebuggerFlag(flag, enabled); - } -} \ No newline at end of file +DllExport void __stdcall SetEmulationFlag(EmulationFlags flag, bool enabled) +{ + _console->GetSettings()->SetFlagState(flag, enabled); +} + +DllExport void __stdcall SetDebuggerFlag(DebuggerFlags flag, bool enabled) +{ + _console->GetSettings()->SetDebuggerFlag(flag, enabled); +} +} diff --git a/InteropDLL/EmuApiWrapper.cpp b/InteropDLL/EmuApiWrapper.cpp index ab742f6..8164c82 100644 --- a/InteropDLL/EmuApiWrapper.cpp +++ b/InteropDLL/EmuApiWrapper.cpp @@ -18,9 +18,9 @@ #include "InteropNotificationListeners.h" #ifdef _WIN32 - #include "../Windows/Renderer.h" - #include "../Windows/SoundManager.h" - #include "../Windows/WindowsKeyManager.h" +#include "../Windows/Renderer.h" +#include "../Windows/SoundManager.h" +#include "../Windows/WindowsKeyManager.h" #else #include "../Linux/SdlRenderer.h" #include "../Linux/SdlSoundManager.h" @@ -61,12 +61,16 @@ enum class ConsoleId shared_ptr GetConsoleById(ConsoleId consoleId) { shared_ptr console; - switch (consoleId) { - case ConsoleId::Main: console = _console; break; - case ConsoleId::HistoryViewer: console = _historyConsole; break; + switch (consoleId) + { + case ConsoleId::Main: console = _console; + break; + case ConsoleId::HistoryViewer: console = _historyConsole; + break; } - if (!console) { + if (!console) + { //Otherwise return the main CPU console = _console; } @@ -74,249 +78,284 @@ shared_ptr GetConsoleById(ConsoleId consoleId) } extern "C" { - DllExport bool __stdcall TestDll() +DllExport bool __stdcall TestDll() +{ + return true; +} + +DllExport uint32_t __stdcall GetMesenVersion() { return _console->GetSettings()->GetVersion(); } + +DllExport void __stdcall InitDll() +{ + _console.reset(new Console()); + KeyManager::SetSettings(_console->GetSettings().get()); +} + +DllExport void __stdcall InitializeEmu(const char* homeFolder, void* windowHandle, void* viewerHandle, bool noAudio, + bool noVideo, bool noInput) +{ + _console->Initialize(); + + FolderUtilities::SetHomeFolder(homeFolder); + _shortcutKeyHandler.reset(new ShortcutKeyHandler(_console)); + + if (windowHandle != nullptr && viewerHandle != nullptr) { - return true; + _windowHandle = windowHandle; + _viewerHandle = viewerHandle; + + if (!noVideo) + { +#ifdef _WIN32 + _renderer.reset(new Renderer(_console, (HWND)_viewerHandle, true)); +#else + _renderer.reset(new SdlRenderer(_console, _viewerHandle, true)); +#endif + } + + if (!noAudio) + { +#ifdef _WIN32 + _soundManager.reset(new SoundManager(_console, (HWND)_windowHandle)); +#else + _soundManager.reset(new SdlSoundManager(_console)); +#endif + } + + if (!noInput) + { +#ifdef _WIN32 + _keyManager.reset(new WindowsKeyManager(_console, (HWND)_windowHandle)); +#else + _keyManager.reset(new LinuxKeyManager(_console)); +#endif + + KeyManager::RegisterKeyManager(_keyManager.get()); + } + } +} + +DllExport void __stdcall SetMasterVolume(double volume, ConsoleId consoleId) +{ + AudioConfig config = GetConsoleById(consoleId)->GetSettings()->GetAudioConfig(); + config.MasterVolume = volume; + GetConsoleById(consoleId)->GetSettings()->SetAudioConfig(config); +} + +DllExport void __stdcall SetVideoScale(double scale, ConsoleId consoleId) +{ + VideoConfig config = GetConsoleById(consoleId)->GetSettings()->GetVideoConfig(); + config.VideoScale = scale; + GetConsoleById(consoleId)->GetSettings()->SetVideoConfig(config); +} + + +DllExport void __stdcall SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, + uint32_t monitorHeight) +{ + if (_renderer) + { + _renderer->SetFullscreenMode(fullscreen, windowHandle, monitorWidth, monitorHeight); + } +} + +DllExport bool __stdcall LoadRom(char* filename, char* patchFile) +{ + GameClient::Disconnect(); + return _console->LoadRom((VirtualFile)filename, patchFile ? (VirtualFile)patchFile : VirtualFile()); +} + +DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); } + +DllExport void __stdcall GetRomInfo(InteropRomInfo& info) +{ + RomInfo romInfo = {}; + string sha1; + if (_console->GetCartridge()) + { + romInfo = _console->GetCartridge()->GetRomInfo(); + sha1 = _console->GetCartridge()->GetSha1Hash(); } - DllExport uint32_t __stdcall GetMesenVersion() { return _console->GetSettings()->GetVersion(); } + _romPath = romInfo.RomFile; + _patchPath = romInfo.PatchFile; - DllExport void __stdcall InitDll() + info.Header = romInfo.Header; + info.RomPath = _romPath.c_str(); + info.PatchPath = _patchPath.c_str(); + info.Coprocessor = romInfo.Coprocessor; + + memcpy(info.Sha1, sha1.c_str(), sha1.size()); +} + +DllExport void __stdcall TakeScreenshot() { _console->GetVideoDecoder()->TakeScreenshot(); } + +DllExport const char* __stdcall GetArchiveRomList(char* filename) +{ + std::ostringstream out; + shared_ptr reader = ArchiveReader::GetReader(filename); + if (reader) { + for (string romName : reader->GetFileList(VirtualFile::RomExtensions)) + { + out << romName << "[!|!]"; + } + } + _returnString = out.str(); + return _returnString.c_str(); +} + +DllExport bool __stdcall IsRunning() +{ + return _console->IsRunning(); +} + +DllExport void __stdcall Stop() +{ + GameClient::Disconnect(); + _console->Stop(true); +} + +DllExport void __stdcall Pause(ConsoleId consoleId) +{ + if (!GameClient::Connected()) + { + GetConsoleById(consoleId)->Pause(); + } +} + +DllExport void __stdcall Resume(ConsoleId consoleId) +{ + if (!GameClient::Connected()) + { + GetConsoleById(consoleId)->Resume(); + } +} + +DllExport bool __stdcall IsPaused(ConsoleId consoleId) +{ + shared_ptr console = GetConsoleById(consoleId); + if (console) + { + return console->IsPaused(); + } + return true; +} + +DllExport void __stdcall Reset() +{ + if (!GameClient::Connected()) + { + _console->GetControlManager()->GetSystemActionManager()->Reset(); + } +} + +DllExport void __stdcall PowerCycle() +{ + if (!GameClient::Connected()) + { + _console->GetControlManager()->GetSystemActionManager()->PowerCycle(); + } +} + +DllExport void __stdcall ReloadRom() +{ + if (!GameClient::Connected()) + { + _console->ReloadRom(false); + } +} + +DllExport void __stdcall Release() +{ + GameClient::Disconnect(); + GameServer::StopServer(); + + _shortcutKeyHandler.reset(); + + _console->Stop(true); + + _console->Release(); + _console.reset(); + + _renderer.reset(); + _soundManager.reset(); + _keyManager.reset(); +} + +DllExport INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback) +{ + return _listeners.RegisterNotificationCallback(callback, _console); +} + +DllExport void __stdcall UnregisterNotificationCallback(INotificationListener* listener) +{ + _listeners.UnregisterNotificationCallback(listener); +} + +DllExport void __stdcall DisplayMessage(char* title, char* message, char* param1) +{ + MessageManager::DisplayMessage(title, message, param1 ? param1 : ""); +} + +DllExport const char* __stdcall GetLog() +{ + _logString = MessageManager::GetLog(); + return _logString.c_str(); +} + +DllExport ScreenSize __stdcall GetScreenSize(bool ignoreScale, ConsoleId console) +{ + return GetConsoleById(console)->GetVideoDecoder()->GetScreenSize(ignoreScale); +} + +DllExport void __stdcall ClearCheats() { _console->GetCheatManager()->ClearCheats(); } +DllExport void __stdcall SetCheats(uint32_t codes[], uint32_t length) +{ + _console->GetCheatManager()->SetCheats(codes, length); +} + +DllExport void __stdcall WriteLogEntry(char* message) { MessageManager::Log(message); } + +DllExport void __stdcall SaveState(uint32_t stateIndex) { _console->GetSaveStateManager()->SaveState(stateIndex); } +DllExport void __stdcall LoadState(uint32_t stateIndex) { _console->GetSaveStateManager()->LoadState(stateIndex); } +DllExport void __stdcall SaveStateFile(char* filepath) { _console->GetSaveStateManager()->SaveState(filepath); } +DllExport void __stdcall LoadStateFile(char* filepath) { _console->GetSaveStateManager()->LoadState(filepath); } +DllExport void __stdcall LoadRecentGame(char* filepath, bool resetGame) +{ + _console->GetSaveStateManager()->LoadRecentGame(filepath, resetGame); +} + +DllExport int32_t __stdcall GetSaveStatePreview(char* saveStatePath, uint8_t* pngData) +{ + return _console->GetSaveStateManager()->GetSaveStatePreview(saveStatePath, pngData); +} + +DllExport void __stdcall PgoRunTest(vector testRoms, bool enableDebugger) +{ + FolderUtilities::SetHomeFolder("../PGOMesenHome"); + + for (size_t i = 0; i < testRoms.size(); i++) + { + std::cout << "Running: " << testRoms[i] << std::endl; + _console.reset(new Console()); KeyManager::SetSettings(_console->GetSettings().get()); - } - - DllExport void __stdcall InitializeEmu(const char* homeFolder, void *windowHandle, void *viewerHandle, bool noAudio, bool noVideo, bool noInput) - { _console->Initialize(); + GameboyConfig cfg = _console->GetSettings()->GetGameboyConfig(); + cfg.Model = GameboyModel::GameboyColor; + _console->GetSettings()->SetGameboyConfig(cfg); + _console->LoadRom((VirtualFile)testRoms[i], VirtualFile()); - FolderUtilities::SetHomeFolder(homeFolder); - _shortcutKeyHandler.reset(new ShortcutKeyHandler(_console)); - - if(windowHandle != nullptr && viewerHandle != nullptr) { - _windowHandle = windowHandle; - _viewerHandle = viewerHandle; - - if(!noVideo) { - #ifdef _WIN32 - _renderer.reset(new Renderer(_console, (HWND)_viewerHandle, true)); - #else - _renderer.reset(new SdlRenderer(_console, _viewerHandle, true)); - #endif - } - - if(!noAudio) { - #ifdef _WIN32 - _soundManager.reset(new SoundManager(_console, (HWND)_windowHandle)); - #else - _soundManager.reset(new SdlSoundManager(_console)); - #endif - } - - if(!noInput) { - #ifdef _WIN32 - _keyManager.reset(new WindowsKeyManager(_console, (HWND)_windowHandle)); - #else - _keyManager.reset(new LinuxKeyManager(_console)); - #endif - - KeyManager::RegisterKeyManager(_keyManager.get()); - } - } - } - - DllExport void __stdcall SetMasterVolume(double volume, ConsoleId consoleId) { - AudioConfig config = GetConsoleById(consoleId)->GetSettings()->GetAudioConfig(); - config.MasterVolume = volume; - GetConsoleById(consoleId)->GetSettings()->SetAudioConfig(config); - } - - DllExport void __stdcall SetVideoScale(double scale, ConsoleId consoleId) { - VideoConfig config = GetConsoleById(consoleId)->GetSettings()->GetVideoConfig(); - config.VideoScale = scale; - GetConsoleById(consoleId)->GetSettings()->SetVideoConfig(config); - } - - - DllExport void __stdcall SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) - { - if(_renderer) { - _renderer->SetFullscreenMode(fullscreen, windowHandle, monitorWidth, monitorHeight); - } - } - - DllExport bool __stdcall LoadRom(char* filename, char* patchFile) - { - GameClient::Disconnect(); - return _console->LoadRom((VirtualFile)filename, patchFile ? (VirtualFile)patchFile : VirtualFile()); - } - - DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); } - - DllExport void __stdcall GetRomInfo(InteropRomInfo &info) - { - RomInfo romInfo = {}; - string sha1; - if(_console->GetCartridge()) { - romInfo = _console->GetCartridge()->GetRomInfo(); - sha1 = _console->GetCartridge()->GetSha1Hash(); + if (enableDebugger) + { + //turn on debugger to profile the debugger's code too + _console->GetDebugger(); } - _romPath = romInfo.RomFile; - _patchPath = romInfo.PatchFile; - - info.Header = romInfo.Header; - info.RomPath = _romPath.c_str(); - info.PatchPath = _patchPath.c_str(); - info.Coprocessor = romInfo.Coprocessor; - - memcpy(info.Sha1, sha1.c_str(), sha1.size()); - } - - DllExport void __stdcall TakeScreenshot() { _console->GetVideoDecoder()->TakeScreenshot(); } - - DllExport const char* __stdcall GetArchiveRomList(char* filename) { - std::ostringstream out; - shared_ptr reader = ArchiveReader::GetReader(filename); - if(reader) { - for(string romName : reader->GetFileList(VirtualFile::RomExtensions)) { - out << romName << "[!|!]"; - } - } - _returnString = out.str(); - return _returnString.c_str(); - } - - DllExport bool __stdcall IsRunning() - { - return _console->IsRunning(); - } - - DllExport void __stdcall Stop() - { - GameClient::Disconnect(); - _console->Stop(true); - } - - DllExport void __stdcall Pause(ConsoleId consoleId) - { - if(!GameClient::Connected()) { - GetConsoleById(consoleId)->Pause(); - } - } - - DllExport void __stdcall Resume(ConsoleId consoleId) - { - if(!GameClient::Connected()) { - GetConsoleById(consoleId)->Resume(); - } - } - - DllExport bool __stdcall IsPaused(ConsoleId consoleId) - { - shared_ptr console = GetConsoleById(consoleId); - if(console) { - return console->IsPaused(); - } - return true; - } - - DllExport void __stdcall Reset() - { - if(!GameClient::Connected()) { - _console->GetControlManager()->GetSystemActionManager()->Reset(); - } - } - - DllExport void __stdcall PowerCycle() - { - if(!GameClient::Connected()) { - _console->GetControlManager()->GetSystemActionManager()->PowerCycle(); - } - } - - DllExport void __stdcall ReloadRom() - { - if(!GameClient::Connected()) { - _console->ReloadRom(false); - } - } - - DllExport void __stdcall Release() - { - GameClient::Disconnect(); - GameServer::StopServer(); - - _shortcutKeyHandler.reset(); - - _console->Stop(true); - + std::this_thread::sleep_for(std::chrono::duration(5000)); + _console->Stop(false); _console->Release(); - _console.reset(); - - _renderer.reset(); - _soundManager.reset(); - _keyManager.reset(); } - - DllExport INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback) - { - return _listeners.RegisterNotificationCallback(callback, _console); - } - - DllExport void __stdcall UnregisterNotificationCallback(INotificationListener *listener) - { - _listeners.UnregisterNotificationCallback(listener); - } - - DllExport void __stdcall DisplayMessage(char* title, char* message, char* param1) { MessageManager::DisplayMessage(title, message, param1 ? param1 : ""); } - DllExport const char* __stdcall GetLog() - { - _logString = MessageManager::GetLog(); - return _logString.c_str(); - } - - DllExport ScreenSize __stdcall GetScreenSize(bool ignoreScale, ConsoleId console) - { - return GetConsoleById(console)->GetVideoDecoder()->GetScreenSize(ignoreScale); - } - - DllExport void __stdcall ClearCheats() { _console->GetCheatManager()->ClearCheats(); } - DllExport void __stdcall SetCheats(uint32_t codes[], uint32_t length) { _console->GetCheatManager()->SetCheats(codes, length); } - - DllExport void __stdcall WriteLogEntry(char* message) { MessageManager::Log(message); } - - DllExport void __stdcall SaveState(uint32_t stateIndex) { _console->GetSaveStateManager()->SaveState(stateIndex); } - DllExport void __stdcall LoadState(uint32_t stateIndex) { _console->GetSaveStateManager()->LoadState(stateIndex); } - DllExport void __stdcall SaveStateFile(char* filepath) { _console->GetSaveStateManager()->SaveState(filepath); } - DllExport void __stdcall LoadStateFile(char* filepath) { _console->GetSaveStateManager()->LoadState(filepath); } - DllExport void __stdcall LoadRecentGame(char* filepath, bool resetGame) { _console->GetSaveStateManager()->LoadRecentGame(filepath, resetGame); } - DllExport int32_t __stdcall GetSaveStatePreview(char* saveStatePath, uint8_t* pngData) { return _console->GetSaveStateManager()->GetSaveStatePreview(saveStatePath, pngData); } - - DllExport void __stdcall PgoRunTest(vector testRoms, bool enableDebugger) - { - FolderUtilities::SetHomeFolder("../PGOMesenHome"); - - for(size_t i = 0; i < testRoms.size(); i++) { - std::cout << "Running: " << testRoms[i] << std::endl; - - _console.reset(new Console()); - KeyManager::SetSettings(_console->GetSettings().get()); - _console->Initialize(); - GameboyConfig cfg = _console->GetSettings()->GetGameboyConfig(); - cfg.Model = GameboyModel::GameboyColor; - _console->GetSettings()->SetGameboyConfig(cfg); - _console->LoadRom((VirtualFile)testRoms[i], VirtualFile()); - - if(enableDebugger) { - //turn on debugger to profile the debugger's code too - _console->GetDebugger(); - } - - std::this_thread::sleep_for(std::chrono::duration(5000)); - _console->Stop(false); - _console->Release(); - } - } -} \ No newline at end of file +} +} diff --git a/InteropDLL/HistoryViewerWrapper.cpp b/InteropDLL/HistoryViewerWrapper.cpp index 28149a4..80d9eae 100644 --- a/InteropDLL/HistoryViewerWrapper.cpp +++ b/InteropDLL/HistoryViewerWrapper.cpp @@ -22,102 +22,108 @@ unique_ptr _historyRenderer; unique_ptr _historySoundManager; enum class VideoCodec; -extern "C" +extern "C" { +DllExport bool __stdcall HistoryViewerEnabled() { - DllExport bool __stdcall HistoryViewerEnabled() - { - shared_ptr rewindManager = _console->GetRewindManager(); - return rewindManager ? rewindManager->HasHistory() : false; - } + shared_ptr rewindManager = _console->GetRewindManager(); + return rewindManager ? rewindManager->HasHistory() : false; +} - DllExport void __stdcall HistoryViewerInitialize(void* windowHandle, void* viewerHandle) - { - _historyConsole.reset(new Console()); - // TODO: something about initializing with settings? - _historyConsole->Initialize(); +DllExport void __stdcall HistoryViewerInitialize(void* windowHandle, void* viewerHandle) +{ + _historyConsole.reset(new Console()); + // TODO: something about initializing with settings? + _historyConsole->Initialize(); - _historyConsole->Lock(); - _historyConsole->LoadRom(_console->GetRomInfo().RomFile, _console->GetRomInfo().PatchFile); - _historyConsole->CopyRewindData(_console); - _historyConsole->Unlock(); + _historyConsole->Lock(); + _historyConsole->LoadRom(_console->GetRomInfo().RomFile, _console->GetRomInfo().PatchFile); + _historyConsole->CopyRewindData(_console); + _historyConsole->Unlock(); + + //Force some settings + VideoConfig config = _historyConsole->GetSettings()->GetVideoConfig(); + config.VideoScale = 2; + _historyConsole->GetSettings()->SetVideoConfig(config); + // TODO + // _historyConsole->GetSettings()->SetEmulationSpeed(100); + // _historyConsole->GetSettings()->ClearFlags(EmulationFlags::InBackground | EmulationFlags::Rewind /*|EmulationFlags::ForceMaxSpeed | EmulationFlags::DebuggerWindowEnabled*/); - //Force some settings - VideoConfig config = _historyConsole->GetSettings()->GetVideoConfig(); - config.VideoScale = 2; - _historyConsole->GetSettings()->SetVideoConfig(config); -// TODO -// _historyConsole->GetSettings()->SetEmulationSpeed(100); -// _historyConsole->GetSettings()->ClearFlags(EmulationFlags::InBackground | EmulationFlags::Rewind /*|EmulationFlags::ForceMaxSpeed | EmulationFlags::DebuggerWindowEnabled*/); - #ifdef _WIN32 - _historyRenderer.reset(new Renderer(_historyConsole, (HWND)viewerHandle, false)); - _historySoundManager.reset(new SoundManager(_historyConsole, (HWND)windowHandle)); -#else + _historyRenderer.reset(new Renderer(_historyConsole, (HWND)viewerHandle, false)); + _historySoundManager.reset(new SoundManager(_historyConsole, (HWND)windowHandle)); +#else _historyRenderer.reset(new SdlRenderer(_historyConsole, viewerHandle, false)); _historySoundManager.reset(new SdlSoundManager(_historyConsole)); #endif - } +} - DllExport void __stdcall HistoryViewerRelease() +DllExport void __stdcall HistoryViewerRelease() +{ + _historyConsole->Stop(true); + _historyConsole->Release(); // Mesen had True, "For ShutDown" + _historyRenderer.reset(); + _historySoundManager.reset(); + _historyConsole.reset(); +} + +DllExport uint32_t __stdcall HistoryViewerGetHistoryLength() +{ + if (_historyConsole) { - _historyConsole->Stop(true); - _historyConsole->Release(); // Mesen had True, "For ShutDown" - _historyRenderer.reset(); - _historySoundManager.reset(); - _historyConsole.reset(); + return _historyConsole->GetHistoryViewer()->GetHistoryLength(); } + return 0; +} - DllExport uint32_t __stdcall HistoryViewerGetHistoryLength() +DllExport void __stdcall HistoryViewerGetSegments(uint32_t* segmentBuffer, uint32_t& bufferSize) +{ + if (_historyConsole) { - if (_historyConsole) { - return _historyConsole->GetHistoryViewer()->GetHistoryLength(); - } - return 0; + _historyConsole->GetHistoryViewer()->GetHistorySegments(segmentBuffer, bufferSize); } +} - DllExport void __stdcall HistoryViewerGetSegments(uint32_t* segmentBuffer, uint32_t& bufferSize) +DllExport bool __stdcall HistoryViewerCreateSaveState(const char* outputFile, uint32_t position) +{ + if (_historyConsole) { - if (_historyConsole) { - _historyConsole->GetHistoryViewer()->GetHistorySegments(segmentBuffer, bufferSize); - } + return _historyConsole->GetHistoryViewer()->CreateSaveState(outputFile, position); } + return false; +} - DllExport bool __stdcall HistoryViewerCreateSaveState(const char* outputFile, uint32_t position) +DllExport bool __stdcall HistoryViewerSaveMovie(const char* movieFile, uint32_t startPosition, uint32_t endPosition) +{ + if (_historyConsole) { - if (_historyConsole) { - return _historyConsole->GetHistoryViewer()->CreateSaveState(outputFile, position); - } - return false; + return _historyConsole->GetHistoryViewer()->SaveMovie(movieFile, startPosition, endPosition); } + return false; +} - DllExport bool __stdcall HistoryViewerSaveMovie(const char* movieFile, uint32_t startPosition, uint32_t endPosition) +DllExport void __stdcall HistoryViewerResumeGameplay(uint32_t resumeAtSecond) +{ + if (_historyConsole) { - if (_historyConsole) { - return _historyConsole->GetHistoryViewer()->SaveMovie(movieFile, startPosition, endPosition); - } - return false; + _historyConsole->GetHistoryViewer()->ResumeGameplay(_console, resumeAtSecond); } +} - DllExport void __stdcall HistoryViewerResumeGameplay(uint32_t resumeAtSecond) +DllExport void __stdcall HistoryViewerSetPosition(uint32_t seekPosition) +{ + if (_historyConsole) { - if (_historyConsole) { - _historyConsole->GetHistoryViewer()->ResumeGameplay(_console, resumeAtSecond); - } + _historyConsole->GetHistoryViewer()->SeekTo(seekPosition); } +} - DllExport void __stdcall HistoryViewerSetPosition(uint32_t seekPosition) +DllExport uint32_t __stdcall HistoryViewerGetPosition() +{ + if (_historyConsole) { - if (_historyConsole) { - _historyConsole->GetHistoryViewer()->SeekTo(seekPosition); - } + return _historyConsole->GetHistoryViewer()->GetPosition(); } + return 0; +} - DllExport uint32_t __stdcall HistoryViewerGetPosition() - { - if (_historyConsole) { - return _historyConsole->GetHistoryViewer()->GetPosition(); - } - return 0; - } - -} \ No newline at end of file +} diff --git a/InteropDLL/InputApiWrapper.cpp b/InteropDLL/InputApiWrapper.cpp index 8b56a84..108d0b6 100644 --- a/InteropDLL/InputApiWrapper.cpp +++ b/InteropDLL/InputApiWrapper.cpp @@ -9,67 +9,74 @@ extern shared_ptr _console; static string _returnString; -extern "C" +extern "C" { +DllExport void __stdcall SetMousePosition(double x, double y) { - DllExport void __stdcall SetMousePosition(double x, double y) - { - KeyManager::SetMousePosition(_console, x, y); - } + KeyManager::SetMousePosition(_console, x, y); +} - DllExport void __stdcall SetMouseMovement(int16_t x, int16_t y) - { - KeyManager::SetMouseMovement(x, y); - } +DllExport void __stdcall SetMouseMovement(int16_t x, int16_t y) +{ + KeyManager::SetMouseMovement(x, y); +} - DllExport void __stdcall UpdateInputDevices() - { - if(_keyManager) { - _keyManager->UpdateDevices(); - } +DllExport void __stdcall UpdateInputDevices() +{ + if (_keyManager) + { + _keyManager->UpdateDevices(); } +} - DllExport void __stdcall GetPressedKeys(uint32_t *keyBuffer) +DllExport void __stdcall GetPressedKeys(uint32_t* keyBuffer) +{ + vector pressedKeys = KeyManager::GetPressedKeys(); + for (size_t i = 0; i < pressedKeys.size() && i < 3; i++) { - vector pressedKeys = KeyManager::GetPressedKeys(); - for(size_t i = 0; i < pressedKeys.size() && i < 3; i++) { - keyBuffer[i] = pressedKeys[i]; - } + keyBuffer[i] = pressedKeys[i]; } +} - DllExport void __stdcall DisableAllKeys(bool disabled) +DllExport void __stdcall DisableAllKeys(bool disabled) +{ + if (_keyManager) { - if(_keyManager) { - _keyManager->SetDisabled(disabled); - } + _keyManager->SetDisabled(disabled); } +} - DllExport void __stdcall SetKeyState(int32_t scanCode, bool state) +DllExport void __stdcall SetKeyState(int32_t scanCode, bool state) +{ + if (_keyManager) { - if(_keyManager) { - _keyManager->SetKeyState(scanCode, state); - _shortcutKeyHandler->ProcessKeys(); - } - } - - DllExport void __stdcall ResetKeyState() - { - if(_keyManager) { - _keyManager->ResetKeyState(); - } + _keyManager->SetKeyState(scanCode, state); + _shortcutKeyHandler->ProcessKeys(); } +} - DllExport const char* __stdcall GetKeyName(uint32_t keyCode) +DllExport void __stdcall ResetKeyState() +{ + if (_keyManager) { - _returnString = KeyManager::GetKeyName(keyCode); - return _returnString.c_str(); + _keyManager->ResetKeyState(); } +} - DllExport uint32_t __stdcall GetKeyCode(char* keyName) +DllExport const char* __stdcall GetKeyName(uint32_t keyCode) +{ + _returnString = KeyManager::GetKeyName(keyCode); + return _returnString.c_str(); +} + +DllExport uint32_t __stdcall GetKeyCode(char* keyName) +{ + if (keyName) { - if(keyName) { - return KeyManager::GetKeyCode(keyName); - } else { - return 0; - } + return KeyManager::GetKeyCode(keyName); } -} \ No newline at end of file + else + { + return 0; + } +} +} diff --git a/InteropDLL/InteropNotificationListener.h b/InteropDLL/InteropNotificationListener.h index e6d5791..bb18ff8 100644 --- a/InteropDLL/InteropNotificationListener.h +++ b/InteropDLL/InteropNotificationListener.h @@ -3,7 +3,7 @@ #include "../Core/INotificationListener.h" #include "../Core/NotificationManager.h" -typedef void(__stdcall *NotificationListenerCallback)(int, void*); +typedef void (__stdcall *NotificationListenerCallback)(int, void*); class InteropNotificationListener : public INotificationListener { @@ -23,4 +23,4 @@ public: { _callback((int)type, parameter); } -}; \ No newline at end of file +}; diff --git a/InteropDLL/InteropNotificationListeners.h b/InteropDLL/InteropNotificationListeners.h index 30520f9..faf0148 100644 --- a/InteropDLL/InteropNotificationListeners.h +++ b/InteropDLL/InteropNotificationListeners.h @@ -6,7 +6,7 @@ #include "../Utilities/SimpleLock.h" #include "InteropNotificationListener.h" -typedef void(__stdcall *NotificationListenerCallback)(int, void*); +typedef void (__stdcall *NotificationListenerCallback)(int, void*); class InteropNotificationListeners { @@ -14,7 +14,8 @@ class InteropNotificationListeners vector> _externalNotificationListeners; public: - INotificationListener* RegisterNotificationCallback(NotificationListenerCallback callback, shared_ptr console) + INotificationListener* RegisterNotificationCallback(NotificationListenerCallback callback, + shared_ptr console) { auto lock = _externalNotificationListenerLock.AcquireSafe(); auto listener = shared_ptr(new InteropNotificationListener(callback)); @@ -23,7 +24,7 @@ public: return listener.get(); } - void UnregisterNotificationCallback(INotificationListener *listener) + void UnregisterNotificationCallback(INotificationListener* listener) { auto lock = _externalNotificationListenerLock.AcquireSafe(); _externalNotificationListeners.erase( @@ -35,4 +36,4 @@ public: _externalNotificationListeners.end() ); } -}; \ No newline at end of file +}; diff --git a/InteropDLL/NetplayApiWrapper.cpp b/InteropDLL/NetplayApiWrapper.cpp index 5e467ec..31bfc0d 100644 --- a/InteropDLL/NetplayApiWrapper.cpp +++ b/InteropDLL/NetplayApiWrapper.cpp @@ -8,43 +8,56 @@ extern shared_ptr _console; extern "C" { - DllExport void __stdcall StartServer(uint16_t port, char* password, char* hostPlayerName) { GameServer::StartServer(_console, port, password, hostPlayerName); } - DllExport void __stdcall StopServer() { GameServer::StopServer(); } - DllExport bool __stdcall IsServerRunning() { return GameServer::Started(); } +DllExport void __stdcall StartServer(uint16_t port, char* password, char* hostPlayerName) +{ + GameServer::StartServer(_console, port, password, hostPlayerName); +} - DllExport void __stdcall Connect(char* host, uint16_t port, char* password, char* playerName, bool spectator) +DllExport void __stdcall StopServer() { GameServer::StopServer(); } +DllExport bool __stdcall IsServerRunning() { return GameServer::Started(); } + +DllExport void __stdcall Connect(char* host, uint16_t port, char* password, char* playerName, bool spectator) +{ + ClientConnectionData connectionData(host, port, password, playerName, spectator); + GameClient::Connect(_console, connectionData); +} + +DllExport void __stdcall Disconnect() { GameClient::Disconnect(); } +DllExport bool __stdcall IsConnected() { return GameClient::Connected(); } + +DllExport int32_t __stdcall NetPlayGetAvailableControllers() +{ + if (GameServer::Started()) { - ClientConnectionData connectionData(host, port, password, playerName, spectator); - GameClient::Connect(_console, connectionData); + return GameServer::GetAvailableControllers(); } - - DllExport void __stdcall Disconnect() { GameClient::Disconnect(); } - DllExport bool __stdcall IsConnected() { return GameClient::Connected(); } - - DllExport int32_t __stdcall NetPlayGetAvailableControllers() + else { - if(GameServer::Started()) { - return GameServer::GetAvailableControllers(); - } else { - return GameClient::GetAvailableControllers(); - } + return GameClient::GetAvailableControllers(); } +} - DllExport void __stdcall NetPlaySelectController(int32_t port) +DllExport void __stdcall NetPlaySelectController(int32_t port) +{ + if (GameServer::Started()) { - if(GameServer::Started()) { - return GameServer::SetHostControllerPort(port); - } else { - return GameClient::SelectController(port); - } + return GameServer::SetHostControllerPort(port); } + else + { + return GameClient::SelectController(port); + } +} - DllExport int32_t __stdcall NetPlayGetControllerPort() +DllExport int32_t __stdcall NetPlayGetControllerPort() +{ + if (GameServer::Started()) { - if(GameServer::Started()) { - return GameServer::GetHostControllerPort(); - } else { - return GameClient::GetControllerPort(); - } + return GameServer::GetHostControllerPort(); } -} \ No newline at end of file + else + { + return GameClient::GetControllerPort(); + } +} +} diff --git a/InteropDLL/RecordApiWrapper.cpp b/InteropDLL/RecordApiWrapper.cpp index 45a80dc..02437fc 100644 --- a/InteropDLL/RecordApiWrapper.cpp +++ b/InteropDLL/RecordApiWrapper.cpp @@ -7,23 +7,26 @@ extern shared_ptr _console; enum class VideoCodec; -extern "C" +extern "C" { +DllExport void __stdcall AviRecord(char* filename, VideoCodec codec, uint32_t compressionLevel) { - DllExport void __stdcall AviRecord(char* filename, VideoCodec codec, uint32_t compressionLevel) { _console->GetVideoRenderer()->StartRecording(filename, codec, compressionLevel); } - DllExport void __stdcall AviStop() { _console->GetVideoRenderer()->StopRecording(); } - DllExport bool __stdcall AviIsRecording() { return _console->GetVideoRenderer()->IsRecording(); } + _console->GetVideoRenderer()->StartRecording(filename, codec, compressionLevel); +} - DllExport void __stdcall WaveRecord(char* filename) { _console->GetSoundMixer()->StartRecording(filename); } - DllExport void __stdcall WaveStop() { _console->GetSoundMixer()->StopRecording(); } - DllExport bool __stdcall WaveIsRecording() { return _console->GetSoundMixer()->IsRecording(); } +DllExport void __stdcall AviStop() { _console->GetVideoRenderer()->StopRecording(); } +DllExport bool __stdcall AviIsRecording() { return _console->GetVideoRenderer()->IsRecording(); } - DllExport void __stdcall MoviePlay(char* filename) { _console->GetMovieManager()->Play(string(filename)); } - DllExport void __stdcall MovieStop() { _console->GetMovieManager()->Stop(); } - DllExport bool __stdcall MoviePlaying() { return _console->GetMovieManager()->Playing(); } - DllExport bool __stdcall MovieRecording() { return _console->GetMovieManager()->Recording(); } - DllExport void __stdcall MovieRecord(RecordMovieOptions *options) - { - RecordMovieOptions opt = *options; - _console->GetMovieManager()->Record(opt); - } -} \ No newline at end of file +DllExport void __stdcall WaveRecord(char* filename) { _console->GetSoundMixer()->StartRecording(filename); } +DllExport void __stdcall WaveStop() { _console->GetSoundMixer()->StopRecording(); } +DllExport bool __stdcall WaveIsRecording() { return _console->GetSoundMixer()->IsRecording(); } + +DllExport void __stdcall MoviePlay(char* filename) { _console->GetMovieManager()->Play(string(filename)); } +DllExport void __stdcall MovieStop() { _console->GetMovieManager()->Stop(); } +DllExport bool __stdcall MoviePlaying() { return _console->GetMovieManager()->Playing(); } +DllExport bool __stdcall MovieRecording() { return _console->GetMovieManager()->Recording(); } +DllExport void __stdcall MovieRecord(RecordMovieOptions* options) +{ + RecordMovieOptions opt = *options; + _console->GetMovieManager()->Record(opt); +} +} diff --git a/InteropDLL/TestApiWrapper.cpp b/InteropDLL/TestApiWrapper.cpp index f2a1b24..52e3949 100644 --- a/InteropDLL/TestApiWrapper.cpp +++ b/InteropDLL/TestApiWrapper.cpp @@ -5,27 +5,27 @@ extern shared_ptr _console; shared_ptr _recordedRomTest; -extern "C" +extern "C" { +DllExport int32_t __stdcall RunRecordedTest(char* filename, bool inBackground) { - DllExport int32_t __stdcall RunRecordedTest(char* filename, bool inBackground) - { - shared_ptr romTest(new RecordedRomTest(inBackground ? nullptr : _console)); - return romTest->Run(filename); - } + shared_ptr romTest(new RecordedRomTest(inBackground ? nullptr : _console)); + return romTest->Run(filename); +} - DllExport void __stdcall RomTestRecord(char* filename, bool reset) - { - _recordedRomTest.reset(new RecordedRomTest(_console)); - _recordedRomTest->Record(filename, reset); - } - - DllExport void __stdcall RomTestStop() - { - if(_recordedRomTest) { - _recordedRomTest->Stop(); - _recordedRomTest.reset(); - } - } +DllExport void __stdcall RomTestRecord(char* filename, bool reset) +{ + _recordedRomTest.reset(new RecordedRomTest(_console)); + _recordedRomTest->Record(filename, reset); +} - DllExport bool __stdcall RomTestRecording() { return _recordedRomTest != nullptr; } -} \ No newline at end of file +DllExport void __stdcall RomTestStop() +{ + if (_recordedRomTest) + { + _recordedRomTest->Stop(); + _recordedRomTest.reset(); + } +} + +DllExport bool __stdcall RomTestRecording() { return _recordedRomTest != nullptr; } +} diff --git a/InteropDLL/stdafx.h b/InteropDLL/stdafx.h index bb738b3..20ba241 100644 --- a/InteropDLL/stdafx.h +++ b/InteropDLL/stdafx.h @@ -6,43 +6,43 @@ #pragma once #if _WIN32 || _WIN64 - #if _WIN64 - #define ENVIRONMENT64 - #else +#if _WIN64 +#define ENVIRONMENT64 +#else #define ENVIRONMENT32 - #endif +#endif #endif #if __GNUC__ - #if __x86_64__ || __ppc64__ +#if __x86_64__ || __ppc64__ #define ENVIRONMENT64 - #else +#else #define ENVIRONMENT32 - #endif +#endif #endif #ifdef _DEBUG - #define MESEN_LIBRARY_DEBUG_SUFFIX "Debug" -#else +#define MESEN_LIBRARY_DEBUG_SUFFIX "Debug" +#else #define MESEN_LIBRARY_DEBUG_SUFFIX "Release" #endif #ifdef ENVIRONMENT32 #define MESEN_LIBRARY_SUFFIX "x86.lib" -#else - #define MESEN_LIBRARY_SUFFIX "x64.lib" +#else +#define MESEN_LIBRARY_SUFFIX "x64.lib" #endif #if _WIN32 || _WIN64 - //#pragma comment(lib, "Core.lib") - //#pragma comment(lib, "Utilities.lib") - //#pragma comment(lib, "Windows.lib") - //#pragma comment(lib, "SevenZip.lib") - //#pragma comment(lib, "Lua.lib") - //#pragma comment(lib, "ws2_32.lib") //Winsock Library - //#pragma comment(lib, "../Dependencies/DirectXTK." MESEN_LIBRARY_DEBUG_SUFFIX ".Static." MESEN_LIBRARY_SUFFIX) - #define DllExport __declspec(dllexport) +//#pragma comment(lib, "Core.lib") +//#pragma comment(lib, "Utilities.lib") +//#pragma comment(lib, "Windows.lib") +//#pragma comment(lib, "SevenZip.lib") +//#pragma comment(lib, "Lua.lib") +//#pragma comment(lib, "ws2_32.lib") //Winsock Library +//#pragma comment(lib, "../Dependencies/DirectXTK." MESEN_LIBRARY_DEBUG_SUFFIX ".Static." MESEN_LIBRARY_SUFFIX) +#define DllExport __declspec(dllexport) #else #define __stdcall #define DllExport __attribute__((visibility("default"))) -#endif \ No newline at end of file +#endif diff --git a/Libretro/LibretroKeyManager.h b/Libretro/LibretroKeyManager.h index aad8964..9679b55 100644 --- a/Libretro/LibretroKeyManager.h +++ b/Libretro/LibretroKeyManager.h @@ -10,18 +10,22 @@ private: shared_ptr _console; retro_input_state_t _getInputState = nullptr; retro_input_poll_t _pollInput = nullptr; - bool _mouseButtons[3] = { false, false, false }; - bool _wasPushed[16] = { }; + bool _mouseButtons[3] = {false, false, false}; + bool _wasPushed[16] = {}; bool ProcessAction(uint32_t button) { - if(_getInputState(0, RETRO_DEVICE_JOYPAD, 0, button)) { - if(!_wasPushed[button]) { + if (_getInputState(0, RETRO_DEVICE_JOYPAD, 0, button)) + { + if (!_wasPushed[button]) + { //Newly pressed, process action _wasPushed[button] = true; return true; } - } else { + } + else + { _wasPushed[button] = false; } return false; @@ -52,11 +56,13 @@ public: // Inherited via IKeyManager virtual void RefreshState() override { - if(_pollInput) { + if (_pollInput) + { _pollInput(); } - if(_getInputState) { + if (_getInputState) + { int32_t x = _getInputState(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); int32_t y = _getInputState(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); @@ -68,18 +74,24 @@ public: int16_t dx = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); int16_t dy = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); KeyManager::SetMouseMovement(dx, dy); - - _mouseButtons[(int)MouseButton::LeftButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT) != 0; - _mouseButtons[(int)MouseButton::RightButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT) != 0; - _mouseButtons[(int)MouseButton::MiddleButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE) != 0; + + _mouseButtons[(int)MouseButton::LeftButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, + RETRO_DEVICE_ID_MOUSE_LEFT) != 0; + _mouseButtons[(int)MouseButton::RightButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, + RETRO_DEVICE_ID_MOUSE_RIGHT) != 0; + _mouseButtons[(int)MouseButton::MiddleButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, + RETRO_DEVICE_ID_MOUSE_MIDDLE) != 0; } } virtual bool IsKeyPressed(uint32_t keyCode) override { - if(keyCode > 0 && _getInputState) { + if (keyCode > 0 && _getInputState) + { return _getInputState(keyCode >> 8, RETRO_DEVICE_JOYPAD, 0, (keyCode - 1) & 0xFF) != 0; - } else { + } + else + { return false; } } @@ -97,7 +109,7 @@ public: { return vector(); } - + virtual string GetKeyName(uint32_t keyCode) override { return string(); @@ -119,4 +131,4 @@ public: virtual void SetDisabled(bool disabled) override { } -}; \ No newline at end of file +}; diff --git a/Libretro/LibretroMessageManager.h b/Libretro/LibretroMessageManager.h index 423fee7..d360f86 100644 --- a/Libretro/LibretroMessageManager.h +++ b/Libretro/LibretroMessageManager.h @@ -25,14 +25,18 @@ public: // Inherited via IMessageManager virtual void DisplayMessage(string title, string message) override { - if(title.empty()) { - if(_log) { + if (title.empty()) + { + if (_log) + { _log(RETRO_LOG_INFO, message.c_str()); } - } else { + } + else + { string osdMessage = "[" + title + "] " + message; - retro_message msg = { osdMessage.c_str(), 180 }; + retro_message msg = {osdMessage.c_str(), 180}; _retroEnv(RETRO_ENVIRONMENT_SET_MESSAGE, &msg); } } -}; \ No newline at end of file +}; diff --git a/Libretro/LibretroRenderer.h b/Libretro/LibretroRenderer.h index 9ad0c58..f47f41b 100644 --- a/Libretro/LibretroRenderer.h +++ b/Libretro/LibretroRenderer.h @@ -30,18 +30,20 @@ public: } // Inherited via IRenderingDevice - virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) override + virtual void UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height) override { - if(!_skipMode && _sendFrame) { + if (!_skipMode && _sendFrame) + { //Use Blargg's NTSC filter's max size as a minimum resolution, to prevent changing resolution too often int32_t newWidth = std::max(width, SNES_NTSC_OUT_WIDTH(256)); int32_t newHeight = std::max(height, 239 * 2); - if(_retroEnv != nullptr && (_previousWidth != newWidth || _previousHeight != newHeight)) { + if (_retroEnv != nullptr && (_previousWidth != newWidth || _previousHeight != newHeight)) + { //Resolution change is needed retro_system_av_info avInfo = {}; GetSystemAudioVideoInfo(avInfo, newWidth, newHeight); _retroEnv(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo); - + _previousWidth = newWidth; _previousHeight = newHeight; } @@ -49,12 +51,14 @@ public: _sendFrame(frameBuffer, width, height, sizeof(uint32_t) * width); } } - - void GetSystemAudioVideoInfo(retro_system_av_info &info, int32_t maxWidth = 0, int32_t maxHeight = 0) + + void GetSystemAudioVideoInfo(retro_system_av_info& info, int32_t maxWidth = 0, int32_t maxHeight = 0) { AudioConfig audio = _console->GetSettings()->GetAudioConfig(); - - info.timing.fps = _console->GetRegion() == ConsoleRegion::Ntsc ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333; + + info.timing.fps = _console->GetRegion() == ConsoleRegion::Ntsc + ? 60.098811862348404716732985230828 + : 50.006977968268290848936010226333; info.timing.sample_rate = audio.SampleRate; OverscanDimensions overscan = _console->GetSettings()->GetOverscan(); @@ -62,15 +66,22 @@ public: int height = (239 - overscan.Top - overscan.Bottom); double aspectRatio = _console->GetSettings()->GetAspectRatio(_console->GetRegion()); - if(aspectRatio != 0.0) { + if (aspectRatio != 0.0) + { VideoAspectRatio aspect = _console->GetSettings()->GetVideoConfig().AspectRatio; - bool usePar = aspect == VideoAspectRatio::NTSC || aspect == VideoAspectRatio::PAL || aspect == VideoAspectRatio::Auto; - if(usePar) { + bool usePar = aspect == VideoAspectRatio::NTSC || aspect == VideoAspectRatio::PAL || aspect == + VideoAspectRatio::Auto; + if (usePar) + { info.geometry.aspect_ratio = (float)(width * aspectRatio / height); - } else { + } + else + { info.geometry.aspect_ratio = (float)aspectRatio; } - } else { + } + else + { info.geometry.aspect_ratio = (float)width / height; } @@ -80,7 +91,8 @@ public: info.geometry.max_width = maxWidth; info.geometry.max_height = maxHeight; - if(maxHeight > 0 && maxWidth > 0) { + if (maxHeight > 0 && maxWidth > 0) + { _previousWidth = maxWidth; _previousHeight = maxHeight; } @@ -95,7 +107,7 @@ public: { _skipMode = skip; } - + virtual void Render() override { } @@ -104,7 +116,8 @@ public: { } - virtual void SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) override + virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, + uint32_t monitorHeight) override { } -}; \ No newline at end of file +}; diff --git a/Libretro/LibretroSoundManager.h b/Libretro/LibretroSoundManager.h index 269c887..1b3498d 100644 --- a/Libretro/LibretroSoundManager.h +++ b/Libretro/LibretroSoundManager.h @@ -23,11 +23,13 @@ public: } // Inherited via IAudioDevice - virtual void PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) override + virtual void PlayBuffer(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) override { - if(!_skipMode && _sendAudioSample) { - for(uint32_t total = 0; total < sampleCount; ) { - total += (uint32_t)_sendAudioSample(soundBuffer + total*2, (size_t)(sampleCount - total)); + if (!_skipMode && _sendAudioSample) + { + for (uint32_t total = 0; total < sampleCount;) + { + total += (uint32_t)_sendAudioSample(soundBuffer + total * 2, (size_t)(sampleCount - total)); } } } diff --git a/Libretro/libretro.cpp b/Libretro/libretro.cpp index ae78824..7da5399 100644 --- a/Libretro/libretro.cpp +++ b/Libretro/libretro.cpp @@ -30,7 +30,7 @@ static retro_log_printf_t logCallback = nullptr; static retro_environment_t retroEnv = nullptr; -static unsigned _inputDevices[5] = { DEVICE_GAMEPAD, DEVICE_GAMEPAD, DEVICE_NONE, DEVICE_NONE, DEVICE_NONE }; +static unsigned _inputDevices[5] = {DEVICE_GAMEPAD, DEVICE_GAMEPAD, DEVICE_NONE, DEVICE_NONE, DEVICE_NONE}; static string _mesenVersion = ""; static int32_t _saveStateSize = -1; @@ -55,709 +55,841 @@ static constexpr const char* MesenGbModel = "mesen-s_gbmodel"; static constexpr const char* MesenGbSgb2 = "mesen-s_sgb2"; extern "C" { - void logMessage(retro_log_level level, const char* message) +void logMessage(retro_log_level level, const char* message) +{ + if (logCallback) { - if(logCallback) { - logCallback(level, message); + logCallback(level, message); + } +} + +RETRO_API unsigned retro_api_version() +{ + return RETRO_API_VERSION; +} + +RETRO_API void retro_init() +{ + struct retro_log_callback log; + if (retroEnv(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) + { + logCallback = log.log; + } + else + { + logCallback = nullptr; + } + + _console.reset(new Console()); + _console->Initialize(); + KeyManager::SetSettings(_console->GetSettings().get()); + + _renderer.reset(new LibretroRenderer(_console, retroEnv)); + _soundManager.reset(new LibretroSoundManager(_console)); + _keyManager.reset(new LibretroKeyManager(_console)); + _messageManager.reset(new LibretroMessageManager(logCallback, retroEnv)); + + AudioConfig audioConfig = _console->GetSettings()->GetAudioConfig(); + audioConfig.DisableDynamicSampleRate = true; + audioConfig.SampleRate = Spc::SpcSampleRate; + _console->GetSettings()->SetAudioConfig(audioConfig); + + PreferencesConfig preferences = _console->GetSettings()->GetPreferences(); + preferences.DisableOsd = true; + preferences.RewindBufferSize = 0; + _console->GetSettings()->SetPreferences(preferences); +} + +RETRO_API void retro_deinit() +{ + _renderer.reset(); + _soundManager.reset(); + _keyManager.reset(); + _messageManager.reset(); + + //_console->SaveBatteries(); + _console->Release(); + _console.reset(); +} + +RETRO_API void retro_set_environment(retro_environment_t env) +{ + retroEnv = env; + + static constexpr struct retro_variable vars[] = { + {MesenNtscFilter, "NTSC filter; Disabled|Composite (Blargg)|S-Video (Blargg)|RGB (Blargg)|Monochrome (Blargg)"}, + {MesenRegion, "Region; Auto|NTSC|PAL"}, + {MesenGbModel, "Game Boy Model; Auto|Game Boy|Game Boy Color|Super Game Boy"}, + {MesenGbSgb2, "Use SGB2; enabled|disabled"}, + {MesenOverscanVertical, "Vertical Overscan; None|8px|16px"}, + {MesenOverscanHorizontal, "Horizontal Overscan; None|8px|16px"}, + {MesenAspectRatio, "Aspect Ratio; Auto|No Stretching|NTSC|PAL|4:3|16:9"}, + {MesenBlendHighRes, "Blend Hi-Res Modes; disabled|enabled"}, + {MesenCubicInterpolation, "Cubic Interpolation (Audio); disabled|enabled"}, + {MesenOverclock, "Overclock; None|Low|Medium|High|Very High"}, + {MesenOverclockType, "Overclock Type; Before NMI|After NMI"}, + {MesenSuperFxOverclock, "Super FX Clock Speed; 100%|200%|300%|400%|500%|1000%"}, + {MesenRamState, "Default power-on state for RAM; Random Values (Default)|All 0s|All 1s"}, + {NULL, NULL}, + }; + + static constexpr struct retro_controller_description pads1[] = { + {"None", DEVICE_NONE}, + {"SNES Controller", DEVICE_GAMEPAD}, + {"SNES Mouse", DEVICE_SNESMOUSE}, + {NULL, 0}, + }; + + static constexpr struct retro_controller_description pads2[] = { + {"None", DEVICE_NONE}, + {"SNES Controller", DEVICE_GAMEPAD}, + {"SNES Mouse", DEVICE_SNESMOUSE}, + {"Super Scope", DEVICE_SUPERSCOPE}, + {"Multitap", DEVICE_MULTITAP}, + {NULL, 0}, + }; + + static constexpr struct retro_controller_description pads3[] = { + {"SNES Controller", DEVICE_GAMEPAD}, + {NULL, 0}, + }; + + static constexpr struct retro_controller_description pads4[] = { + {"SNES Controller", DEVICE_GAMEPAD}, + {NULL, 0}, + }; + + static constexpr struct retro_controller_description pads5[] = { + {"SNES Controller", DEVICE_GAMEPAD}, + {NULL, 0}, + }; + + static constexpr struct retro_controller_info ports[] = { + {pads1, 3}, + {pads2, 5}, + {pads3, 1}, + {pads4, 1}, + {pads5, 1}, + {0}, + }; + + retroEnv(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); + retroEnv(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); +} + +RETRO_API void retro_set_video_refresh(retro_video_refresh_t sendFrame) +{ + _renderer->SetVideoCallback(sendFrame); +} + +RETRO_API void retro_set_audio_sample(retro_audio_sample_t sendAudioSample) +{ +} + +RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t audioSampleBatch) +{ + _soundManager->SetSendAudioSample(audioSampleBatch); +} + +RETRO_API void retro_set_input_poll(retro_input_poll_t pollInput) +{ + _keyManager->SetPollInput(pollInput); +} + +RETRO_API void retro_set_input_state(retro_input_state_t getInputState) +{ + _keyManager->SetGetInputState(getInputState); +} + +RETRO_API void retro_reset() +{ + _console->Reset(); +} + +bool readVariable(const char* key, retro_variable& var) +{ + var.key = key; + var.value = nullptr; + if (retroEnv(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value != nullptr) + { + return true; + } + return false; +} + +void update_settings() +{ + struct retro_variable var = {}; + shared_ptr settings = _console->GetSettings(); + VideoConfig video = settings->GetVideoConfig(); + AudioConfig audio = settings->GetAudioConfig(); + EmulationConfig emulation = settings->GetEmulationConfig(); + GameboyConfig gbConfig = settings->GetGameboyConfig(); + InputConfig input = settings->GetInputConfig(); + video.Brightness = 0; + video.Contrast = 0; + video.Hue = 0; + video.Saturation = 0; + video.ScanlineIntensity = 0; + + if (readVariable(MesenNtscFilter, var)) + { + string value = string(var.value); + if (value == "Disabled") + { + video.VideoFilter = VideoFilterType::None; + } + else if (value == "Composite (Blargg)") + { + video.VideoFilter = VideoFilterType::NTSC; + video.NtscArtifacts = 0; + video.NtscBleed = 0; + video.NtscFringing = 0; + video.NtscGamma = 0; + video.NtscResolution = 0; + video.NtscSharpness = 0; + video.NtscMergeFields = false; + } + else if (value == "S-Video (Blargg)") + { + video.VideoFilter = VideoFilterType::NTSC; + video.NtscArtifacts = -1.0; + video.NtscBleed = 0; + video.NtscFringing = -1.0; + video.NtscGamma = 0; + video.NtscResolution = 0.2; + video.NtscSharpness = 0.2; + video.NtscMergeFields = false; + } + else if (value == "RGB (Blargg)") + { + video.VideoFilter = VideoFilterType::NTSC; + video.NtscArtifacts = -1.0; + video.NtscBleed = -1.0; + video.NtscFringing = -1.0; + video.NtscGamma = 0; + video.NtscResolution = 0.7; + video.NtscSharpness = 0.2; + video.NtscMergeFields = false; + } + else if (value == "Monochrome (Blargg)") + { + video.VideoFilter = VideoFilterType::NTSC; + video.Saturation = -1.0; + video.NtscArtifacts = -0.2; + video.NtscBleed = -1.0; + video.NtscFringing = -0.2; + video.NtscGamma = 0; + video.NtscResolution = 0.2; + video.NtscSharpness = 0.2; + video.NtscMergeFields = false; } } - RETRO_API unsigned retro_api_version() + bool beforeNmi = true; + if (readVariable(MesenOverclockType, var)) { - return RETRO_API_VERSION; + string value = string(var.value); + if (value == "After NMI") + { + beforeNmi = false; + } } - RETRO_API void retro_init() + if (readVariable(MesenOverclock, var)) { - struct retro_log_callback log; - if(retroEnv(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) { - logCallback = log.log; - } else { - logCallback = nullptr; + string value = string(var.value); + int lineCount = 0; + if (value == "None") + { + lineCount = 0; + } + else if (value == "Low") + { + lineCount = 100; + } + else if (value == "Medium") + { + lineCount = 250; + } + else if (value == "High") + { + lineCount = 500; + } + else if (value == "Very High") + { + lineCount = 1000; } - _console.reset(new Console()); - _console->Initialize(); - KeyManager::SetSettings(_console->GetSettings().get()); - - _renderer.reset(new LibretroRenderer(_console, retroEnv)); - _soundManager.reset(new LibretroSoundManager(_console)); - _keyManager.reset(new LibretroKeyManager(_console)); - _messageManager.reset(new LibretroMessageManager(logCallback, retroEnv)); - - AudioConfig audioConfig = _console->GetSettings()->GetAudioConfig(); - audioConfig.DisableDynamicSampleRate = true; - audioConfig.SampleRate = Spc::SpcSampleRate; - _console->GetSettings()->SetAudioConfig(audioConfig); - - PreferencesConfig preferences = _console->GetSettings()->GetPreferences(); - preferences.DisableOsd = true; - preferences.RewindBufferSize = 0; - _console->GetSettings()->SetPreferences(preferences); + if (beforeNmi) + { + emulation.PpuExtraScanlinesBeforeNmi = lineCount; + emulation.PpuExtraScanlinesAfterNmi = 0; + } + else + { + emulation.PpuExtraScanlinesAfterNmi = lineCount; + emulation.PpuExtraScanlinesBeforeNmi = 0; + } } - RETRO_API void retro_deinit() + emulation.GsuClockSpeed = 100; + if (readVariable(MesenSuperFxOverclock, var)) { - _renderer.reset(); - _soundManager.reset(); - _keyManager.reset(); - _messageManager.reset(); - - //_console->SaveBatteries(); - _console->Release(); - _console.reset(); + string value = string(var.value); + if (value == "100%") + { + emulation.GsuClockSpeed = 100; + } + else if (value == "200%") + { + emulation.GsuClockSpeed = 200; + } + else if (value == "300%") + { + emulation.GsuClockSpeed = 300; + } + else if (value == "400%") + { + emulation.GsuClockSpeed = 400; + } + else if (value == "500%") + { + emulation.GsuClockSpeed = 500; + } + else if (value == "1000%") + { + emulation.GsuClockSpeed = 1000; + } } - RETRO_API void retro_set_environment(retro_environment_t env) + int overscanHorizontal = 0; + int overscanVertical = 0; + if (readVariable(MesenOverscanHorizontal, var)) { - retroEnv = env; - - static constexpr struct retro_variable vars[] = { - { MesenNtscFilter, "NTSC filter; Disabled|Composite (Blargg)|S-Video (Blargg)|RGB (Blargg)|Monochrome (Blargg)" }, - { MesenRegion, "Region; Auto|NTSC|PAL" }, - { MesenGbModel, "Game Boy Model; Auto|Game Boy|Game Boy Color|Super Game Boy" }, - { MesenGbSgb2, "Use SGB2; enabled|disabled" }, - { MesenOverscanVertical, "Vertical Overscan; None|8px|16px" }, - { MesenOverscanHorizontal, "Horizontal Overscan; None|8px|16px" }, - { MesenAspectRatio, "Aspect Ratio; Auto|No Stretching|NTSC|PAL|4:3|16:9" }, - { MesenBlendHighRes, "Blend Hi-Res Modes; disabled|enabled" }, - { MesenCubicInterpolation, "Cubic Interpolation (Audio); disabled|enabled" }, - { MesenOverclock, "Overclock; None|Low|Medium|High|Very High" }, - { MesenOverclockType, "Overclock Type; Before NMI|After NMI" }, - { MesenSuperFxOverclock, "Super FX Clock Speed; 100%|200%|300%|400%|500%|1000%" }, - { MesenRamState, "Default power-on state for RAM; Random Values (Default)|All 0s|All 1s" }, - { NULL, NULL }, - }; - - static constexpr struct retro_controller_description pads1[] = { - { "None", DEVICE_NONE }, - { "SNES Controller", DEVICE_GAMEPAD }, - { "SNES Mouse", DEVICE_SNESMOUSE }, - { NULL, 0 }, - }; - - static constexpr struct retro_controller_description pads2[] = { - { "None", DEVICE_NONE }, - { "SNES Controller", DEVICE_GAMEPAD }, - { "SNES Mouse", DEVICE_SNESMOUSE }, - { "Super Scope", DEVICE_SUPERSCOPE }, - { "Multitap", DEVICE_MULTITAP }, - { NULL, 0 }, - }; - - static constexpr struct retro_controller_description pads3[] = { - { "SNES Controller", DEVICE_GAMEPAD }, - { NULL, 0 }, - }; - - static constexpr struct retro_controller_description pads4[] = { - { "SNES Controller", DEVICE_GAMEPAD }, - { NULL, 0 }, - }; - - static constexpr struct retro_controller_description pads5[] = { - { "SNES Controller", DEVICE_GAMEPAD }, - { NULL, 0 }, - }; - - static constexpr struct retro_controller_info ports[] = { - { pads1, 3 }, - { pads2, 5 }, - { pads3, 1 }, - { pads4, 1 }, - { pads5, 1 }, - { 0 }, - }; - - retroEnv(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); - retroEnv(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); + string value = string(var.value); + if (value == "8px") + { + overscanHorizontal = 8; + } + else if (value == "16px") + { + overscanHorizontal = 16; + } } - RETRO_API void retro_set_video_refresh(retro_video_refresh_t sendFrame) + if (readVariable(MesenOverscanVertical, var)) { - _renderer->SetVideoCallback(sendFrame); + string value = string(var.value); + if (value == "8px") + { + overscanVertical = 8; + } + else if (value == "16px") + { + overscanVertical = 16; + } } - RETRO_API void retro_set_audio_sample(retro_audio_sample_t sendAudioSample) + video.OverscanLeft = overscanHorizontal; + video.OverscanRight = overscanHorizontal; + video.OverscanTop = std::max(0, overscanVertical - 1); + video.OverscanBottom = overscanVertical; + + if (readVariable(MesenAspectRatio, var)) { + string value = string(var.value); + if (value == "Auto") + { + video.AspectRatio = VideoAspectRatio::Auto; + } + else if (value == "No Stretching") + { + video.AspectRatio = VideoAspectRatio::NoStretching; + } + else if (value == "NTSC") + { + video.AspectRatio = VideoAspectRatio::NTSC; + } + else if (value == "PAL") + { + video.AspectRatio = VideoAspectRatio::PAL; + } + else if (value == "4:3") + { + video.AspectRatio = VideoAspectRatio::Standard; + } + else if (value == "16:9") + { + video.AspectRatio = VideoAspectRatio::Widescreen; + } } - RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t audioSampleBatch) + if (readVariable(MesenRegion, var)) { - _soundManager->SetSendAudioSample(audioSampleBatch); + string value = string(var.value); + if (value == "Auto") + { + emulation.Region = ConsoleRegion::Auto; + } + else if (value == "NTSC") + { + emulation.Region = ConsoleRegion::Ntsc; + } + else if (value == "PAL") + { + emulation.Region = ConsoleRegion::Pal; + } } - RETRO_API void retro_set_input_poll(retro_input_poll_t pollInput) - { - _keyManager->SetPollInput(pollInput); + if (readVariable(MesenRamState, var)) + { + string value = string(var.value); + if (value == "Random Values (Default)") + { + emulation.RamPowerOnState = RamState::Random; + } + else if (value == "All 0s") + { + emulation.RamPowerOnState = RamState::AllZeros; + } + else if (value == "All 1s") + { + emulation.RamPowerOnState = RamState::AllOnes; + } } - RETRO_API void retro_set_input_state(retro_input_state_t getInputState) + if (readVariable(MesenBlendHighRes, var)) { - _keyManager->SetGetInputState(getInputState); + string value = string(var.value); + video.BlendHighResolutionModes = (value == "enabled"); } - RETRO_API void retro_reset() + if (readVariable(MesenCubicInterpolation, var)) { - _console->Reset(); + string value = string(var.value); + audio.EnableCubicInterpolation = (value == "enabled"); } - bool readVariable(const char* key, retro_variable &var) + if (readVariable(MesenGbModel, var)) { - var.key = key; - var.value = nullptr; - if(retroEnv(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value != nullptr) { - return true; + string value = string(var.value); + if (value == "Game Boy") + { + gbConfig.Model = GameboyModel::Gameboy; + } + else if (value == "Game Boy Color") + { + gbConfig.Model = GameboyModel::GameboyColor; + } + else if (value == "Super Game Boy") + { + gbConfig.Model = GameboyModel::SuperGameboy; + } + else + { + gbConfig.Model = GameboyModel::Auto; } - return false; } - void update_settings() + if (readVariable(MesenGbSgb2, var)) { - struct retro_variable var = { }; - shared_ptr settings = _console->GetSettings(); - VideoConfig video = settings->GetVideoConfig(); - AudioConfig audio = settings->GetAudioConfig(); - EmulationConfig emulation = settings->GetEmulationConfig(); - GameboyConfig gbConfig = settings->GetGameboyConfig(); - InputConfig input = settings->GetInputConfig(); - video.Brightness = 0; - video.Contrast = 0; - video.Hue = 0; - video.Saturation = 0; - video.ScanlineIntensity = 0; + string value = string(var.value); + gbConfig.UseSgb2 = (value == "enabled"); + } - if(readVariable(MesenNtscFilter, var)) { - string value = string(var.value); - if(value == "Disabled") { - video.VideoFilter = VideoFilterType::None; - } else if(value == "Composite (Blargg)") { - video.VideoFilter = VideoFilterType::NTSC; - video.NtscArtifacts = 0; - video.NtscBleed = 0; - video.NtscFringing = 0; - video.NtscGamma = 0; - video.NtscResolution = 0; - video.NtscSharpness = 0; - video.NtscMergeFields = false; - } else if(value == "S-Video (Blargg)") { - video.VideoFilter = VideoFilterType::NTSC; - video.NtscArtifacts = -1.0; - video.NtscBleed = 0; - video.NtscFringing = -1.0; - video.NtscGamma = 0; - video.NtscResolution = 0.2; - video.NtscSharpness = 0.2; - video.NtscMergeFields = false; - } else if(value == "RGB (Blargg)") { - video.VideoFilter = VideoFilterType::NTSC; - video.NtscArtifacts = -1.0; - video.NtscBleed = -1.0; - video.NtscFringing = -1.0; - video.NtscGamma = 0; - video.NtscResolution = 0.7; - video.NtscSharpness = 0.2; - video.NtscMergeFields = false; - } else if(value == "Monochrome (Blargg)") { - video.VideoFilter = VideoFilterType::NTSC; - video.Saturation = -1.0; - video.NtscArtifacts = -0.2; - video.NtscBleed = -1.0; - video.NtscFringing = -0.2; - video.NtscGamma = 0; - video.NtscResolution = 0.2; - video.NtscSharpness = 0.2; - video.NtscMergeFields = false; - } - } + auto getKeyCode = [=](int port, int retroKey) + { + return (port << 8) | (retroKey + 1); + }; - bool beforeNmi = true; - if(readVariable(MesenOverclockType, var)) { - string value = string(var.value); - if(value == "After NMI") { - beforeNmi = false; - } - } + auto getKeyBindings = [=](int port) + { + KeyMappingSet keyMappings; + keyMappings.TurboSpeed = 0; + keyMappings.Mapping1.L = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_L); + keyMappings.Mapping1.R = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_R); + keyMappings.Mapping1.A = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_A); + keyMappings.Mapping1.B = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_B); + keyMappings.Mapping1.X = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_X); + keyMappings.Mapping1.Y = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_Y); - if(readVariable(MesenOverclock, var)) { - string value = string(var.value); - int lineCount = 0; - if(value == "None") { - lineCount = 0; - } else if(value == "Low") { - lineCount = 100; - } else if(value == "Medium") { - lineCount = 250; - } else if(value == "High") { - lineCount = 500; - } else if(value == "Very High") { - lineCount = 1000; - } + keyMappings.Mapping1.Start = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_START); + keyMappings.Mapping1.Select = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_SELECT); - if(beforeNmi) { - emulation.PpuExtraScanlinesBeforeNmi = lineCount; - emulation.PpuExtraScanlinesAfterNmi = 0; - } else { - emulation.PpuExtraScanlinesAfterNmi = lineCount; - emulation.PpuExtraScanlinesBeforeNmi = 0; - } - } + keyMappings.Mapping1.Up = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_UP); + keyMappings.Mapping1.Down = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_DOWN); + keyMappings.Mapping1.Left = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_LEFT); + keyMappings.Mapping1.Right = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_RIGHT); - emulation.GsuClockSpeed = 100; - if(readVariable(MesenSuperFxOverclock, var)) { - string value = string(var.value); - if(value == "100%") { - emulation.GsuClockSpeed = 100; - } else if(value == "200%") { - emulation.GsuClockSpeed = 200; - } else if(value == "300%") { - emulation.GsuClockSpeed = 300; - } else if(value == "400%") { - emulation.GsuClockSpeed = 400; - } else if(value == "500%") { - emulation.GsuClockSpeed = 500; - } else if(value == "1000%") { - emulation.GsuClockSpeed = 1000; - } - } + return keyMappings; + }; - int overscanHorizontal = 0; - int overscanVertical = 0; - if(readVariable(MesenOverscanHorizontal, var)) { - string value = string(var.value); - if(value == "8px") { - overscanHorizontal = 8; - } else if(value == "16px") { - overscanHorizontal = 16; - } - } + input.Controllers[0].Keys = getKeyBindings(0); + input.Controllers[1].Keys = getKeyBindings(1); + input.Controllers[2].Keys = getKeyBindings(2); + input.Controllers[3].Keys = getKeyBindings(3); - if(readVariable(MesenOverscanVertical, var)) { - string value = string(var.value); - if(value == "8px") { - overscanVertical = 8; - } else if(value == "16px") { - overscanVertical = 16; - } - } - - video.OverscanLeft = overscanHorizontal; - video.OverscanRight = overscanHorizontal; - video.OverscanTop = std::max(0, overscanVertical - 1); - video.OverscanBottom = overscanVertical; + settings->SetVideoConfig(video); + settings->SetEmulationConfig(emulation); + settings->SetInputConfig(input); + settings->SetAudioConfig(audio); + settings->SetGameboyConfig(gbConfig); - if(readVariable(MesenAspectRatio, var)) { - string value = string(var.value); - if(value == "Auto") { - video.AspectRatio = VideoAspectRatio::Auto; - } else if(value == "No Stretching") { - video.AspectRatio = VideoAspectRatio::NoStretching; - } else if(value == "NTSC") { - video.AspectRatio = VideoAspectRatio::NTSC; - } else if(value == "PAL") { - video.AspectRatio = VideoAspectRatio::PAL; - } else if(value == "4:3") { - video.AspectRatio = VideoAspectRatio::Standard; - } else if(value == "16:9") { - video.AspectRatio = VideoAspectRatio::Widescreen; - } - } + retro_system_av_info avInfo = {}; + _renderer->GetSystemAudioVideoInfo(avInfo); + retroEnv(RETRO_ENVIRONMENT_SET_GEOMETRY, &avInfo); +} - if(readVariable(MesenRegion, var)) { - string value = string(var.value); - if(value == "Auto") { - emulation.Region = ConsoleRegion::Auto; - } else if(value == "NTSC") { - emulation.Region = ConsoleRegion::Ntsc; - } else if(value == "PAL") { - emulation.Region = ConsoleRegion::Pal; - } - } +RETRO_API void retro_run() +{ + bool updated = false; + if (retroEnv(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) + { + update_settings(); + } - if(readVariable(MesenRamState, var)) { - string value = string(var.value); - if(value == "Random Values (Default)") { - emulation.RamPowerOnState = RamState::Random; - } else if(value == "All 0s") { - emulation.RamPowerOnState = RamState::AllZeros; - } else if(value == "All 1s") { - emulation.RamPowerOnState = RamState::AllOnes; - } - } + bool isFastForward = false; + EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig(); + if (retroEnv(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &isFastForward) && isFastForward) + { + //Allow core to skip frame rendering during fast forwarding + cfg.EmulationSpeed = 0; + } + else + { + cfg.EmulationSpeed = 100; + } + _console->GetSettings()->SetEmulationConfig(cfg); - if(readVariable(MesenBlendHighRes, var)) { - string value = string(var.value); - video.BlendHighResolutionModes = (value == "enabled"); - } - - if(readVariable(MesenCubicInterpolation, var)) { - string value = string(var.value); - audio.EnableCubicInterpolation = (value == "enabled"); - } - - if(readVariable(MesenGbModel, var)) { - string value = string(var.value); - if(value == "Game Boy") { - gbConfig.Model = GameboyModel::Gameboy; - } else if(value == "Game Boy Color") { - gbConfig.Model = GameboyModel::GameboyColor; - } else if(value == "Super Game Boy") { - gbConfig.Model = GameboyModel::SuperGameboy; - } else { - gbConfig.Model = GameboyModel::Auto; - } - } - - if(readVariable(MesenGbSgb2, var)) { - string value = string(var.value); - gbConfig.UseSgb2 = (value == "enabled"); - } - - auto getKeyCode = [=](int port, int retroKey) { - return (port << 8) | (retroKey + 1); - }; - - auto getKeyBindings = [=](int port) { - KeyMappingSet keyMappings; - keyMappings.TurboSpeed = 0; - keyMappings.Mapping1.L = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_L); - keyMappings.Mapping1.R = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_R); - keyMappings.Mapping1.A = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_A); - keyMappings.Mapping1.B = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_B); - keyMappings.Mapping1.X = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_X); - keyMappings.Mapping1.Y = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_Y); - - keyMappings.Mapping1.Start = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_START); - keyMappings.Mapping1.Select = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_SELECT); - - keyMappings.Mapping1.Up = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_UP); - keyMappings.Mapping1.Down = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_DOWN); - keyMappings.Mapping1.Left = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_LEFT); - keyMappings.Mapping1.Right = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_RIGHT); - - return keyMappings; - }; - - input.Controllers[0].Keys = getKeyBindings(0); - input.Controllers[1].Keys = getKeyBindings(1); - input.Controllers[2].Keys = getKeyBindings(2); - input.Controllers[3].Keys = getKeyBindings(3); - - settings->SetVideoConfig(video); - settings->SetEmulationConfig(emulation); - settings->SetInputConfig(input); - settings->SetAudioConfig(audio); - settings->SetGameboyConfig(gbConfig); + _console->RunSingleFrame(); + if (updated) + { + //Update geometry after running the frame, in case the console's region changed (affects "auto" aspect ratio) retro_system_av_info avInfo = {}; _renderer->GetSystemAudioVideoInfo(avInfo); retroEnv(RETRO_ENVIRONMENT_SET_GEOMETRY, &avInfo); } +} - RETRO_API void retro_run() +RETRO_API size_t retro_serialize_size() +{ + return _saveStateSize; +} + +RETRO_API bool retro_serialize(void* data, size_t size) +{ + std::stringstream ss; + _console->GetSaveStateManager()->SaveState(ss); + + string saveStateData = ss.str(); + memset(data, 0, size); + memcpy(data, saveStateData.c_str(), std::min(size, saveStateData.size())); + + return true; +} + +RETRO_API bool retro_unserialize(const void* data, size_t size) +{ + std::stringstream ss; + ss.write((const char*)data, size); + return _console->GetSaveStateManager()->LoadState(ss); +} + +RETRO_API void retro_cheat_reset() +{ + _console->GetCheatManager()->ClearCheats(); +} + +RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char* codeStr) +{ + if (codeStr) { - bool updated = false; - if(retroEnv(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) { - update_settings(); - } - - bool isFastForward = false; - EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig(); - if(retroEnv(RETRO_ENVIRONMENT_GET_FASTFORWARDING, &isFastForward) && isFastForward) { - //Allow core to skip frame rendering during fast forwarding - cfg.EmulationSpeed = 0; - } else { - cfg.EmulationSpeed = 100; - } - _console->GetSettings()->SetEmulationConfig(cfg); - - _console->RunSingleFrame(); - - if(updated) { - //Update geometry after running the frame, in case the console's region changed (affects "auto" aspect ratio) - retro_system_av_info avInfo = {}; - _renderer->GetSystemAudioVideoInfo(avInfo); - retroEnv(RETRO_ENVIRONMENT_SET_GEOMETRY, &avInfo); - } + _console->GetCheatManager()->AddStringCheat(codeStr); } +} - RETRO_API size_t retro_serialize_size() +void update_input_descriptors() +{ + vector desc; + + auto addDesc = [&desc](unsigned port, unsigned button, const char* name) { - return _saveStateSize; - } + retro_input_descriptor d = {port, RETRO_DEVICE_JOYPAD, 0, button, name}; + desc.push_back(d); + }; - RETRO_API bool retro_serialize(void *data, size_t size) + auto setupPlayerButtons = [addDesc](int port) { - std::stringstream ss; - _console->GetSaveStateManager()->SaveState(ss); - - string saveStateData = ss.str(); - memset(data, 0, size); - memcpy(data, saveStateData.c_str(), std::min(size, saveStateData.size())); + unsigned device = _inputDevices[port]; + if (device == DEVICE_AUTO) + { + if (port <= 4) + { + switch (_console->GetSettings()->GetInputConfig().Controllers[port].Type) + { + case ControllerType::Multitap: + case ControllerType::SnesController: device = DEVICE_GAMEPAD; + break; - return true; - } - - RETRO_API bool retro_unserialize(const void *data, size_t size) - { - std::stringstream ss; - ss.write((const char*)data, size); - return _console->GetSaveStateManager()->LoadState(ss); - } - - RETRO_API void retro_cheat_reset() - { - _console->GetCheatManager()->ClearCheats(); - } - - RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *codeStr) - { - if(codeStr) { - _console->GetCheatManager()->AddStringCheat(codeStr); - } - } - - void update_input_descriptors() - { - vector desc; - - auto addDesc = [&desc](unsigned port, unsigned button, const char* name) { - retro_input_descriptor d = { port, RETRO_DEVICE_JOYPAD, 0, button, name }; - desc.push_back(d); - }; - - auto setupPlayerButtons = [addDesc](int port) { - unsigned device = _inputDevices[port]; - if(device == DEVICE_AUTO) { - if(port <= 4) { - switch(_console->GetSettings()->GetInputConfig().Controllers[port].Type) { - case ControllerType::Multitap: - case ControllerType::SnesController: device = DEVICE_GAMEPAD; break; - - case ControllerType::SuperScope: device = DEVICE_SUPERSCOPE; break; - case ControllerType::SnesMouse: device = DEVICE_SNESMOUSE; break; - default: return; - } + case ControllerType::SuperScope: device = DEVICE_SUPERSCOPE; + break; + case ControllerType::SnesMouse: device = DEVICE_SNESMOUSE; + break; + default: return; } } + } - if(device == DEVICE_GAMEPAD) { - addDesc(port, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_A, "A"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_B, "B"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_X, "X"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_Y, "Y"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_L, "L"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_R, "R"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_START, "Start"); - addDesc(port, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"); - } + if (device == DEVICE_GAMEPAD) + { + addDesc(port, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_A, "A"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_B, "B"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_X, "X"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_Y, "Y"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_L, "L"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_R, "R"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_START, "Start"); + addDesc(port, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"); + } + }; + + setupPlayerButtons(0); + setupPlayerButtons(1); + if (_console->GetSettings()->GetInputConfig().Controllers[1].Type == ControllerType::Multitap) + { + setupPlayerButtons(2); + setupPlayerButtons(3); + setupPlayerButtons(4); + } + + retro_input_descriptor end = {0}; + desc.push_back(end); + + retroEnv(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc.data()); +} + +void update_core_controllers() +{ + InputConfig input = _console->GetSettings()->GetInputConfig(); + for (int port = 0; port < 2; port++) + { + ControllerType type = ControllerType::SnesController; + switch (_inputDevices[port]) + { + case RETRO_DEVICE_NONE: type = ControllerType::None; + break; + case DEVICE_GAMEPAD: type = ControllerType::SnesController; + break; + case DEVICE_MULTITAP: type = ControllerType::Multitap; + break; + case DEVICE_SNESMOUSE: type = ControllerType::SnesMouse; + break; + case DEVICE_SUPERSCOPE: type = ControllerType::SuperScope; + break; + } + input.Controllers[port].Type = type; + } + + _console->GetSettings()->SetInputConfig(input); +} + +void retro_set_memory_maps() +{ + shared_ptr cart = _console->GetCartridge(); + Gameboy* gb = cart->GetGameboy(); + if (gb) + { + retro_memory_descriptor descriptors[20] = {}; + uint32_t count = 0; + + auto addDescriptor = [&count, &descriptors](uint8_t* ptr, uint32_t address, uint32_t length) + { + descriptors[count].ptr = ptr; + descriptors[count].start = (size_t)address; + descriptors[count].len = (size_t)length; + count++; }; - setupPlayerButtons(0); - setupPlayerButtons(1); - if(_console->GetSettings()->GetInputConfig().Controllers[1].Type == ControllerType::Multitap) { - setupPlayerButtons(2); - setupPlayerButtons(3); - setupPlayerButtons(4); + addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbPrgRom), 0x0000, + std::min(0x8000, (int)gb->DebugGetMemorySize(SnesMemoryType::GbPrgRom))); + addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbVideoRam), 0x8000, 0x2000); + if (gb->DebugGetMemory(SnesMemoryType::GbCartRam)) + { + uint32_t size = std::min(0x2000u, gb->DebugGetMemorySize(SnesMemoryType::GbCartRam)); + addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbCartRam), 0xA000, size); } - retro_input_descriptor end = { 0 }; - desc.push_back(end); + addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbWorkRam), 0xC000, 0x2000); + addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbWorkRam), 0xE000, 0x1E00); //WRAM Mirror - retroEnv(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc.data()); + addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbHighRam), 0xFF80, 0x80); + + if (gb->DebugGetMemorySize(SnesMemoryType::GbWorkRam) == 0x8000) + { + //GBC - map extra work ram at "fake" 0x10000-0x16000 range + addDescriptor(gb->DebugGetMemory(SnesMemoryType::WorkRam) + 0x2000, 0x10000, 0x6000); + } + + retro_memory_map memoryMap = {}; + memoryMap.descriptors = descriptors; + memoryMap.num_descriptors = count; + retroEnv(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &memoryMap); } +} - void update_core_controllers() +RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device) +{ + if (port < 5 && _inputDevices[port] != device) { - InputConfig input = _console->GetSettings()->GetInputConfig(); - for(int port = 0; port < 2; port++) { - ControllerType type = ControllerType::SnesController; - switch(_inputDevices[port]) { - case RETRO_DEVICE_NONE: type = ControllerType::None; break; - case DEVICE_GAMEPAD: type = ControllerType::SnesController; break; - case DEVICE_MULTITAP: type = ControllerType::Multitap; break; - case DEVICE_SNESMOUSE: type = ControllerType::SnesMouse; break; - case DEVICE_SUPERSCOPE: type = ControllerType::SuperScope; break; - } - input.Controllers[port].Type = type; - } - - _console->GetSettings()->SetInputConfig(input); + _inputDevices[port] = device; + update_core_controllers(); + update_input_descriptors(); } +} - void retro_set_memory_maps() - { - shared_ptr cart = _console->GetCartridge(); - Gameboy* gb = cart->GetGameboy(); - if(gb) { - retro_memory_descriptor descriptors[20] = {}; - uint32_t count = 0; - - auto addDescriptor = [&count, &descriptors](uint8_t* ptr, uint32_t address, uint32_t length) { - descriptors[count].ptr = ptr; - descriptors[count].start = (size_t)address; - descriptors[count].len = (size_t)length; - count++; - }; - - addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbPrgRom), 0x0000, std::min(0x8000, (int)gb->DebugGetMemorySize(SnesMemoryType::GbPrgRom))); - addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbVideoRam), 0x8000, 0x2000); - if(gb->DebugGetMemory(SnesMemoryType::GbCartRam)) { - uint32_t size = std::min(0x2000u, gb->DebugGetMemorySize(SnesMemoryType::GbCartRam)); - addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbCartRam), 0xA000, size); - } - - addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbWorkRam), 0xC000, 0x2000); - addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbWorkRam), 0xE000, 0x1E00); //WRAM Mirror - - addDescriptor(gb->DebugGetMemory(SnesMemoryType::GbHighRam), 0xFF80, 0x80); - - if(gb->DebugGetMemorySize(SnesMemoryType::GbWorkRam) == 0x8000) { - //GBC - map extra work ram at "fake" 0x10000-0x16000 range - addDescriptor(gb->DebugGetMemory(SnesMemoryType::WorkRam) + 0x2000, 0x10000, 0x6000); - } - - retro_memory_map memoryMap = {}; - memoryMap.descriptors = descriptors; - memoryMap.num_descriptors = count; - retroEnv(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &memoryMap); - } - } - - RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device) - { - if(port < 5 && _inputDevices[port] != device) { - _inputDevices[port] = device; - update_core_controllers(); - update_input_descriptors(); - } - } - - RETRO_API bool retro_load_game(const struct retro_game_info *game) - { - char *systemFolder; - if(!retroEnv(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemFolder) || !systemFolder) { - return false; - } - - char *saveFolder; - if(!retroEnv(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &saveFolder)) { - logMessage(RETRO_LOG_ERROR, "Could not find save directory.\n"); - } - - enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; - if(!retroEnv(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) { - logMessage(RETRO_LOG_ERROR, "XRGB8888 is not supported.\n"); - return false; - } - - //Expect the following structure: - // /saves/*.sav - FolderUtilities::SetHomeFolder(systemFolder); - FolderUtilities::SetFolderOverrides(saveFolder, "", "", systemFolder); - - update_settings(); - - //Plug in 2 standard controllers by default, game database will switch the controller types for recognized games - /* - _console->GetSettings()->SetControllerType(0, ControllerType::SnesController); - _console->GetSettings()->SetControllerType(1, ControllerType::SnesController); - _console->GetSettings()->SetControllerType(2, ControllerType::None); - _console->GetSettings()->SetControllerType(3, ControllerType::None);*/ - - VirtualFile romData(game->data, game->size, game->path); - VirtualFile patch; - bool result = _console->LoadRom(romData, patch); - - if(result) { - update_core_controllers(); - update_input_descriptors(); - - //Savestates in Mesen may change size over time - //Retroarch doesn't like this for netplay or rewinding - it requires the states to always be the exact same size - //So we need to send a large enough size to Retroarch to ensure Mesen's state will always fit within that buffer. - std::stringstream ss; - _console->Serialize(ss); - - //Round up to the next 1kb multiple - _saveStateSize = ((ss.str().size() * 2) + 0x400) & ~0x3FF; - retro_set_memory_maps(); - } - - return result; - } - - RETRO_API bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info) +RETRO_API bool retro_load_game(const struct retro_game_info* game) +{ + char* systemFolder; + if (!retroEnv(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemFolder) || !systemFolder) { return false; } - RETRO_API void retro_unload_game() + char* saveFolder; + if (!retroEnv(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &saveFolder)) { - _console->Stop(false); + logMessage(RETRO_LOG_ERROR, "Could not find save directory.\n"); } - RETRO_API unsigned retro_get_region() + enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; + if (!retroEnv(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) { - ConsoleRegion region = _console->GetRegion(); - return region == ConsoleRegion::Ntsc ? RETRO_REGION_NTSC : RETRO_REGION_PAL; + logMessage(RETRO_LOG_ERROR, "XRGB8888 is not supported.\n"); + return false; } - RETRO_API void retro_get_system_info(struct retro_system_info *info) - { - if(!_console) { - _console.reset(new Console()); - _console->Initialize(); - } - _mesenVersion = _console->GetSettings()->GetVersionString(); + //Expect the following structure: + // /saves/*.sav + FolderUtilities::SetHomeFolder(systemFolder); + FolderUtilities::SetFolderOverrides(saveFolder, "", "", systemFolder); - info->library_name = "Mesen-S"; - info->library_version = _mesenVersion.c_str(); - info->need_fullpath = false; - info->valid_extensions = "sfc|smc|fig|swc|gb|gbc|bs"; - info->block_extract = false; + update_settings(); + + //Plug in 2 standard controllers by default, game database will switch the controller types for recognized games + /* + _console->GetSettings()->SetControllerType(0, ControllerType::SnesController); + _console->GetSettings()->SetControllerType(1, ControllerType::SnesController); + _console->GetSettings()->SetControllerType(2, ControllerType::None); + _console->GetSettings()->SetControllerType(3, ControllerType::None);*/ + + VirtualFile romData(game->data, game->size, game->path); + VirtualFile patch; + bool result = _console->LoadRom(romData, patch); + + if (result) + { + update_core_controllers(); + update_input_descriptors(); + + //Savestates in Mesen may change size over time + //Retroarch doesn't like this for netplay or rewinding - it requires the states to always be the exact same size + //So we need to send a large enough size to Retroarch to ensure Mesen's state will always fit within that buffer. + std::stringstream ss; + _console->Serialize(ss); + + //Round up to the next 1kb multiple + _saveStateSize = ((ss.str().size() * 2) + 0x400) & ~0x3FF; + retro_set_memory_maps(); } - RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info) - { - _renderer->GetSystemAudioVideoInfo(*info, SNES_NTSC_OUT_WIDTH(256), 239 * 2); - } - - RETRO_API void *retro_get_memory_data(unsigned id) - { - shared_ptr cart = _console->GetCartridge(); - if(cart->GetGameboy()) { - switch(id) { - case RETRO_MEMORY_SAVE_RAM: return cart->GetGameboy()->DebugGetMemory(SnesMemoryType::GbCartRam); - case RETRO_MEMORY_SYSTEM_RAM: return cart->GetGameboy()->DebugGetMemory(SnesMemoryType::GbWorkRam); - } - } else { - switch(id) { - case RETRO_MEMORY_SAVE_RAM: return cart->DebugGetSaveRam(); - case RETRO_MEMORY_SYSTEM_RAM: return _console->GetMemoryManager()->DebugGetWorkRam(); - } - } - return nullptr; - } - - RETRO_API size_t retro_get_memory_size(unsigned id) - { - shared_ptr cart = _console->GetCartridge(); - if(cart->GetGameboy()) { - switch(id) { - case RETRO_MEMORY_SAVE_RAM: return cart->GetGameboy()->DebugGetMemorySize(SnesMemoryType::GbCartRam); - case RETRO_MEMORY_SYSTEM_RAM: return cart->GetGameboy()->DebugGetMemorySize(SnesMemoryType::GbWorkRam); - } - } else { - switch(id) { - case RETRO_MEMORY_SAVE_RAM: return cart->DebugGetSaveRamSize(); break; - case RETRO_MEMORY_SYSTEM_RAM: return MemoryManager::WorkRamSize; - } - } - return 0; - } + return result; +} + +RETRO_API bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info) +{ + return false; +} + +RETRO_API void retro_unload_game() +{ + _console->Stop(false); +} + +RETRO_API unsigned retro_get_region() +{ + ConsoleRegion region = _console->GetRegion(); + return region == ConsoleRegion::Ntsc ? RETRO_REGION_NTSC : RETRO_REGION_PAL; +} + +RETRO_API void retro_get_system_info(struct retro_system_info* info) +{ + if (!_console) + { + _console.reset(new Console()); + _console->Initialize(); + } + _mesenVersion = _console->GetSettings()->GetVersionString(); + + info->library_name = "Mesen-S"; + info->library_version = _mesenVersion.c_str(); + info->need_fullpath = false; + info->valid_extensions = "sfc|smc|fig|swc|gb|gbc|bs"; + info->block_extract = false; +} + +RETRO_API void retro_get_system_av_info(struct retro_system_av_info* info) +{ + _renderer->GetSystemAudioVideoInfo(*info, SNES_NTSC_OUT_WIDTH(256), 239 * 2); +} + +RETRO_API void* retro_get_memory_data(unsigned id) +{ + shared_ptr cart = _console->GetCartridge(); + if (cart->GetGameboy()) + { + switch (id) + { + case RETRO_MEMORY_SAVE_RAM: return cart->GetGameboy()->DebugGetMemory(SnesMemoryType::GbCartRam); + case RETRO_MEMORY_SYSTEM_RAM: return cart->GetGameboy()->DebugGetMemory(SnesMemoryType::GbWorkRam); + } + } + else + { + switch (id) + { + case RETRO_MEMORY_SAVE_RAM: return cart->DebugGetSaveRam(); + case RETRO_MEMORY_SYSTEM_RAM: return _console->GetMemoryManager()->DebugGetWorkRam(); + } + } + return nullptr; +} + +RETRO_API size_t retro_get_memory_size(unsigned id) +{ + shared_ptr cart = _console->GetCartridge(); + if (cart->GetGameboy()) + { + switch (id) + { + case RETRO_MEMORY_SAVE_RAM: return cart->GetGameboy()->DebugGetMemorySize(SnesMemoryType::GbCartRam); + case RETRO_MEMORY_SYSTEM_RAM: return cart->GetGameboy()->DebugGetMemorySize(SnesMemoryType::GbWorkRam); + } + } + else + { + switch (id) + { + case RETRO_MEMORY_SAVE_RAM: return cart->DebugGetSaveRamSize(); + break; + case RETRO_MEMORY_SYSTEM_RAM: return MemoryManager::WorkRamSize; + } + } + return 0; +} } diff --git a/Libretro/libretro.h b/Libretro/libretro.h index bfe42be..9acf5ac 100644 --- a/Libretro/libretro.h +++ b/Libretro/libretro.h @@ -259,29 +259,29 @@ extern "C" { /* Id values for LANGUAGE */ enum retro_language { - RETRO_LANGUAGE_ENGLISH = 0, - RETRO_LANGUAGE_JAPANESE = 1, - RETRO_LANGUAGE_FRENCH = 2, - RETRO_LANGUAGE_SPANISH = 3, - RETRO_LANGUAGE_GERMAN = 4, - RETRO_LANGUAGE_ITALIAN = 5, - RETRO_LANGUAGE_DUTCH = 6, - RETRO_LANGUAGE_PORTUGUESE_BRAZIL = 7, - RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8, - RETRO_LANGUAGE_RUSSIAN = 9, - RETRO_LANGUAGE_KOREAN = 10, - RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11, - RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 12, - RETRO_LANGUAGE_ESPERANTO = 13, - RETRO_LANGUAGE_POLISH = 14, - RETRO_LANGUAGE_VIETNAMESE = 15, - RETRO_LANGUAGE_ARABIC = 16, - RETRO_LANGUAGE_GREEK = 17, - RETRO_LANGUAGE_TURKISH = 18, - RETRO_LANGUAGE_LAST, + RETRO_LANGUAGE_ENGLISH = 0, + RETRO_LANGUAGE_JAPANESE = 1, + RETRO_LANGUAGE_FRENCH = 2, + RETRO_LANGUAGE_SPANISH = 3, + RETRO_LANGUAGE_GERMAN = 4, + RETRO_LANGUAGE_ITALIAN = 5, + RETRO_LANGUAGE_DUTCH = 6, + RETRO_LANGUAGE_PORTUGUESE_BRAZIL = 7, + RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8, + RETRO_LANGUAGE_RUSSIAN = 9, + RETRO_LANGUAGE_KOREAN = 10, + RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11, + RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 12, + RETRO_LANGUAGE_ESPERANTO = 13, + RETRO_LANGUAGE_POLISH = 14, + RETRO_LANGUAGE_VIETNAMESE = 15, + RETRO_LANGUAGE_ARABIC = 16, + RETRO_LANGUAGE_GREEK = 17, + RETRO_LANGUAGE_TURKISH = 18, + RETRO_LANGUAGE_LAST, - /* Ensure sizeof(enum) == sizeof(int) */ - RETRO_LANGUAGE_DUMMY = INT_MAX + /* Ensure sizeof(enum) == sizeof(int) */ + RETRO_LANGUAGE_DUMMY = INT_MAX }; /* Passed to retro_get_memory_data/size(). @@ -311,173 +311,173 @@ enum retro_language /* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */ enum retro_key { - RETROK_UNKNOWN = 0, - RETROK_FIRST = 0, - RETROK_BACKSPACE = 8, - RETROK_TAB = 9, - RETROK_CLEAR = 12, - RETROK_RETURN = 13, - RETROK_PAUSE = 19, - RETROK_ESCAPE = 27, - RETROK_SPACE = 32, - RETROK_EXCLAIM = 33, - RETROK_QUOTEDBL = 34, - RETROK_HASH = 35, - RETROK_DOLLAR = 36, - RETROK_AMPERSAND = 38, - RETROK_QUOTE = 39, - RETROK_LEFTPAREN = 40, - RETROK_RIGHTPAREN = 41, - RETROK_ASTERISK = 42, - RETROK_PLUS = 43, - RETROK_COMMA = 44, - RETROK_MINUS = 45, - RETROK_PERIOD = 46, - RETROK_SLASH = 47, - RETROK_0 = 48, - RETROK_1 = 49, - RETROK_2 = 50, - RETROK_3 = 51, - RETROK_4 = 52, - RETROK_5 = 53, - RETROK_6 = 54, - RETROK_7 = 55, - RETROK_8 = 56, - RETROK_9 = 57, - RETROK_COLON = 58, - RETROK_SEMICOLON = 59, - RETROK_LESS = 60, - RETROK_EQUALS = 61, - RETROK_GREATER = 62, - RETROK_QUESTION = 63, - RETROK_AT = 64, - RETROK_LEFTBRACKET = 91, - RETROK_BACKSLASH = 92, - RETROK_RIGHTBRACKET = 93, - RETROK_CARET = 94, - RETROK_UNDERSCORE = 95, - RETROK_BACKQUOTE = 96, - RETROK_a = 97, - RETROK_b = 98, - RETROK_c = 99, - RETROK_d = 100, - RETROK_e = 101, - RETROK_f = 102, - RETROK_g = 103, - RETROK_h = 104, - RETROK_i = 105, - RETROK_j = 106, - RETROK_k = 107, - RETROK_l = 108, - RETROK_m = 109, - RETROK_n = 110, - RETROK_o = 111, - RETROK_p = 112, - RETROK_q = 113, - RETROK_r = 114, - RETROK_s = 115, - RETROK_t = 116, - RETROK_u = 117, - RETROK_v = 118, - RETROK_w = 119, - RETROK_x = 120, - RETROK_y = 121, - RETROK_z = 122, - RETROK_LEFTBRACE = 123, - RETROK_BAR = 124, - RETROK_RIGHTBRACE = 125, - RETROK_TILDE = 126, - RETROK_DELETE = 127, + RETROK_UNKNOWN = 0, + RETROK_FIRST = 0, + RETROK_BACKSPACE = 8, + RETROK_TAB = 9, + RETROK_CLEAR = 12, + RETROK_RETURN = 13, + RETROK_PAUSE = 19, + RETROK_ESCAPE = 27, + RETROK_SPACE = 32, + RETROK_EXCLAIM = 33, + RETROK_QUOTEDBL = 34, + RETROK_HASH = 35, + RETROK_DOLLAR = 36, + RETROK_AMPERSAND = 38, + RETROK_QUOTE = 39, + RETROK_LEFTPAREN = 40, + RETROK_RIGHTPAREN = 41, + RETROK_ASTERISK = 42, + RETROK_PLUS = 43, + RETROK_COMMA = 44, + RETROK_MINUS = 45, + RETROK_PERIOD = 46, + RETROK_SLASH = 47, + RETROK_0 = 48, + RETROK_1 = 49, + RETROK_2 = 50, + RETROK_3 = 51, + RETROK_4 = 52, + RETROK_5 = 53, + RETROK_6 = 54, + RETROK_7 = 55, + RETROK_8 = 56, + RETROK_9 = 57, + RETROK_COLON = 58, + RETROK_SEMICOLON = 59, + RETROK_LESS = 60, + RETROK_EQUALS = 61, + RETROK_GREATER = 62, + RETROK_QUESTION = 63, + RETROK_AT = 64, + RETROK_LEFTBRACKET = 91, + RETROK_BACKSLASH = 92, + RETROK_RIGHTBRACKET = 93, + RETROK_CARET = 94, + RETROK_UNDERSCORE = 95, + RETROK_BACKQUOTE = 96, + RETROK_a = 97, + RETROK_b = 98, + RETROK_c = 99, + RETROK_d = 100, + RETROK_e = 101, + RETROK_f = 102, + RETROK_g = 103, + RETROK_h = 104, + RETROK_i = 105, + RETROK_j = 106, + RETROK_k = 107, + RETROK_l = 108, + RETROK_m = 109, + RETROK_n = 110, + RETROK_o = 111, + RETROK_p = 112, + RETROK_q = 113, + RETROK_r = 114, + RETROK_s = 115, + RETROK_t = 116, + RETROK_u = 117, + RETROK_v = 118, + RETROK_w = 119, + RETROK_x = 120, + RETROK_y = 121, + RETROK_z = 122, + RETROK_LEFTBRACE = 123, + RETROK_BAR = 124, + RETROK_RIGHTBRACE = 125, + RETROK_TILDE = 126, + RETROK_DELETE = 127, - RETROK_KP0 = 256, - RETROK_KP1 = 257, - RETROK_KP2 = 258, - RETROK_KP3 = 259, - RETROK_KP4 = 260, - RETROK_KP5 = 261, - RETROK_KP6 = 262, - RETROK_KP7 = 263, - RETROK_KP8 = 264, - RETROK_KP9 = 265, - RETROK_KP_PERIOD = 266, - RETROK_KP_DIVIDE = 267, - RETROK_KP_MULTIPLY = 268, - RETROK_KP_MINUS = 269, - RETROK_KP_PLUS = 270, - RETROK_KP_ENTER = 271, - RETROK_KP_EQUALS = 272, + RETROK_KP0 = 256, + RETROK_KP1 = 257, + RETROK_KP2 = 258, + RETROK_KP3 = 259, + RETROK_KP4 = 260, + RETROK_KP5 = 261, + RETROK_KP6 = 262, + RETROK_KP7 = 263, + RETROK_KP8 = 264, + RETROK_KP9 = 265, + RETROK_KP_PERIOD = 266, + RETROK_KP_DIVIDE = 267, + RETROK_KP_MULTIPLY = 268, + RETROK_KP_MINUS = 269, + RETROK_KP_PLUS = 270, + RETROK_KP_ENTER = 271, + RETROK_KP_EQUALS = 272, - RETROK_UP = 273, - RETROK_DOWN = 274, - RETROK_RIGHT = 275, - RETROK_LEFT = 276, - RETROK_INSERT = 277, - RETROK_HOME = 278, - RETROK_END = 279, - RETROK_PAGEUP = 280, - RETROK_PAGEDOWN = 281, + RETROK_UP = 273, + RETROK_DOWN = 274, + RETROK_RIGHT = 275, + RETROK_LEFT = 276, + RETROK_INSERT = 277, + RETROK_HOME = 278, + RETROK_END = 279, + RETROK_PAGEUP = 280, + RETROK_PAGEDOWN = 281, - RETROK_F1 = 282, - RETROK_F2 = 283, - RETROK_F3 = 284, - RETROK_F4 = 285, - RETROK_F5 = 286, - RETROK_F6 = 287, - RETROK_F7 = 288, - RETROK_F8 = 289, - RETROK_F9 = 290, - RETROK_F10 = 291, - RETROK_F11 = 292, - RETROK_F12 = 293, - RETROK_F13 = 294, - RETROK_F14 = 295, - RETROK_F15 = 296, + RETROK_F1 = 282, + RETROK_F2 = 283, + RETROK_F3 = 284, + RETROK_F4 = 285, + RETROK_F5 = 286, + RETROK_F6 = 287, + RETROK_F7 = 288, + RETROK_F8 = 289, + RETROK_F9 = 290, + RETROK_F10 = 291, + RETROK_F11 = 292, + RETROK_F12 = 293, + RETROK_F13 = 294, + RETROK_F14 = 295, + RETROK_F15 = 296, - RETROK_NUMLOCK = 300, - RETROK_CAPSLOCK = 301, - RETROK_SCROLLOCK = 302, - RETROK_RSHIFT = 303, - RETROK_LSHIFT = 304, - RETROK_RCTRL = 305, - RETROK_LCTRL = 306, - RETROK_RALT = 307, - RETROK_LALT = 308, - RETROK_RMETA = 309, - RETROK_LMETA = 310, - RETROK_LSUPER = 311, - RETROK_RSUPER = 312, - RETROK_MODE = 313, - RETROK_COMPOSE = 314, + RETROK_NUMLOCK = 300, + RETROK_CAPSLOCK = 301, + RETROK_SCROLLOCK = 302, + RETROK_RSHIFT = 303, + RETROK_LSHIFT = 304, + RETROK_RCTRL = 305, + RETROK_LCTRL = 306, + RETROK_RALT = 307, + RETROK_LALT = 308, + RETROK_RMETA = 309, + RETROK_LMETA = 310, + RETROK_LSUPER = 311, + RETROK_RSUPER = 312, + RETROK_MODE = 313, + RETROK_COMPOSE = 314, - RETROK_HELP = 315, - RETROK_PRINT = 316, - RETROK_SYSREQ = 317, - RETROK_BREAK = 318, - RETROK_MENU = 319, - RETROK_POWER = 320, - RETROK_EURO = 321, - RETROK_UNDO = 322, - RETROK_OEM_102 = 323, + RETROK_HELP = 315, + RETROK_PRINT = 316, + RETROK_SYSREQ = 317, + RETROK_BREAK = 318, + RETROK_MENU = 319, + RETROK_POWER = 320, + RETROK_EURO = 321, + RETROK_UNDO = 322, + RETROK_OEM_102 = 323, - RETROK_LAST, + RETROK_LAST, - RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ + RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ }; enum retro_mod { - RETROKMOD_NONE = 0x0000, + RETROKMOD_NONE = 0x0000, - RETROKMOD_SHIFT = 0x01, - RETROKMOD_CTRL = 0x02, - RETROKMOD_ALT = 0x04, - RETROKMOD_META = 0x08, + RETROKMOD_SHIFT = 0x01, + RETROKMOD_CTRL = 0x02, + RETROKMOD_ALT = 0x04, + RETROKMOD_META = 0x08, - RETROKMOD_NUMLOCK = 0x10, - RETROKMOD_CAPSLOCK = 0x20, - RETROKMOD_SCROLLOCK = 0x40, + RETROKMOD_NUMLOCK = 0x10, + RETROKMOD_CAPSLOCK = 0x20, + RETROKMOD_SCROLLOCK = 0x40, - RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ + RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ }; /* If set, this call is not part of the public libretro API yet. It can @@ -504,9 +504,9 @@ enum retro_mod * passing NULL to video frame callback. */ - /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), - * and reserved to avoid possible ABI clash. - */ +/* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), + * and reserved to avoid possible ABI clash. + */ #define RETRO_ENVIRONMENT_SET_MESSAGE 6 /* const struct retro_message * -- * Sets a message to be displayed in implementation-specific manner @@ -521,771 +521,771 @@ enum retro_mod * way to shutdown the game from a menu item or similar. */ #define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8 - /* const unsigned * -- - * Gives a hint to the frontend how demanding this implementation - * is on a system. E.g. reporting a level of 2 means - * this implementation should run decently on all frontends - * of level 2 and up. - * - * It can be used by the frontend to potentially warn - * about too demanding implementations. - * - * The levels are "floating". - * - * This function can be called on a per-game basis, - * as certain games an implementation can play might be - * particularly demanding. - * If called, it should be called in retro_load_game(). - */ +/* const unsigned * -- + * Gives a hint to the frontend how demanding this implementation + * is on a system. E.g. reporting a level of 2 means + * this implementation should run decently on all frontends + * of level 2 and up. + * + * It can be used by the frontend to potentially warn + * about too demanding implementations. + * + * The levels are "floating". + * + * This function can be called on a per-game basis, + * as certain games an implementation can play might be + * particularly demanding. + * If called, it should be called in retro_load_game(). + */ #define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9 - /* const char ** -- - * Returns the "system" directory of the frontend. - * This directory can be used to store system specific - * content such as BIOSes, configuration data, etc. - * The returned value can be NULL. - * If so, no such directory is defined, - * and it's up to the implementation to find a suitable directory. - * - * NOTE: Some cores used this folder also for "save" data such as - * memory cards, etc, for lack of a better place to put it. - * This is now discouraged, and if possible, cores should try to - * use the new GET_SAVE_DIRECTORY. - */ +/* const char ** -- + * Returns the "system" directory of the frontend. + * This directory can be used to store system specific + * content such as BIOSes, configuration data, etc. + * The returned value can be NULL. + * If so, no such directory is defined, + * and it's up to the implementation to find a suitable directory. + * + * NOTE: Some cores used this folder also for "save" data such as + * memory cards, etc, for lack of a better place to put it. + * This is now discouraged, and if possible, cores should try to + * use the new GET_SAVE_DIRECTORY. + */ #define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10 - /* const enum retro_pixel_format * -- - * Sets the internal pixel format used by the implementation. - * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555. - * This pixel format however, is deprecated (see enum retro_pixel_format). - * If the call returns false, the frontend does not support this pixel - * format. - * - * This function should be called inside retro_load_game() or - * retro_get_system_av_info(). - */ +/* const enum retro_pixel_format * -- + * Sets the internal pixel format used by the implementation. + * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555. + * This pixel format however, is deprecated (see enum retro_pixel_format). + * If the call returns false, the frontend does not support this pixel + * format. + * + * This function should be called inside retro_load_game() or + * retro_get_system_av_info(). + */ #define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11 - /* const struct retro_input_descriptor * -- - * Sets an array of retro_input_descriptors. - * It is up to the frontend to present this in a usable way. - * The array is terminated by retro_input_descriptor::description - * being set to NULL. - * This function can be called at any time, but it is recommended - * to call it as early as possible. - */ +/* const struct retro_input_descriptor * -- + * Sets an array of retro_input_descriptors. + * It is up to the frontend to present this in a usable way. + * The array is terminated by retro_input_descriptor::description + * being set to NULL. + * This function can be called at any time, but it is recommended + * to call it as early as possible. + */ #define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12 - /* const struct retro_keyboard_callback * -- - * Sets a callback function used to notify core about keyboard events. - */ +/* const struct retro_keyboard_callback * -- + * Sets a callback function used to notify core about keyboard events. + */ #define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13 - /* const struct retro_disk_control_callback * -- - * Sets an interface which frontend can use to eject and insert - * disk images. - * This is used for games which consist of multiple images and - * must be manually swapped out by the user (e.g. PSX). - */ +/* const struct retro_disk_control_callback * -- + * Sets an interface which frontend can use to eject and insert + * disk images. + * This is used for games which consist of multiple images and + * must be manually swapped out by the user (e.g. PSX). + */ #define RETRO_ENVIRONMENT_SET_HW_RENDER 14 - /* struct retro_hw_render_callback * -- - * Sets an interface to let a libretro core render with - * hardware acceleration. - * Should be called in retro_load_game(). - * If successful, libretro cores will be able to render to a - * frontend-provided framebuffer. - * The size of this framebuffer will be at least as large as - * max_width/max_height provided in get_av_info(). - * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or - * NULL to retro_video_refresh_t. - */ +/* struct retro_hw_render_callback * -- + * Sets an interface to let a libretro core render with + * hardware acceleration. + * Should be called in retro_load_game(). + * If successful, libretro cores will be able to render to a + * frontend-provided framebuffer. + * The size of this framebuffer will be at least as large as + * max_width/max_height provided in get_av_info(). + * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or + * NULL to retro_video_refresh_t. + */ #define RETRO_ENVIRONMENT_GET_VARIABLE 15 - /* struct retro_variable * -- - * Interface to acquire user-defined information from environment - * that cannot feasibly be supported in a multi-system way. - * 'key' should be set to a key which has already been set by - * SET_VARIABLES. - * 'data' will be set to a value or NULL. - */ +/* struct retro_variable * -- + * Interface to acquire user-defined information from environment + * that cannot feasibly be supported in a multi-system way. + * 'key' should be set to a key which has already been set by + * SET_VARIABLES. + * 'data' will be set to a value or NULL. + */ #define RETRO_ENVIRONMENT_SET_VARIABLES 16 - /* const struct retro_variable * -- - * Allows an implementation to signal the environment - * which variables it might want to check for later using - * GET_VARIABLE. - * This allows the frontend to present these variables to - * a user dynamically. - * This should be called the first time as early as - * possible (ideally in retro_set_environment). - * Afterward it may be called again for the core to communicate - * updated options to the frontend, but the number of core - * options must not change from the number in the initial call. - * - * 'data' points to an array of retro_variable structs - * terminated by a { NULL, NULL } element. - * retro_variable::key should be namespaced to not collide - * with other implementations' keys. E.g. A core called - * 'foo' should use keys named as 'foo_option'. - * retro_variable::value should contain a human readable - * description of the key as well as a '|' delimited list - * of expected values. - * - * The number of possible options should be very limited, - * i.e. it should be feasible to cycle through options - * without a keyboard. - * - * First entry should be treated as a default. - * - * Example entry: - * { "foo_option", "Speed hack coprocessor X; false|true" } - * - * Text before first ';' is description. This ';' must be - * followed by a space, and followed by a list of possible - * values split up with '|'. - * - * Only strings are operated on. The possible values will - * generally be displayed and stored as-is by the frontend. - */ +/* const struct retro_variable * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterward it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * 'data' points to an array of retro_variable structs + * terminated by a { NULL, NULL } element. + * retro_variable::key should be namespaced to not collide + * with other implementations' keys. E.g. A core called + * 'foo' should use keys named as 'foo_option'. + * retro_variable::value should contain a human readable + * description of the key as well as a '|' delimited list + * of expected values. + * + * The number of possible options should be very limited, + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * First entry should be treated as a default. + * + * Example entry: + * { "foo_option", "Speed hack coprocessor X; false|true" } + * + * Text before first ';' is description. This ';' must be + * followed by a space, and followed by a list of possible + * values split up with '|'. + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ #define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17 - /* bool * -- - * Result is set to true if some variables are updated by - * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. - * Variables should be queried with GET_VARIABLE. - */ +/* bool * -- + * Result is set to true if some variables are updated by + * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. + * Variables should be queried with GET_VARIABLE. + */ #define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 - /* const bool * -- - * If true, the libretro implementation supports calls to - * retro_load_game() with NULL as argument. - * Used by cores which can run without particular game data. - * This should be called within retro_set_environment() only. - */ +/* const bool * -- + * If true, the libretro implementation supports calls to + * retro_load_game() with NULL as argument. + * Used by cores which can run without particular game data. + * This should be called within retro_set_environment() only. + */ #define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19 - /* const char ** -- - * Retrieves the absolute path from where this libretro - * implementation was loaded. - * NULL is returned if the libretro was loaded statically - * (i.e. linked statically to frontend), or if the path cannot be - * determined. - * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can - * be loaded without ugly hacks. - */ +/* const char ** -- + * Retrieves the absolute path from where this libretro + * implementation was loaded. + * NULL is returned if the libretro was loaded statically + * (i.e. linked statically to frontend), or if the path cannot be + * determined. + * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can + * be loaded without ugly hacks. + */ - /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. - * It was not used by any known core at the time, - * and was removed from the API. */ +/* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. + * It was not used by any known core at the time, + * and was removed from the API. */ #define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 - /* const struct retro_frame_time_callback * -- - * Lets the core know how much time has passed since last - * invocation of retro_run(). - * The frontend can tamper with the timing to fake fast-forward, - * slow-motion, frame stepping, etc. - * In this case the delta time will use the reference value - * in frame_time_callback.. - */ +/* const struct retro_frame_time_callback * -- + * Lets the core know how much time has passed since last + * invocation of retro_run(). + * The frontend can tamper with the timing to fake fast-forward, + * slow-motion, frame stepping, etc. + * In this case the delta time will use the reference value + * in frame_time_callback.. + */ #define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 - /* const struct retro_audio_callback * -- - * Sets an interface which is used to notify a libretro core about audio - * being available for writing. - * The callback can be called from any thread, so a core using this must - * have a thread safe audio implementation. - * It is intended for games where audio and video are completely - * asynchronous and audio can be generated on the fly. - * This interface is not recommended for use with emulators which have - * highly synchronous audio. - * - * The callback only notifies about writability; the libretro core still - * has to call the normal audio callbacks - * to write audio. The audio callbacks must be called from within the - * notification callback. - * The amount of audio data to write is up to the implementation. - * Generally, the audio callback will be called continously in a loop. - * - * Due to thread safety guarantees and lack of sync between audio and - * video, a frontend can selectively disallow this interface based on - * internal configuration. A core using this interface must also - * implement the "normal" audio interface. - * - * A libretro core using SET_AUDIO_CALLBACK should also make use of - * SET_FRAME_TIME_CALLBACK. - */ +/* const struct retro_audio_callback * -- + * Sets an interface which is used to notify a libretro core about audio + * being available for writing. + * The callback can be called from any thread, so a core using this must + * have a thread safe audio implementation. + * It is intended for games where audio and video are completely + * asynchronous and audio can be generated on the fly. + * This interface is not recommended for use with emulators which have + * highly synchronous audio. + * + * The callback only notifies about writability; the libretro core still + * has to call the normal audio callbacks + * to write audio. The audio callbacks must be called from within the + * notification callback. + * The amount of audio data to write is up to the implementation. + * Generally, the audio callback will be called continously in a loop. + * + * Due to thread safety guarantees and lack of sync between audio and + * video, a frontend can selectively disallow this interface based on + * internal configuration. A core using this interface must also + * implement the "normal" audio interface. + * + * A libretro core using SET_AUDIO_CALLBACK should also make use of + * SET_FRAME_TIME_CALLBACK. + */ #define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 - /* struct retro_rumble_interface * -- - * Gets an interface which is used by a libretro core to set - * state of rumble motors in controllers. - * A strong and weak motor is supported, and they can be - * controlled indepedently. - */ +/* struct retro_rumble_interface * -- + * Gets an interface which is used by a libretro core to set + * state of rumble motors in controllers. + * A strong and weak motor is supported, and they can be + * controlled indepedently. + */ #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 - /* uint64_t * -- - * Gets a bitmask telling which device type are expected to be - * handled properly in a call to retro_input_state_t. - * Devices which are not handled or recognized always return - * 0 in retro_input_state_t. - * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). - * Should only be called in retro_run(). - */ +/* uint64_t * -- + * Gets a bitmask telling which device type are expected to be + * handled properly in a call to retro_input_state_t. + * Devices which are not handled or recognized always return + * 0 in retro_input_state_t. + * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). + * Should only be called in retro_run(). + */ #define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_sensor_interface * -- - * Gets access to the sensor interface. - * The purpose of this interface is to allow - * setting state related to sensors such as polling rate, - * enabling/disable it entirely, etc. - * Reading sensor state is done via the normal - * input_state_callback API. - */ +/* struct retro_sensor_interface * -- + * Gets access to the sensor interface. + * The purpose of this interface is to allow + * setting state related to sensors such as polling rate, + * enabling/disable it entirely, etc. + * Reading sensor state is done via the normal + * input_state_callback API. + */ #define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_camera_callback * -- - * Gets an interface to a video camera driver. - * A libretro core can use this interface to get access to a - * video camera. - * New video frames are delivered in a callback in same - * thread as retro_run(). - * - * GET_CAMERA_INTERFACE should be called in retro_load_game(). - * - * Depending on the camera implementation used, camera frames - * will be delivered as a raw framebuffer, - * or as an OpenGL texture directly. - * - * The core has to tell the frontend here which types of - * buffers can be handled properly. - * An OpenGL texture can only be handled when using a - * libretro GL core (SET_HW_RENDER). - * It is recommended to use a libretro GL core when - * using camera interface. - * - * The camera is not started automatically. The retrieved start/stop - * functions must be used to explicitly - * start and stop the camera driver. - */ +/* struct retro_camera_callback * -- + * Gets an interface to a video camera driver. + * A libretro core can use this interface to get access to a + * video camera. + * New video frames are delivered in a callback in same + * thread as retro_run(). + * + * GET_CAMERA_INTERFACE should be called in retro_load_game(). + * + * Depending on the camera implementation used, camera frames + * will be delivered as a raw framebuffer, + * or as an OpenGL texture directly. + * + * The core has to tell the frontend here which types of + * buffers can be handled properly. + * An OpenGL texture can only be handled when using a + * libretro GL core (SET_HW_RENDER). + * It is recommended to use a libretro GL core when + * using camera interface. + * + * The camera is not started automatically. The retrieved start/stop + * functions must be used to explicitly + * start and stop the camera driver. + */ #define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27 - /* struct retro_log_callback * -- - * Gets an interface for logging. This is useful for - * logging in a cross-platform way - * as certain platforms cannot use stderr for logging. - * It also allows the frontend to - * show logging information in a more suitable way. - * If this interface is not used, libretro cores should - * log to stderr as desired. - */ +/* struct retro_log_callback * -- + * Gets an interface for logging. This is useful for + * logging in a cross-platform way + * as certain platforms cannot use stderr for logging. + * It also allows the frontend to + * show logging information in a more suitable way. + * If this interface is not used, libretro cores should + * log to stderr as desired. + */ #define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28 - /* struct retro_perf_callback * -- - * Gets an interface for performance counters. This is useful - * for performance logging in a cross-platform way and for detecting - * architecture-specific features, such as SIMD support. - */ +/* struct retro_perf_callback * -- + * Gets an interface for performance counters. This is useful + * for performance logging in a cross-platform way and for detecting + * architecture-specific features, such as SIMD support. + */ #define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29 - /* struct retro_location_callback * -- - * Gets access to the location interface. - * The purpose of this interface is to be able to retrieve - * location-based information from the host device, - * such as current latitude / longitude. - */ +/* struct retro_location_callback * -- + * Gets access to the location interface. + * The purpose of this interface is to be able to retrieve + * location-based information from the host device, + * such as current latitude / longitude. + */ #define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* Old name, kept for compatibility. */ #define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30 - /* const char ** -- - * Returns the "core assets" directory of the frontend. - * This directory can be used to store specific assets that the - * core relies upon, such as art assets, - * input data, etc etc. - * The returned value can be NULL. - * If so, no such directory is defined, - * and it's up to the implementation to find a suitable directory. - */ +/* const char ** -- + * Returns the "core assets" directory of the frontend. + * This directory can be used to store specific assets that the + * core relies upon, such as art assets, + * input data, etc etc. + * The returned value can be NULL. + * If so, no such directory is defined, + * and it's up to the implementation to find a suitable directory. + */ #define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31 - /* const char ** -- - * Returns the "save" directory of the frontend, unless there is no - * save directory available. The save directory should be used to - * store SRAM, memory cards, high scores, etc, if the libretro core - * cannot use the regular memory interface (retro_get_memory_data()). - * - * If the frontend cannot designate a save directory, it will return - * NULL to indicate that the core should attempt to operate without a - * save directory set. - * - * NOTE: early libretro cores used the system directory for save - * files. Cores that need to be backwards-compatible can still check - * GET_SYSTEM_DIRECTORY. - */ +/* const char ** -- + * Returns the "save" directory of the frontend, unless there is no + * save directory available. The save directory should be used to + * store SRAM, memory cards, high scores, etc, if the libretro core + * cannot use the regular memory interface (retro_get_memory_data()). + * + * If the frontend cannot designate a save directory, it will return + * NULL to indicate that the core should attempt to operate without a + * save directory set. + * + * NOTE: early libretro cores used the system directory for save + * files. Cores that need to be backwards-compatible can still check + * GET_SYSTEM_DIRECTORY. + */ #define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 - /* const struct retro_system_av_info * -- - * Sets a new av_info structure. This can only be called from - * within retro_run(). - * This should *only* be used if the core is completely altering the - * internal resolutions, aspect ratios, timings, sampling rate, etc. - * Calling this can require a full reinitialization of video/audio - * drivers in the frontend, - * - * so it is important to call it very sparingly, and usually only with - * the users explicit consent. - * An eventual driver reinitialize will happen so that video and - * audio callbacks - * happening after this call within the same retro_run() call will - * target the newly initialized driver. - * - * This callback makes it possible to support configurable resolutions - * in games, which can be useful to - * avoid setting the "worst case" in max_width/max_height. - * - * ***HIGHLY RECOMMENDED*** Do not call this callback every time - * resolution changes in an emulator core if it's - * expected to be a temporary change, for the reasons of possible - * driver reinitialization. - * This call is not a free pass for not trying to provide - * correct values in retro_get_system_av_info(). If you need to change - * things like aspect ratio or nominal width/height, - * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant - * of SET_SYSTEM_AV_INFO. - * - * If this returns false, the frontend does not acknowledge a - * changed av_info struct. - */ +/* const struct retro_system_av_info * -- + * Sets a new av_info structure. This can only be called from + * within retro_run(). + * This should *only* be used if the core is completely altering the + * internal resolutions, aspect ratios, timings, sampling rate, etc. + * Calling this can require a full reinitialization of video/audio + * drivers in the frontend, + * + * so it is important to call it very sparingly, and usually only with + * the users explicit consent. + * An eventual driver reinitialize will happen so that video and + * audio callbacks + * happening after this call within the same retro_run() call will + * target the newly initialized driver. + * + * This callback makes it possible to support configurable resolutions + * in games, which can be useful to + * avoid setting the "worst case" in max_width/max_height. + * + * ***HIGHLY RECOMMENDED*** Do not call this callback every time + * resolution changes in an emulator core if it's + * expected to be a temporary change, for the reasons of possible + * driver reinitialization. + * This call is not a free pass for not trying to provide + * correct values in retro_get_system_av_info(). If you need to change + * things like aspect ratio or nominal width/height, + * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant + * of SET_SYSTEM_AV_INFO. + * + * If this returns false, the frontend does not acknowledge a + * changed av_info struct. + */ #define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33 - /* const struct retro_get_proc_address_interface * -- - * Allows a libretro core to announce support for the - * get_proc_address() interface. - * This interface allows for a standard way to extend libretro where - * use of environment calls are too indirect, - * e.g. for cases where the frontend wants to call directly into the core. - * - * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK - * **MUST** be called from within retro_set_environment(). - */ +/* const struct retro_get_proc_address_interface * -- + * Allows a libretro core to announce support for the + * get_proc_address() interface. + * This interface allows for a standard way to extend libretro where + * use of environment calls are too indirect, + * e.g. for cases where the frontend wants to call directly into the core. + * + * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK + * **MUST** be called from within retro_set_environment(). + */ #define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34 - /* const struct retro_subsystem_info * -- - * This environment call introduces the concept of libretro "subsystems". - * A subsystem is a variant of a libretro core which supports - * different kinds of games. - * The purpose of this is to support e.g. emulators which might - * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo. - * It can also be used to pick among subsystems in an explicit way - * if the libretro implementation is a multi-system emulator itself. - * - * Loading a game via a subsystem is done with retro_load_game_special(), - * and this environment call allows a libretro core to expose which - * subsystems are supported for use with retro_load_game_special(). - * A core passes an array of retro_game_special_info which is terminated - * with a zeroed out retro_game_special_info struct. - * - * If a core wants to use this functionality, SET_SUBSYSTEM_INFO - * **MUST** be called from within retro_set_environment(). - */ +/* const struct retro_subsystem_info * -- + * This environment call introduces the concept of libretro "subsystems". + * A subsystem is a variant of a libretro core which supports + * different kinds of games. + * The purpose of this is to support e.g. emulators which might + * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo. + * It can also be used to pick among subsystems in an explicit way + * if the libretro implementation is a multi-system emulator itself. + * + * Loading a game via a subsystem is done with retro_load_game_special(), + * and this environment call allows a libretro core to expose which + * subsystems are supported for use with retro_load_game_special(). + * A core passes an array of retro_game_special_info which is terminated + * with a zeroed out retro_game_special_info struct. + * + * If a core wants to use this functionality, SET_SUBSYSTEM_INFO + * **MUST** be called from within retro_set_environment(). + */ #define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35 - /* const struct retro_controller_info * -- - * This environment call lets a libretro core tell the frontend - * which controller subclasses are recognized in calls to - * retro_set_controller_port_device(). - * - * Some emulators such as Super Nintendo support multiple lightgun - * types which must be specifically selected from. It is therefore - * sometimes necessary for a frontend to be able to tell the core - * about a special kind of input device which is not specifcally - * provided by the Libretro API. - * - * In order for a frontend to understand the workings of those devices, - * they must be defined as a specialized subclass of the generic device - * types already defined in the libretro API. - * - * The core must pass an array of const struct retro_controller_info which - * is terminated with a blanked out struct. Each element of the - * retro_controller_info struct corresponds to the ascending port index - * that is passed to retro_set_controller_port_device() when that function - * is called to indicate to the core that the frontend has changed the - * active device subclass. SEE ALSO: retro_set_controller_port_device() - * - * The ascending input port indexes provided by the core in the struct - * are generally presented by frontends as ascending User # or Player #, - * such as Player 1, Player 2, Player 3, etc. Which device subclasses are - * supported can vary per input port. - * - * The first inner element of each entry in the retro_controller_info array - * is a retro_controller_description struct that specifies the names and - * codes of all device subclasses that are available for the corresponding - * User or Player, beginning with the generic Libretro device that the - * subclasses are derived from. The second inner element of each entry is the - * total number of subclasses that are listed in the retro_controller_description. - * - * NOTE: Even if special device types are set in the libretro core, - * libretro should only poll input based on the base input device types. - */ +/* const struct retro_controller_info * -- + * This environment call lets a libretro core tell the frontend + * which controller subclasses are recognized in calls to + * retro_set_controller_port_device(). + * + * Some emulators such as Super Nintendo support multiple lightgun + * types which must be specifically selected from. It is therefore + * sometimes necessary for a frontend to be able to tell the core + * about a special kind of input device which is not specifcally + * provided by the Libretro API. + * + * In order for a frontend to understand the workings of those devices, + * they must be defined as a specialized subclass of the generic device + * types already defined in the libretro API. + * + * The core must pass an array of const struct retro_controller_info which + * is terminated with a blanked out struct. Each element of the + * retro_controller_info struct corresponds to the ascending port index + * that is passed to retro_set_controller_port_device() when that function + * is called to indicate to the core that the frontend has changed the + * active device subclass. SEE ALSO: retro_set_controller_port_device() + * + * The ascending input port indexes provided by the core in the struct + * are generally presented by frontends as ascending User # or Player #, + * such as Player 1, Player 2, Player 3, etc. Which device subclasses are + * supported can vary per input port. + * + * The first inner element of each entry in the retro_controller_info array + * is a retro_controller_description struct that specifies the names and + * codes of all device subclasses that are available for the corresponding + * User or Player, beginning with the generic Libretro device that the + * subclasses are derived from. The second inner element of each entry is the + * total number of subclasses that are listed in the retro_controller_description. + * + * NOTE: Even if special device types are set in the libretro core, + * libretro should only poll input based on the base input device types. + */ #define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_memory_map * -- - * This environment call lets a libretro core tell the frontend - * about the memory maps this core emulates. - * This can be used to implement, for example, cheats in a core-agnostic way. - * - * Should only be used by emulators; it doesn't make much sense for - * anything else. - * It is recommended to expose all relevant pointers through - * retro_get_memory_* as well. - * - * Can be called from retro_init and retro_load_game. - */ +/* const struct retro_memory_map * -- + * This environment call lets a libretro core tell the frontend + * about the memory maps this core emulates. + * This can be used to implement, for example, cheats in a core-agnostic way. + * + * Should only be used by emulators; it doesn't make much sense for + * anything else. + * It is recommended to expose all relevant pointers through + * retro_get_memory_* as well. + * + * Can be called from retro_init and retro_load_game. + */ #define RETRO_ENVIRONMENT_SET_GEOMETRY 37 - /* const struct retro_game_geometry * -- - * This environment call is similar to SET_SYSTEM_AV_INFO for changing - * video parameters, but provides a guarantee that drivers will not be - * reinitialized. - * This can only be called from within retro_run(). - * - * The purpose of this call is to allow a core to alter nominal - * width/heights as well as aspect ratios on-the-fly, which can be - * useful for some emulators to change in run-time. - * - * max_width/max_height arguments are ignored and cannot be changed - * with this call as this could potentially require a reinitialization or a - * non-constant time operation. - * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required. - * - * A frontend must guarantee that this environment call completes in - * constant time. - */ +/* const struct retro_game_geometry * -- + * This environment call is similar to SET_SYSTEM_AV_INFO for changing + * video parameters, but provides a guarantee that drivers will not be + * reinitialized. + * This can only be called from within retro_run(). + * + * The purpose of this call is to allow a core to alter nominal + * width/heights as well as aspect ratios on-the-fly, which can be + * useful for some emulators to change in run-time. + * + * max_width/max_height arguments are ignored and cannot be changed + * with this call as this could potentially require a reinitialization or a + * non-constant time operation. + * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required. + * + * A frontend must guarantee that this environment call completes in + * constant time. + */ #define RETRO_ENVIRONMENT_GET_USERNAME 38 - /* const char ** - * Returns the specified username of the frontend, if specified by the user. - * This username can be used as a nickname for a core that has online facilities - * or any other mode where personalization of the user is desirable. - * The returned value can be NULL. - * If this environ callback is used by a core that requires a valid username, - * a default username should be specified by the core. - */ +/* const char ** + * Returns the specified username of the frontend, if specified by the user. + * This username can be used as a nickname for a core that has online facilities + * or any other mode where personalization of the user is desirable. + * The returned value can be NULL. + * If this environ callback is used by a core that requires a valid username, + * a default username should be specified by the core. + */ #define RETRO_ENVIRONMENT_GET_LANGUAGE 39 - /* unsigned * -- - * Returns the specified language of the frontend, if specified by the user. - * It can be used by the core for localization purposes. - */ +/* unsigned * -- + * Returns the specified language of the frontend, if specified by the user. + * It can be used by the core for localization purposes. + */ #define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_framebuffer * -- - * Returns a preallocated framebuffer which the core can use for rendering - * the frame into when not using SET_HW_RENDER. - * The framebuffer returned from this call must not be used - * after the current call to retro_run() returns. - * - * The goal of this call is to allow zero-copy behavior where a core - * can render directly into video memory, avoiding extra bandwidth cost by copying - * memory from core to video memory. - * - * If this call succeeds and the core renders into it, - * the framebuffer pointer and pitch can be passed to retro_video_refresh_t. - * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used, - * the core must pass the exact - * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER; - * i.e. passing a pointer which is offset from the - * buffer is undefined. The width, height and pitch parameters - * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER. - * - * It is possible for a frontend to return a different pixel format - * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend - * needs to perform conversion. - * - * It is still valid for a core to render to a different buffer - * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds. - * - * A frontend must make sure that the pointer obtained from this function is - * writeable (and readable). - */ +/* struct retro_framebuffer * -- + * Returns a preallocated framebuffer which the core can use for rendering + * the frame into when not using SET_HW_RENDER. + * The framebuffer returned from this call must not be used + * after the current call to retro_run() returns. + * + * The goal of this call is to allow zero-copy behavior where a core + * can render directly into video memory, avoiding extra bandwidth cost by copying + * memory from core to video memory. + * + * If this call succeeds and the core renders into it, + * the framebuffer pointer and pitch can be passed to retro_video_refresh_t. + * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used, + * the core must pass the exact + * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER; + * i.e. passing a pointer which is offset from the + * buffer is undefined. The width, height and pitch parameters + * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER. + * + * It is possible for a frontend to return a different pixel format + * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend + * needs to perform conversion. + * + * It is still valid for a core to render to a different buffer + * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds. + * + * A frontend must make sure that the pointer obtained from this function is + * writeable (and readable). + */ #define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_hw_render_interface ** -- - * Returns an API specific rendering interface for accessing API specific data. - * Not all HW rendering APIs support or need this. - * The contents of the returned pointer is specific to the rendering API - * being used. See the various headers like libretro_vulkan.h, etc. - * - * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. - * Similarly, after context_destroyed callback returns, - * the contents of the HW_RENDER_INTERFACE are invalidated. - */ +/* const struct retro_hw_render_interface ** -- + * Returns an API specific rendering interface for accessing API specific data. + * Not all HW rendering APIs support or need this. + * The contents of the returned pointer is specific to the rendering API + * being used. See the various headers like libretro_vulkan.h, etc. + * + * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. + * Similarly, after context_destroyed callback returns, + * the contents of the HW_RENDER_INTERFACE are invalidated. + */ #define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const bool * -- - * If true, the libretro implementation supports achievements - * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS - * or via retro_get_memory_data/retro_get_memory_size. - * - * This must be called before the first call to retro_run. - */ +/* const bool * -- + * If true, the libretro implementation supports achievements + * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS + * or via retro_get_memory_data/retro_get_memory_size. + * + * This must be called before the first call to retro_run. + */ #define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_hw_render_context_negotiation_interface * -- - * Sets an interface which lets the libretro core negotiate with frontend how a context is created. - * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. - * This interface will be used when the frontend is trying to create a HW rendering context, - * so it will be used after SET_HW_RENDER, but before the context_reset callback. - */ +/* const struct retro_hw_render_context_negotiation_interface * -- + * Sets an interface which lets the libretro core negotiate with frontend how a context is created. + * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. + * This interface will be used when the frontend is trying to create a HW rendering context, + * so it will be used after SET_HW_RENDER, but before the context_reset callback. + */ #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 - /* uint64_t * -- - * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't - * recognize or support. Should be set in either retro_init or retro_load_game, but not both. - */ +/* uint64_t * -- + * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't + * recognize or support. Should be set in either retro_init or retro_load_game, but not both. + */ #define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* N/A (null) * -- - * The frontend will try to use a 'shared' hardware context (mostly applicable - * to OpenGL) when a hardware context is being set up. - * - * Returns true if the frontend supports shared hardware contexts and false - * if the frontend does not support shared hardware contexts. - * - * This will do nothing on its own until SET_HW_RENDER env callbacks are - * being used. - */ +/* N/A (null) * -- + * The frontend will try to use a 'shared' hardware context (mostly applicable + * to OpenGL) when a hardware context is being set up. + * + * Returns true if the frontend supports shared hardware contexts and false + * if the frontend does not support shared hardware contexts. + * + * This will do nothing on its own until SET_HW_RENDER env callbacks are + * being used. + */ #define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_vfs_interface_info * -- - * Gets access to the VFS interface. - * VFS presence needs to be queried prior to load_game or any - * get_system/save/other_directory being called to let front end know - * core supports VFS before it starts handing out paths. - * It is recomended to do so in retro_set_environment - */ +/* struct retro_vfs_interface_info * -- + * Gets access to the VFS interface. + * VFS presence needs to be queried prior to load_game or any + * get_system/save/other_directory being called to let front end know + * core supports VFS before it starts handing out paths. + * It is recomended to do so in retro_set_environment + */ #define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_led_interface * -- - * Gets an interface which is used by a libretro core to set - * state of LEDs. - */ +/* struct retro_led_interface * -- + * Gets an interface which is used by a libretro core to set + * state of LEDs. + */ #define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* int * -- - * Tells the core if the frontend wants audio or video. - * If disabled, the frontend will discard the audio or video, - * so the core may decide to skip generating a frame or generating audio. - * This is mainly used for increasing performance. - * Bit 0 (value 1): Enable Video - * Bit 1 (value 2): Enable Audio - * Bit 2 (value 4): Use Fast Savestates. - * Bit 3 (value 8): Hard Disable Audio - * Other bits are reserved for future use and will default to zero. - * If video is disabled: - * * The frontend wants the core to not generate any video, - * including presenting frames via hardware acceleration. - * * The frontend's video frame callback will do nothing. - * * After running the frame, the video output of the next frame should be - * no different than if video was enabled, and saving and loading state - * should have no issues. - * If audio is disabled: - * * The frontend wants the core to not generate any audio. - * * The frontend's audio callbacks will do nothing. - * * After running the frame, the audio output of the next frame should be - * no different than if audio was enabled, and saving and loading state - * should have no issues. - * Fast Savestates: - * * Guaranteed to be created by the same binary that will load them. - * * Will not be written to or read from the disk. - * * Suggest that the core assumes loading state will succeed. - * * Suggest that the core updates its memory buffers in-place if possible. - * * Suggest that the core skips clearing memory. - * * Suggest that the core skips resetting the system. - * * Suggest that the core may skip validation steps. - * Hard Disable Audio: - * * Used for a secondary core when running ahead. - * * Indicates that the frontend will never need audio from the core. - * * Suggests that the core may stop synthesizing audio, but this should not - * compromise emulation accuracy. - * * Audio output for the next frame does not matter, and the frontend will - * never need an accurate audio state in the future. - * * State will never be saved when using Hard Disable Audio. - */ +/* int * -- + * Tells the core if the frontend wants audio or video. + * If disabled, the frontend will discard the audio or video, + * so the core may decide to skip generating a frame or generating audio. + * This is mainly used for increasing performance. + * Bit 0 (value 1): Enable Video + * Bit 1 (value 2): Enable Audio + * Bit 2 (value 4): Use Fast Savestates. + * Bit 3 (value 8): Hard Disable Audio + * Other bits are reserved for future use and will default to zero. + * If video is disabled: + * * The frontend wants the core to not generate any video, + * including presenting frames via hardware acceleration. + * * The frontend's video frame callback will do nothing. + * * After running the frame, the video output of the next frame should be + * no different than if video was enabled, and saving and loading state + * should have no issues. + * If audio is disabled: + * * The frontend wants the core to not generate any audio. + * * The frontend's audio callbacks will do nothing. + * * After running the frame, the audio output of the next frame should be + * no different than if audio was enabled, and saving and loading state + * should have no issues. + * Fast Savestates: + * * Guaranteed to be created by the same binary that will load them. + * * Will not be written to or read from the disk. + * * Suggest that the core assumes loading state will succeed. + * * Suggest that the core updates its memory buffers in-place if possible. + * * Suggest that the core skips clearing memory. + * * Suggest that the core skips resetting the system. + * * Suggest that the core may skip validation steps. + * Hard Disable Audio: + * * Used for a secondary core when running ahead. + * * Indicates that the frontend will never need audio from the core. + * * Suggests that the core may stop synthesizing audio, but this should not + * compromise emulation accuracy. + * * Audio output for the next frame does not matter, and the frontend will + * never need an accurate audio state in the future. + * * State will never be saved when using Hard Disable Audio. + */ #define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_midi_interface ** -- - * Returns a MIDI interface that can be used for raw data I/O. - */ +/* struct retro_midi_interface ** -- + * Returns a MIDI interface that can be used for raw data I/O. + */ #define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* bool * -- - * Boolean value that indicates whether or not the frontend is in - * fastforwarding mode. - */ +/* bool * -- +* Boolean value that indicates whether or not the frontend is in +* fastforwarding mode. +*/ #define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* float * -- - * Float value that lets us know what target refresh rate - * is curently in use by the frontend. - * - * The core can use the returned value to set an ideal - * refresh rate/framerate. - */ +/* float * -- +* Float value that lets us know what target refresh rate +* is curently in use by the frontend. +* +* The core can use the returned value to set an ideal +* refresh rate/framerate. +*/ #define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* bool * -- - * Boolean value that indicates whether or not the frontend supports - * input bitmasks being returned by retro_input_state_t. The advantage - * of this is that retro_input_state_t has to be only called once to - * grab all button states instead of multiple times. - * - * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' - * to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD). - * It will return a bitmask of all the digital buttons. - */ +/* bool * -- +* Boolean value that indicates whether or not the frontend supports +* input bitmasks being returned by retro_input_state_t. The advantage +* of this is that retro_input_state_t has to be only called once to +* grab all button states instead of multiple times. +* +* If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' +* to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD). +* It will return a bitmask of all the digital buttons. +*/ #define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52 - /* unsigned * -- - * Unsigned value is the API version number of the core options - * interface supported by the frontend. If callback return false, - * API version is assumed to be 0. - * - * In legacy code, core options are set by passing an array of - * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES. - * This may be still be done regardless of the core options - * interface version. - * - * If version is >= 1 however, core options may instead be set by - * passing an array of retro_core_option_definition structs to - * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of - * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. - * This allows the core to additionally set option sublabel information - * and/or provide localisation support. - */ +/* unsigned * -- + * Unsigned value is the API version number of the core options + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, core options are set by passing an array of + * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES. + * This may be still be done regardless of the core options + * interface version. + * + * If version is >= 1 however, core options may instead be set by + * passing an array of retro_core_option_definition structs to + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of + * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. + * This allows the core to additionally set option sublabel information + * and/or provide localisation support. + */ #define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53 - /* const struct retro_core_option_definition ** -- - * Allows an implementation to signal the environment - * which variables it might want to check for later using - * GET_VARIABLE. - * This allows the frontend to present these variables to - * a user dynamically. - * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION - * returns an API version of >= 1. - * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. - * This should be called the first time as early as - * possible (ideally in retro_set_environment). - * Afterwards it may be called again for the core to communicate - * updated options to the frontend, but the number of core - * options must not change from the number in the initial call. - * - * 'data' points to an array of retro_core_option_definition structs - * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element. - * retro_core_option_definition::key should be namespaced to not collide - * with other implementations' keys. e.g. A core called - * 'foo' should use keys named as 'foo_option'. - * retro_core_option_definition::desc should contain a human readable - * description of the key. - * retro_core_option_definition::info should contain any additional human - * readable information text that a typical user may need to - * understand the functionality of the option. - * retro_core_option_definition::values is an array of retro_core_option_value - * structs terminated by a { NULL, NULL } element. - * > retro_core_option_definition::values[index].value is an expected option - * value. - * > retro_core_option_definition::values[index].label is a human readable - * label used when displaying the value on screen. If NULL, - * the value itself is used. - * retro_core_option_definition::default_value is the default core option - * setting. It must match one of the expected option values in the - * retro_core_option_definition::values array. If it does not, or the - * default value is NULL, the first entry in the - * retro_core_option_definition::values array is treated as the default. - * - * The number of possible options should be very limited, - * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. - * i.e. it should be feasible to cycle through options - * without a keyboard. - * - * Example entry: - * { - * "foo_option", - * "Speed hack coprocessor X", - * "Provides increased performance at the expense of reduced accuracy", - * { - * { "false", NULL }, - * { "true", NULL }, - * { "unstable", "Turbo (Unstable)" }, - * { NULL, NULL }, - * }, - * "false" - * } - * - * Only strings are operated on. The possible values will - * generally be displayed and stored as-is by the frontend. - */ +/* const struct retro_core_option_definition ** -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * 'data' points to an array of retro_core_option_definition structs + * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element. + * retro_core_option_definition::key should be namespaced to not collide + * with other implementations' keys. e.g. A core called + * 'foo' should use keys named as 'foo_option'. + * retro_core_option_definition::desc should contain a human readable + * description of the key. + * retro_core_option_definition::info should contain any additional human + * readable information text that a typical user may need to + * understand the functionality of the option. + * retro_core_option_definition::values is an array of retro_core_option_value + * structs terminated by a { NULL, NULL } element. + * > retro_core_option_definition::values[index].value is an expected option + * value. + * > retro_core_option_definition::values[index].label is a human readable + * label used when displaying the value on screen. If NULL, + * the value itself is used. + * retro_core_option_definition::default_value is the default core option + * setting. It must match one of the expected option values in the + * retro_core_option_definition::values array. If it does not, or the + * default value is NULL, the first entry in the + * retro_core_option_definition::values array is treated as the default. + * + * The number of possible options should be very limited, + * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * Example entry: + * { + * "foo_option", + * "Speed hack coprocessor X", + * "Provides increased performance at the expense of reduced accuracy", + * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, + * { NULL, NULL }, + * }, + * "false" + * } + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ #define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54 - /* const struct retro_core_options_intl * -- - * Allows an implementation to signal the environment - * which variables it might want to check for later using - * GET_VARIABLE. - * This allows the frontend to present these variables to - * a user dynamically. - * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION - * returns an API version of >= 1. - * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. - * This should be called the first time as early as - * possible (ideally in retro_set_environment). - * Afterwards it may be called again for the core to communicate - * updated options to the frontend, but the number of core - * options must not change from the number in the initial call. - * - * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS, - * with the addition of localisation support. The description of the - * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted - * for further details. - * - * 'data' points to a retro_core_options_intl struct. - * - * retro_core_options_intl::us is a pointer to an array of - * retro_core_option_definition structs defining the US English - * core options implementation. It must point to a valid array. - * - * retro_core_options_intl::local is a pointer to an array of - * retro_core_option_definition structs defining core options for - * the current frontend language. It may be NULL (in which case - * retro_core_options_intl::us is used by the frontend). Any items - * missing from this array will be read from retro_core_options_intl::us - * instead. - * - * NOTE: Default core option values are always taken from the - * retro_core_options_intl::us array. Any default values in - * retro_core_options_intl::local array will be ignored. - */ +/* const struct retro_core_options_intl * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION + * returns an API version of >= 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS, + * with the addition of localisation support. The description of the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted + * for further details. + * + * 'data' points to a retro_core_options_intl struct. + * + * retro_core_options_intl::us is a pointer to an array of + * retro_core_option_definition structs defining the US English + * core options implementation. It must point to a valid array. + * + * retro_core_options_intl::local is a pointer to an array of + * retro_core_option_definition structs defining core options for + * the current frontend language. It may be NULL (in which case + * retro_core_options_intl::us is used by the frontend). Any items + * missing from this array will be read from retro_core_options_intl::us + * instead. + * + * NOTE: Default core option values are always taken from the + * retro_core_options_intl::us array. Any default values in + * retro_core_options_intl::local array will be ignored. + */ #define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55 - /* struct retro_core_option_display * -- - * - * Allows an implementation to signal the environment to show - * or hide a variable when displaying core options. This is - * considered a *suggestion*. The frontend is free to ignore - * this callback, and its implementation not considered mandatory. - * - * 'data' points to a retro_core_option_display struct - * - * retro_core_option_display::key is a variable identifier - * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS. - * - * retro_core_option_display::visible is a boolean, specifying - * whether variable should be displayed - * - * Note that all core option variables will be set visible by - * default when calling SET_VARIABLES/SET_CORE_OPTIONS. - */ +/* struct retro_core_option_display * -- + * + * Allows an implementation to signal the environment to show + * or hide a variable when displaying core options. This is + * considered a *suggestion*. The frontend is free to ignore + * this callback, and its implementation not considered mandatory. + * + * 'data' points to a retro_core_option_display struct + * + * retro_core_option_display::key is a variable identifier + * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS. + * + * retro_core_option_display::visible is a boolean, specifying + * whether variable should be displayed + * + * Note that all core option variables will be set visible by + * default when calling SET_VARIABLES/SET_CORE_OPTIONS. + */ #define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56 - /* unsigned * -- - * - * Allows an implementation to ask frontend preferred hardware - * context to use. Core should use this information to deal - * with what specific context to request with SET_HW_RENDER. - * - * 'data' points to an unsigned variable - */ +/* unsigned * -- + * + * Allows an implementation to ask frontend preferred hardware + * context to use. Core should use this information to deal + * with what specific context to request with SET_HW_RENDER. + * + * 'data' points to an unsigned variable + */ #define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57 - /* unsigned * -- - * Unsigned value is the API version number of the disk control - * interface supported by the frontend. If callback return false, - * API version is assumed to be 0. - * - * In legacy code, the disk control interface is defined by passing - * a struct of type retro_disk_control_callback to - * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. - * This may be still be done regardless of the disk control - * interface version. - * - * If version is >= 1 however, the disk control interface may - * instead be defined by passing a struct of type - * retro_disk_control_ext_callback to - * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. - * This allows the core to provide additional information about - * disk images to the frontend and/or enables extra - * disk control functionality by the frontend. - */ +/* unsigned * -- + * Unsigned value is the API version number of the disk control + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, the disk control interface is defined by passing + * a struct of type retro_disk_control_callback to + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. + * This may be still be done regardless of the disk control + * interface version. + * + * If version is >= 1 however, the disk control interface may + * instead be defined by passing a struct of type + * retro_disk_control_ext_callback to + * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE. + * This allows the core to provide additional information about + * disk images to the frontend and/or enables extra + * disk control functionality by the frontend. + */ #define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58 - /* const struct retro_disk_control_ext_callback * -- - * Sets an interface which frontend can use to eject and insert - * disk images, and also obtain information about individual - * disk image files registered by the core. - * This is used for games which consist of multiple images and - * must be manually swapped out by the user (e.g. PSX, floppy disk - * based systems). - */ +/* const struct retro_disk_control_ext_callback * -- + * Sets an interface which frontend can use to eject and insert + * disk images, and also obtain information about individual + * disk image files registered by the core. + * This is used for games which consist of multiple images and + * must be manually swapped out by the user (e.g. PSX, floppy disk + * based systems). + */ /* VFS functionality */ @@ -1339,90 +1339,92 @@ struct retro_vfs_dir_handle; /* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle * Introduced in VFS API v1 */ -typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream); +typedef const char*(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle* stream); /* Open a file for reading or writing. If path points to a directory, this will * fail. Returns the opaque file handle, or NULL for error. * Introduced in VFS API v1 */ -typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints); +typedef struct retro_vfs_file_handle*(RETRO_CALLCONV *retro_vfs_open_t +)(const char* path, unsigned mode, unsigned hints); /* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure. * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. * Introduced in VFS API v1 */ -typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream); +typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle* stream); /* Return the size of the file in bytes, or -1 for error. * Introduced in VFS API v1 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream); +typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle* stream); /* Truncate file to specified size. Returns 0 on success or -1 on error * Introduced in VFS API v2 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length); +typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle* stream, int64_t length); /* Get the current read / write position for the file. Returns -1 for error. * Introduced in VFS API v1 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream); +typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle* stream); /* Set the current read/write position for the file. Returns the new position, -1 for error. * Introduced in VFS API v1 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position); +typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle* stream, int64_t offset, + int seek_position); /* Read data from a file. Returns the number of bytes read, or -1 for error. * Introduced in VFS API v1 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len); +typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle* stream, void* s, uint64_t len); /* Write data to a file. Returns the number of bytes written, or -1 for error. * Introduced in VFS API v1 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len); +typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle* stream, const void* s, uint64_t len); /* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure. * Introduced in VFS API v1 */ -typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream); +typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle* stream); /* Delete the specified file. Returns 0 on success, -1 on failure * Introduced in VFS API v1 */ -typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path); +typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char* path); /* Rename the specified file. Returns 0 on success, -1 on failure * Introduced in VFS API v1 */ -typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path); +typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char* old_path, const char* new_path); /* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid. * Additionally stores file size in given variable, unless NULL is given. * Introduced in VFS API v3 */ -typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size); +typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char* path, int32_t* size); /* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists. * Introduced in VFS API v3 */ -typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir); +typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char* dir); /* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error. * Support for the include_hidden argument may vary depending on the platform. * Introduced in VFS API v3 */ -typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden); +typedef struct retro_vfs_dir_handle*(RETRO_CALLCONV *retro_vfs_opendir_t)(const char* dir, bool include_hidden); /* Read the directory entry at the current position, and move the read pointer to the next position. * Returns true on success, false if already on the last entry. * Introduced in VFS API v3 */ -typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream); +typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle* dirstream); /* Get the name of the last entry read. Returns a string on success, or NULL for error. * The returned string pointer is valid until the next call to readdir or closedir. * Introduced in VFS API v3 */ -typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream); +typedef const char*(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle* dirstream); /* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error). * Introduced in VFS API v3 */ -typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream); +typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle* dirstream); /* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure. * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. * Introduced in VFS API v3 */ -typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream); +typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle* dirstream); struct retro_vfs_interface { - /* VFS API v1 */ + /* VFS API v1 */ retro_vfs_get_path_t get_path; retro_vfs_open_t open; retro_vfs_close_t close; @@ -1434,54 +1436,55 @@ struct retro_vfs_interface retro_vfs_flush_t flush; retro_vfs_remove_t remove; retro_vfs_rename_t rename; - /* VFS API v2 */ - retro_vfs_truncate_t truncate; - /* VFS API v3 */ - retro_vfs_stat_t stat; - retro_vfs_mkdir_t mkdir; - retro_vfs_opendir_t opendir; - retro_vfs_readdir_t readdir; - retro_vfs_dirent_get_name_t dirent_get_name; - retro_vfs_dirent_is_dir_t dirent_is_dir; - retro_vfs_closedir_t closedir; + /* VFS API v2 */ + retro_vfs_truncate_t truncate; + /* VFS API v3 */ + retro_vfs_stat_t stat; + retro_vfs_mkdir_t mkdir; + retro_vfs_opendir_t opendir; + retro_vfs_readdir_t readdir; + retro_vfs_dirent_get_name_t dirent_get_name; + retro_vfs_dirent_is_dir_t dirent_is_dir; + retro_vfs_closedir_t closedir; }; struct retro_vfs_interface_info { - /* Set by core: should this be higher than the version the front end supports, - * front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call - * Introduced in VFS API v1 */ - uint32_t required_interface_version; + /* Set by core: should this be higher than the version the front end supports, + * front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call + * Introduced in VFS API v1 */ + uint32_t required_interface_version; - /* Frontend writes interface pointer here. The frontend also sets the actual - * version, must be at least required_interface_version. - * Introduced in VFS API v1 */ - struct retro_vfs_interface *iface; + /* Frontend writes interface pointer here. The frontend also sets the actual + * version, must be at least required_interface_version. + * Introduced in VFS API v1 */ + struct retro_vfs_interface* iface; }; enum retro_hw_render_interface_type { RETRO_HW_RENDER_INTERFACE_VULKAN = 0, - RETRO_HW_RENDER_INTERFACE_D3D9 = 1, - RETRO_HW_RENDER_INTERFACE_D3D10 = 2, - RETRO_HW_RENDER_INTERFACE_D3D11 = 3, - RETRO_HW_RENDER_INTERFACE_D3D12 = 4, - RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5, - RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX + RETRO_HW_RENDER_INTERFACE_D3D9 = 1, + RETRO_HW_RENDER_INTERFACE_D3D10 = 2, + RETRO_HW_RENDER_INTERFACE_D3D11 = 3, + RETRO_HW_RENDER_INTERFACE_D3D12 = 4, + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5, + RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX }; /* Base struct. All retro_hw_render_interface_* types * contain at least these fields. */ struct retro_hw_render_interface { - enum retro_hw_render_interface_type interface_type; - unsigned interface_version; + enum retro_hw_render_interface_type interface_type; + unsigned interface_version; }; typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state); + struct retro_led_interface { - retro_set_led_state_t set_led_state; + retro_set_led_state_t set_led_state; }; /* Retrieves the current state of the MIDI input. @@ -1494,7 +1497,7 @@ typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void); /* Reads next byte from the input stream. * Returns true if byte is read, false otherwise. */ -typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte); +typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t* byte); /* Writes byte to the output stream. * 'delta_time' is in microseconds and represent time elapsed since previous write. @@ -1507,25 +1510,25 @@ typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void); struct retro_midi_interface { - retro_midi_input_enabled_t input_enabled; - retro_midi_output_enabled_t output_enabled; - retro_midi_read_t read; - retro_midi_write_t write; - retro_midi_flush_t flush; + retro_midi_input_enabled_t input_enabled; + retro_midi_output_enabled_t output_enabled; + retro_midi_read_t read; + retro_midi_write_t write; + retro_midi_flush_t flush; }; enum retro_hw_render_context_negotiation_interface_type { - RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0, - RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0, + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX }; /* Base struct. All retro_hw_render_context_negotiation_interface_* types * contain at least these fields. */ struct retro_hw_render_context_negotiation_interface { - enum retro_hw_render_context_negotiation_interface_type interface_type; - unsigned interface_version; + enum retro_hw_render_context_negotiation_interface_type interface_type; + unsigned interface_version; }; /* Serialized state is incomplete in some way. Set if serialization is @@ -1563,112 +1566,113 @@ struct retro_hw_render_context_negotiation_interface #define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ #define RETRO_MEMDESC_MINSIZE_4 (2 << 24) #define RETRO_MEMDESC_MINSIZE_8 (3 << 24) + struct retro_memory_descriptor { - uint64_t flags; + uint64_t flags; - /* Pointer to the start of the relevant ROM or RAM chip. - * It's strongly recommended to use 'offset' if possible, rather than - * doing math on the pointer. - * - * If the same byte is mapped my multiple descriptors, their descriptors - * must have the same pointer. - * If 'start' does not point to the first byte in the pointer, put the - * difference in 'offset' instead. - * - * May be NULL if there's nothing usable here (e.g. hardware registers and - * open bus). No flags should be set if the pointer is NULL. - * It's recommended to minimize the number of descriptors if possible, - * but not mandatory. */ - void *ptr; - size_t offset; + /* Pointer to the start of the relevant ROM or RAM chip. + * It's strongly recommended to use 'offset' if possible, rather than + * doing math on the pointer. + * + * If the same byte is mapped my multiple descriptors, their descriptors + * must have the same pointer. + * If 'start' does not point to the first byte in the pointer, put the + * difference in 'offset' instead. + * + * May be NULL if there's nothing usable here (e.g. hardware registers and + * open bus). No flags should be set if the pointer is NULL. + * It's recommended to minimize the number of descriptors if possible, + * but not mandatory. */ + void* ptr; + size_t offset; - /* This is the location in the emulated address space - * where the mapping starts. */ - size_t start; + /* This is the location in the emulated address space + * where the mapping starts. */ + size_t start; - /* Which bits must be same as in 'start' for this mapping to apply. - * The first memory descriptor to claim a certain byte is the one - * that applies. - * A bit which is set in 'start' must also be set in this. - * Can be zero, in which case each byte is assumed mapped exactly once. - * In this case, 'len' must be a power of two. */ - size_t select; + /* Which bits must be same as in 'start' for this mapping to apply. + * The first memory descriptor to claim a certain byte is the one + * that applies. + * A bit which is set in 'start' must also be set in this. + * Can be zero, in which case each byte is assumed mapped exactly once. + * In this case, 'len' must be a power of two. */ + size_t select; - /* If this is nonzero, the set bits are assumed not connected to the - * memory chip's address pins. */ - size_t disconnect; + /* If this is nonzero, the set bits are assumed not connected to the + * memory chip's address pins. */ + size_t disconnect; - /* This one tells the size of the current memory area. - * If, after start+disconnect are applied, the address is higher than - * this, the highest bit of the address is cleared. - * - * If the address is still too high, the next highest bit is cleared. - * Can be zero, in which case it's assumed to be infinite (as limited - * by 'select' and 'disconnect'). */ - size_t len; + /* This one tells the size of the current memory area. + * If, after start+disconnect are applied, the address is higher than + * this, the highest bit of the address is cleared. + * + * If the address is still too high, the next highest bit is cleared. + * Can be zero, in which case it's assumed to be infinite (as limited + * by 'select' and 'disconnect'). */ + size_t len; - /* To go from emulated address to physical address, the following - * order applies: - * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */ + /* To go from emulated address to physical address, the following + * order applies: + * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */ - /* The address space name must consist of only a-zA-Z0-9_-, - * should be as short as feasible (maximum length is 8 plus the NUL), - * and may not be any other address space plus one or more 0-9A-F - * at the end. - * However, multiple memory descriptors for the same address space is - * allowed, and the address space name can be empty. NULL is treated - * as empty. - * - * Address space names are case sensitive, but avoid lowercase if possible. - * The same pointer may exist in multiple address spaces. - * - * Examples: - * blank+blank - valid (multiple things may be mapped in the same namespace) - * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace) - * 'A'+'B' - valid (neither is a prefix of each other) - * 'S'+blank - valid ('S' is not in 0-9A-F) - * 'a'+blank - valid ('a' is not in 0-9A-F) - * 'a'+'A' - valid (neither is a prefix of each other) - * 'AR'+blank - valid ('R' is not in 0-9A-F) - * 'ARB'+blank - valid (the B can't be part of the address either, because - * there is no namespace 'AR') - * blank+'B' - not valid, because it's ambigous which address space B1234 - * would refer to. - * The length can't be used for that purpose; the frontend may want - * to append arbitrary data to an address, without a separator. */ - const char *addrspace; + /* The address space name must consist of only a-zA-Z0-9_-, + * should be as short as feasible (maximum length is 8 plus the NUL), + * and may not be any other address space plus one or more 0-9A-F + * at the end. + * However, multiple memory descriptors for the same address space is + * allowed, and the address space name can be empty. NULL is treated + * as empty. + * + * Address space names are case sensitive, but avoid lowercase if possible. + * The same pointer may exist in multiple address spaces. + * + * Examples: + * blank+blank - valid (multiple things may be mapped in the same namespace) + * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace) + * 'A'+'B' - valid (neither is a prefix of each other) + * 'S'+blank - valid ('S' is not in 0-9A-F) + * 'a'+blank - valid ('a' is not in 0-9A-F) + * 'a'+'A' - valid (neither is a prefix of each other) + * 'AR'+blank - valid ('R' is not in 0-9A-F) + * 'ARB'+blank - valid (the B can't be part of the address either, because + * there is no namespace 'AR') + * blank+'B' - not valid, because it's ambigous which address space B1234 + * would refer to. + * The length can't be used for that purpose; the frontend may want + * to append arbitrary data to an address, without a separator. */ + const char* addrspace; - /* TODO: When finalizing this one, add a description field, which should be - * "WRAM" or something roughly equally long. */ + /* TODO: When finalizing this one, add a description field, which should be + * "WRAM" or something roughly equally long. */ - /* TODO: When finalizing this one, replace 'select' with 'limit', which tells - * which bits can vary and still refer to the same address (limit = ~select). - * TODO: limit? range? vary? something else? */ + /* TODO: When finalizing this one, replace 'select' with 'limit', which tells + * which bits can vary and still refer to the same address (limit = ~select). + * TODO: limit? range? vary? something else? */ - /* TODO: When finalizing this one, if 'len' is above what 'select' (or - * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len' - * and 'select' != 0, and the mappings don't tell how the system switches the - * banks. */ + /* TODO: When finalizing this one, if 'len' is above what 'select' (or + * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len' + * and 'select' != 0, and the mappings don't tell how the system switches the + * banks. */ - /* TODO: When finalizing this one, fix the 'len' bit removal order. - * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00. - * Algorithm: Take bits highest to lowest, but if it goes above len, clear - * the most recent addition and continue on the next bit. - * TODO: Can the above be optimized? Is "remove the lowest bit set in both - * pointer and 'len'" equivalent? */ + /* TODO: When finalizing this one, fix the 'len' bit removal order. + * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00. + * Algorithm: Take bits highest to lowest, but if it goes above len, clear + * the most recent addition and continue on the next bit. + * TODO: Can the above be optimized? Is "remove the lowest bit set in both + * pointer and 'len'" equivalent? */ - /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing - * the emulated memory in 32-bit chunks, native endian. But that's nothing - * compared to Darek Mihocka - * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE - * RAM backwards! I'll want to represent both of those, via some flags. - * - * I suspect MAME either didn't think of that idea, or don't want the #ifdef. - * Not sure which, nor do I really care. */ + /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing + * the emulated memory in 32-bit chunks, native endian. But that's nothing + * compared to Darek Mihocka + * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE + * RAM backwards! I'll want to represent both of those, via some flags. + * + * I suspect MAME either didn't think of that idea, or don't want the #ifdef. + * Not sure which, nor do I really care. */ - /* TODO: Some of those flags are unused and/or don't really make sense. Clean - * them up. */ + /* TODO: Some of those flags are unused and/or don't really make sense. Clean + * them up. */ }; /* The frontend may use the largest value of 'start'+'select' in a @@ -1711,91 +1715,91 @@ struct retro_memory_descriptor struct retro_memory_map { - const struct retro_memory_descriptor *descriptors; - unsigned num_descriptors; + const struct retro_memory_descriptor* descriptors; + unsigned num_descriptors; }; struct retro_controller_description { - /* Human-readable description of the controller. Even if using a generic - * input device type, this can be set to the particular device type the - * core uses. */ - const char *desc; + /* Human-readable description of the controller. Even if using a generic + * input device type, this can be set to the particular device type the + * core uses. */ + const char* desc; - /* Device type passed to retro_set_controller_port_device(). If the device - * type is a sub-class of a generic input device type, use the - * RETRO_DEVICE_SUBCLASS macro to create an ID. - * - * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */ - unsigned id; + /* Device type passed to retro_set_controller_port_device(). If the device + * type is a sub-class of a generic input device type, use the + * RETRO_DEVICE_SUBCLASS macro to create an ID. + * + * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */ + unsigned id; }; struct retro_controller_info { - const struct retro_controller_description *types; - unsigned num_types; + const struct retro_controller_description* types; + unsigned num_types; }; struct retro_subsystem_memory_info { - /* The extension associated with a memory type, e.g. "psram". */ - const char *extension; + /* The extension associated with a memory type, e.g. "psram". */ + const char* extension; - /* The memory type for retro_get_memory(). This should be at - * least 0x100 to avoid conflict with standardized - * libretro memory types. */ - unsigned type; + /* The memory type for retro_get_memory(). This should be at + * least 0x100 to avoid conflict with standardized + * libretro memory types. */ + unsigned type; }; struct retro_subsystem_rom_info { - /* Describes what the content is (SGB BIOS, GB ROM, etc). */ - const char *desc; + /* Describes what the content is (SGB BIOS, GB ROM, etc). */ + const char* desc; - /* Same definition as retro_get_system_info(). */ - const char *valid_extensions; + /* Same definition as retro_get_system_info(). */ + const char* valid_extensions; - /* Same definition as retro_get_system_info(). */ - bool need_fullpath; + /* Same definition as retro_get_system_info(). */ + bool need_fullpath; - /* Same definition as retro_get_system_info(). */ - bool block_extract; + /* Same definition as retro_get_system_info(). */ + bool block_extract; - /* This is set if the content is required to load a game. - * If this is set to false, a zeroed-out retro_game_info can be passed. */ - bool required; + /* This is set if the content is required to load a game. + * If this is set to false, a zeroed-out retro_game_info can be passed. */ + bool required; - /* Content can have multiple associated persistent - * memory types (retro_get_memory()). */ - const struct retro_subsystem_memory_info *memory; - unsigned num_memory; + /* Content can have multiple associated persistent + * memory types (retro_get_memory()). */ + const struct retro_subsystem_memory_info* memory; + unsigned num_memory; }; struct retro_subsystem_info { - /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */ - const char *desc; + /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */ + const char* desc; - /* A computer friendly short string identifier for the subsystem type. - * This name must be [a-z]. - * E.g. if desc is "Super GameBoy", this can be "sgb". - * This identifier can be used for command-line interfaces, etc. - */ - const char *ident; + /* A computer friendly short string identifier for the subsystem type. + * This name must be [a-z]. + * E.g. if desc is "Super GameBoy", this can be "sgb". + * This identifier can be used for command-line interfaces, etc. + */ + const char* ident; - /* Infos for each content file. The first entry is assumed to be the - * "most significant" content for frontend purposes. - * E.g. with Super GameBoy, the first content should be the GameBoy ROM, - * as it is the most "significant" content to a user. - * If a frontend creates new file paths based on the content used - * (e.g. savestates), it should use the path for the first ROM to do so. */ - const struct retro_subsystem_rom_info *roms; + /* Infos for each content file. The first entry is assumed to be the + * "most significant" content for frontend purposes. + * E.g. with Super GameBoy, the first content should be the GameBoy ROM, + * as it is the most "significant" content to a user. + * If a frontend creates new file paths based on the content used + * (e.g. savestates), it should use the path for the first ROM to do so. */ + const struct retro_subsystem_rom_info* roms; - /* Number of content files associated with a subsystem. */ - unsigned num_roms; + /* Number of content files associated with a subsystem. */ + unsigned num_roms; - /* The type passed to retro_load_game_special(). */ - unsigned id; + /* The type passed to retro_load_game_special(). */ + unsigned id; }; typedef void (RETRO_CALLCONV *retro_proc_address_t)(void); @@ -1814,30 +1818,30 @@ typedef void (RETRO_CALLCONV *retro_proc_address_t)(void); * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo". * The returned function pointer must be cast to the corresponding type. */ -typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym); +typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char* sym); struct retro_get_proc_address_interface { - retro_get_proc_address_t get_proc_address; + retro_get_proc_address_t get_proc_address; }; enum retro_log_level { - RETRO_LOG_DEBUG = 0, - RETRO_LOG_INFO, - RETRO_LOG_WARN, - RETRO_LOG_ERROR, + RETRO_LOG_DEBUG = 0, + RETRO_LOG_INFO, + RETRO_LOG_WARN, + RETRO_LOG_ERROR, - RETRO_LOG_DUMMY = INT_MAX + RETRO_LOG_DUMMY = INT_MAX }; /* Logging function. Takes log level argument as well. */ typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level, - const char *fmt, ...); + const char* fmt, ...); struct retro_log_callback { - retro_log_printf_t log; + retro_log_printf_t log; }; /* Performance related functions */ @@ -1871,12 +1875,12 @@ typedef int64_t retro_time_t; struct retro_perf_counter { - const char *ident; - retro_perf_tick_t start; - retro_perf_tick_t total; - retro_perf_tick_t call_cnt; + const char* ident; + retro_perf_tick_t start; + retro_perf_tick_t total; + retro_perf_tick_t call_cnt; - bool registered; + bool registered; }; /* Returns current time in microseconds. @@ -1903,13 +1907,13 @@ typedef void (RETRO_CALLCONV *retro_perf_log_t)(void); * retro_perf_counter must be 0. * Registering can be called multiple times. To avoid calling to * frontend redundantly, you can check registered field first. */ -typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter); +typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter* counter); /* Starts a registered counter. */ -typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter); +typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter* counter); /* Stops a registered counter. */ -typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter); +typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter* counter); /* For convenience it can be useful to wrap register, start and stop in macros. * E.g.: @@ -1946,14 +1950,14 @@ typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *coun struct retro_perf_callback { - retro_perf_get_time_usec_t get_time_usec; - retro_get_cpu_features_t get_cpu_features; + retro_perf_get_time_usec_t get_time_usec; + retro_get_cpu_features_t get_cpu_features; - retro_perf_get_counter_t get_perf_counter; - retro_perf_register_t perf_register; - retro_perf_start_t perf_start; - retro_perf_stop_t perf_stop; - retro_perf_log_t perf_log; + retro_perf_get_counter_t get_perf_counter; + retro_perf_register_t perf_register; + retro_perf_start_t perf_start; + retro_perf_stop_t perf_stop; + retro_perf_log_t perf_log; }; /* FIXME: Document the sensor API and work out behavior. @@ -1961,14 +1965,14 @@ struct retro_perf_callback */ enum retro_sensor_action { - RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, - RETRO_SENSOR_ACCELEROMETER_DISABLE, - RETRO_SENSOR_GYROSCOPE_ENABLE, - RETRO_SENSOR_GYROSCOPE_DISABLE, - RETRO_SENSOR_ILLUMINANCE_ENABLE, - RETRO_SENSOR_ILLUMINANCE_DISABLE, + RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, + RETRO_SENSOR_ACCELEROMETER_DISABLE, + RETRO_SENSOR_GYROSCOPE_ENABLE, + RETRO_SENSOR_GYROSCOPE_DISABLE, + RETRO_SENSOR_ILLUMINANCE_ENABLE, + RETRO_SENSOR_ILLUMINANCE_DISABLE, - RETRO_SENSOR_DUMMY = INT_MAX + RETRO_SENSOR_DUMMY = INT_MAX }; /* Id values for SENSOR types. */ @@ -1981,22 +1985,22 @@ enum retro_sensor_action #define RETRO_SENSOR_ILLUMINANCE 6 typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port, - enum retro_sensor_action action, unsigned rate); + enum retro_sensor_action action, unsigned rate); typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id); struct retro_sensor_interface { - retro_set_sensor_state_t set_sensor_state; - retro_sensor_get_input_t get_sensor_input; + retro_set_sensor_state_t set_sensor_state; + retro_sensor_get_input_t get_sensor_input; }; enum retro_camera_buffer { - RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, - RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, + RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, + RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, - RETRO_CAMERA_BUFFER_DUMMY = INT_MAX + RETRO_CAMERA_BUFFER_DUMMY = INT_MAX }; /* Starts the camera driver. Can only be called in retro_run(). */ @@ -2015,8 +2019,8 @@ typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void); * Width, height and pitch are similar to retro_video_refresh_t. * First pixel is top-left origin. */ -typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, - unsigned width, unsigned height, size_t pitch); +typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t* buffer, + unsigned width, unsigned height, size_t pitch); /* A callback for when OpenGL textures are used. * @@ -2037,40 +2041,40 @@ typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32 * the API definition. */ typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id, - unsigned texture_target, const float *affine); + unsigned texture_target, const float* affine); struct retro_camera_callback { - /* Set by libretro core. - * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). - */ - uint64_t caps; + /* Set by libretro core. + * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). + */ + uint64_t caps; - /* Desired resolution for camera. Is only used as a hint. */ - unsigned width; - unsigned height; + /* Desired resolution for camera. Is only used as a hint. */ + unsigned width; + unsigned height; - /* Set by frontend. */ - retro_camera_start_t start; - retro_camera_stop_t stop; + /* Set by frontend. */ + retro_camera_start_t start; + retro_camera_stop_t stop; - /* Set by libretro core if raw framebuffer callbacks will be used. */ - retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; + /* Set by libretro core if raw framebuffer callbacks will be used. */ + retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; - /* Set by libretro core if OpenGL texture callbacks will be used. */ - retro_camera_frame_opengl_texture_t frame_opengl_texture; + /* Set by libretro core if OpenGL texture callbacks will be used. */ + retro_camera_frame_opengl_texture_t frame_opengl_texture; - /* Set by libretro core. Called after camera driver is initialized and - * ready to be started. - * Can be NULL, in which this callback is not called. - */ - retro_camera_lifetime_status_t initialized; + /* Set by libretro core. Called after camera driver is initialized and + * ready to be started. + * Can be NULL, in which this callback is not called. + */ + retro_camera_lifetime_status_t initialized; - /* Set by libretro core. Called right before camera driver is - * deinitialized. - * Can be NULL, in which this callback is not called. - */ - retro_camera_lifetime_status_t deinitialized; + /* Set by libretro core. Called right before camera driver is + * deinitialized. + * Can be NULL, in which this callback is not called. + */ + retro_camera_lifetime_status_t deinitialized; }; /* Sets the interval of time and/or distance at which to update/poll @@ -2083,7 +2087,7 @@ struct retro_camera_callback * interval_distance is the distance interval expressed in meters. */ typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms, - unsigned interval_distance); + unsigned interval_distance); /* Start location services. The device will start listening for changes to the * current location at regular intervals (which are defined with @@ -2096,8 +2100,8 @@ typedef void (RETRO_CALLCONV *retro_location_stop_t)(void); /* Get the position of the current location. Will set parameters to * 0 if no new location update has happened since the last time. */ -typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon, - double *horiz_accuracy, double *vert_accuracy); +typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double* lat, double* lon, + double* horiz_accuracy, double* vert_accuracy); /* Callback which signals when the location driver is initialized * and/or deinitialized. @@ -2107,21 +2111,21 @@ typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void); struct retro_location_callback { - retro_location_start_t start; - retro_location_stop_t stop; - retro_location_get_position_t get_position; - retro_location_set_interval_t set_interval; + retro_location_start_t start; + retro_location_stop_t stop; + retro_location_get_position_t get_position; + retro_location_set_interval_t set_interval; - retro_location_lifetime_status_t initialized; - retro_location_lifetime_status_t deinitialized; + retro_location_lifetime_status_t initialized; + retro_location_lifetime_status_t deinitialized; }; enum retro_rumble_effect { - RETRO_RUMBLE_STRONG = 0, - RETRO_RUMBLE_WEAK = 1, + RETRO_RUMBLE_STRONG = 0, + RETRO_RUMBLE_WEAK = 1, - RETRO_RUMBLE_DUMMY = INT_MAX + RETRO_RUMBLE_DUMMY = INT_MAX }; /* Sets rumble state for joypad plugged in port 'port'. @@ -2132,11 +2136,11 @@ enum retro_rumble_effect * Returns true if rumble state request was honored. * Calling this before first retro_run() is likely to return false. */ typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port, - enum retro_rumble_effect effect, uint16_t strength); + enum retro_rumble_effect effect, uint16_t strength); struct retro_rumble_interface { - retro_set_rumble_state_t set_rumble_state; + retro_set_rumble_state_t set_rumble_state; }; /* Notifies libretro that audio data should be written. */ @@ -2153,8 +2157,8 @@ typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled); struct retro_audio_callback { - retro_audio_callback_t callback; - retro_audio_set_state_callback_t set_state; + retro_audio_callback_t callback; + retro_audio_set_state_callback_t set_state; }; /* Notifies a libretro core of time spent since last invocation @@ -2167,13 +2171,14 @@ struct retro_audio_callback * In those scenarios the reference frame time value will be used. */ typedef int64_t retro_usec_t; typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec); + struct retro_frame_time_callback { - retro_frame_time_callback_t callback; - /* Represents the time of one frame. It is computed as - * 1000000 / fps, but the implementation will resolve the - * rounding to ensure that framestepping, etc is exact. */ - retro_usec_t reference; + retro_frame_time_callback_t callback; + /* Represents the time of one frame. It is computed as + * 1000000 / fps, but the implementation will resolve the + * rounding to ensure that framestepping, etc is exact. */ + retro_usec_t reference; }; /* Pass this to retro_video_refresh_t if rendering to hardware. @@ -2198,117 +2203,117 @@ typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void); typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void); /* Get a symbol from HW context. */ -typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym); +typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char* sym); enum retro_hw_context_type { - RETRO_HW_CONTEXT_NONE = 0, - /* OpenGL 2.x. Driver can choose to use latest compatibility context. */ - RETRO_HW_CONTEXT_OPENGL = 1, - /* OpenGL ES 2.0. */ - RETRO_HW_CONTEXT_OPENGLES2 = 2, - /* Modern desktop core GL context. Use version_major/ - * version_minor fields to set GL version. */ - RETRO_HW_CONTEXT_OPENGL_CORE = 3, - /* OpenGL ES 3.0 */ - RETRO_HW_CONTEXT_OPENGLES3 = 4, - /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3, - * use the corresponding enums directly. */ - RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, + RETRO_HW_CONTEXT_NONE = 0, + /* OpenGL 2.x. Driver can choose to use latest compatibility context. */ + RETRO_HW_CONTEXT_OPENGL = 1, + /* OpenGL ES 2.0. */ + RETRO_HW_CONTEXT_OPENGLES2 = 2, + /* Modern desktop core GL context. Use version_major/ + * version_minor fields to set GL version. */ + RETRO_HW_CONTEXT_OPENGL_CORE = 3, + /* OpenGL ES 3.0 */ + RETRO_HW_CONTEXT_OPENGLES3 = 4, + /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3, + * use the corresponding enums directly. */ + RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, - /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */ - RETRO_HW_CONTEXT_VULKAN = 6, + /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */ + RETRO_HW_CONTEXT_VULKAN = 6, - /* Direct3D, set version_major to select the type of interface - * returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ - RETRO_HW_CONTEXT_DIRECT3D = 7, + /* Direct3D, set version_major to select the type of interface + * returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ + RETRO_HW_CONTEXT_DIRECT3D = 7, - RETRO_HW_CONTEXT_DUMMY = INT_MAX + RETRO_HW_CONTEXT_DUMMY = INT_MAX }; struct retro_hw_render_callback { - /* Which API to use. Set by libretro core. */ - enum retro_hw_context_type context_type; + /* Which API to use. Set by libretro core. */ + enum retro_hw_context_type context_type; - /* Called when a context has been created or when it has been reset. - * An OpenGL context is only valid after context_reset() has been called. - * - * When context_reset is called, OpenGL resources in the libretro - * implementation are guaranteed to be invalid. - * - * It is possible that context_reset is called multiple times during an - * application lifecycle. - * If context_reset is called without any notification (context_destroy), - * the OpenGL context was lost and resources should just be recreated - * without any attempt to "free" old resources. - */ - retro_hw_context_reset_t context_reset; + /* Called when a context has been created or when it has been reset. + * An OpenGL context is only valid after context_reset() has been called. + * + * When context_reset is called, OpenGL resources in the libretro + * implementation are guaranteed to be invalid. + * + * It is possible that context_reset is called multiple times during an + * application lifecycle. + * If context_reset is called without any notification (context_destroy), + * the OpenGL context was lost and resources should just be recreated + * without any attempt to "free" old resources. + */ + retro_hw_context_reset_t context_reset; - /* Set by frontend. - * TODO: This is rather obsolete. The frontend should not - * be providing preallocated framebuffers. */ - retro_hw_get_current_framebuffer_t get_current_framebuffer; + /* Set by frontend. + * TODO: This is rather obsolete. The frontend should not + * be providing preallocated framebuffers. */ + retro_hw_get_current_framebuffer_t get_current_framebuffer; - /* Set by frontend. - * Can return all relevant functions, including glClear on Windows. */ - retro_hw_get_proc_address_t get_proc_address; + /* Set by frontend. + * Can return all relevant functions, including glClear on Windows. */ + retro_hw_get_proc_address_t get_proc_address; - /* Set if render buffers should have depth component attached. - * TODO: Obsolete. */ - bool depth; + /* Set if render buffers should have depth component attached. + * TODO: Obsolete. */ + bool depth; - /* Set if stencil buffers should be attached. - * TODO: Obsolete. */ - bool stencil; + /* Set if stencil buffers should be attached. + * TODO: Obsolete. */ + bool stencil; - /* If depth and stencil are true, a packed 24/8 buffer will be added. - * Only attaching stencil is invalid and will be ignored. */ + /* If depth and stencil are true, a packed 24/8 buffer will be added. + * Only attaching stencil is invalid and will be ignored. */ - /* Use conventional bottom-left origin convention. If false, - * standard libretro top-left origin semantics are used. - * TODO: Move to GL specific interface. */ - bool bottom_left_origin; + /* Use conventional bottom-left origin convention. If false, + * standard libretro top-left origin semantics are used. + * TODO: Move to GL specific interface. */ + bool bottom_left_origin; - /* Major version number for core GL context or GLES 3.1+. */ - unsigned version_major; + /* Major version number for core GL context or GLES 3.1+. */ + unsigned version_major; - /* Minor version number for core GL context or GLES 3.1+. */ - unsigned version_minor; + /* Minor version number for core GL context or GLES 3.1+. */ + unsigned version_minor; - /* If this is true, the frontend will go very far to avoid - * resetting context in scenarios like toggling fullscreen, etc. - * TODO: Obsolete? Maybe frontend should just always assume this ... - */ - bool cache_context; + /* If this is true, the frontend will go very far to avoid + * resetting context in scenarios like toggling fullscreen, etc. + * TODO: Obsolete? Maybe frontend should just always assume this ... + */ + bool cache_context; - /* The reset callback might still be called in extreme situations - * such as if the context is lost beyond recovery. - * - * For optimal stability, set this to false, and allow context to be - * reset at any time. - */ + /* The reset callback might still be called in extreme situations + * such as if the context is lost beyond recovery. + * + * For optimal stability, set this to false, and allow context to be + * reset at any time. + */ - /* A callback to be called before the context is destroyed in a - * controlled way by the frontend. */ - retro_hw_context_reset_t context_destroy; + /* A callback to be called before the context is destroyed in a + * controlled way by the frontend. */ + retro_hw_context_reset_t context_destroy; - /* OpenGL resources can be deinitialized cleanly at this step. - * context_destroy can be set to NULL, in which resources will - * just be destroyed without any notification. - * - * Even when context_destroy is non-NULL, it is possible that - * context_reset is called without any destroy notification. - * This happens if context is lost by external factors (such as - * notified by GL_ARB_robustness). - * - * In this case, the context is assumed to be already dead, - * and the libretro implementation must not try to free any OpenGL - * resources in the subsequent context_reset. - */ + /* OpenGL resources can be deinitialized cleanly at this step. + * context_destroy can be set to NULL, in which resources will + * just be destroyed without any notification. + * + * Even when context_destroy is non-NULL, it is possible that + * context_reset is called without any destroy notification. + * This happens if context is lost by external factors (such as + * notified by GL_ARB_robustness). + * + * In this case, the context is assumed to be already dead, + * and the libretro implementation must not try to free any OpenGL + * resources in the subsequent context_reset. + */ - /* Creates a debug context. */ - bool debug_context; + /* Creates a debug context. */ + bool debug_context; }; /* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. @@ -2329,11 +2334,11 @@ struct retro_hw_render_callback * character, character should be 0. */ typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode, - uint32_t character, uint16_t key_modifiers); + uint32_t character, uint16_t key_modifiers); struct retro_keyboard_callback { - retro_keyboard_event_t callback; + retro_keyboard_event_t callback; }; /* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE & @@ -2387,7 +2392,7 @@ struct retro_game_info; * Index 1 will be removed, and the new index is 3. */ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index, - const struct retro_game_info *info); + const struct retro_game_info* info); /* Adds a new valid index (get_num_images()) to the internal disk list. * This will increment subsequent return values from get_num_images() by 1. @@ -2419,13 +2424,13 @@ typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void); * Returns 'false' if index or 'path' are invalid, or core * does not support this functionality */ -typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path); +typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char* path); /* Fetches the path of the specified disk image file. * Returns 'false' if index is invalid (index >= get_num_images()) * or path is otherwise unavailable. */ -typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len); +typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char* path, size_t len); /* Fetches a core-provided 'label' for the specified disk * image file. In the simplest case this may be a file name @@ -2440,70 +2445,70 @@ typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path * Returns 'false' if index is invalid (index >= get_num_images()) * or label is otherwise unavailable. */ -typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len); +typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char* label, size_t len); struct retro_disk_control_callback { - retro_set_eject_state_t set_eject_state; - retro_get_eject_state_t get_eject_state; + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; - retro_get_image_index_t get_image_index; - retro_set_image_index_t set_image_index; - retro_get_num_images_t get_num_images; + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; - retro_replace_image_index_t replace_image_index; - retro_add_image_index_t add_image_index; + retro_replace_image_index_t replace_image_index; + retro_add_image_index_t add_image_index; }; struct retro_disk_control_ext_callback { - retro_set_eject_state_t set_eject_state; - retro_get_eject_state_t get_eject_state; + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; - retro_get_image_index_t get_image_index; - retro_set_image_index_t set_image_index; - retro_get_num_images_t get_num_images; + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; - retro_replace_image_index_t replace_image_index; - retro_add_image_index_t add_image_index; + retro_replace_image_index_t replace_image_index; + retro_add_image_index_t add_image_index; - /* NOTE: Frontend will only attempt to record/restore - * last used disk index if both set_initial_image() - * and get_image_path() are implemented */ - retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */ + /* NOTE: Frontend will only attempt to record/restore + * last used disk index if both set_initial_image() + * and get_image_path() are implemented */ + retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */ - retro_get_image_path_t get_image_path; /* Optional - may be NULL */ - retro_get_image_label_t get_image_label; /* Optional - may be NULL */ + retro_get_image_path_t get_image_path; /* Optional - may be NULL */ + retro_get_image_label_t get_image_label; /* Optional - may be NULL */ }; enum retro_pixel_format { - /* 0RGB1555, native endian. - * 0 bit must be set to 0. - * This pixel format is default for compatibility concerns only. - * If a 15/16-bit pixel format is desired, consider using RGB565. */ - RETRO_PIXEL_FORMAT_0RGB1555 = 0, + /* 0RGB1555, native endian. + * 0 bit must be set to 0. + * This pixel format is default for compatibility concerns only. + * If a 15/16-bit pixel format is desired, consider using RGB565. */ + RETRO_PIXEL_FORMAT_0RGB1555 = 0, - /* XRGB8888, native endian. - * X bits are ignored. */ - RETRO_PIXEL_FORMAT_XRGB8888 = 1, + /* XRGB8888, native endian. + * X bits are ignored. */ + RETRO_PIXEL_FORMAT_XRGB8888 = 1, - /* RGB565, native endian. - * This pixel format is the recommended format to use if a 15/16-bit - * format is desired as it is the pixel format that is typically - * available on a wide range of low-power devices. - * - * It is also natively supported in APIs like OpenGL ES. */ - RETRO_PIXEL_FORMAT_RGB565 = 2, + /* RGB565, native endian. + * This pixel format is the recommended format to use if a 15/16-bit + * format is desired as it is the pixel format that is typically + * available on a wide range of low-power devices. + * + * It is also natively supported in APIs like OpenGL ES. */ + RETRO_PIXEL_FORMAT_RGB565 = 2, - /* Ensure sizeof() == sizeof(int). */ - RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX + /* Ensure sizeof() == sizeof(int). */ + RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX }; struct retro_message { - const char *msg; /* Message to be displayed. */ - unsigned frames; /* Duration in frames of message. */ + const char* msg; /* Message to be displayed. */ + unsigned frames; /* Duration in frames of message. */ }; /* Describes how the libretro implementation maps a libretro input bind @@ -2511,71 +2516,71 @@ struct retro_message * This string can be used to better let a user configure input. */ struct retro_input_descriptor { - /* Associates given parameters with a description. */ - unsigned port; - unsigned device; - unsigned index; - unsigned id; + /* Associates given parameters with a description. */ + unsigned port; + unsigned device; + unsigned index; + unsigned id; - /* Human readable description for parameters. - * The pointer must remain valid until - * retro_unload_game() is called. */ - const char *description; + /* Human readable description for parameters. + * The pointer must remain valid until + * retro_unload_game() is called. */ + const char* description; }; struct retro_system_info { - /* All pointers are owned by libretro implementation, and pointers must - * remain valid until retro_deinit() is called. */ + /* All pointers are owned by libretro implementation, and pointers must + * remain valid until retro_deinit() is called. */ - const char *library_name; /* Descriptive name of library. Should not + const char* library_name; /* Descriptive name of library. Should not * contain any version numbers, etc. */ - const char *library_version; /* Descriptive version of core. */ + const char* library_version; /* Descriptive version of core. */ - const char *valid_extensions; /* A string listing probably content + const char* valid_extensions; /* A string listing probably content * extensions the core will be able to * load, separated with pipe. * I.e. "bin|rom|iso". * Typically used for a GUI to filter * out extensions. */ - /* Libretro cores that need to have direct access to their content - * files, including cores which use the path of the content files to - * determine the paths of other files, should set need_fullpath to true. - * - * Cores should strive for setting need_fullpath to false, - * as it allows the frontend to perform patching, etc. - * - * If need_fullpath is true and retro_load_game() is called: - * - retro_game_info::path is guaranteed to have a valid path - * - retro_game_info::data and retro_game_info::size are invalid - * - * If need_fullpath is false and retro_load_game() is called: - * - retro_game_info::path may be NULL - * - retro_game_info::data and retro_game_info::size are guaranteed - * to be valid - * - * See also: - * - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY - * - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY - */ - bool need_fullpath; + /* Libretro cores that need to have direct access to their content + * files, including cores which use the path of the content files to + * determine the paths of other files, should set need_fullpath to true. + * + * Cores should strive for setting need_fullpath to false, + * as it allows the frontend to perform patching, etc. + * + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info::path is guaranteed to have a valid path + * - retro_game_info::data and retro_game_info::size are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - retro_game_info::path may be NULL + * - retro_game_info::data and retro_game_info::size are guaranteed + * to be valid + * + * See also: + * - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY + * - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY + */ + bool need_fullpath; - /* If true, the frontend is not allowed to extract any archives before - * loading the real content. - * Necessary for certain libretro implementations that load games - * from zipped archives. */ - bool block_extract; + /* If true, the frontend is not allowed to extract any archives before + * loading the real content. + * Necessary for certain libretro implementations that load games + * from zipped archives. */ + bool block_extract; }; struct retro_game_geometry { - unsigned base_width; /* Nominal video width of game. */ - unsigned base_height; /* Nominal video height of game. */ - unsigned max_width; /* Maximum possible width of game. */ - unsigned max_height; /* Maximum possible height of game. */ + unsigned base_width; /* Nominal video width of game. */ + unsigned base_height; /* Nominal video height of game. */ + unsigned max_width; /* Maximum possible width of game. */ + unsigned max_height; /* Maximum possible height of game. */ - float aspect_ratio; /* Nominal aspect ratio of game. If + float aspect_ratio; /* Nominal aspect ratio of game. If * aspect_ratio is <= 0.0, an aspect ratio * of base_width / base_height is assumed. * A frontend could override this setting, @@ -2584,39 +2589,39 @@ struct retro_game_geometry struct retro_system_timing { - double fps; /* FPS of video content. */ - double sample_rate; /* Sampling rate of audio. */ + double fps; /* FPS of video content. */ + double sample_rate; /* Sampling rate of audio. */ }; struct retro_system_av_info { - struct retro_game_geometry geometry; - struct retro_system_timing timing; + struct retro_game_geometry geometry; + struct retro_system_timing timing; }; struct retro_variable { - /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. - * If NULL, obtains the complete environment string if more - * complex parsing is necessary. - * The environment string is formatted as key-value pairs - * delimited by semicolons as so: - * "key1=value1;key2=value2;..." - */ - const char *key; + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. + * If NULL, obtains the complete environment string if more + * complex parsing is necessary. + * The environment string is formatted as key-value pairs + * delimited by semicolons as so: + * "key1=value1;key2=value2;..." + */ + const char* key; - /* Value to be obtained. If key does not exist, it is set to NULL. */ - const char *value; + /* Value to be obtained. If key does not exist, it is set to NULL. */ + const char* value; }; struct retro_core_option_display { - /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */ - const char *key; + /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */ + const char* key; - /* Specifies whether variable should be displayed - * when presenting core options to the user */ - bool visible; + /* Specifies whether variable should be displayed + * when presenting core options to the user */ + bool visible; }; /* Maximum number of values permitted for a core option @@ -2638,50 +2643,50 @@ struct retro_core_option_display struct retro_core_option_value { - /* Expected option value */ - const char *value; + /* Expected option value */ + const char* value; - /* Human-readable value label. If NULL, value itself - * will be displayed by the frontend */ - const char *label; + /* Human-readable value label. If NULL, value itself + * will be displayed by the frontend */ + const char* label; }; struct retro_core_option_definition { - /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */ - const char *key; + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */ + const char* key; - /* Human-readable core option description (used as menu label) */ - const char *desc; + /* Human-readable core option description (used as menu label) */ + const char* desc; - /* Human-readable core option information (used as menu sublabel) */ - const char *info; + /* Human-readable core option information (used as menu sublabel) */ + const char* info; - /* Array of retro_core_option_value structs, terminated by NULL */ - struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX]; + /* Array of retro_core_option_value structs, terminated by NULL */ + struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX]; - /* Default core option value. Must match one of the values - * in the retro_core_option_value array, otherwise will be - * ignored */ - const char *default_value; + /* Default core option value. Must match one of the values + * in the retro_core_option_value array, otherwise will be + * ignored */ + const char* default_value; }; struct retro_core_options_intl { - /* Pointer to an array of retro_core_option_definition structs - * - US English implementation - * - Must point to a valid array */ - struct retro_core_option_definition *us; + /* Pointer to an array of retro_core_option_definition structs + * - US English implementation + * - Must point to a valid array */ + struct retro_core_option_definition* us; - /* Pointer to an array of retro_core_option_definition structs - * - Implementation for current frontend language - * - May be NULL */ - struct retro_core_option_definition *local; + /* Pointer to an array of retro_core_option_definition structs + * - Implementation for current frontend language + * - May be NULL */ + struct retro_core_option_definition* local; }; struct retro_game_info { - const char *path; /* Path to game, UTF-8 encoded. + const char* path; /* Path to game, UTF-8 encoded. * Sometimes used as a reference for building other paths. * May be NULL if game was loaded from stdin or similar, * but in this case some cores will be unable to load `data`. @@ -2689,38 +2694,38 @@ struct retro_game_info * of passing NULL, which will help more cores to succeed. * retro_system_info::need_fullpath requires * that this path is valid. */ - const void *data; /* Memory buffer of loaded game. Will be NULL + const void* data; /* Memory buffer of loaded game. Will be NULL * if need_fullpath was set. */ - size_t size; /* Size of memory buffer. */ - const char *meta; /* String of implementation specific meta-data. */ + size_t size; /* Size of memory buffer. */ + const char* meta; /* String of implementation specific meta-data. */ }; #define RETRO_MEMORY_ACCESS_WRITE (1 << 0) - /* The core will write to the buffer provided by retro_framebuffer::data. */ +/* The core will write to the buffer provided by retro_framebuffer::data. */ #define RETRO_MEMORY_ACCESS_READ (1 << 1) - /* The core will read from retro_framebuffer::data. */ +/* The core will read from retro_framebuffer::data. */ #define RETRO_MEMORY_TYPE_CACHED (1 << 0) - /* The memory in data is cached. - * If not cached, random writes and/or reading from the buffer is expected to be very slow. */ +/* The memory in data is cached. + * If not cached, random writes and/or reading from the buffer is expected to be very slow. */ struct retro_framebuffer { - void *data; /* The framebuffer which the core can render into. + void* data; /* The framebuffer which the core can render into. Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. The initial contents of data are unspecified. */ - unsigned width; /* The framebuffer width used by the core. Set by core. */ - unsigned height; /* The framebuffer height used by the core. Set by core. */ - size_t pitch; /* The number of bytes between the beginning of a scanline, + unsigned width; /* The framebuffer width used by the core. Set by core. */ + unsigned height; /* The framebuffer height used by the core. Set by core. */ + size_t pitch; /* The number of bytes between the beginning of a scanline, and beginning of the next scanline. Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ - enum retro_pixel_format format; /* The pixel format the core must use to render into data. + enum retro_pixel_format format; /* The pixel format the core must use to render into data. This format could differ from the format used in SET_PIXEL_FORMAT. Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ - unsigned access_flags; /* How the core will access the memory in the framebuffer. + unsigned access_flags; /* How the core will access the memory in the framebuffer. RETRO_MEMORY_ACCESS_* flags. Set by core. */ - unsigned memory_flags; /* Flags telling core how the memory has been mapped. + unsigned memory_flags; /* Flags telling core how the memory has been mapped. RETRO_MEMORY_TYPE_* flags. Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ }; @@ -2729,7 +2734,7 @@ struct retro_framebuffer /* Environment callback. Gives implementations a way of performing * uncommon tasks. Extensible. */ -typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data); +typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void* data); /* Render a frame. Pixel format is 15-bit 0RGB1555 native endian * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT). @@ -2742,8 +2747,8 @@ typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data); * Certain graphic APIs, such as OpenGL ES, do not like textures * that are not packed in memory. */ -typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width, - unsigned height, size_t pitch); +typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void* data, unsigned width, + unsigned height, size_t pitch); /* Renders a single audio frame. Should only be used if implementation * generates a single sample at a time. @@ -2757,8 +2762,8 @@ typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right) * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. * Only one of the audio callbacks must ever be used. */ -typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data, - size_t frames); +typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t* data, + size_t frames); /* Polls input. */ typedef void (RETRO_CALLCONV *retro_input_poll_t)(void); @@ -2771,7 +2776,7 @@ typedef void (RETRO_CALLCONV *retro_input_poll_t)(void); * will still use the higher level RETRO_DEVICE_JOYPAD to request input. */ typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device, - unsigned index, unsigned id); + unsigned index, unsigned id); /* Sets callbacks. retro_set_environment() is guaranteed to be called * before retro_init(). @@ -2796,7 +2801,7 @@ RETRO_API unsigned retro_api_version(void); /* Gets statically known system info. Pointers provided in *info * must be statically allocated. * Can be called at any time, even before retro_init(). */ -RETRO_API void retro_get_system_info(struct retro_system_info *info); +RETRO_API void retro_get_system_info(struct retro_system_info* info); /* Gets information about system audio/video timings and geometry. * Can be called only after retro_load_game() has successfully completed. @@ -2804,7 +2809,7 @@ RETRO_API void retro_get_system_info(struct retro_system_info *info); * variable if needed. * E.g. geom.aspect_ratio might not be initialized if core doesn't * desire a particular aspect ratio. */ -RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info); +RETRO_API void retro_get_system_av_info(struct retro_system_av_info* info); /* Sets device to be used for player 'port'. * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all @@ -2845,22 +2850,22 @@ RETRO_API size_t retro_serialize_size(void); /* Serializes internal state. If failed, or size is lower than * retro_serialize_size(), it should return false, true otherwise. */ -RETRO_API bool retro_serialize(void *data, size_t size); -RETRO_API bool retro_unserialize(const void *data, size_t size); +RETRO_API bool retro_serialize(void* data, size_t size); +RETRO_API bool retro_unserialize(const void* data, size_t size); RETRO_API void retro_cheat_reset(void); -RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code); +RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char* code); /* Loads a game. * Return true to indicate successful loading and false to indicate load failure. */ -RETRO_API bool retro_load_game(const struct retro_game_info *game); +RETRO_API bool retro_load_game(const struct retro_game_info* game); /* Loads a "special" kind of game. Should not be used, * except in extreme cases. */ RETRO_API bool retro_load_game_special( - unsigned game_type, - const struct retro_game_info *info, size_t num_info + unsigned game_type, + const struct retro_game_info* info, size_t num_info ); /* Unloads the currently loaded game. Called before retro_deinit(void). */ @@ -2870,7 +2875,7 @@ RETRO_API void retro_unload_game(void); RETRO_API unsigned retro_get_region(void); /* Gets region of memory. */ -RETRO_API void *retro_get_memory_data(unsigned id); +RETRO_API void* retro_get_memory_data(unsigned id); RETRO_API size_t retro_get_memory_size(unsigned id); #ifdef __cplusplus diff --git a/Lua/auxiliar.c b/Lua/auxiliar.c index 5251549..38b18b8 100644 --- a/Lua/auxiliar.c +++ b/Lua/auxiliar.c @@ -13,146 +13,163 @@ /*-------------------------------------------------------------------------*\ * Initializes the module \*-------------------------------------------------------------------------*/ -int auxiliar_open(lua_State *L) { - (void) L; - return 0; +int auxiliar_open(lua_State* L) +{ + (void)L; + return 0; } /*-------------------------------------------------------------------------*\ * Creates a new class with given methods * Methods whose names start with __ are passed directly to the metatable. \*-------------------------------------------------------------------------*/ -void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) { - luaL_newmetatable(L, classname); /* mt */ - /* create __index table to place methods */ - lua_pushstring(L, "__index"); /* mt,"__index" */ - lua_newtable(L); /* mt,"__index",it */ - /* put class name into class metatable */ - lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ - lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ - lua_rawset(L, -3); /* mt,"__index",it */ - /* pass all methods that start with _ to the metatable, and all others - * to the index table */ - for (; func->name; func++) { /* mt,"__index",it */ - lua_pushstring(L, func->name); - lua_pushcfunction(L, func->func); - lua_rawset(L, func->name[0] == '_' ? -5: -3); - } - lua_rawset(L, -3); /* mt */ - lua_pop(L, 1); +void auxiliar_newclass(lua_State* L, const char* classname, luaL_Reg* func) +{ + luaL_newmetatable(L, classname); /* mt */ + /* create __index table to place methods */ + lua_pushstring(L, "__index"); /* mt,"__index" */ + lua_newtable(L); /* mt,"__index",it */ + /* put class name into class metatable */ + lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ + lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ + lua_rawset(L, -3); /* mt,"__index",it */ + /* pass all methods that start with _ to the metatable, and all others + * to the index table */ + for (; func->name; func++) + { + /* mt,"__index",it */ + lua_pushstring(L, func->name); + lua_pushcfunction(L, func->func); + lua_rawset(L, func->name[0] == '_' ? -5 : -3); + } + lua_rawset(L, -3); /* mt */ + lua_pop(L, 1); } /*-------------------------------------------------------------------------*\ * Prints the value of a class in a nice way \*-------------------------------------------------------------------------*/ -int auxiliar_tostring(lua_State *L) { - char buf[32]; - if (!lua_getmetatable(L, 1)) goto error; - lua_pushstring(L, "__index"); - lua_gettable(L, -2); - if (!lua_istable(L, -1)) goto error; - lua_pushstring(L, "class"); - lua_gettable(L, -2); - if (!lua_isstring(L, -1)) goto error; - sprintf(buf, "%p", lua_touserdata(L, 1)); - lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); - return 1; +int auxiliar_tostring(lua_State* L) +{ + char buf[32]; + if (!lua_getmetatable(L, 1)) goto error; + lua_pushstring(L, "__index"); + lua_gettable(L, -2); + if (!lua_istable(L, -1)) goto error; + lua_pushstring(L, "class"); + lua_gettable(L, -2); + if (!lua_isstring(L, -1)) goto error; + sprintf(buf, "%p", lua_touserdata(L, 1)); + lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); + return 1; error: - lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); - lua_error(L); - return 1; + lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); + lua_error(L); + return 1; } /*-------------------------------------------------------------------------*\ * Insert class into group \*-------------------------------------------------------------------------*/ -void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) { - luaL_getmetatable(L, classname); - lua_pushstring(L, groupname); - lua_pushboolean(L, 1); - lua_rawset(L, -3); - lua_pop(L, 1); +void auxiliar_add2group(lua_State* L, const char* classname, const char* groupname) +{ + luaL_getmetatable(L, classname); + lua_pushstring(L, groupname); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + lua_pop(L, 1); } /*-------------------------------------------------------------------------*\ * Make sure argument is a boolean \*-------------------------------------------------------------------------*/ -int auxiliar_checkboolean(lua_State *L, int objidx) { - if (!lua_isboolean(L, objidx)) - auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); - return lua_toboolean(L, objidx); +int auxiliar_checkboolean(lua_State* L, int objidx) +{ + if (!lua_isboolean(L, objidx)) + auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); + return lua_toboolean(L, objidx); } /*-------------------------------------------------------------------------*\ * Return userdata pointer if object belongs to a given class, abort with * error otherwise \*-------------------------------------------------------------------------*/ -void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { - void *data = auxiliar_getclassudata(L, classname, objidx); - if (!data) { - char msg[45]; - sprintf(msg, "%.35s expected", classname); - luaL_argerror(L, objidx, msg); - } - return data; +void* auxiliar_checkclass(lua_State* L, const char* classname, int objidx) +{ + void* data = auxiliar_getclassudata(L, classname, objidx); + if (!data) + { + char msg[45]; + sprintf(msg, "%.35s expected", classname); + luaL_argerror(L, objidx, msg); + } + return data; } /*-------------------------------------------------------------------------*\ * Return userdata pointer if object belongs to a given group, abort with * error otherwise \*-------------------------------------------------------------------------*/ -void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { - void *data = auxiliar_getgroupudata(L, groupname, objidx); - if (!data) { - char msg[45]; - sprintf(msg, "%.35s expected", groupname); - luaL_argerror(L, objidx, msg); - } - return data; +void* auxiliar_checkgroup(lua_State* L, const char* groupname, int objidx) +{ + void* data = auxiliar_getgroupudata(L, groupname, objidx); + if (!data) + { + char msg[45]; + sprintf(msg, "%.35s expected", groupname); + luaL_argerror(L, objidx, msg); + } + return data; } /*-------------------------------------------------------------------------*\ * Set object class \*-------------------------------------------------------------------------*/ -void auxiliar_setclass(lua_State *L, const char *classname, int objidx) { - luaL_getmetatable(L, classname); - if (objidx < 0) objidx--; - lua_setmetatable(L, objidx); +void auxiliar_setclass(lua_State* L, const char* classname, int objidx) +{ + luaL_getmetatable(L, classname); + if (objidx < 0) objidx--; + lua_setmetatable(L, objidx); } /*-------------------------------------------------------------------------*\ * Get a userdata pointer if object belongs to a given group. Return NULL * otherwise \*-------------------------------------------------------------------------*/ -void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { - if (!lua_getmetatable(L, objidx)) - return NULL; - lua_pushstring(L, groupname); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 2); - return NULL; - } else { - lua_pop(L, 2); - return lua_touserdata(L, objidx); - } +void* auxiliar_getgroupudata(lua_State* L, const char* groupname, int objidx) +{ + if (!lua_getmetatable(L, objidx)) + return NULL; + lua_pushstring(L, groupname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) + { + lua_pop(L, 2); + return NULL; + } + else + { + lua_pop(L, 2); + return lua_touserdata(L, objidx); + } } /*-------------------------------------------------------------------------*\ * Get a userdata pointer if object belongs to a given class. Return NULL * otherwise \*-------------------------------------------------------------------------*/ -void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { - return luaL_testudata(L, objidx, classname); +void* auxiliar_getclassudata(lua_State* L, const char* classname, int objidx) +{ + return luaL_testudata(L, objidx, classname); } /*-------------------------------------------------------------------------*\ * Throws error when argument does not have correct type. * Used to be part of lauxlib in Lua 5.1, was dropped from 5.2. \*-------------------------------------------------------------------------*/ -int auxiliar_typeerror (lua_State *L, int narg, const char *tname) { - const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, - luaL_typename(L, narg)); - return luaL_argerror(L, narg, msg); +int auxiliar_typeerror(lua_State* L, int narg, const char* tname) +{ + const char* msg = lua_pushfstring(L, "%s expected, got %s", tname, + luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); } - diff --git a/Lua/auxiliar.h b/Lua/auxiliar.h index 65511d4..5a1b522 100644 --- a/Lua/auxiliar.h +++ b/Lua/auxiliar.h @@ -33,16 +33,16 @@ #include "lauxlib.h" #include "compat.h" -int auxiliar_open(lua_State *L); -void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); -void auxiliar_add2group(lua_State *L, const char *classname, const char *group); -void auxiliar_setclass(lua_State *L, const char *classname, int objidx); -void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); -void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); -void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); -void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); -int auxiliar_checkboolean(lua_State *L, int objidx); -int auxiliar_tostring(lua_State *L); -int auxiliar_typeerror(lua_State *L, int narg, const char *tname); +int auxiliar_open(lua_State* L); +void auxiliar_newclass(lua_State* L, const char* classname, luaL_Reg* func); +void auxiliar_add2group(lua_State* L, const char* classname, const char* group); +void auxiliar_setclass(lua_State* L, const char* classname, int objidx); +void* auxiliar_checkclass(lua_State* L, const char* classname, int objidx); +void* auxiliar_checkgroup(lua_State* L, const char* groupname, int objidx); +void* auxiliar_getclassudata(lua_State* L, const char* groupname, int objidx); +void* auxiliar_getgroupudata(lua_State* L, const char* groupname, int objidx); +int auxiliar_checkboolean(lua_State* L, int objidx); +int auxiliar_tostring(lua_State* L); +int auxiliar_typeerror(lua_State* L, int narg, const char* tname); #endif /* AUXILIAR_H */ diff --git a/Lua/buffer.c b/Lua/buffer.c index fff1634..4498e93 100644 --- a/Lua/buffer.c +++ b/Lua/buffer.c @@ -11,12 +11,12 @@ /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ -static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); -static int recvline(p_buffer buf, luaL_Buffer *b); -static int recvall(p_buffer buf, luaL_Buffer *b); -static int buffer_get(p_buffer buf, const char **data, size_t *count); +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer* b); +static int recvline(p_buffer buf, luaL_Buffer* b); +static int recvall(p_buffer buf, luaL_Buffer* b); +static int buffer_get(p_buffer buf, const char** data, size_t* count); static void buffer_skip(p_buffer buf, size_t count); -static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); +static int sendraw(p_buffer buf, const char* data, size_t count, size_t* sent); /* min and max macros */ #ifndef MIN @@ -32,130 +32,147 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int buffer_open(lua_State *L) { - (void) L; - return 0; +int buffer_open(lua_State* L) +{ + (void)L; + return 0; } /*-------------------------------------------------------------------------*\ * Initializes C structure \*-------------------------------------------------------------------------*/ -void buffer_init(p_buffer buf, p_io io, p_timeout tm) { - buf->first = buf->last = 0; - buf->io = io; - buf->tm = tm; - buf->received = buf->sent = 0; - buf->birthday = timeout_gettime(); +void buffer_init(p_buffer buf, p_io io, p_timeout tm) +{ + buf->first = buf->last = 0; + buf->io = io; + buf->tm = tm; + buf->received = buf->sent = 0; + buf->birthday = timeout_gettime(); } /*-------------------------------------------------------------------------*\ * object:getstats() interface \*-------------------------------------------------------------------------*/ -int buffer_meth_getstats(lua_State *L, p_buffer buf) { - lua_pushnumber(L, (lua_Number) buf->received); - lua_pushnumber(L, (lua_Number) buf->sent); - lua_pushnumber(L, timeout_gettime() - buf->birthday); - return 3; +int buffer_meth_getstats(lua_State* L, p_buffer buf) +{ + lua_pushnumber(L, (lua_Number)buf->received); + lua_pushnumber(L, (lua_Number)buf->sent); + lua_pushnumber(L, timeout_gettime() - buf->birthday); + return 3; } /*-------------------------------------------------------------------------*\ * object:setstats() interface \*-------------------------------------------------------------------------*/ -int buffer_meth_setstats(lua_State *L, p_buffer buf) { - buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); - buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); - if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); - lua_pushnumber(L, 1); - return 1; +int buffer_meth_setstats(lua_State* L, p_buffer buf) +{ + buf->received = (long)luaL_optnumber(L, 2, (lua_Number)buf->received); + buf->sent = (long)luaL_optnumber(L, 3, (lua_Number)buf->sent); + if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * object:send() interface \*-------------------------------------------------------------------------*/ -int buffer_meth_send(lua_State *L, p_buffer buf) { - int top = lua_gettop(L); - int err = IO_DONE; - size_t size = 0, sent = 0; - const char *data = luaL_checklstring(L, 2, &size); - long start = (long) luaL_optnumber(L, 3, 1); - long end = (long) luaL_optnumber(L, 4, -1); - timeout_markstart(buf->tm); - if (start < 0) start = (long) (size+start+1); - if (end < 0) end = (long) (size+end+1); - if (start < 1) start = (long) 1; - if (end > (long) size) end = (long) size; - if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); - /* check if there was an error */ - if (err != IO_DONE) { - lua_pushnil(L); - lua_pushstring(L, buf->io->error(buf->io->ctx, err)); - lua_pushnumber(L, (lua_Number) (sent+start-1)); - } else { - lua_pushnumber(L, (lua_Number) (sent+start-1)); - lua_pushnil(L); - lua_pushnil(L); - } +int buffer_meth_send(lua_State* L, p_buffer buf) +{ + int top = lua_gettop(L); + int err = IO_DONE; + size_t size = 0, sent = 0; + const char* data = luaL_checklstring(L, 2, &size); + long start = (long)luaL_optnumber(L, 3, 1); + long end = (long)luaL_optnumber(L, 4, -1); + timeout_markstart(buf->tm); + if (start < 0) start = (long)(size + start + 1); + if (end < 0) end = (long)(size + end + 1); + if (start < 1) start = (long)1; + if (end > (long)size) end = (long)size; + if (start <= end) err = sendraw(buf, data + start - 1, end - start + 1, &sent); + /* check if there was an error */ + if (err != IO_DONE) + { + lua_pushnil(L); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushnumber(L, (lua_Number)(sent + start - 1)); + } + else + { + lua_pushnumber(L, (lua_Number)(sent + start - 1)); + lua_pushnil(L); + lua_pushnil(L); + } #ifdef LUASOCKET_DEBUG /* push time elapsed during operation as the last return value */ lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); #endif - return lua_gettop(L) - top; + return lua_gettop(L) - top; } /*-------------------------------------------------------------------------*\ * object:receive() interface \*-------------------------------------------------------------------------*/ -int buffer_meth_receive(lua_State *L, p_buffer buf) { - int err = IO_DONE, top = lua_gettop(L); - luaL_Buffer b; - size_t size; - const char *part = luaL_optlstring(L, 3, "", &size); - timeout_markstart(buf->tm); - /* initialize buffer with optional extra prefix - * (useful for concatenating previous partial results) */ - luaL_buffinit(L, &b); - luaL_addlstring(&b, part, size); - /* receive new patterns */ - if (!lua_isnumber(L, 2)) { - const char *p= luaL_optstring(L, 2, "*l"); - if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); - else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); - else luaL_argcheck(L, 0, 2, "invalid receive pattern"); - /* get a fixed number of bytes (minus what was already partially - * received) */ - } else { - double n = lua_tonumber(L, 2); - size_t wanted = (size_t) n; - luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); - if (size == 0 || wanted > size) - err = recvraw(buf, wanted-size, &b); - } - /* check if there was an error */ - if (err != IO_DONE) { - /* we can't push anyting in the stack before pushing the - * contents of the buffer. this is the reason for the complication */ - luaL_pushresult(&b); - lua_pushstring(L, buf->io->error(buf->io->ctx, err)); - lua_pushvalue(L, -2); - lua_pushnil(L); - lua_replace(L, -4); - } else { - luaL_pushresult(&b); - lua_pushnil(L); - lua_pushnil(L); - } +int buffer_meth_receive(lua_State* L, p_buffer buf) +{ + int err = IO_DONE, top = lua_gettop(L); + luaL_Buffer b; + size_t size; + const char* part = luaL_optlstring(L, 3, "", &size); + timeout_markstart(buf->tm); + /* initialize buffer with optional extra prefix + * (useful for concatenating previous partial results) */ + luaL_buffinit(L, &b); + luaL_addlstring(&b, part, size); + /* receive new patterns */ + if (!lua_isnumber(L, 2)) + { + const char* p = luaL_optstring(L, 2, "*l"); + if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); + else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); + else + luaL_argcheck(L, 0, 2, "invalid receive pattern"); + /* get a fixed number of bytes (minus what was already partially + * received) */ + } + else + { + double n = lua_tonumber(L, 2); + size_t wanted = (size_t)n; + luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); + if (size == 0 || wanted > size) + err = recvraw(buf, wanted - size, &b); + } + /* check if there was an error */ + if (err != IO_DONE) + { + /* we can't push anyting in the stack before pushing the + * contents of the buffer. this is the reason for the complication */ + luaL_pushresult(&b); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushvalue(L, -2); + lua_pushnil(L); + lua_replace(L, -4); + } + else + { + luaL_pushresult(&b); + lua_pushnil(L); + lua_pushnil(L); + } #ifdef LUASOCKET_DEBUG /* push time elapsed during operation as the last return value */ lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); #endif - return lua_gettop(L) - top; + return lua_gettop(L) - top; } /*-------------------------------------------------------------------------*\ * Determines if there is any data in the read buffer \*-------------------------------------------------------------------------*/ -int buffer_isempty(p_buffer buf) { - return buf->first >= buf->last; +int buffer_isempty(p_buffer buf) +{ + return buf->first >= buf->last; } /*=========================================================================*\ @@ -165,109 +182,131 @@ int buffer_isempty(p_buffer buf) { * Sends a block of data (unbuffered) \*-------------------------------------------------------------------------*/ #define STEPSIZE 8192 -static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { - p_io io = buf->io; - p_timeout tm = buf->tm; - size_t total = 0; - int err = IO_DONE; - while (total < count && err == IO_DONE) { - size_t done = 0; - size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; - err = io->send(io->ctx, data+total, step, &done, tm); - total += done; - } - *sent = total; - buf->sent += total; - return err; + +static int sendraw(p_buffer buf, const char* data, size_t count, size_t* sent) +{ + p_io io = buf->io; + p_timeout tm = buf->tm; + size_t total = 0; + int err = IO_DONE; + while (total < count && err == IO_DONE) + { + size_t done = 0; + size_t step = (count - total <= STEPSIZE) ? count - total : STEPSIZE; + err = io->send(io->ctx, data + total, step, &done, tm); + total += done; + } + *sent = total; + buf->sent += total; + return err; } /*-------------------------------------------------------------------------*\ * Reads a fixed number of bytes (buffered) \*-------------------------------------------------------------------------*/ -static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { - int err = IO_DONE; - size_t total = 0; - while (err == IO_DONE) { - size_t count; const char *data; - err = buffer_get(buf, &data, &count); - count = MIN(count, wanted - total); - luaL_addlstring(b, data, count); - buffer_skip(buf, count); - total += count; - if (total >= wanted) break; - } - return err; +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer* b) +{ + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) + { + size_t count; + const char* data; + err = buffer_get(buf, &data, &count); + count = MIN(count, wanted - total); + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + total += count; + if (total >= wanted) break; + } + return err; } /*-------------------------------------------------------------------------*\ * Reads everything until the connection is closed (buffered) \*-------------------------------------------------------------------------*/ -static int recvall(p_buffer buf, luaL_Buffer *b) { - int err = IO_DONE; - size_t total = 0; - while (err == IO_DONE) { - const char *data; size_t count; - err = buffer_get(buf, &data, &count); - total += count; - luaL_addlstring(b, data, count); - buffer_skip(buf, count); - } - if (err == IO_CLOSED) { - if (total > 0) return IO_DONE; - else return IO_CLOSED; - } else return err; +static int recvall(p_buffer buf, luaL_Buffer* b) +{ + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) + { + const char* data; + size_t count; + err = buffer_get(buf, &data, &count); + total += count; + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + } + if (err == IO_CLOSED) + { + if (total > 0) return IO_DONE; + else return IO_CLOSED; + } + else return err; } /*-------------------------------------------------------------------------*\ * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF * are not returned by the function and are discarded from the buffer \*-------------------------------------------------------------------------*/ -static int recvline(p_buffer buf, luaL_Buffer *b) { - int err = IO_DONE; - while (err == IO_DONE) { - size_t count, pos; const char *data; - err = buffer_get(buf, &data, &count); - pos = 0; - while (pos < count && data[pos] != '\n') { - /* we ignore all \r's */ - if (data[pos] != '\r') luaL_addchar(b, data[pos]); - pos++; - } - if (pos < count) { /* found '\n' */ - buffer_skip(buf, pos+1); /* skip '\n' too */ - break; /* we are done */ - } else /* reached the end of the buffer */ - buffer_skip(buf, pos); - } - return err; +static int recvline(p_buffer buf, luaL_Buffer* b) +{ + int err = IO_DONE; + while (err == IO_DONE) + { + size_t count, pos; + const char* data; + err = buffer_get(buf, &data, &count); + pos = 0; + while (pos < count && data[pos] != '\n') + { + /* we ignore all \r's */ + if (data[pos] != '\r') + luaL_addchar(b, data[pos]); + pos++; + } + if (pos < count) + { + /* found '\n' */ + buffer_skip(buf, pos + 1); /* skip '\n' too */ + break; /* we are done */ + } + else /* reached the end of the buffer */ + buffer_skip(buf, pos); + } + return err; } /*-------------------------------------------------------------------------*\ * Skips a given number of bytes from read buffer. No data is read from the * transport layer \*-------------------------------------------------------------------------*/ -static void buffer_skip(p_buffer buf, size_t count) { - buf->received += count; - buf->first += count; - if (buffer_isempty(buf)) - buf->first = buf->last = 0; +static void buffer_skip(p_buffer buf, size_t count) +{ + buf->received += count; + buf->first += count; + if (buffer_isempty(buf)) + buf->first = buf->last = 0; } /*-------------------------------------------------------------------------*\ * Return any data available in buffer, or get more data from transport layer * if buffer is empty \*-------------------------------------------------------------------------*/ -static int buffer_get(p_buffer buf, const char **data, size_t *count) { - int err = IO_DONE; - p_io io = buf->io; - p_timeout tm = buf->tm; - if (buffer_isempty(buf)) { - size_t got; - err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); - buf->first = 0; - buf->last = got; - } - *count = buf->last - buf->first; - *data = buf->data + buf->first; - return err; +static int buffer_get(p_buffer buf, const char** data, size_t* count) +{ + int err = IO_DONE; + p_io io = buf->io; + p_timeout tm = buf->tm; + if (buffer_isempty(buf)) + { + size_t got; + err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); + buf->first = 0; + buf->last = got; + } + *count = buf->last - buf->first; + *data = buf->data + buf->first; + return err; } diff --git a/Lua/buffer.h b/Lua/buffer.h index 1281bb3..4e3d525 100644 --- a/Lua/buffer.h +++ b/Lua/buffer.h @@ -24,22 +24,24 @@ #define BUF_SIZE 8192 /* buffer control structure */ -typedef struct t_buffer_ { - double birthday; /* throttle support info: creation time, */ - size_t sent, received; /* bytes sent, and bytes received */ - p_io io; /* IO driver used for this buffer */ - p_timeout tm; /* timeout management for this buffer */ - size_t first, last; /* index of first and last bytes of stored data */ - char data[BUF_SIZE]; /* storage space for buffer data */ +typedef struct t_buffer_ +{ + double birthday; /* throttle support info: creation time, */ + size_t sent, received; /* bytes sent, and bytes received */ + p_io io; /* IO driver used for this buffer */ + p_timeout tm; /* timeout management for this buffer */ + size_t first, last; /* index of first and last bytes of stored data */ + char data[BUF_SIZE]; /* storage space for buffer data */ } t_buffer; -typedef t_buffer *p_buffer; -int buffer_open(lua_State *L); +typedef t_buffer* p_buffer; + +int buffer_open(lua_State* L); void buffer_init(p_buffer buf, p_io io, p_timeout tm); -int buffer_meth_send(lua_State *L, p_buffer buf); -int buffer_meth_receive(lua_State *L, p_buffer buf); -int buffer_meth_getstats(lua_State *L, p_buffer buf); -int buffer_meth_setstats(lua_State *L, p_buffer buf); +int buffer_meth_send(lua_State* L, p_buffer buf); +int buffer_meth_receive(lua_State* L, p_buffer buf); +int buffer_meth_getstats(lua_State* L, p_buffer buf); +int buffer_meth_setstats(lua_State* L, p_buffer buf); int buffer_isempty(p_buffer buf); #endif /* BUF_H */ diff --git a/Lua/except.c b/Lua/except.c index 60b5005..80769ac 100644 --- a/Lua/except.c +++ b/Lua/except.c @@ -22,77 +22,90 @@ typedef int lua_KContext; /*=========================================================================*\ * Internal function prototypes. \*=========================================================================*/ -static int global_protect(lua_State *L); -static int global_newtry(lua_State *L); -static int protected_(lua_State *L); -static int finalize(lua_State *L); -static int do_nothing(lua_State *L); +static int global_protect(lua_State* L); +static int global_newtry(lua_State* L); +static int protected_(lua_State* L); +static int finalize(lua_State* L); +static int do_nothing(lua_State* L); /* except functions */ static luaL_Reg func[] = { - {"newtry", global_newtry}, - {"protect", global_protect}, - {NULL, NULL} + {"newtry", global_newtry}, + {"protect", global_protect}, + {NULL, NULL} }; /*-------------------------------------------------------------------------*\ * Try factory \*-------------------------------------------------------------------------*/ -static void wrap(lua_State *L) { - lua_createtable(L, 1, 0); - lua_pushvalue(L, -2); - lua_rawseti(L, -2, 1); - lua_pushvalue(L, lua_upvalueindex(1)); - lua_setmetatable(L, -2); +static void wrap(lua_State* L) +{ + lua_createtable(L, 1, 0); + lua_pushvalue(L, -2); + lua_rawseti(L, -2, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_setmetatable(L, -2); } -static int finalize(lua_State *L) { - if (!lua_toboolean(L, 1)) { - lua_pushvalue(L, lua_upvalueindex(2)); - lua_call(L, 0, 0); - lua_settop(L, 2); - wrap(L); - lua_error(L); - return 0; - } else return lua_gettop(L); +static int finalize(lua_State* L) +{ + if (!lua_toboolean(L, 1)) + { + lua_pushvalue(L, lua_upvalueindex(2)); + lua_call(L, 0, 0); + lua_settop(L, 2); + wrap(L); + lua_error(L); + return 0; + } + else return lua_gettop(L); } -static int do_nothing(lua_State *L) { - (void) L; - return 0; +static int do_nothing(lua_State* L) +{ + (void)L; + return 0; } -static int global_newtry(lua_State *L) { - lua_settop(L, 1); - if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); - lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, -2); - lua_pushcclosure(L, finalize, 2); - return 1; +static int global_newtry(lua_State* L) +{ + lua_settop(L, 1); + if (lua_isnil(L, 1)) + lua_pushcfunction(L, do_nothing); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, -2); + lua_pushcclosure(L, finalize, 2); + return 1; } /*-------------------------------------------------------------------------*\ * Protect factory \*-------------------------------------------------------------------------*/ -static int unwrap(lua_State *L) { - if (lua_istable(L, -1) && lua_getmetatable(L, -1)) { - int r = lua_rawequal(L, -1, lua_upvalueindex(1)); - lua_pop(L, 1); - if (r) { - lua_pushnil(L); - lua_rawgeti(L, -2, 1); - return 1; - } - } - return 0; +static int unwrap(lua_State* L) +{ + if (lua_istable(L, -1) && lua_getmetatable(L, -1)) + { + int r = lua_rawequal(L, -1, lua_upvalueindex(1)); + lua_pop(L, 1); + if (r) + { + lua_pushnil(L); + lua_rawgeti(L, -2, 1); + return 1; + } + } + return 0; } -static int protected_finish(lua_State *L, int status, lua_KContext ctx) { - (void)ctx; - if (status != 0 && status != LUA_YIELD) { - if (unwrap(L)) return 2; - else return lua_error(L); - } else return lua_gettop(L); +static int protected_finish(lua_State* L, int status, lua_KContext ctx) +{ + (void)ctx; + if (status != 0 && status != LUA_YIELD) + { + if (unwrap(L)) return 2; + else return lua_error(L); + } + else return lua_gettop(L); } #if LUA_VERSION_NUM == 502 @@ -105,29 +118,32 @@ static int protected_cont(lua_State *L) { #define protected_cont protected_finish #endif -static int protected_(lua_State *L) { - int status; - lua_pushvalue(L, lua_upvalueindex(2)); - lua_insert(L, 1); - status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); - return protected_finish(L, status, 0); +static int protected_(lua_State* L) +{ + int status; + lua_pushvalue(L, lua_upvalueindex(2)); + lua_insert(L, 1); + status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); + return protected_finish(L, status, 0); } -static int global_protect(lua_State *L) { - lua_settop(L, 1); - lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, 1); - lua_pushcclosure(L, protected_, 2); - return 1; +static int global_protect(lua_State* L) +{ + lua_settop(L, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + lua_pushcclosure(L, protected_, 2); + return 1; } /*-------------------------------------------------------------------------*\ * Init module \*-------------------------------------------------------------------------*/ -int except_open(lua_State *L) { - lua_newtable(L); /* metatable for wrapped exceptions */ - lua_pushboolean(L, 0); - lua_setfield(L, -2, "__metatable"); - luaL_setfuncs(L, func, 1); - return 0; +int except_open(lua_State* L) +{ + lua_newtable(L); /* metatable for wrapped exceptions */ + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + luaL_setfuncs(L, func, 1); + return 0; } diff --git a/Lua/except.h b/Lua/except.h index 2497c05..29bceca 100644 --- a/Lua/except.h +++ b/Lua/except.h @@ -33,6 +33,6 @@ #include "lua.h" -int except_open(lua_State *L); +int except_open(lua_State* L); #endif diff --git a/Lua/inet.c b/Lua/inet.c index 84d0ebd..65a427c 100644 --- a/Lua/inet.c +++ b/Lua/inet.c @@ -15,21 +15,21 @@ /*=========================================================================*\ * Internal function prototypes. \*=========================================================================*/ -static int inet_global_toip(lua_State *L); -static int inet_global_getaddrinfo(lua_State *L); -static int inet_global_tohostname(lua_State *L); -static int inet_global_getnameinfo(lua_State *L); -static void inet_pushresolved(lua_State *L, struct hostent *hp); -static int inet_global_gethostname(lua_State *L); +static int inet_global_toip(lua_State* L); +static int inet_global_getaddrinfo(lua_State* L); +static int inet_global_tohostname(lua_State* L); +static int inet_global_getnameinfo(lua_State* L); +static void inet_pushresolved(lua_State* L, struct hostent* hp); +static int inet_global_gethostname(lua_State* L); /* DNS functions */ static luaL_Reg func[] = { - { "toip", inet_global_toip}, - { "getaddrinfo", inet_global_getaddrinfo}, - { "tohostname", inet_global_tohostname}, - { "getnameinfo", inet_global_getnameinfo}, - { "gethostname", inet_global_gethostname}, - { NULL, NULL} + {"toip", inet_global_toip}, + {"getaddrinfo", inet_global_getaddrinfo}, + {"tohostname", inet_global_tohostname}, + {"getnameinfo", inet_global_getnameinfo}, + {"gethostname", inet_global_gethostname}, + {NULL, NULL} }; /*=========================================================================*\ @@ -38,13 +38,13 @@ static luaL_Reg func[] = { /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int inet_open(lua_State *L) +int inet_open(lua_State* L) { - lua_pushstring(L, "dns"); - lua_newtable(L); - luaL_setfuncs(L, func, 0); - lua_settable(L, -3); - return 0; + lua_pushstring(L, "dns"); + lua_newtable(L); + luaL_setfuncs(L, func, 0); + lua_settable(L, -3); + return 0; } /*=========================================================================*\ @@ -54,186 +54,204 @@ int inet_open(lua_State *L) * Returns all information provided by the resolver given a host name * or ip address \*-------------------------------------------------------------------------*/ -static int inet_gethost(const char *address, struct hostent **hp) { - struct in_addr addr; - if (inet_aton(address, &addr)) - return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); - else - return socket_gethostbyname(address, hp); -} - -/*-------------------------------------------------------------------------*\ -* Returns all information provided by the resolver given a host name -* or ip address -\*-------------------------------------------------------------------------*/ -static int inet_global_tohostname(lua_State *L) { - const char *address = luaL_checkstring(L, 1); - struct hostent *hp = NULL; - int err = inet_gethost(address, &hp); - if (err != IO_DONE) { - lua_pushnil(L); - lua_pushstring(L, socket_hoststrerror(err)); - return 2; - } - lua_pushstring(L, hp->h_name); - inet_pushresolved(L, hp); - return 2; -} - -static int inet_global_getnameinfo(lua_State *L) { - char hbuf[NI_MAXHOST]; - char sbuf[NI_MAXSERV]; - int i, ret; - struct addrinfo hints; - struct addrinfo *resolved, *iter; - const char *host = luaL_optstring(L, 1, NULL); - const char *serv = luaL_optstring(L, 2, NULL); - - if (!(host || serv)) - luaL_error(L, "host and serv cannot be both nil"); - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_UNSPEC; - - ret = getaddrinfo(host, serv, &hints, &resolved); - if (ret != 0) { - lua_pushnil(L); - lua_pushstring(L, socket_gaistrerror(ret)); - return 2; - } - - lua_newtable(L); - for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { - getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, - hbuf, host? (socklen_t) sizeof(hbuf): 0, - sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); - if (host) { - lua_pushnumber(L, i); - lua_pushstring(L, hbuf); - lua_settable(L, -3); - } - } - freeaddrinfo(resolved); - - if (serv) { - lua_pushstring(L, sbuf); - return 2; - } else { - return 1; - } -} - -/*-------------------------------------------------------------------------*\ -* Returns all information provided by the resolver given a host name -* or ip address -\*-------------------------------------------------------------------------*/ -static int inet_global_toip(lua_State *L) +static int inet_gethost(const char* address, struct hostent** hp) { - const char *address = luaL_checkstring(L, 1); - struct hostent *hp = NULL; - int err = inet_gethost(address, &hp); - if (err != IO_DONE) { - lua_pushnil(L); - lua_pushstring(L, socket_hoststrerror(err)); - return 2; - } - lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); - inet_pushresolved(L, hp); - return 2; + struct in_addr addr; + if (inet_aton(address, &addr)) + return socket_gethostbyaddr((char*)&addr, sizeof(addr), hp); + else + return socket_gethostbyname(address, hp); +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_tohostname(lua_State* L) +{ + const char* address = luaL_checkstring(L, 1); + struct hostent* hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) + { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, hp->h_name); + inet_pushresolved(L, hp); + return 2; +} + +static int inet_global_getnameinfo(lua_State* L) +{ + char hbuf[NI_MAXHOST]; + char sbuf[NI_MAXSERV]; + int i, ret; + struct addrinfo hints; + struct addrinfo *resolved, *iter; + const char* host = luaL_optstring(L, 1, NULL); + const char* serv = luaL_optstring(L, 2, NULL); + + if (!(host || serv)) + luaL_error(L, "host and serv cannot be both nil"); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + + ret = getaddrinfo(host, serv, &hints, &resolved); + if (ret != 0) + { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + + lua_newtable(L); + for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) + { + getnameinfo(iter->ai_addr, (socklen_t)iter->ai_addrlen, + hbuf, host ? (socklen_t)sizeof(hbuf) : 0, + sbuf, serv ? (socklen_t)sizeof(sbuf) : 0, 0); + if (host) + { + lua_pushnumber(L, i); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + } + } + freeaddrinfo(resolved); + + if (serv) + { + lua_pushstring(L, sbuf); + return 2; + } + else + { + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_toip(lua_State* L) +{ + const char* address = luaL_checkstring(L, 1); + struct hostent* hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) + { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, inet_ntoa(*((struct in_addr*)hp->h_addr))); + inet_pushresolved(L, hp); + return 2; } int inet_optfamily(lua_State* L, int narg, const char* def) { - static const char* optname[] = { "unspec", "inet", "inet6", NULL }; - static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; + static const char* optname[] = {"unspec", "inet", "inet6", NULL}; + static int optvalue[] = {AF_UNSPEC, AF_INET, AF_INET6, 0}; - return optvalue[luaL_checkoption(L, narg, def, optname)]; + return optvalue[luaL_checkoption(L, narg, def, optname)]; } int inet_optsocktype(lua_State* L, int narg, const char* def) { - static const char* optname[] = { "stream", "dgram", NULL }; - static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; + static const char* optname[] = {"stream", "dgram", NULL}; + static int optvalue[] = {SOCK_STREAM, SOCK_DGRAM, 0}; - return optvalue[luaL_checkoption(L, narg, def, optname)]; + return optvalue[luaL_checkoption(L, narg, def, optname)]; } -static int inet_global_getaddrinfo(lua_State *L) +static int inet_global_getaddrinfo(lua_State* L) { - const char *hostname = luaL_checkstring(L, 1); - struct addrinfo *iterator = NULL, *resolved = NULL; - struct addrinfo hints; - int i = 1, ret = 0; - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_UNSPEC; - ret = getaddrinfo(hostname, NULL, &hints, &resolved); - if (ret != 0) { - lua_pushnil(L); - lua_pushstring(L, socket_gaistrerror(ret)); - return 2; - } - lua_newtable(L); - for (iterator = resolved; iterator; iterator = iterator->ai_next) { - char hbuf[NI_MAXHOST]; - ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, - hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); - if (ret){ - freeaddrinfo(resolved); - lua_pushnil(L); - lua_pushstring(L, socket_gaistrerror(ret)); - return 2; - } - lua_pushnumber(L, i); - lua_newtable(L); - switch (iterator->ai_family) { - case AF_INET: - lua_pushliteral(L, "family"); - lua_pushliteral(L, "inet"); - lua_settable(L, -3); - break; - case AF_INET6: - lua_pushliteral(L, "family"); - lua_pushliteral(L, "inet6"); - lua_settable(L, -3); - break; - case AF_UNSPEC: - lua_pushliteral(L, "family"); - lua_pushliteral(L, "unspec"); - lua_settable(L, -3); - break; - default: - lua_pushliteral(L, "family"); - lua_pushliteral(L, "unknown"); - lua_settable(L, -3); - break; - } - lua_pushliteral(L, "addr"); - lua_pushstring(L, hbuf); - lua_settable(L, -3); - lua_settable(L, -3); - i++; - } - freeaddrinfo(resolved); - return 1; + const char* hostname = luaL_checkstring(L, 1); + struct addrinfo *iterator = NULL, *resolved = NULL; + struct addrinfo hints; + int i = 1, ret = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + ret = getaddrinfo(hostname, NULL, &hints, &resolved); + if (ret != 0) + { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_newtable(L); + for (iterator = resolved; iterator; iterator = iterator->ai_next) + { + char hbuf[NI_MAXHOST]; + ret = getnameinfo(iterator->ai_addr, (socklen_t)iterator->ai_addrlen, + hbuf, (socklen_t)sizeof(hbuf), NULL, 0, NI_NUMERICHOST); + if (ret) + { + freeaddrinfo(resolved); + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_pushnumber(L, i); + lua_newtable(L); + switch (iterator->ai_family) + { + case AF_INET: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet"); + lua_settable(L, -3); + break; + case AF_INET6: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet6"); + lua_settable(L, -3); + break; + case AF_UNSPEC: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unspec"); + lua_settable(L, -3); + break; + default: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unknown"); + lua_settable(L, -3); + break; + } + lua_pushliteral(L, "addr"); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + lua_settable(L, -3); + i++; + } + freeaddrinfo(resolved); + return 1; } /*-------------------------------------------------------------------------*\ * Gets the host name \*-------------------------------------------------------------------------*/ -static int inet_global_gethostname(lua_State *L) +static int inet_global_gethostname(lua_State* L) { - char name[257]; - name[256] = '\0'; - if (gethostname(name, 256) < 0) { - lua_pushnil(L); - lua_pushstring(L, socket_strerror(errno)); - return 2; - } else { - lua_pushstring(L, name); - return 1; - } + char name[257]; + name[256] = '\0'; + if (gethostname(name, 256) < 0) + { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + else + { + lua_pushstring(L, name); + return 1; + } } /*=========================================================================*\ @@ -242,68 +260,82 @@ static int inet_global_gethostname(lua_State *L) /*-------------------------------------------------------------------------*\ * Retrieves socket peer name \*-------------------------------------------------------------------------*/ -int inet_meth_getpeername(lua_State *L, p_socket ps, int family) +int inet_meth_getpeername(lua_State* L, p_socket ps, int family) { - int err; - struct sockaddr_storage peer; - socklen_t peer_len = sizeof(peer); - char name[INET6_ADDRSTRLEN]; - char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ - if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { - lua_pushnil(L); - lua_pushstring(L, socket_strerror(errno)); - return 2; - } - err = getnameinfo((struct sockaddr *) &peer, peer_len, - name, INET6_ADDRSTRLEN, - port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); - if (err) { - lua_pushnil(L); - lua_pushstring(L, gai_strerrorA(err)); - return 2; - } - lua_pushstring(L, name); - lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); - switch (family) { - case AF_INET: lua_pushliteral(L, "inet"); break; - case AF_INET6: lua_pushliteral(L, "inet6"); break; - case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; - default: lua_pushliteral(L, "unknown"); break; - } - return 3; + int err; + struct sockaddr_storage peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ + if (getpeername(*ps, (SA*)&peer, &peer_len) < 0) + { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + err = getnameinfo((struct sockaddr*)&peer, peer_len, + name, INET6_ADDRSTRLEN, + port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, gai_strerrorA(err)); + return 2; + } + lua_pushstring(L, name); + lua_pushinteger(L, (int)strtol(port, (char**)NULL, 10)); + switch (family) + { + case AF_INET: lua_pushliteral(L, "inet"); + break; + case AF_INET6: lua_pushliteral(L, "inet6"); + break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); + break; + default: lua_pushliteral(L, "unknown"); + break; + } + return 3; } /*-------------------------------------------------------------------------*\ * Retrieves socket local name \*-------------------------------------------------------------------------*/ -int inet_meth_getsockname(lua_State *L, p_socket ps, int family) +int inet_meth_getsockname(lua_State* L, p_socket ps, int family) { - int err; - struct sockaddr_storage peer; - socklen_t peer_len = sizeof(peer); - char name[INET6_ADDRSTRLEN]; - char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ - if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) { - lua_pushnil(L); - lua_pushstring(L, socket_strerror(errno)); - return 2; - } - err=getnameinfo((struct sockaddr *)&peer, peer_len, - name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); - if (err) { - lua_pushnil(L); - lua_pushstring(L, gai_strerrorA(err)); - return 2; - } - lua_pushstring(L, name); - lua_pushstring(L, port); - switch (family) { - case AF_INET: lua_pushliteral(L, "inet"); break; - case AF_INET6: lua_pushliteral(L, "inet6"); break; - case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; - default: lua_pushliteral(L, "unknown"); break; - } - return 3; + int err; + struct sockaddr_storage peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ + if (getsockname(*ps, (SA*)&peer, &peer_len) < 0) + { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + err = getnameinfo((struct sockaddr*)&peer, peer_len, + name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, gai_strerrorA(err)); + return 2; + } + lua_pushstring(L, name); + lua_pushstring(L, port); + switch (family) + { + case AF_INET: lua_pushliteral(L, "inet"); + break; + case AF_INET6: lua_pushliteral(L, "inet6"); + break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); + break; + default: lua_pushliteral(L, "unknown"); + break; + } + return 3; } /*=========================================================================*\ @@ -312,209 +344,239 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) /*-------------------------------------------------------------------------*\ * Passes all resolver information to Lua as a table \*-------------------------------------------------------------------------*/ -static void inet_pushresolved(lua_State *L, struct hostent *hp) +static void inet_pushresolved(lua_State* L, struct hostent* hp) { - char **alias; - struct in_addr **addr; - int i, resolved; - lua_newtable(L); resolved = lua_gettop(L); - lua_pushstring(L, "name"); - lua_pushstring(L, hp->h_name); - lua_settable(L, resolved); - lua_pushstring(L, "ip"); - lua_pushstring(L, "alias"); - i = 1; - alias = hp->h_aliases; - lua_newtable(L); - if (alias) { - while (*alias) { - lua_pushnumber(L, i); - lua_pushstring(L, *alias); - lua_settable(L, -3); - i++; alias++; - } - } - lua_settable(L, resolved); - i = 1; - lua_newtable(L); - addr = (struct in_addr **) hp->h_addr_list; - if (addr) { - while (*addr) { - lua_pushnumber(L, i); - lua_pushstring(L, inet_ntoa(**addr)); - lua_settable(L, -3); - i++; addr++; - } - } - lua_settable(L, resolved); + char** alias; + struct in_addr** addr; + int i, resolved; + lua_newtable(L); + resolved = lua_gettop(L); + lua_pushstring(L, "name"); + lua_pushstring(L, hp->h_name); + lua_settable(L, resolved); + lua_pushstring(L, "ip"); + lua_pushstring(L, "alias"); + i = 1; + alias = hp->h_aliases; + lua_newtable(L); + if (alias) + { + while (*alias) + { + lua_pushnumber(L, i); + lua_pushstring(L, *alias); + lua_settable(L, -3); + i++; + alias++; + } + } + lua_settable(L, resolved); + i = 1; + lua_newtable(L); + addr = (struct in_addr**)hp->h_addr_list; + if (addr) + { + while (*addr) + { + lua_pushnumber(L, i); + lua_pushstring(L, inet_ntoa(**addr)); + lua_settable(L, -3); + i++; + addr++; + } + } + lua_settable(L, resolved); } /*-------------------------------------------------------------------------*\ * Tries to create a new inet socket \*-------------------------------------------------------------------------*/ -const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { - const char *err = socket_strerror(socket_create(ps, family, type, protocol)); - if (err == NULL && family == AF_INET6) { - int yes = 1; - setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); - } - return err; +const char* inet_trycreate(p_socket ps, int family, int type, int protocol) +{ + const char* err = socket_strerror(socket_create(ps, family, type, protocol)); + if (err == NULL && family == AF_INET6) + { + int yes = 1; + setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(yes)); + } + return err; } /*-------------------------------------------------------------------------*\ * "Disconnects" a DGRAM socket \*-------------------------------------------------------------------------*/ -const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) +const char* inet_trydisconnect(p_socket ps, int family, p_timeout tm) { - switch (family) { - case AF_INET: { - struct sockaddr_in sin; - memset((char *) &sin, 0, sizeof(sin)); - sin.sin_family = AF_UNSPEC; - sin.sin_addr.s_addr = INADDR_ANY; - return socket_strerror(socket_connect(ps, (SA *) &sin, - sizeof(sin), tm)); - } - case AF_INET6: { - struct sockaddr_in6 sin6; - struct in6_addr addrany = IN6ADDR_ANY_INIT; - memset((char *) &sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_UNSPEC; - sin6.sin6_addr = addrany; - return socket_strerror(socket_connect(ps, (SA *) &sin6, - sizeof(sin6), tm)); - } - } - return NULL; + switch (family) + { + case AF_INET: + { + struct sockaddr_in sin; + memset((char*)&sin, 0, sizeof(sin)); + sin.sin_family = AF_UNSPEC; + sin.sin_addr.s_addr = INADDR_ANY; + return socket_strerror(socket_connect(ps, (SA*)&sin, + sizeof(sin), tm)); + } + case AF_INET6: + { + struct sockaddr_in6 sin6; + struct in6_addr addrany = IN6ADDR_ANY_INIT; + memset((char*)&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_UNSPEC; + sin6.sin6_addr = addrany; + return socket_strerror(socket_connect(ps, (SA*)&sin6, + sizeof(sin6), tm)); + } + } + return NULL; } /*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ -const char *inet_tryconnect(p_socket ps, int *family, const char *address, - const char *serv, p_timeout tm, struct addrinfo *connecthints) +const char* inet_tryconnect(p_socket ps, int* family, const char* address, + const char* serv, p_timeout tm, struct addrinfo* connecthints) { - struct addrinfo *iterator = NULL, *resolved = NULL; - const char *err = NULL; - int current_family = *family; - /* try resolving */ - err = socket_gaistrerror(getaddrinfo(address, serv, - connecthints, &resolved)); - if (err != NULL) { - if (resolved) freeaddrinfo(resolved); - return err; - } - for (iterator = resolved; iterator; iterator = iterator->ai_next) { - timeout_markstart(tm); - /* create new socket if necessary. if there was no - * bind, we need to create one for every new family - * that shows up while iterating. if there was a - * bind, all families will be the same and we will - * not enter this branch. */ - if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { - socket_destroy(ps); - err = inet_trycreate(ps, iterator->ai_family, - iterator->ai_socktype, iterator->ai_protocol); - if (err) continue; - current_family = iterator->ai_family; - /* set non-blocking before connect */ - socket_setnonblocking(ps); - } - /* try connecting to remote address */ - err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, - (socklen_t) iterator->ai_addrlen, tm)); - /* if success or timeout is zero, break out of loop */ - if (err == NULL || timeout_iszero(tm)) { - *family = current_family; - break; - } - } - freeaddrinfo(resolved); - /* here, if err is set, we failed */ - return err; + struct addrinfo *iterator = NULL, *resolved = NULL; + const char* err = NULL; + int current_family = *family; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, + connecthints, &resolved)); + if (err != NULL) + { + if (resolved) freeaddrinfo(resolved); + return err; + } + for (iterator = resolved; iterator; iterator = iterator->ai_next) + { + timeout_markstart(tm); + /* create new socket if necessary. if there was no + * bind, we need to create one for every new family + * that shows up while iterating. if there was a + * bind, all families will be the same and we will + * not enter this branch. */ + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) + { + socket_destroy(ps); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); + if (err) continue; + current_family = iterator->ai_family; + /* set non-blocking before connect */ + socket_setnonblocking(ps); + } + /* try connecting to remote address */ + err = socket_strerror(socket_connect(ps, (SA*)iterator->ai_addr, + (socklen_t)iterator->ai_addrlen, tm)); + /* if success or timeout is zero, break out of loop */ + if (err == NULL || timeout_iszero(tm)) + { + *family = current_family; + break; + } + } + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; } /*-------------------------------------------------------------------------*\ * Tries to accept a socket \*-------------------------------------------------------------------------*/ -const char *inet_tryaccept(p_socket server, int family, p_socket client, - p_timeout tm) { +const char* inet_tryaccept(p_socket server, int family, p_socket client, + p_timeout tm) +{ socklen_t len; t_sockaddr_storage addr; - switch (family) { - case AF_INET6: len = sizeof(struct sockaddr_in6); break; - case AF_INET: len = sizeof(struct sockaddr_in); break; - default: len = sizeof(addr); break; - } - return socket_strerror(socket_accept(server, client, (SA *) &addr, - &len, tm)); + switch (family) + { + case AF_INET6: len = sizeof(struct sockaddr_in6); + break; + case AF_INET: len = sizeof(struct sockaddr_in); + break; + default: len = sizeof(addr); + break; + } + return socket_strerror(socket_accept(server, client, (SA*)&addr, + &len, tm)); } /*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ -const char *inet_trybind(p_socket ps, int *family, const char *address, - const char *serv, struct addrinfo *bindhints) { - struct addrinfo *iterator = NULL, *resolved = NULL; - const char *err = NULL; - int current_family = *family; - /* translate luasocket special values to C */ - if (strcmp(address, "*") == 0) address = NULL; - if (!serv) serv = "0"; - /* try resolving */ - err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); - if (err) { - if (resolved) freeaddrinfo(resolved); - return err; - } - /* iterate over resolved addresses until one is good */ - for (iterator = resolved; iterator; iterator = iterator->ai_next) { - if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { - socket_destroy(ps); - err = inet_trycreate(ps, iterator->ai_family, - iterator->ai_socktype, iterator->ai_protocol); - if (err) continue; - current_family = iterator->ai_family; - } - /* try binding to local address */ - err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, - (socklen_t) iterator->ai_addrlen)); - /* keep trying unless bind succeeded */ - if (err == NULL) { - *family = current_family; - /* set to non-blocking after bind */ - socket_setnonblocking(ps); - break; - } - } - /* cleanup and return error */ - freeaddrinfo(resolved); - /* here, if err is set, we failed */ - return err; +const char* inet_trybind(p_socket ps, int* family, const char* address, + const char* serv, struct addrinfo* bindhints) +{ + struct addrinfo *iterator = NULL, *resolved = NULL; + const char* err = NULL; + int current_family = *family; + /* translate luasocket special values to C */ + if (strcmp(address, "*") == 0) address = NULL; + if (!serv) serv = "0"; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); + if (err) + { + if (resolved) freeaddrinfo(resolved); + return err; + } + /* iterate over resolved addresses until one is good */ + for (iterator = resolved; iterator; iterator = iterator->ai_next) + { + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) + { + socket_destroy(ps); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); + if (err) continue; + current_family = iterator->ai_family; + } + /* try binding to local address */ + err = socket_strerror(socket_bind(ps, (SA*)iterator->ai_addr, + (socklen_t)iterator->ai_addrlen)); + /* keep trying unless bind succeeded */ + if (err == NULL) + { + *family = current_family; + /* set to non-blocking after bind */ + socket_setnonblocking(ps); + break; + } + } + /* cleanup and return error */ + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; } /*-------------------------------------------------------------------------*\ * Some systems do not provide these so that we provide our own. \*-------------------------------------------------------------------------*/ #ifdef LUASOCKET_INET_ATON -int inet_aton(const char *cp, struct in_addr *inp) +int inet_aton(const char* cp, struct in_addr* inp) { - unsigned int a = 0, b = 0, c = 0, d = 0; - int n = 0, r; - unsigned long int addr = 0; - r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); - if (r == 0 || n == 0) return 0; - cp += n; - if (*cp) return 0; - if (a > 255 || b > 255 || c > 255 || d > 255) return 0; - if (inp) { - addr += a; addr <<= 8; - addr += b; addr <<= 8; - addr += c; addr <<= 8; - addr += d; - inp->s_addr = htonl(addr); - } - return 1; + unsigned int a = 0, b = 0, c = 0, d = 0; + int n = 0, r; + unsigned long int addr = 0; + r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); + if (r == 0 || n == 0) return 0; + cp += n; + if (*cp) return 0; + if (a > 255 || b > 255 || c > 255 || d > 255) return 0; + if (inp) + { + addr += a; + addr <<= 8; + addr += b; + addr <<= 8; + addr += c; + addr <<= 8; + addr += d; + inp->s_addr = htonl(addr); + } + return 1; } #endif diff --git a/Lua/inet.h b/Lua/inet.h index feb3541..2385060 100644 --- a/Lua/inet.h +++ b/Lua/inet.h @@ -22,24 +22,24 @@ #define LUASOCKET_INET_ATON #endif -int inet_open(lua_State *L); +int inet_open(lua_State* L); -const char *inet_trycreate(p_socket ps, int family, int type, int protocol); -const char *inet_tryconnect(p_socket ps, int *family, const char *address, - const char *serv, p_timeout tm, struct addrinfo *connecthints); -const char *inet_trybind(p_socket ps, int *family, const char *address, - const char *serv, struct addrinfo *bindhints); -const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); -const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); +const char* inet_trycreate(p_socket ps, int family, int type, int protocol); +const char* inet_tryconnect(p_socket ps, int* family, const char* address, + const char* serv, p_timeout tm, struct addrinfo* connecthints); +const char* inet_trybind(p_socket ps, int* family, const char* address, + const char* serv, struct addrinfo* bindhints); +const char* inet_trydisconnect(p_socket ps, int family, p_timeout tm); +const char* inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); -int inet_meth_getpeername(lua_State *L, p_socket ps, int family); -int inet_meth_getsockname(lua_State *L, p_socket ps, int family); +int inet_meth_getpeername(lua_State* L, p_socket ps, int family); +int inet_meth_getsockname(lua_State* L, p_socket ps, int family); int inet_optfamily(lua_State* L, int narg, const char* def); int inet_optsocktype(lua_State* L, int narg, const char* def); #ifdef LUASOCKET_INET_ATON -int inet_aton(const char *cp, struct in_addr *inp); +int inet_aton(const char* cp, struct in_addr* inp); #endif #ifdef LUASOCKET_INET_PTON diff --git a/Lua/io.c b/Lua/io.c index a4230ce..1b04689 100644 --- a/Lua/io.c +++ b/Lua/io.c @@ -10,21 +10,24 @@ /*-------------------------------------------------------------------------*\ * Initializes C structure \*-------------------------------------------------------------------------*/ -void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { - io->send = send; - io->recv = recv; - io->error = error; - io->ctx = ctx; +void io_init(p_io io, p_send send, p_recv recv, p_error error, void* ctx) +{ + io->send = send; + io->recv = recv; + io->error = error; + io->ctx = ctx; } /*-------------------------------------------------------------------------*\ * I/O error strings \*-------------------------------------------------------------------------*/ -const char *io_strerror(int err) { - switch (err) { - case IO_DONE: return NULL; - case IO_CLOSED: return "closed"; - case IO_TIMEOUT: return "timeout"; - default: return "unknown error"; - } +const char* io_strerror(int err) +{ + switch (err) + { + case IO_DONE: return NULL; + case IO_CLOSED: return "closed"; + case IO_TIMEOUT: return "timeout"; + default: return "unknown error"; + } } diff --git a/Lua/io.h b/Lua/io.h index 8cca08a..22ddcb3 100644 --- a/Lua/io.h +++ b/Lua/io.h @@ -18,48 +18,53 @@ #include "timeout.h" /* IO error codes */ -enum { - IO_DONE = 0, /* operation completed successfully */ - IO_TIMEOUT = -1, /* operation timed out */ - IO_CLOSED = -2, /* the connection has been closed */ +enum +{ + IO_DONE = 0, + /* operation completed successfully */ + IO_TIMEOUT = -1, + /* operation timed out */ + IO_CLOSED = -2, + /* the connection has been closed */ IO_UNKNOWN = -3 }; /* interface to error message function */ -typedef const char *(*p_error) ( - void *ctx, /* context needed by send */ - int err /* error code */ +typedef const char*(*p_error)( + void* ctx, /* context needed by send */ + int err /* error code */ ); /* interface to send function */ -typedef int (*p_send) ( - void *ctx, /* context needed by send */ - const char *data, /* pointer to buffer with data to send */ - size_t count, /* number of bytes to send from buffer */ - size_t *sent, /* number of bytes sent uppon return */ - p_timeout tm /* timeout control */ +typedef int (*p_send)( + void* ctx, /* context needed by send */ + const char* data, /* pointer to buffer with data to send */ + size_t count, /* number of bytes to send from buffer */ + size_t* sent, /* number of bytes sent uppon return */ + p_timeout tm /* timeout control */ ); /* interface to recv function */ -typedef int (*p_recv) ( - void *ctx, /* context needed by recv */ - char *data, /* pointer to buffer where data will be writen */ - size_t count, /* number of bytes to receive into buffer */ - size_t *got, /* number of bytes received uppon return */ - p_timeout tm /* timeout control */ +typedef int (*p_recv)( + void* ctx, /* context needed by recv */ + char* data, /* pointer to buffer where data will be writen */ + size_t count, /* number of bytes to receive into buffer */ + size_t* got, /* number of bytes received uppon return */ + p_timeout tm /* timeout control */ ); /* IO driver definition */ -typedef struct t_io_ { - void *ctx; /* context needed by send/recv */ - p_send send; /* send function pointer */ - p_recv recv; /* receive function pointer */ - p_error error; /* strerror function */ +typedef struct t_io_ +{ + void* ctx; /* context needed by send/recv */ + p_send send; /* send function pointer */ + p_recv recv; /* receive function pointer */ + p_error error; /* strerror function */ } t_io; -typedef t_io *p_io; -void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); -const char *io_strerror(int err); +typedef t_io* p_io; + +void io_init(p_io io, p_send send, p_recv recv, p_error error, void* ctx); +const char* io_strerror(int err); #endif /* IO_H */ - diff --git a/Lua/lapi.c b/Lua/lapi.c index c9455a5..f1614b9 100644 --- a/Lua/lapi.c +++ b/Lua/lapi.c @@ -30,10 +30,9 @@ #include "lvm.h" - const char lua_ident[] = - "$LuaVersion: " LUA_COPYRIGHT " $" - "$LuaAuthors: " LUA_AUTHORS " $"; + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; /* value at a non-valid index */ @@ -57,30 +56,37 @@ const char lua_ident[] = api_check(l, isstackindex(i, o), "index not in the stack") -static TValue *index2addr (lua_State *L, int idx) { - CallInfo *ci = L->ci; - if (idx > 0) { - TValue *o = ci->func + idx; - api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); - if (o >= L->top) return NONVALIDVALUE; - else return o; - } - else if (!ispseudo(idx)) { /* negative index */ - api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); - return L->top + idx; - } - else if (idx == LUA_REGISTRYINDEX) - return &G(L)->l_registry; - else { /* upvalues */ - idx = LUA_REGISTRYINDEX - idx; - api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); - if (ttislcf(ci->func)) /* light C function? */ - return NONVALIDVALUE; /* it has no upvalues */ - else { - CClosure *func = clCvalue(ci->func); - return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; - } - } +static TValue* index2addr(lua_State* L, int idx) +{ + CallInfo* ci = L->ci; + if (idx > 0) + { + TValue* o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); + if (o >= L->top) return NONVALIDVALUE; + else return o; + } + else if (!ispseudo(idx)) + { + /* negative index */ + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); + return L->top + idx; + } + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else + { + /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return NONVALIDVALUE; /* it has no upvalues */ + else + { + CClosure* func = clCvalue(ci->func); + return (idx <= func->nupvalues) ? &func->upvalue[idx - 1] : NONVALIDVALUE; + } + } } @@ -88,67 +94,74 @@ static TValue *index2addr (lua_State *L, int idx) { ** to be called by 'lua_checkstack' in protected mode, to grow stack ** capturing memory errors */ -static void growstack (lua_State *L, void *ud) { - int size = *(int *)ud; - luaD_growstack(L, size); +static void growstack(lua_State* L, void* ud) +{ + int size = *(int*)ud; + luaD_growstack(L, size); } -LUA_API int lua_checkstack (lua_State *L, int n) { - int res; - CallInfo *ci = L->ci; - lua_lock(L); - api_check(L, n >= 0, "negative 'n'"); - if (L->stack_last - L->top > n) /* stack large enough? */ - res = 1; /* yes; check is OK */ - else { /* no; need to grow stack */ - int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; - if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ - res = 0; /* no */ - else /* try to grow stack */ - res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); - } - if (res && ci->top < L->top + n) - ci->top = L->top + n; /* adjust frame top */ - lua_unlock(L); - return res; +LUA_API int lua_checkstack(lua_State* L, int n) +{ + int res; + CallInfo* ci = L->ci; + lua_lock(L); + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last - L->top > n) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else + { + /* no; need to grow stack */ + int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; + if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ + res = 0; /* no */ + else /* try to grow stack */ + res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); + } + if (res && ci->top < L->top + n) + ci->top = L->top + n; /* adjust frame top */ + lua_unlock(L); + return res; } -LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { - int i; - if (from == to) return; - lua_lock(to); - api_checknelems(from, n); - api_check(from, G(from) == G(to), "moving among independent states"); - api_check(from, to->ci->top - to->top >= n, "stack overflow"); - from->top -= n; - for (i = 0; i < n; i++) { - setobj2s(to, to->top, from->top + i); - to->top++; /* stack already checked by previous 'api_check' */ - } - lua_unlock(to); +LUA_API void lua_xmove(lua_State* from, lua_State* to, int n) +{ + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top - to->top >= n, "stack overflow"); + from->top -= n; + for (i = 0; i < n; i++) + { + setobj2s(to, to->top, from->top + i); + to->top++; /* stack already checked by previous 'api_check' */ + } + lua_unlock(to); } -LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { - lua_CFunction old; - lua_lock(L); - old = G(L)->panic; - G(L)->panic = panicf; - lua_unlock(L); - return old; +LUA_API lua_CFunction lua_atpanic(lua_State* L, lua_CFunction panicf) +{ + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; } -LUA_API const lua_Number *lua_version (lua_State *L) { - static const lua_Number version = LUA_VERSION_NUM; - if (L == NULL) return &version; - else return G(L)->version; +LUA_API const lua_Number* lua_version(lua_State* L) +{ + static const lua_Number version = LUA_VERSION_NUM; + if (L == NULL) return &version; + else return G(L)->version; } - /* ** basic stack manipulation */ @@ -157,32 +170,37 @@ LUA_API const lua_Number *lua_version (lua_State *L) { /* ** convert an acceptable stack index into an absolute index */ -LUA_API int lua_absindex (lua_State *L, int idx) { - return (idx > 0 || ispseudo(idx)) - ? idx - : cast_int(L->top - L->ci->func) + idx; +LUA_API int lua_absindex(lua_State* L, int idx) +{ + return (idx > 0 || ispseudo(idx)) + ? idx + : cast_int(L->top - L->ci->func) + idx; } -LUA_API int lua_gettop (lua_State *L) { - return cast_int(L->top - (L->ci->func + 1)); +LUA_API int lua_gettop(lua_State* L) +{ + return cast_int(L->top - (L->ci->func + 1)); } -LUA_API void lua_settop (lua_State *L, int idx) { - StkId func = L->ci->func; - lua_lock(L); - if (idx >= 0) { - api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); - while (L->top < (func + 1) + idx) - setnilvalue(L->top++); - L->top = (func + 1) + idx; - } - else { - api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); - L->top += idx+1; /* 'subtract' index (index is negative) */ - } - lua_unlock(L); +LUA_API void lua_settop(lua_State* L, int idx) +{ + StkId func = L->ci->func; + lua_lock(L); + if (idx >= 0) + { + api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); + while (L->top < (func + 1) + idx) + setnilvalue(L->top++); + L->top = (func + 1) + idx; + } + else + { + api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); + L->top += idx + 1; /* 'subtract' index (index is negative) */ + } + lua_unlock(L); } @@ -190,13 +208,15 @@ LUA_API void lua_settop (lua_State *L, int idx) { ** Reverse the stack segment from 'from' to 'to' ** (auxiliary to 'lua_rotate') */ -static void reverse (lua_State *L, StkId from, StkId to) { - for (; from < to; from++, to--) { - TValue temp; - setobj(L, &temp, from); - setobjs2s(L, from, to); - setobj2s(L, to, &temp); - } +static void reverse(lua_State* L, StkId from, StkId to) +{ + for (; from < to; from++, to--) + { + TValue temp; + setobj(L, &temp, from); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } } @@ -204,270 +224,307 @@ static void reverse (lua_State *L, StkId from, StkId to) { ** Let x = AB, where A is a prefix of length 'n'. Then, ** rotate x n == BA. But BA == (A^r . B^r)^r. */ -LUA_API void lua_rotate (lua_State *L, int idx, int n) { - StkId p, t, m; - lua_lock(L); - t = L->top - 1; /* end of stack segment being rotated */ - p = index2addr(L, idx); /* start of segment */ - api_checkstackindex(L, idx, p); - api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); - m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ - reverse(L, p, m); /* reverse the prefix with length 'n' */ - reverse(L, m + 1, t); /* reverse the suffix */ - reverse(L, p, t); /* reverse the entire segment */ - lua_unlock(L); +LUA_API void lua_rotate(lua_State* L, int idx, int n) +{ + StkId p, t, m; + lua_lock(L); + t = L->top - 1; /* end of stack segment being rotated */ + p = index2addr(L, idx); /* start of segment */ + api_checkstackindex(L, idx, p); + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ + lua_unlock(L); } -LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { - TValue *fr, *to; - lua_lock(L); - fr = index2addr(L, fromidx); - to = index2addr(L, toidx); - api_checkvalidindex(L, to); - setobj(L, to, fr); - if (isupvalue(toidx)) /* function upvalue? */ - luaC_barrier(L, clCvalue(L->ci->func), fr); - /* LUA_REGISTRYINDEX does not need gc barrier - (collector revisits it before finishing collection) */ - lua_unlock(L); +LUA_API void lua_copy(lua_State* L, int fromidx, int toidx) +{ + TValue *fr, *to; + lua_lock(L); + fr = index2addr(L, fromidx); + to = index2addr(L, toidx); + api_checkvalidindex(L, to); + setobj(L, to, fr); + if (isupvalue(toidx)) /* function upvalue? */ + luaC_barrier(L, clCvalue(L->ci->func), fr); + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ + lua_unlock(L); } -LUA_API void lua_pushvalue (lua_State *L, int idx) { - lua_lock(L); - setobj2s(L, L->top, index2addr(L, idx)); - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_pushvalue(lua_State* L, int idx) +{ + lua_lock(L); + setobj2s(L, L->top, index2addr(L, idx)); + api_incr_top(L); + lua_unlock(L); } - /* ** access functions (stack -> C) */ -LUA_API int lua_type (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (isvalid(o) ? ttnov(o) : LUA_TNONE); +LUA_API int lua_type(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + return (isvalid(o) ? ttnov(o) : LUA_TNONE); } -LUA_API const char *lua_typename (lua_State *L, int t) { - UNUSED(L); - api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); - return ttypename(t); +LUA_API const char* lua_typename(lua_State* L, int t) +{ + UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); + return ttypename(t); } -LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (ttislcf(o) || (ttisCclosure(o))); +LUA_API int lua_iscfunction(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + return (ttislcf(o) || (ttisCclosure(o))); } -LUA_API int lua_isinteger (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return ttisinteger(o); +LUA_API int lua_isinteger(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + return ttisinteger(o); } -LUA_API int lua_isnumber (lua_State *L, int idx) { - lua_Number n; - const TValue *o = index2addr(L, idx); - return tonumber(o, &n); +LUA_API int lua_isnumber(lua_State* L, int idx) +{ + lua_Number n; + const TValue* o = index2addr(L, idx); + return tonumber(o, &n); } -LUA_API int lua_isstring (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return (ttisstring(o) || cvt2str(o)); +LUA_API int lua_isstring(lua_State* L, int idx) +{ + const TValue* o = index2addr(L, idx); + return (ttisstring(o) || cvt2str(o)); } -LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return (ttisfulluserdata(o) || ttislightuserdata(o)); +LUA_API int lua_isuserdata(lua_State* L, int idx) +{ + const TValue* o = index2addr(L, idx); + return (ttisfulluserdata(o) || ttislightuserdata(o)); } -LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = index2addr(L, index1); - StkId o2 = index2addr(L, index2); - return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; +LUA_API int lua_rawequal(lua_State* L, int index1, int index2) +{ + StkId o1 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); + return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; } -LUA_API void lua_arith (lua_State *L, int op) { - lua_lock(L); - if (op != LUA_OPUNM && op != LUA_OPBNOT) - api_checknelems(L, 2); /* all other operations expect two operands */ - else { /* for unary operations, add fake 2nd operand */ - api_checknelems(L, 1); - setobjs2s(L, L->top, L->top - 1); - api_incr_top(L); - } - /* first operand at top - 2, second at top - 1; result go to top - 2 */ - luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); - L->top--; /* remove second operand */ - lua_unlock(L); +LUA_API void lua_arith(lua_State* L, int op) +{ + lua_lock(L); + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else + { + /* for unary operations, add fake 2nd operand */ + api_checknelems(L, 1); + setobjs2s(L, L->top, L->top - 1); + api_incr_top(L); + } + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); + L->top--; /* remove second operand */ + lua_unlock(L); } -LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { - StkId o1, o2; - int i = 0; - lua_lock(L); /* may call tag method */ - o1 = index2addr(L, index1); - o2 = index2addr(L, index2); - if (isvalid(o1) && isvalid(o2)) { - switch (op) { - case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; - case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; - case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; - default: api_check(L, 0, "invalid option"); - } - } - lua_unlock(L); - return i; +LUA_API int lua_compare(lua_State* L, int index1, int index2, int op) +{ + StkId o1, o2; + int i = 0; + lua_lock(L); /* may call tag method */ + o1 = index2addr(L, index1); + o2 = index2addr(L, index2); + if (isvalid(o1) && isvalid(o2)) + { + switch (op) + { + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); + break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); + break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); + break; + default: api_check(L, 0, "invalid option"); + } + } + lua_unlock(L); + return i; } -LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { - size_t sz = luaO_str2num(s, L->top); - if (sz != 0) - api_incr_top(L); - return sz; +LUA_API size_t lua_stringtonumber(lua_State* L, const char* s) +{ + size_t sz = luaO_str2num(s, L->top); + if (sz != 0) + api_incr_top(L); + return sz; } -LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { - lua_Number n; - const TValue *o = index2addr(L, idx); - int isnum = tonumber(o, &n); - if (!isnum) - n = 0; /* call to 'tonumber' may change 'n' even if it fails */ - if (pisnum) *pisnum = isnum; - return n; +LUA_API lua_Number lua_tonumberx(lua_State* L, int idx, int* pisnum) +{ + lua_Number n; + const TValue* o = index2addr(L, idx); + int isnum = tonumber(o, &n); + if (!isnum) + n = 0; /* call to 'tonumber' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return n; } -LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { - lua_Integer res; - const TValue *o = index2addr(L, idx); - int isnum = tointeger(o, &res); - if (!isnum) - res = 0; /* call to 'tointeger' may change 'n' even if it fails */ - if (pisnum) *pisnum = isnum; - return res; +LUA_API lua_Integer lua_tointegerx(lua_State* L, int idx, int* pisnum) +{ + lua_Integer res; + const TValue* o = index2addr(L, idx); + int isnum = tointeger(o, &res); + if (!isnum) + res = 0; /* call to 'tointeger' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return res; } -LUA_API int lua_toboolean (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return !l_isfalse(o); +LUA_API int lua_toboolean(lua_State* L, int idx) +{ + const TValue* o = index2addr(L, idx); + return !l_isfalse(o); } -LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { - StkId o = index2addr(L, idx); - if (!ttisstring(o)) { - if (!cvt2str(o)) { /* not convertible? */ - if (len != NULL) *len = 0; - return NULL; - } - lua_lock(L); /* 'luaO_tostring' may create a new string */ - luaO_tostring(L, o); - luaC_checkGC(L); - o = index2addr(L, idx); /* previous call may reallocate the stack */ - lua_unlock(L); - } - if (len != NULL) - *len = vslen(o); - return svalue(o); +LUA_API const char* lua_tolstring(lua_State* L, int idx, size_t* len) +{ + StkId o = index2addr(L, idx); + if (!ttisstring(o)) + { + if (!cvt2str(o)) + { + /* not convertible? */ + if (len != NULL) *len = 0; + return NULL; + } + lua_lock(L); /* 'luaO_tostring' may create a new string */ + luaO_tostring(L, o); + luaC_checkGC(L); + o = index2addr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + if (len != NULL) + *len = vslen(o); + return svalue(o); } -LUA_API size_t lua_rawlen (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttype(o)) { - case LUA_TSHRSTR: return tsvalue(o)->shrlen; - case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; - case LUA_TUSERDATA: return uvalue(o)->len; - case LUA_TTABLE: return luaH_getn(hvalue(o)); - default: return 0; - } +LUA_API size_t lua_rawlen(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + switch (ttype(o)) + { + case LUA_TSHRSTR: return tsvalue(o)->shrlen; + case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return luaH_getn(hvalue(o)); + default: return 0; + } } -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - if (ttislcf(o)) return fvalue(o); - else if (ttisCclosure(o)) - return clCvalue(o)->f; - else return NULL; /* not a C function */ +LUA_API lua_CFunction lua_tocfunction(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + if (ttislcf(o)) return fvalue(o); + else if (ttisCclosure(o)) + return clCvalue(o)->f; + else return NULL; /* not a C function */ } -LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttnov(o)) { - case LUA_TUSERDATA: return getudatamem(uvalue(o)); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return NULL; - } +LUA_API void* lua_touserdata(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + switch (ttnov(o)) + { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } } -LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (!ttisthread(o)) ? NULL : thvalue(o); +LUA_API lua_State* lua_tothread(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); } -LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TLCL: return clLvalue(o); - case LUA_TCCL: return clCvalue(o); - case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: return getudatamem(uvalue(o)); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return NULL; - } +LUA_API const void* lua_topointer(lua_State* L, int idx) +{ + StkId o = index2addr(L, idx); + switch (ttype(o)) + { + case LUA_TTABLE: return hvalue(o); + case LUA_TLCL: return clLvalue(o); + case LUA_TCCL: return clCvalue(o); + case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } } - /* ** push functions (C -> stack) */ -LUA_API void lua_pushnil (lua_State *L) { - lua_lock(L); - setnilvalue(L->top); - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_pushnil(lua_State* L) +{ + lua_lock(L); + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(L); } -LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { - lua_lock(L); - setfltvalue(L->top, n); - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_pushnumber(lua_State* L, lua_Number n) +{ + lua_lock(L); + setfltvalue(L->top, n); + api_incr_top(L); + lua_unlock(L); } -LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { - lua_lock(L); - setivalue(L->top, n); - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_pushinteger(lua_State* L, lua_Integer n) +{ + lua_lock(L); + setivalue(L->top, n); + api_incr_top(L); + lua_unlock(L); } @@ -476,259 +533,287 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { ** 'len' == 0 (as 's' can be NULL in that case), due to later use of ** 'memcmp' and 'memcpy'. */ -LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { - TString *ts; - lua_lock(L); - ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); - setsvalue2s(L, L->top, ts); - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); - return getstr(ts); +LUA_API const char* lua_pushlstring(lua_State* L, const char* s, size_t len) +{ + TString* ts; + lua_lock(L); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); + setsvalue2s(L, L->top, ts); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getstr(ts); } -LUA_API const char *lua_pushstring (lua_State *L, const char *s) { - lua_lock(L); - if (s == NULL) - setnilvalue(L->top); - else { - TString *ts; - ts = luaS_new(L, s); - setsvalue2s(L, L->top, ts); - s = getstr(ts); /* internal copy's address */ - } - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); - return s; +LUA_API const char* lua_pushstring(lua_State* L, const char* s) +{ + lua_lock(L); + if (s == NULL) + setnilvalue(L->top); + else + { + TString* ts; + ts = luaS_new(L, s); + setsvalue2s(L, L->top, ts); + s = getstr(ts); /* internal copy's address */ + } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return s; } -LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, - va_list argp) { - const char *ret; - lua_lock(L); - ret = luaO_pushvfstring(L, fmt, argp); - luaC_checkGC(L); - lua_unlock(L); - return ret; +LUA_API const char* lua_pushvfstring(lua_State* L, const char* fmt, + va_list argp) +{ + const char* ret; + lua_lock(L); + ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; } -LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { - const char *ret; - va_list argp; - lua_lock(L); - va_start(argp, fmt); - ret = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - luaC_checkGC(L); - lua_unlock(L); - return ret; +LUA_API const char* lua_pushfstring(lua_State* L, const char* fmt, ...) +{ + const char* ret; + va_list argp; + lua_lock(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; } -LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - lua_lock(L); - if (n == 0) { - setfvalue(L->top, fn); - } - else { - CClosure *cl; - api_checknelems(L, n); - api_check(L, n <= MAXUPVAL, "upvalue index too large"); - cl = luaF_newCclosure(L, n); - cl->f = fn; - L->top -= n; - while (n--) { - setobj2n(L, &cl->upvalue[n], L->top + n); - /* does not need barrier because closure is white */ - } - setclCvalue(L, L->top, cl); - } - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); +LUA_API void lua_pushcclosure(lua_State* L, lua_CFunction fn, int n) +{ + lua_lock(L); + if (n == 0) + { + setfvalue(L->top, fn); + } + else + { + CClosure* cl; + api_checknelems(L, n); + api_check(L, n <= MAXUPVAL, "upvalue index too large"); + cl = luaF_newCclosure(L, n); + cl->f = fn; + L->top -= n; + while (n--) + { + setobj2n(L, &cl->upvalue[n], L->top + n); + /* does not need barrier because closure is white */ + } + setclCvalue(L, L->top, cl); + } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); } -LUA_API void lua_pushboolean (lua_State *L, int b) { - lua_lock(L); - setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_pushboolean(lua_State* L, int b) +{ + lua_lock(L); + setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ + api_incr_top(L); + lua_unlock(L); } -LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { - lua_lock(L); - setpvalue(L->top, p); - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_pushlightuserdata(lua_State* L, void* p) +{ + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); } -LUA_API int lua_pushthread (lua_State *L) { - lua_lock(L); - setthvalue(L, L->top, L); - api_incr_top(L); - lua_unlock(L); - return (G(L)->mainthread == L); +LUA_API int lua_pushthread(lua_State* L) +{ + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); } - /* ** get functions (Lua -> stack) */ -static int auxgetstr (lua_State *L, const TValue *t, const char *k) { - const TValue *slot; - TString *str = luaS_new(L, k); - if (luaV_fastget(L, t, str, slot, luaH_getstr)) { - setobj2s(L, L->top, slot); - api_incr_top(L); - } - else { - setsvalue2s(L, L->top, str); - api_incr_top(L); - luaV_finishget(L, t, L->top - 1, L->top - 1, slot); - } - lua_unlock(L); - return ttnov(L->top - 1); +static int auxgetstr(lua_State* L, const TValue* t, const char* k) +{ + const TValue* slot; + TString* str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) + { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else + { + setsvalue2s(L, L->top, str); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API int lua_getglobal (lua_State *L, const char *name) { - Table *reg = hvalue(&G(L)->l_registry); - lua_lock(L); - return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); +LUA_API int lua_getglobal(lua_State* L, const char* name) +{ + Table* reg = hvalue(&G(L)->l_registry); + lua_lock(L); + return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } -LUA_API int lua_gettable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - luaV_gettable(L, t, L->top - 1, L->top - 1); - lua_unlock(L); - return ttnov(L->top - 1); +LUA_API int lua_gettable(lua_State* L, int idx) +{ + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { - lua_lock(L); - return auxgetstr(L, index2addr(L, idx), k); +LUA_API int lua_getfield(lua_State* L, int idx, const char* k) +{ + lua_lock(L); + return auxgetstr(L, index2addr(L, idx), k); } -LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { - StkId t; - const TValue *slot; - lua_lock(L); - t = index2addr(L, idx); - if (luaV_fastget(L, t, n, slot, luaH_getint)) { - setobj2s(L, L->top, slot); - api_incr_top(L); - } - else { - setivalue(L->top, n); - api_incr_top(L); - luaV_finishget(L, t, L->top - 1, L->top - 1, slot); - } - lua_unlock(L); - return ttnov(L->top - 1); +LUA_API int lua_geti(lua_State* L, int idx, lua_Integer n) +{ + StkId t; + const TValue* slot; + lua_lock(L); + t = index2addr(L, idx); + if (luaV_fastget(L, t, n, slot, luaH_getint)) + { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else + { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API int lua_rawget (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); - lua_unlock(L); - return ttnov(L->top - 1); +LUA_API int lua_rawget(lua_State* L, int idx) +{ + StkId t; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); + lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setobj2s(L, L->top, luaH_getint(hvalue(t), n)); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); +LUA_API int lua_rawgeti(lua_State* L, int idx, lua_Integer n) +{ + StkId t; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top, luaH_getint(hvalue(t), n)); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { - StkId t; - TValue k; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setpvalue(&k, cast(void *, p)); - setobj2s(L, L->top, luaH_get(hvalue(t), &k)); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); +LUA_API int lua_rawgetp(lua_State* L, int idx, const void* p) +{ + StkId t; + TValue k; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setpvalue(&k, cast(void *, p)); + setobj2s(L, L->top, luaH_get(hvalue(t), &k)); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { - Table *t; - lua_lock(L); - t = luaH_new(L); - sethvalue(L, L->top, t); - api_incr_top(L); - if (narray > 0 || nrec > 0) - luaH_resize(L, t, narray, nrec); - luaC_checkGC(L); - lua_unlock(L); +LUA_API void lua_createtable(lua_State* L, int narray, int nrec) +{ + Table* t; + lua_lock(L); + t = luaH_new(L); + sethvalue(L, L->top, t); + api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); + lua_unlock(L); } -LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TValue *obj; - Table *mt; - int res = 0; - lua_lock(L); - obj = index2addr(L, objindex); - switch (ttnov(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->metatable; - break; - default: - mt = G(L)->mt[ttnov(obj)]; - break; - } - if (mt != NULL) { - sethvalue(L, L->top, mt); - api_incr_top(L); - res = 1; - } - lua_unlock(L); - return res; +LUA_API int lua_getmetatable(lua_State* L, int objindex) +{ + const TValue* obj; + Table* mt; + int res = 0; + lua_lock(L); + obj = index2addr(L, objindex); + switch (ttnov(obj)) + { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttnov(obj)]; + break; + } + if (mt != NULL) + { + sethvalue(L, L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; } -LUA_API int lua_getuservalue (lua_State *L, int idx) { - StkId o; - lua_lock(L); - o = index2addr(L, idx); - api_check(L, ttisfulluserdata(o), "full userdata expected"); - getuservalue(L, uvalue(o), L->top); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); +LUA_API int lua_getuservalue(lua_State* L, int idx) +{ + StkId o; + lua_lock(L); + o = index2addr(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + getuservalue(L, uvalue(o), L->top); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); } @@ -739,159 +824,178 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) { /* ** t[k] = value at the top of the stack (where 'k' is a string) */ -static void auxsetstr (lua_State *L, const TValue *t, const char *k) { - const TValue *slot; - TString *str = luaS_new(L, k); - api_checknelems(L, 1); - if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) - L->top--; /* pop value */ - else { - setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ - api_incr_top(L); - luaV_finishset(L, t, L->top - 1, L->top - 2, slot); - L->top -= 2; /* pop value and key */ - } - lua_unlock(L); /* lock done by caller */ +static void auxsetstr(lua_State* L, const TValue* t, const char* k) +{ + const TValue* slot; + TString* str = luaS_new(L, k); + api_checknelems(L, 1); + if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) + L->top--; /* pop value */ + else + { + setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ } -LUA_API void lua_setglobal (lua_State *L, const char *name) { - Table *reg = hvalue(&G(L)->l_registry); - lua_lock(L); /* unlock done in 'auxsetstr' */ - auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); +LUA_API void lua_setglobal(lua_State* L, const char* name) +{ + Table* reg = hvalue(&G(L)->l_registry); + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } -LUA_API void lua_settable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - api_checknelems(L, 2); - t = index2addr(L, idx); - luaV_settable(L, t, L->top - 2, L->top - 1); - L->top -= 2; /* pop index and value */ - lua_unlock(L); +LUA_API void lua_settable(lua_State* L, int idx) +{ + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2addr(L, idx); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ + lua_unlock(L); } -LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { - lua_lock(L); /* unlock done in 'auxsetstr' */ - auxsetstr(L, index2addr(L, idx), k); +LUA_API void lua_setfield(lua_State* L, int idx, const char* k) +{ + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2addr(L, idx), k); } -LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { - StkId t; - const TValue *slot; - lua_lock(L); - api_checknelems(L, 1); - t = index2addr(L, idx); - if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) - L->top--; /* pop value */ - else { - setivalue(L->top, n); - api_incr_top(L); - luaV_finishset(L, t, L->top - 1, L->top - 2, slot); - L->top -= 2; /* pop value and key */ - } - lua_unlock(L); +LUA_API void lua_seti(lua_State* L, int idx, lua_Integer n) +{ + StkId t; + const TValue* slot; + lua_lock(L); + api_checknelems(L, 1); + t = index2addr(L, idx); + if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) + L->top--; /* pop value */ + else + { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); } -LUA_API void lua_rawset (lua_State *L, int idx) { - StkId o; - TValue *slot; - lua_lock(L); - api_checknelems(L, 2); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - slot = luaH_set(L, hvalue(o), L->top - 2); - setobj2t(L, slot, L->top - 1); - invalidateTMcache(hvalue(o)); - luaC_barrierback(L, hvalue(o), L->top-1); - L->top -= 2; - lua_unlock(L); +LUA_API void lua_rawset(lua_State* L, int idx) +{ + StkId o; + TValue* slot; + lua_lock(L); + api_checknelems(L, 2); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + slot = luaH_set(L, hvalue(o), L->top - 2); + setobj2t(L, slot, L->top - 1); + invalidateTMcache(hvalue(o)); + luaC_barrierback(L, hvalue(o), L->top-1); + L->top -= 2; + lua_unlock(L); } -LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - luaH_setint(L, hvalue(o), n, L->top - 1); - luaC_barrierback(L, hvalue(o), L->top-1); - L->top--; - lua_unlock(L); +LUA_API void lua_rawseti(lua_State* L, int idx, lua_Integer n) +{ + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + luaH_setint(L, hvalue(o), n, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top-1); + L->top--; + lua_unlock(L); } -LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { - StkId o; - TValue k, *slot; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - setpvalue(&k, cast(void *, p)); - slot = luaH_set(L, hvalue(o), &k); - setobj2t(L, slot, L->top - 1); - luaC_barrierback(L, hvalue(o), L->top - 1); - L->top--; - lua_unlock(L); +LUA_API void lua_rawsetp(lua_State* L, int idx, const void* p) +{ + StkId o; + TValue k, *slot; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setpvalue(&k, cast(void *, p)); + slot = luaH_set(L, hvalue(o), &k); + setobj2t(L, slot, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top - 1); + L->top--; + lua_unlock(L); } -LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TValue *obj; - Table *mt; - lua_lock(L); - api_checknelems(L, 1); - obj = index2addr(L, objindex); - if (ttisnil(L->top - 1)) - mt = NULL; - else { - api_check(L, ttistable(L->top - 1), "table expected"); - mt = hvalue(L->top - 1); - } - switch (ttnov(obj)) { - case LUA_TTABLE: { - hvalue(obj)->metatable = mt; - if (mt) { - luaC_objbarrier(L, gcvalue(obj), mt); - luaC_checkfinalizer(L, gcvalue(obj), mt); - } - break; - } - case LUA_TUSERDATA: { - uvalue(obj)->metatable = mt; - if (mt) { - luaC_objbarrier(L, uvalue(obj), mt); - luaC_checkfinalizer(L, gcvalue(obj), mt); - } - break; - } - default: { - G(L)->mt[ttnov(obj)] = mt; - break; - } - } - L->top--; - lua_unlock(L); - return 1; +LUA_API int lua_setmetatable(lua_State* L, int objindex) +{ + TValue* obj; + Table* mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2addr(L, objindex); + if (ttisnil(L->top - 1)) + mt = NULL; + else + { + api_check(L, ttistable(L->top - 1), "table expected"); + mt = hvalue(L->top - 1); + } + switch (ttnov(obj)) + { + case LUA_TTABLE: + { + hvalue(obj)->metatable = mt; + if (mt) + { + luaC_objbarrier(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + case LUA_TUSERDATA: + { + uvalue(obj)->metatable = mt; + if (mt) + { + luaC_objbarrier(L, uvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + default: + { + G(L)->mt[ttnov(obj)] = mt; + break; + } + } + L->top--; + lua_unlock(L); + return 1; } -LUA_API void lua_setuservalue (lua_State *L, int idx) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttisfulluserdata(o), "full userdata expected"); - setuservalue(L, uvalue(o), L->top - 1); - luaC_barrier(L, gcvalue(o), L->top - 1); - L->top--; - lua_unlock(L); +LUA_API void lua_setuservalue(lua_State* L, int idx) +{ + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + setuservalue(L, uvalue(o), L->top - 1); + luaC_barrier(L, gcvalue(o), L->top - 1); + L->top--; + lua_unlock(L); } @@ -905,130 +1009,147 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { "results from function overflow current stack size") -LUA_API void lua_callk (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k) { - StkId func; - lua_lock(L); - api_check(L, k == NULL || !isLua(L->ci), - "cannot use continuations inside hooks"); - api_checknelems(L, nargs+1); - api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); - checkresults(L, nargs, nresults); - func = L->top - (nargs+1); - if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ - L->ci->u.c.k = k; /* save continuation */ - L->ci->u.c.ctx = ctx; /* save context */ - luaD_call(L, func, nresults); /* do the call */ - } - else /* no continuation or no yieldable */ - luaD_callnoyield(L, func, nresults); /* just do the call */ - adjustresults(L, nresults); - lua_unlock(L); +LUA_API void lua_callk(lua_State* L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) +{ + StkId func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + func = L->top - (nargs + 1); + if (k != NULL && L->nny == 0) + { + /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_callnoyield(L, func, nresults); /* just do the call */ + adjustresults(L, nresults); + lua_unlock(L); } - /* ** Execute a protected call. */ -struct CallS { /* data to 'f_call' */ - StkId func; - int nresults; +struct CallS +{ + /* data to 'f_call' */ + StkId func; + int nresults; }; -static void f_call (lua_State *L, void *ud) { - struct CallS *c = cast(struct CallS *, ud); - luaD_callnoyield(L, c->func, c->nresults); +static void f_call(lua_State* L, void* ud) +{ + struct CallS* c = cast(struct CallS *, ud); + luaD_callnoyield(L, c->func, c->nresults); } - -LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k) { - struct CallS c; - int status; - ptrdiff_t func; - lua_lock(L); - api_check(L, k == NULL || !isLua(L->ci), - "cannot use continuations inside hooks"); - api_checknelems(L, nargs+1); - api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); - checkresults(L, nargs, nresults); - if (errfunc == 0) - func = 0; - else { - StkId o = index2addr(L, errfunc); - api_checkstackindex(L, errfunc, o); - func = savestack(L, o); - } - c.func = L->top - (nargs+1); /* function to be called */ - if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ - c.nresults = nresults; /* do a 'conventional' protected call */ - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); - } - else { /* prepare continuation (call is already protected by 'resume') */ - CallInfo *ci = L->ci; - ci->u.c.k = k; /* save continuation */ - ci->u.c.ctx = ctx; /* save context */ - /* save information for error recovery */ - ci->extra = savestack(L, c.func); - ci->u.c.old_errfunc = L->errfunc; - L->errfunc = func; - setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ - ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ - luaD_call(L, c.func, nresults); /* do the call */ - ci->callstatus &= ~CIST_YPCALL; - L->errfunc = ci->u.c.old_errfunc; - status = LUA_OK; /* if it is here, there were no errors */ - } - adjustresults(L, nresults); - lua_unlock(L); - return status; +LUA_API int lua_pcallk(lua_State* L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k) +{ + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else + { + StkId o = index2addr(L, errfunc); + api_checkstackindex(L, errfunc, o); + func = savestack(L, o); + } + c.func = L->top - (nargs + 1); /* function to be called */ + if (k == NULL || L->nny > 0) + { + /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else + { + /* prepare continuation (call is already protected by 'resume') */ + CallInfo* ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->extra = savestack(L, c.func); + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } + adjustresults(L, nresults); + lua_unlock(L); + return status; } -LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, - const char *chunkname, const char *mode) { - ZIO z; - int status; - lua_lock(L); - if (!chunkname) chunkname = "?"; - luaZ_init(L, &z, reader, data); - status = luaD_protectedparser(L, &z, chunkname, mode); - if (status == LUA_OK) { /* no errors? */ - LClosure *f = clLvalue(L->top - 1); /* get newly created function */ - if (f->nupvalues >= 1) { /* does it have an upvalue? */ - /* get global table from registry */ - Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ - setobj(L, f->upvals[0]->v, gt); - luaC_upvalbarrier(L, f->upvals[0]); - } - } - lua_unlock(L); - return status; +LUA_API int lua_load(lua_State* L, lua_Reader reader, void* data, + const char* chunkname, const char* mode) +{ + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) + { + /* no errors? */ + LClosure* f = clLvalue(L->top - 1); /* get newly created function */ + if (f->nupvalues >= 1) + { + /* does it have an upvalue? */ + /* get global table from registry */ + Table* reg = hvalue(&G(L)->l_registry); + const TValue* gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ + setobj(L, f->upvals[0]->v, gt); + luaC_upvalbarrier(L, f->upvals[0]); + } + } + lua_unlock(L); + return status; } -LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { - int status; - TValue *o; - lua_lock(L); - api_checknelems(L, 1); - o = L->top - 1; - if (isLfunction(o)) - status = luaU_dump(L, getproto(o), writer, data, strip); - else - status = 1; - lua_unlock(L); - return status; +LUA_API int lua_dump(lua_State* L, lua_Writer writer, void* data, int strip) +{ + int status; + TValue* o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o)) + status = luaU_dump(L, getproto(o), writer, data, strip); + else + status = 1; + lua_unlock(L); + return status; } -LUA_API int lua_status (lua_State *L) { - return L->status; +LUA_API int lua_status(lua_State* L) +{ + return L->status; } @@ -1036,263 +1157,303 @@ LUA_API int lua_status (lua_State *L) { ** Garbage-collection function */ -LUA_API int lua_gc (lua_State *L, int what, int data) { - int res = 0; - global_State *g; - lua_lock(L); - g = G(L); - switch (what) { - case LUA_GCSTOP: { - g->gcrunning = 0; - break; - } - case LUA_GCRESTART: { - luaE_setdebt(g, 0); - g->gcrunning = 1; - break; - } - case LUA_GCCOLLECT: { - luaC_fullgc(L, 0); - break; - } - case LUA_GCCOUNT: { - /* GC values are expressed in Kbytes: #bytes/2^10 */ - res = cast_int(gettotalbytes(g) >> 10); - break; - } - case LUA_GCCOUNTB: { - res = cast_int(gettotalbytes(g) & 0x3ff); - break; - } - case LUA_GCSTEP: { - l_mem debt = 1; /* =1 to signal that it did an actual step */ - lu_byte oldrunning = g->gcrunning; - g->gcrunning = 1; /* allow GC to run */ - if (data == 0) { - luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ - luaC_step(L); - } - else { /* add 'data' to total debt */ - debt = cast(l_mem, data) * 1024 + g->GCdebt; - luaE_setdebt(g, debt); - luaC_checkGC(L); - } - g->gcrunning = oldrunning; /* restore previous state */ - if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ - res = 1; /* signal it */ - break; - } - case LUA_GCSETPAUSE: { - res = g->gcpause; - g->gcpause = data; - break; - } - case LUA_GCSETSTEPMUL: { - res = g->gcstepmul; - if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ - g->gcstepmul = data; - break; - } - case LUA_GCISRUNNING: { - res = g->gcrunning; - break; - } - default: res = -1; /* invalid option */ - } - lua_unlock(L); - return res; +LUA_API int lua_gc(lua_State* L, int what, int data) +{ + int res = 0; + global_State* g; + lua_lock(L); + g = G(L); + switch (what) + { + case LUA_GCSTOP: + { + g->gcrunning = 0; + break; + } + case LUA_GCRESTART: + { + luaE_setdebt(g, 0); + g->gcrunning = 1; + break; + } + case LUA_GCCOLLECT: + { + luaC_fullgc(L, 0); + break; + } + case LUA_GCCOUNT: + { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(gettotalbytes(g) >> 10); + break; + } + case LUA_GCCOUNTB: + { + res = cast_int(gettotalbytes(g) & 0x3ff); + break; + } + case LUA_GCSTEP: + { + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldrunning = g->gcrunning; + g->gcrunning = 1; /* allow GC to run */ + if (data == 0) + { + luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ + luaC_step(L); + } + else + { + /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); + } + g->gcrunning = oldrunning; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: + { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: + { + res = g->gcstepmul; + if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ + g->gcstepmul = data; + break; + } + case LUA_GCISRUNNING: + { + res = g->gcrunning; + break; + } + default: res = -1; /* invalid option */ + } + lua_unlock(L); + return res; } - /* ** miscellaneous functions */ -LUA_API int lua_error (lua_State *L) { - lua_lock(L); - api_checknelems(L, 1); - luaG_errormsg(L); - /* code unreachable; will unlock when control actually leaves the kernel */ - return 0; /* to avoid warnings */ +LUA_API int lua_error(lua_State* L) +{ + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + /* code unreachable; will unlock when control actually leaves the kernel */ + return 0; /* to avoid warnings */ } -LUA_API int lua_next (lua_State *L, int idx) { - StkId t; - int more; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - more = luaH_next(L, hvalue(t), L->top - 1); - if (more) { - api_incr_top(L); - } - else /* no more elements */ - L->top -= 1; /* remove key */ - lua_unlock(L); - return more; +LUA_API int lua_next(lua_State* L, int idx) +{ + StkId t; + int more; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + more = luaH_next(L, hvalue(t), L->top - 1); + if (more) + { + api_incr_top(L); + } + else /* no more elements */ + L->top -= 1; /* remove key */ + lua_unlock(L); + return more; } -LUA_API void lua_concat (lua_State *L, int n) { - lua_lock(L); - api_checknelems(L, n); - if (n >= 2) { - luaV_concat(L, n); - } - else if (n == 0) { /* push empty string */ - setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); - api_incr_top(L); - } - /* else n == 1; nothing to do */ - luaC_checkGC(L); - lua_unlock(L); +LUA_API void lua_concat(lua_State* L, int n) +{ + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) + { + luaV_concat(L, n); + } + else if (n == 0) + { + /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + luaC_checkGC(L); + lua_unlock(L); } -LUA_API void lua_len (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - luaV_objlen(L, L->top, t); - api_incr_top(L); - lua_unlock(L); +LUA_API void lua_len(lua_State* L, int idx) +{ + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_objlen(L, L->top, t); + api_incr_top(L); + lua_unlock(L); } -LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { - lua_Alloc f; - lua_lock(L); - if (ud) *ud = G(L)->ud; - f = G(L)->frealloc; - lua_unlock(L); - return f; +LUA_API lua_Alloc lua_getallocf(lua_State* L, void** ud) +{ + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; } -LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { - lua_lock(L); - G(L)->ud = ud; - G(L)->frealloc = f; - lua_unlock(L); +LUA_API void lua_setallocf(lua_State* L, lua_Alloc f, void* ud) +{ + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); } -LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - Udata *u; - lua_lock(L); - u = luaS_newudata(L, size); - setuvalue(L, L->top, u); - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); - return getudatamem(u); +LUA_API void* lua_newuserdata(lua_State* L, size_t size) +{ + Udata* u; + lua_lock(L); + u = luaS_newudata(L, size); + setuvalue(L, L->top, u); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getudatamem(u); } - -static const char *aux_upvalue (StkId fi, int n, TValue **val, - CClosure **owner, UpVal **uv) { - switch (ttype(fi)) { - case LUA_TCCL: { /* C closure */ - CClosure *f = clCvalue(fi); - if (!(1 <= n && n <= f->nupvalues)) return NULL; - *val = &f->upvalue[n-1]; - if (owner) *owner = f; - return ""; - } - case LUA_TLCL: { /* Lua closure */ - LClosure *f = clLvalue(fi); - TString *name; - Proto *p = f->p; - if (!(1 <= n && n <= p->sizeupvalues)) return NULL; - *val = f->upvals[n-1]->v; - if (uv) *uv = f->upvals[n - 1]; - name = p->upvalues[n-1].name; - return (name == NULL) ? "(*no name)" : getstr(name); - } - default: return NULL; /* not a closure */ - } +static const char* aux_upvalue(StkId fi, int n, TValue** val, + CClosure** owner, UpVal** uv) +{ + switch (ttype(fi)) + { + case LUA_TCCL: + { + /* C closure */ + CClosure* f = clCvalue(fi); + if (!(1 <= n && n <= f->nupvalues)) return NULL; + *val = &f->upvalue[n - 1]; + if (owner) *owner = f; + return ""; + } + case LUA_TLCL: + { + /* Lua closure */ + LClosure* f = clLvalue(fi); + TString* name; + Proto* p = f->p; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; + *val = f->upvals[n - 1]->v; + if (uv) *uv = f->upvals[n - 1]; + name = p->upvalues[n - 1].name; + return (name == NULL) ? "(*no name)" : getstr(name); + } + default: return NULL; /* not a closure */ + } } -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TValue *val = NULL; /* to avoid warnings */ - lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); - if (name) { - setobj2s(L, L->top, val); - api_incr_top(L); - } - lua_unlock(L); - return name; +LUA_API const char* lua_getupvalue(lua_State* L, int funcindex, int n) +{ + const char* name; + TValue* val = NULL; /* to avoid warnings */ + lua_lock(L); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); + if (name) + { + setobj2s(L, L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; } -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TValue *val = NULL; /* to avoid warnings */ - CClosure *owner = NULL; - UpVal *uv = NULL; - StkId fi; - lua_lock(L); - fi = index2addr(L, funcindex); - api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner, &uv); - if (name) { - L->top--; - setobj(L, val, L->top); - if (owner) { luaC_barrier(L, owner, L->top); } - else if (uv) { luaC_upvalbarrier(L, uv); } - } - lua_unlock(L); - return name; +LUA_API const char* lua_setupvalue(lua_State* L, int funcindex, int n) +{ + const char* name; + TValue* val = NULL; /* to avoid warnings */ + CClosure* owner = NULL; + UpVal* uv = NULL; + StkId fi; + lua_lock(L); + fi = index2addr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val, &owner, &uv); + if (name) + { + L->top--; + setobj(L, val, L->top); + if (owner) { luaC_barrier(L, owner, L->top); } + else if (uv) { luaC_upvalbarrier(L, uv); } + } + lua_unlock(L); + return name; } -static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { - LClosure *f; - StkId fi = index2addr(L, fidx); - api_check(L, ttisLclosure(fi), "Lua function expected"); - f = clLvalue(fi); - api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); - if (pf) *pf = f; - return &f->upvals[n - 1]; /* get its upvalue pointer */ +static UpVal** getupvalref(lua_State* L, int fidx, int n, LClosure** pf) +{ + LClosure* f; + StkId fi = index2addr(L, fidx); + api_check(L, ttisLclosure(fi), "Lua function expected"); + f = clLvalue(fi); + api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); + if (pf) *pf = f; + return &f->upvals[n - 1]; /* get its upvalue pointer */ } -LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { - StkId fi = index2addr(L, fidx); - switch (ttype(fi)) { - case LUA_TLCL: { /* lua closure */ - return *getupvalref(L, fidx, n, NULL); - } - case LUA_TCCL: { /* C closure */ - CClosure *f = clCvalue(fi); - api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); - return &f->upvalue[n - 1]; - } - default: { - api_check(L, 0, "closure expected"); - return NULL; - } - } +LUA_API void* lua_upvalueid(lua_State* L, int fidx, int n) +{ + StkId fi = index2addr(L, fidx); + switch (ttype(fi)) + { + case LUA_TLCL: + { + /* lua closure */ + return *getupvalref(L, fidx, n, NULL); + } + case LUA_TCCL: + { + /* C closure */ + CClosure* f = clCvalue(fi); + api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); + return &f->upvalue[n - 1]; + } + default: + { + api_check(L, 0, "closure expected"); + return NULL; + } + } } -LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, - int fidx2, int n2) { - LClosure *f1; - UpVal **up1 = getupvalref(L, fidx1, n1, &f1); - UpVal **up2 = getupvalref(L, fidx2, n2, NULL); - luaC_upvdeccount(L, *up1); - *up1 = *up2; - (*up1)->refcount++; - if (upisopen(*up1)) (*up1)->u.open.touched = 1; - luaC_upvalbarrier(L, *up1); +LUA_API void lua_upvaluejoin(lua_State* L, int fidx1, int n1, + int fidx2, int n2) +{ + LClosure* f1; + UpVal** up1 = getupvalref(L, fidx1, n1, &f1); + UpVal** up2 = getupvalref(L, fidx2, n2, NULL); + luaC_upvdeccount(L, *up1); + *up1 = *up2; + (*up1)->refcount++; + if (upisopen(*up1)) (*up1)->u.open.touched = 1; + luaC_upvalbarrier(L, *up1); } - - diff --git a/Lua/lauxlib.c b/Lua/lauxlib.c index f7a3836..69e83a0 100644 --- a/Lua/lauxlib.c +++ b/Lua/lauxlib.c @@ -38,118 +38,145 @@ #define LEVELS2 11 /* size of the second part of the stack */ - /* ** search for 'objidx' in table at index -1. ** return 1 + string at top if find a good name. */ -static int findfield (lua_State *L, int objidx, int level) { - if (level == 0 || !lua_istable(L, -1)) - return 0; /* not found */ - lua_pushnil(L); /* start 'next' loop */ - while (lua_next(L, -2)) { /* for each pair in table */ - if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ - if (lua_rawequal(L, objidx, -1)) { /* found object? */ - lua_pop(L, 1); /* remove value (but keep name) */ - return 1; - } - else if (findfield(L, objidx, level - 1)) { /* try recursively */ - lua_remove(L, -2); /* remove table (but keep name) */ - lua_pushliteral(L, "."); - lua_insert(L, -2); /* place '.' between the two names */ - lua_concat(L, 3); - return 1; - } - } - lua_pop(L, 1); /* remove value */ - } - return 0; /* not found */ +static int findfield(lua_State* L, int objidx, int level) +{ + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) + { + /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) + { + /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) + { + /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) + { + /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ } /* ** Search for a name for a function in all loaded modules */ -static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); - lua_getinfo(L, "f", ar); /* push function */ - lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - if (findfield(L, top + 1, 2)) { - const char *name = lua_tostring(L, -1); - if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ - lua_pushstring(L, name + 3); /* push name without prefix */ - lua_remove(L, -2); /* remove original name */ - } - lua_copy(L, -1, top + 1); /* move name to proper place */ - lua_pop(L, 2); /* remove pushed values */ - return 1; - } - else { - lua_settop(L, top); /* remove function and global table */ - return 0; - } +static int pushglobalfuncname(lua_State* L, lua_Debug* ar) +{ + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + if (findfield(L, top + 1, 2)) + { + const char* name = lua_tostring(L, -1); + if (strncmp(name, "_G.", 3) == 0) + { + /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else + { + lua_settop(L, top); /* remove function and global table */ + return 0; + } } -static void pushfuncname (lua_State *L, lua_Debug *ar) { - if (pushglobalfuncname(L, ar)) { /* try first a global name */ - lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else if (*ar->namewhat != '\0') /* is there a name from code? */ - lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ - else if (*ar->what == 'm') /* main? */ - lua_pushliteral(L, "main chunk"); - else if (*ar->what != 'C') /* for Lua functions, use */ - lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); - else /* nothing left... */ - lua_pushliteral(L, "?"); +static void pushfuncname(lua_State* L, lua_Debug* ar) +{ + if (pushglobalfuncname(L, ar)) + { + /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what != 'C') /* for Lua functions, use */ + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); } -static int lastlevel (lua_State *L) { - lua_Debug ar; - int li = 1, le = 1; - /* find an upper bound */ - while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } - /* do a binary search */ - while (li < le) { - int m = (li + le)/2; - if (lua_getstack(L, m, &ar)) li = m + 1; - else le = m; - } - return le - 1; +static int lastlevel(lua_State* L) +{ + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) + { + li = le; + le *= 2; + } + /* do a binary search */ + while (li < le) + { + int m = (li + le) / 2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; } -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level) { - lua_Debug ar; - int top = lua_gettop(L); - int last = lastlevel(L1); - int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; - if (msg) - lua_pushfstring(L, "%s\n", msg); - luaL_checkstack(L, 10, NULL); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (n1-- == 0) { /* too many levels? */ - lua_pushliteral(L, "\n\t..."); /* add a '...' */ - level = last - LEVELS2 + 1; /* and skip to last ones */ - } - else { - lua_getinfo(L1, "Slnt", &ar); - lua_pushfstring(L, "\n\t%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - lua_pushliteral(L, " in "); - pushfuncname(L, &ar); - if (ar.istailcall) - lua_pushliteral(L, "\n\t(...tail calls...)"); - lua_concat(L, lua_gettop(L) - top); - } - } - lua_concat(L, lua_gettop(L) - top); +LUALIB_API void luaL_traceback(lua_State* L, lua_State* L1, + const char* msg, int level) +{ + lua_Debug ar; + int top = lua_gettop(L); + int last = lastlevel(L1); + int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + if (msg) + lua_pushfstring(L, "%s\n", msg); + luaL_checkstack(L, 10, NULL); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) + { + if (n1-- == 0) + { + /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = last - LEVELS2 + 1; /* and skip to last ones */ + } + else + { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + pushfuncname(L, &ar); + if (ar.istailcall) + lua_pushliteral(L, "\n\t(...tail calls...)"); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); } /* }====================================================== */ @@ -161,40 +188,44 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, ** ======================================================= */ -LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { - lua_Debug ar; - if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); - lua_getinfo(L, "n", &ar); - if (strcmp(ar.namewhat, "method") == 0) { - arg--; /* do not count 'self' */ - if (arg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling '%s' on bad self (%s)", - ar.name, extramsg); - } - if (ar.name == NULL) - ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; - return luaL_error(L, "bad argument #%d to '%s' (%s)", - arg, ar.name, extramsg); +LUALIB_API int luaL_argerror(lua_State* L, int arg, const char* extramsg) +{ + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) + { + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); } -static int typeerror (lua_State *L, int arg, const char *tname) { - const char *msg; - const char *typearg; /* name for the type of the actual argument */ - if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) - typearg = lua_tostring(L, -1); /* use the given type name */ - else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) - typearg = "light userdata"; /* special name for messages */ - else - typearg = luaL_typename(L, arg); /* standard name */ - msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); - return luaL_argerror(L, arg, msg); +static int typeerror(lua_State* L, int arg, const char* tname) +{ + const char* msg; + const char* typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); } -static void tag_error (lua_State *L, int arg, int tag) { - typeerror(L, arg, lua_typename(L, tag)); +static void tag_error(lua_State* L, int arg, int tag) +{ + typeerror(L, arg, lua_typename(L, tag)); } @@ -202,16 +233,21 @@ static void tag_error (lua_State *L, int arg, int tag) { ** The use of 'lua_pushfstring' ensures this function does not ** need reserved stack space when called. */ -LUALIB_API void luaL_where (lua_State *L, int level) { - lua_Debug ar; - if (lua_getstack(L, level, &ar)) { /* check function at level */ - lua_getinfo(L, "Sl", &ar); /* get info about it */ - if (ar.currentline > 0) { /* is there info? */ - lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); - return; - } - } - lua_pushfstring(L, ""); /* else, no information available... */ +LUALIB_API void luaL_where(lua_State* L, int level) +{ + lua_Debug ar; + if (lua_getstack(L, level, &ar)) + { + /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) + { + /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushfstring(L, ""); /* else, no information available... */ } @@ -220,32 +256,36 @@ LUALIB_API void luaL_where (lua_State *L, int level) { ** not need reserved stack space when called. (At worst, it generates ** an error with "stack overflow" instead of the given message.) */ -LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - luaL_where(L, 1); - lua_pushvfstring(L, fmt, argp); - va_end(argp); - lua_concat(L, 2); - return lua_error(L); +LUALIB_API int luaL_error(lua_State* L, const char* fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); } -LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { - int en = errno; /* calls to Lua API may change this value */ - if (stat) { - lua_pushboolean(L, 1); - return 1; - } - else { - lua_pushnil(L); - if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); - else - lua_pushstring(L, strerror(en)); - lua_pushinteger(L, en); - return 3; - } +LUALIB_API int luaL_fileresult(lua_State* L, int stat, const char* fname) +{ + int en = errno; /* calls to Lua API may change this value */ + if (stat) + { + lua_pushboolean(L, 1); + return 1; + } + else + { + lua_pushnil(L); + if (fname) + lua_pushfstring(L, "%s: %s", fname, strerror(en)); + else + lua_pushstring(L, strerror(en)); + lua_pushinteger(L, en); + return 3; + } } @@ -271,20 +311,22 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { #endif /* } */ -LUALIB_API int luaL_execresult (lua_State *L, int stat) { - const char *what = "exit"; /* type of termination */ - if (stat == -1) /* error? */ - return luaL_fileresult(L, 0, NULL); - else { - l_inspectstat(stat, what); /* interpret result */ - if (*what == 'e' && stat == 0) /* successful termination? */ - lua_pushboolean(L, 1); - else - lua_pushnil(L); - lua_pushstring(L, what); - lua_pushinteger(L, stat); - return 3; /* return true/nil,what,code */ - } +LUALIB_API int luaL_execresult(lua_State* L, int stat) +{ + const char* what = "exit"; /* type of termination */ + if (stat == -1) /* error? */ + return luaL_fileresult(L, 0, NULL); + else + { + l_inspectstat(stat, what); /* interpret result */ + if (*what == 'e' && stat == 0) /* successful termination? */ + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/nil,what,code */ + } } /* }====================================================== */ @@ -296,44 +338,52 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) { ** ======================================================= */ -LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ - return 0; /* leave previous value on top, but return 0 */ - lua_pop(L, 1); - lua_createtable(L, 0, 2); /* create metatable */ - lua_pushstring(L, tname); - lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ - return 1; +LUALIB_API int luaL_newmetatable(lua_State* L, const char* tname) +{ + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; } -LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); +LUALIB_API void luaL_setmetatable(lua_State* L, const char* tname) +{ + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); } -LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { - void *p = lua_touserdata(L, ud); - if (p != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - luaL_getmetatable(L, tname); /* get correct metatable */ - if (!lua_rawequal(L, -1, -2)) /* not the same? */ - p = NULL; /* value is a userdata with wrong metatable */ - lua_pop(L, 2); /* remove both metatables */ - return p; - } - } - return NULL; /* value is not a userdata with a metatable */ +LUALIB_API void* luaL_testudata(lua_State* L, int ud, const char* tname) +{ + void* p = lua_touserdata(L, ud); + if (p != NULL) + { + /* value is a userdata? */ + if (lua_getmetatable(L, ud)) + { + /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ } -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - void *p = luaL_testudata(L, ud, tname); - if (p == NULL) typeerror(L, ud, tname); - return p; +LUALIB_API void* luaL_checkudata(lua_State* L, int ud, const char* tname) +{ + void* p = luaL_testudata(L, ud, tname); + if (p == NULL) typeerror(L, ud, tname); + return p; } /* }====================================================== */ @@ -345,16 +395,16 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { ** ======================================================= */ -LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, - const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, arg, def) : - luaL_checkstring(L, arg); - int i; - for (i=0; lst[i]; i++) - if (strcmp(lst[i], name) == 0) - return i; - return luaL_argerror(L, arg, - lua_pushfstring(L, "invalid option '%s'", name)); +LUALIB_API int luaL_checkoption(lua_State* L, int arg, const char* def, + const char* const lst[]) +{ + const char* name = (def) ? luaL_optstring(L, arg, def) : luaL_checkstring(L, arg); + int i; + for (i = 0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); } @@ -365,81 +415,94 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, ** this extra space, Lua will generate the same 'stack overflow' error, ** but without 'msg'.) */ -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - if (!lua_checkstack(L, space)) { - if (msg) - luaL_error(L, "stack overflow (%s)", msg); - else - luaL_error(L, "stack overflow"); - } +LUALIB_API void luaL_checkstack(lua_State* L, int space, const char* msg) +{ + if (!lua_checkstack(L, space)) + { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } } -LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { - if (lua_type(L, arg) != t) - tag_error(L, arg, t); +LUALIB_API void luaL_checktype(lua_State* L, int arg, int t) +{ + if (lua_type(L, arg) != t) + tag_error(L, arg, t); } -LUALIB_API void luaL_checkany (lua_State *L, int arg) { - if (lua_type(L, arg) == LUA_TNONE) - luaL_argerror(L, arg, "value expected"); +LUALIB_API void luaL_checkany(lua_State* L, int arg) +{ + if (lua_type(L, arg) == LUA_TNONE) + luaL_argerror(L, arg, "value expected"); } -LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { - const char *s = lua_tolstring(L, arg, len); - if (!s) tag_error(L, arg, LUA_TSTRING); - return s; +LUALIB_API const char* luaL_checklstring(lua_State* L, int arg, size_t* len) +{ + const char* s = lua_tolstring(L, arg, len); + if (!s) tag_error(L, arg, LUA_TSTRING); + return s; } -LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, - const char *def, size_t *len) { - if (lua_isnoneornil(L, arg)) { - if (len) - *len = (def ? strlen(def) : 0); - return def; - } - else return luaL_checklstring(L, arg, len); +LUALIB_API const char* luaL_optlstring(lua_State* L, int arg, + const char* def, size_t* len) +{ + if (lua_isnoneornil(L, arg)) + { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, arg, len); } -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { - int isnum; - lua_Number d = lua_tonumberx(L, arg, &isnum); - if (!isnum) - tag_error(L, arg, LUA_TNUMBER); - return d; +LUALIB_API lua_Number luaL_checknumber(lua_State* L, int arg) +{ + int isnum; + lua_Number d = lua_tonumberx(L, arg, &isnum); + if (!isnum) + tag_error(L, arg, LUA_TNUMBER); + return d; } -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { - return luaL_opt(L, luaL_checknumber, arg, def); +LUALIB_API lua_Number luaL_optnumber(lua_State* L, int arg, lua_Number def) +{ + return luaL_opt(L, luaL_checknumber, arg, def); } -static void interror (lua_State *L, int arg) { - if (lua_isnumber(L, arg)) - luaL_argerror(L, arg, "number has no integer representation"); - else - tag_error(L, arg, LUA_TNUMBER); +static void interror(lua_State* L, int arg) +{ + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); } -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { - int isnum; - lua_Integer d = lua_tointegerx(L, arg, &isnum); - if (!isnum) { - interror(L, arg); - } - return d; +LUALIB_API lua_Integer luaL_checkinteger(lua_State* L, int arg) +{ + int isnum; + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (!isnum) + { + interror(L, arg); + } + return d; } -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, - lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, arg, def); +LUALIB_API lua_Integer luaL_optinteger(lua_State* L, int arg, + lua_Integer def) +{ + return luaL_opt(L, luaL_checkinteger, arg, def); } /* }====================================================== */ @@ -452,43 +515,51 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, */ /* userdata to box arbitrary data */ -typedef struct UBox { - void *box; - size_t bsize; +typedef struct UBox +{ + void* box; + size_t bsize; } UBox; -static void *resizebox (lua_State *L, int idx, size_t newsize) { - void *ud; - lua_Alloc allocf = lua_getallocf(L, &ud); - UBox *box = (UBox *)lua_touserdata(L, idx); - void *temp = allocf(ud, box->box, box->bsize, newsize); - if (temp == NULL && newsize > 0) { /* allocation error? */ - resizebox(L, idx, 0); /* free buffer */ - luaL_error(L, "not enough memory for buffer allocation"); - } - box->box = temp; - box->bsize = newsize; - return temp; +static void* resizebox(lua_State* L, int idx, size_t newsize) +{ + void* ud; + lua_Alloc allocf = lua_getallocf(L, &ud); + UBox* box = (UBox*)lua_touserdata(L, idx); + void* temp = allocf(ud, box->box, box->bsize, newsize); + if (temp == NULL && newsize > 0) + { + /* allocation error? */ + resizebox(L, idx, 0); /* free buffer */ + luaL_error(L, "not enough memory for buffer allocation"); + } + box->box = temp; + box->bsize = newsize; + return temp; } -static int boxgc (lua_State *L) { - resizebox(L, 1, 0); - return 0; +static int boxgc(lua_State* L) +{ + resizebox(L, 1, 0); + return 0; } -static void *newbox (lua_State *L, size_t newsize) { - UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); - box->box = NULL; - box->bsize = 0; - if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ - lua_pushcfunction(L, boxgc); - lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ - } - lua_setmetatable(L, -2); - return resizebox(L, -1, newsize); +static void* newbox(lua_State* L, size_t newsize) +{ + UBox* box = (UBox*)lua_newuserdata(L, sizeof(UBox)); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "LUABOX")) + { + /* creating metatable? */ + lua_pushcfunction(L, boxgc); + lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ + } + lua_setmetatable(L, -2); + return resizebox(L, -1, newsize); } @@ -502,81 +573,96 @@ static void *newbox (lua_State *L, size_t newsize) { /* ** returns a pointer to a free area with at least 'sz' bytes */ -LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { - lua_State *L = B->L; - if (B->size - B->n < sz) { /* not enough space? */ - char *newbuff; - size_t newsize = B->size * 2; /* double buffer size */ - if (newsize - B->n < sz) /* not big enough? */ - newsize = B->n + sz; - if (newsize < B->n || newsize - B->n < sz) - luaL_error(L, "buffer too large"); - /* create larger buffer */ - if (buffonstack(B)) - newbuff = (char *)resizebox(L, -1, newsize); - else { /* no buffer yet */ - newbuff = (char *)newbox(L, newsize); - memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ - } - B->b = newbuff; - B->size = newsize; - } - return &B->b[B->n]; +LUALIB_API char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) +{ + lua_State* L = B->L; + if (B->size - B->n < sz) + { + /* not enough space? */ + char* newbuff; + size_t newsize = B->size * 2; /* double buffer size */ + if (newsize - B->n < sz) /* not big enough? */ + newsize = B->n + sz; + if (newsize < B->n || newsize - B->n < sz) + luaL_error(L, "buffer too large"); + /* create larger buffer */ + if (buffonstack(B)) + newbuff = (char*)resizebox(L, -1, newsize); + else + { + /* no buffer yet */ + newbuff = (char*)newbox(L, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } + B->b = newbuff; + B->size = newsize; + } + return &B->b[B->n]; } -LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ - char *b = luaL_prepbuffsize(B, l); - memcpy(b, s, l * sizeof(char)); - luaL_addsize(B, l); - } +LUALIB_API void luaL_addlstring(luaL_Buffer* B, const char* s, size_t l) +{ + if (l > 0) + { + /* avoid 'memcpy' when 's' can be NULL */ + char* b = luaL_prepbuffsize(B, l); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } } -LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { - luaL_addlstring(B, s, strlen(s)); +LUALIB_API void luaL_addstring(luaL_Buffer* B, const char* s) +{ + luaL_addlstring(B, s, strlen(s)); } -LUALIB_API void luaL_pushresult (luaL_Buffer *B) { - lua_State *L = B->L; - lua_pushlstring(L, B->b, B->n); - if (buffonstack(B)) { - resizebox(L, -2, 0); /* delete old buffer */ - lua_remove(L, -2); /* remove its header from the stack */ - } +LUALIB_API void luaL_pushresult(luaL_Buffer* B) +{ + lua_State* L = B->L; + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) + { + resizebox(L, -2, 0); /* delete old buffer */ + lua_remove(L, -2); /* remove its header from the stack */ + } } -LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { - luaL_addsize(B, sz); - luaL_pushresult(B); +LUALIB_API void luaL_pushresultsize(luaL_Buffer* B, size_t sz) +{ + luaL_addsize(B, sz); + luaL_pushresult(B); } -LUALIB_API void luaL_addvalue (luaL_Buffer *B) { - lua_State *L = B->L; - size_t l; - const char *s = lua_tolstring(L, -1, &l); - if (buffonstack(B)) - lua_insert(L, -2); /* put value below buffer */ - luaL_addlstring(B, s, l); - lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ +LUALIB_API void luaL_addvalue(luaL_Buffer* B) +{ + lua_State* L = B->L; + size_t l; + const char* s = lua_tolstring(L, -1, &l); + if (buffonstack(B)) + lua_insert(L, -2); /* put value below buffer */ + luaL_addlstring(B, s, l); + lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ } -LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - B->L = L; - B->b = B->initb; - B->n = 0; - B->size = LUAL_BUFFERSIZE; +LUALIB_API void luaL_buffinit(lua_State* L, luaL_Buffer* B) +{ + B->L = L; + B->b = B->initb; + B->n = 0; + B->size = LUAL_BUFFERSIZE; } -LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { - luaL_buffinit(L, B); - return luaL_prepbuffsize(B, sz); +LUALIB_API char* luaL_buffinitsize(lua_State* L, luaL_Buffer* B, size_t sz) +{ + luaL_buffinit(L, B); + return luaL_prepbuffsize(B, sz); } /* }====================================================== */ @@ -592,35 +678,41 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { #define freelist 0 -LUALIB_API int luaL_ref (lua_State *L, int t) { - int ref; - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* 'nil' has a unique fixed reference */ - } - t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); /* get first free element */ - ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ - lua_pop(L, 1); /* remove it from stack */ - if (ref != 0) { /* any free element? */ - lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ - } - else /* no free elements */ - ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ - lua_rawseti(L, t, ref); - return ref; +LUALIB_API int luaL_ref(lua_State* L, int t) +{ + int ref; + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ + } + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); /* get first free element */ + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) + { + /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ + } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); + return ref; } -LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { - if (ref >= 0) { - t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); - lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ - lua_pushinteger(L, ref); - lua_rawseti(L, t, freelist); /* t[freelist] = ref */ - } +LUALIB_API void luaL_unref(lua_State* L, int t, int ref) +{ + if (ref >= 0) + { + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ + } } /* }====================================================== */ @@ -632,51 +724,61 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { ** ======================================================= */ -typedef struct LoadF { - int n; /* number of pre-read characters */ - FILE *f; /* file being read */ - char buff[BUFSIZ]; /* area for reading file */ +typedef struct LoadF +{ + int n; /* number of pre-read characters */ + FILE* f; /* file being read */ + char buff[BUFSIZ]; /* area for reading file */ } LoadF; -static const char *getF (lua_State *L, void *ud, size_t *size) { - LoadF *lf = (LoadF *)ud; - (void)L; /* not used */ - if (lf->n > 0) { /* are there pre-read characters to be read? */ - *size = lf->n; /* return them (chars already in buffer) */ - lf->n = 0; /* no more pre-read characters */ - } - else { /* read a block from file */ - /* 'fread' can return > 0 *and* set the EOF flag. If next call to - 'getF' called 'fread', it might still wait for user input. - The next check avoids this problem. */ - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ - } - return lf->buff; +static const char* getF(lua_State* L, void* ud, size_t* size) +{ + LoadF* lf = (LoadF*)ud; + (void)L; /* not used */ + if (lf->n > 0) + { + /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else + { + /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; } -static int errfile (lua_State *L, const char *what, int fnameindex) { - const char *serr = strerror(errno); - const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); - lua_remove(L, fnameindex); - return LUA_ERRFILE; +static int errfile(lua_State* L, const char* what, int fnameindex) +{ + const char* serr = strerror(errno); + const char* filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; } -static int skipBOM (LoadF *lf) { - const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ - int c; - lf->n = 0; - do { - c = getc(lf->f); - if (c == EOF || c != *(const unsigned char *)p++) return c; - lf->buff[lf->n++] = c; /* to be read by the parser */ - } while (*p != '\0'); - lf->n = 0; /* prefix matched; discard it */ - return getc(lf->f); /* return next character */ +static int skipBOM(LoadF* lf) +{ + const char* p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ + int c; + lf->n = 0; + do + { + c = getc(lf->f); + if (c == EOF || c != *(const unsigned char*)p++) return c; + lf->buff[lf->n++] = c; /* to be read by the parser */ + } + while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ } @@ -687,161 +789,186 @@ static int skipBOM (LoadF *lf) { ** first "valid" character of the file (after the optional BOM and ** a first-line comment). */ -static int skipcomment (LoadF *lf, int *cp) { - int c = *cp = skipBOM(lf); - if (c == '#') { /* first line is a comment (Unix exec. file)? */ - do { /* skip first line */ - c = getc(lf->f); - } while (c != EOF && c != '\n'); - *cp = getc(lf->f); /* skip end-of-line, if present */ - return 1; /* there was a comment */ - } - else return 0; /* no comment */ +static int skipcomment(LoadF* lf, int* cp) +{ + int c = *cp = skipBOM(lf); + if (c == '#') + { + /* first line is a comment (Unix exec. file)? */ + do + { + /* skip first line */ + c = getc(lf->f); + } + while (c != EOF && c != '\n'); + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ } -LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, - const char *mode) { - LoadF lf; - int status, readstatus; - int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - if (filename == NULL) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - } - else { - lua_pushfstring(L, "@%s", filename); - lf.f = fopen(filename, "r"); - if (lf.f == NULL) return errfile(L, "open", fnameindex); - } - if (skipcomment(&lf, &c)) /* read initial portion */ - lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ - if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ - lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ - if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - skipcomment(&lf, &c); /* re-read initial portion */ - } - if (c != EOF) - lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ - status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); - readstatus = ferror(lf.f); - if (filename) fclose(lf.f); /* close file (even in case of errors) */ - if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ - return errfile(L, "read", fnameindex); - } - lua_remove(L, fnameindex); - return status; +LUALIB_API int luaL_loadfilex(lua_State* L, const char* filename, + const char* mode) +{ + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) + { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else + { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + if (skipcomment(&lf, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) + { + /* binary file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + skipcomment(&lf, &c); /* re-read initial portion */ + } + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) + { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; } -typedef struct LoadS { - const char *s; - size_t size; +typedef struct LoadS +{ + const char* s; + size_t size; } LoadS; -static const char *getS (lua_State *L, void *ud, size_t *size) { - LoadS *ls = (LoadS *)ud; - (void)L; /* not used */ - if (ls->size == 0) return NULL; - *size = ls->size; - ls->size = 0; - return ls->s; +static const char* getS(lua_State* L, void* ud, size_t* size) +{ + LoadS* ls = (LoadS*)ud; + (void)L; /* not used */ + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; } -LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, - const char *name, const char *mode) { - LoadS ls; - ls.s = buff; - ls.size = size; - return lua_load(L, getS, &ls, name, mode); +LUALIB_API int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, + const char* name, const char* mode) +{ + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name, mode); } -LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { - return luaL_loadbuffer(L, s, strlen(s), s); +LUALIB_API int luaL_loadstring(lua_State* L, const char* s) +{ + return luaL_loadbuffer(L, s, strlen(s), s); } /* }====================================================== */ - -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { - if (!lua_getmetatable(L, obj)) /* no metatable? */ - return LUA_TNIL; - else { - int tt; - lua_pushstring(L, event); - tt = lua_rawget(L, -2); - if (tt == LUA_TNIL) /* is metafield nil? */ - lua_pop(L, 2); /* remove metatable and metafield */ - else - lua_remove(L, -2); /* remove only metatable */ - return tt; /* return metafield type */ - } +LUALIB_API int luaL_getmetafield(lua_State* L, int obj, const char* event) +{ + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return LUA_TNIL; + else + { + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ + } } -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = lua_absindex(L, obj); - if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; +LUALIB_API int luaL_callmeta(lua_State* L, int obj, const char* event) +{ + obj = lua_absindex(L, obj); + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; } -LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { - lua_Integer l; - int isnum; - lua_len(L, idx); - l = lua_tointegerx(L, -1, &isnum); - if (!isnum) - luaL_error(L, "object length is not an integer"); - lua_pop(L, 1); /* remove object */ - return l; +LUALIB_API lua_Integer luaL_len(lua_State* L, int idx) +{ + lua_Integer l; + int isnum; + lua_len(L, idx); + l = lua_tointegerx(L, -1, &isnum); + if (!isnum) + luaL_error(L, "object length is not an integer"); + lua_pop(L, 1); /* remove object */ + return l; } -LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { - if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ - if (!lua_isstring(L, -1)) - luaL_error(L, "'__tostring' must return a string"); - } - else { - switch (lua_type(L, idx)) { - case LUA_TNUMBER: { - if (lua_isinteger(L, idx)) - lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); - else - lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); - break; - } - case LUA_TSTRING: - lua_pushvalue(L, idx); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: { - int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ - const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : - luaL_typename(L, idx); - lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); - if (tt != LUA_TNIL) - lua_remove(L, -2); /* remove '__name' */ - break; - } - } - } - return lua_tolstring(L, -1, len); +LUALIB_API const char* luaL_tolstring(lua_State* L, int idx, size_t* len) +{ + if (luaL_callmeta(L, idx, "__tostring")) + { + /* metafield? */ + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + else + { + switch (lua_type(L, idx)) + { + case LUA_TNUMBER: + { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); + break; + } + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + { + int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ + const char* kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : luaL_typename(L, idx); + lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_remove(L, -2); /* remove '__name' */ + break; + } + } + } + return lua_tolstring(L, -1, len); } @@ -931,16 +1058,19 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** function gets the 'nup' elements at the top as upvalues. ** Returns with only the table at the stack. */ -LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_setfield(L, -(nup + 2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ +LUALIB_API void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) +{ + luaL_checkstack(L, nup, "too many upvalues"); + for (; l->name != NULL; l++) + { + /* fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_setfield(L, -(nup + 2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ } @@ -948,17 +1078,19 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { ** ensure that stack[idx][fname] has a table and push that table ** into the stack */ -LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { - if (lua_getfield(L, idx, fname) == LUA_TTABLE) - return 1; /* table already there */ - else { - lua_pop(L, 1); /* remove previous result */ - idx = lua_absindex(L, idx); - lua_newtable(L); - lua_pushvalue(L, -1); /* copy to be left at top */ - lua_setfield(L, idx, fname); /* assign new table to field */ - return 0; /* false, because did not find table there */ - } +LUALIB_API int luaL_getsubtable(lua_State* L, int idx, const char* fname) +{ + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ + else + { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ + } } @@ -968,76 +1100,87 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { ** if 'glb' is true, also registers the result in the global table. ** Leaves resulting module on the top. */ -LUALIB_API void luaL_requiref (lua_State *L, const char *modname, - lua_CFunction openf, int glb) { - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_getfield(L, -1, modname); /* LOADED[modname] */ - if (!lua_toboolean(L, -1)) { /* package not already loaded? */ - lua_pop(L, 1); /* remove field */ - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); /* argument to open function */ - lua_call(L, 1, 1); /* call 'openf' to open module */ - lua_pushvalue(L, -1); /* make copy of module (call result) */ - lua_setfield(L, -3, modname); /* LOADED[modname] = module */ - } - lua_remove(L, -2); /* remove LOADED table */ - if (glb) { - lua_pushvalue(L, -1); /* copy of module */ - lua_setglobal(L, modname); /* _G[modname] = module */ - } +LUALIB_API void luaL_requiref(lua_State* L, const char* modname, + lua_CFunction openf, int glb) +{ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, -1, modname); /* LOADED[modname] */ + if (!lua_toboolean(L, -1)) + { + /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove LOADED table */ + if (glb) + { + lua_pushvalue(L, -1); /* copy of module */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } } -LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, - const char *r) { - const char *wild; - size_t l = strlen(p); - luaL_Buffer b; - luaL_buffinit(L, &b); - while ((wild = strstr(s, p)) != NULL) { - luaL_addlstring(&b, s, wild - s); /* push prefix */ - luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after 'p' */ - } - luaL_addstring(&b, s); /* push last suffix */ - luaL_pushresult(&b); - return lua_tostring(L, -1); +LUALIB_API const char* luaL_gsub(lua_State* L, const char* s, const char* p, + const char* r) +{ + const char* wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) + { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after 'p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); } -static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { - (void)ud; (void)osize; /* not used */ - if (nsize == 0) { - free(ptr); - return NULL; - } - else - return realloc(ptr, nsize); +static void* l_alloc(void* ud, void* ptr, size_t osize, size_t nsize) +{ + (void)ud; + (void)osize; /* not used */ + if (nsize == 0) + { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); } -static int panic (lua_State *L) { - lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); - return 0; /* return to Lua to abort */ +static int panic(lua_State* L) +{ + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; /* return to Lua to abort */ } -LUALIB_API lua_State *luaL_newstate (void) { - lua_State *L = lua_newstate(l_alloc, NULL); - if (L) lua_atpanic(L, &panic); - return L; +LUALIB_API lua_State* luaL_newstate(void) +{ + lua_State* L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + return L; } -LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { - const lua_Number *v = lua_version(L); - if (sz != LUAL_NUMSIZES) /* check numeric types */ - luaL_error(L, "core and library have incompatible numeric types"); - if (v != lua_version(NULL)) - luaL_error(L, "multiple Lua VMs detected"); - else if (*v != ver) - luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", - (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v); +LUALIB_API void luaL_checkversion_(lua_State* L, lua_Number ver, size_t sz) +{ + const lua_Number* v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); + if (v != lua_version(NULL)) + luaL_error(L, "multiple Lua VMs detected"); + else if (*v != ver) + luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", + (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v); } - diff --git a/Lua/lauxlib.h b/Lua/lauxlib.h index 9a2e66a..4eba667 100644 --- a/Lua/lauxlib.h +++ b/Lua/lauxlib.h @@ -15,7 +15,6 @@ #include "lua.h" - /* extra error code for 'luaL_loadfilex' */ #define LUA_ERRFILE (LUA_ERRERR+1) @@ -28,83 +27,84 @@ #define LUA_PRELOAD_TABLE "_PRELOAD" -typedef struct luaL_Reg { - const char *name; - lua_CFunction func; +typedef struct luaL_Reg +{ + const char* name; + lua_CFunction func; } luaL_Reg; #define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) -LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +LUALIB_API void (luaL_checkversion_)(lua_State* L, lua_Number ver, size_t sz); #define luaL_checkversion(L) \ luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) -LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); -LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, - size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, - const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); +LUALIB_API int (luaL_getmetafield)(lua_State* L, int obj, const char* e); +LUALIB_API int (luaL_callmeta)(lua_State* L, int obj, const char* e); +LUALIB_API const char*(luaL_tolstring)(lua_State* L, int idx, size_t* len); +LUALIB_API int (luaL_argerror)(lua_State* L, int arg, const char* extramsg); +LUALIB_API const char*(luaL_checklstring)(lua_State* L, int arg, + size_t* l); +LUALIB_API const char*(luaL_optlstring)(lua_State* L, int arg, + const char* def, size_t* l); +LUALIB_API lua_Number (luaL_checknumber)(lua_State* L, int arg); +LUALIB_API lua_Number (luaL_optnumber)(lua_State* L, int arg, lua_Number def); -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, - lua_Integer def); +LUALIB_API lua_Integer (luaL_checkinteger)(lua_State* L, int arg); +LUALIB_API lua_Integer (luaL_optinteger)(lua_State* L, int arg, + lua_Integer def); -LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); -LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int arg); +LUALIB_API void (luaL_checkstack)(lua_State* L, int sz, const char* msg); +LUALIB_API void (luaL_checktype)(lua_State* L, int arg, int t); +LUALIB_API void (luaL_checkany)(lua_State* L, int arg); -LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); -LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); -LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); -LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); +LUALIB_API int (luaL_newmetatable)(lua_State* L, const char* tname); +LUALIB_API void (luaL_setmetatable)(lua_State* L, const char* tname); +LUALIB_API void*(luaL_testudata)(lua_State* L, int ud, const char* tname); +LUALIB_API void*(luaL_checkudata)(lua_State* L, int ud, const char* tname); -LUALIB_API void (luaL_where) (lua_State *L, int lvl); -LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); +LUALIB_API void (luaL_where)(lua_State* L, int lvl); +LUALIB_API int (luaL_error)(lua_State* L, const char* fmt, ...); -LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, - const char *const lst[]); +LUALIB_API int (luaL_checkoption)(lua_State* L, int arg, const char* def, + const char* const lst[]); -LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); -LUALIB_API int (luaL_execresult) (lua_State *L, int stat); +LUALIB_API int (luaL_fileresult)(lua_State* L, int stat, const char* fname); +LUALIB_API int (luaL_execresult)(lua_State* L, int stat); /* predefined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) -LUALIB_API int (luaL_ref) (lua_State *L, int t); -LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); +LUALIB_API int (luaL_ref)(lua_State* L, int t); +LUALIB_API void (luaL_unref)(lua_State* L, int t, int ref); -LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, - const char *mode); +LUALIB_API int (luaL_loadfilex)(lua_State* L, const char* filename, + const char* mode); #define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) -LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); +LUALIB_API int (luaL_loadbufferx)(lua_State* L, const char* buff, size_t sz, + const char* name, const char* mode); +LUALIB_API int (luaL_loadstring)(lua_State* L, const char* s); -LUALIB_API lua_State *(luaL_newstate) (void); +LUALIB_API lua_State*(luaL_newstate)(void); -LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); +LUALIB_API lua_Integer (luaL_len)(lua_State* L, int idx); -LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, - const char *r); +LUALIB_API const char*(luaL_gsub)(lua_State* L, const char* s, const char* p, + const char* r); -LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); +LUALIB_API void (luaL_setfuncs)(lua_State* L, const luaL_Reg* l, int nup); -LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); +LUALIB_API int (luaL_getsubtable)(lua_State* L, int idx, const char* fname); -LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, - const char *msg, int level); +LUALIB_API void (luaL_traceback)(lua_State* L, lua_State* L1, + const char* msg, int level); -LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, - lua_CFunction openf, int glb); +LUALIB_API void (luaL_requiref)(lua_State* L, const char* modname, + lua_CFunction openf, int glb); /* ** =============================================================== @@ -145,12 +145,13 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, ** ======================================================= */ -typedef struct luaL_Buffer { - char *b; /* buffer address */ - size_t size; /* buffer size */ - size_t n; /* number of characters in buffer */ - lua_State *L; - char initb[LUAL_BUFFERSIZE]; /* initial buffer */ +typedef struct luaL_Buffer +{ + char* b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ + lua_State* L; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ } luaL_Buffer; @@ -160,21 +161,20 @@ typedef struct luaL_Buffer { #define luaL_addsize(B,s) ((B)->n += (s)) -LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); -LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); -LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); -LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); -LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); +LUALIB_API void (luaL_buffinit)(lua_State* L, luaL_Buffer* B); +LUALIB_API char*(luaL_prepbuffsize)(luaL_Buffer* B, size_t sz); +LUALIB_API void (luaL_addlstring)(luaL_Buffer* B, const char* s, size_t l); +LUALIB_API void (luaL_addstring)(luaL_Buffer* B, const char* s); +LUALIB_API void (luaL_addvalue)(luaL_Buffer* B); +LUALIB_API void (luaL_pushresult)(luaL_Buffer* B); +LUALIB_API void (luaL_pushresultsize)(luaL_Buffer* B, size_t sz); +LUALIB_API char*(luaL_buffinitsize)(lua_State* L, luaL_Buffer* B, size_t sz); #define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) /* }====================================================== */ - /* ** {====================================================== ** File handles for IO library @@ -190,15 +190,15 @@ LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); #define LUA_FILEHANDLE "FILE*" -typedef struct luaL_Stream { - FILE *f; /* stream (NULL for incompletely created streams) */ - lua_CFunction closef; /* to close stream (NULL for closed streams) */ +typedef struct luaL_Stream +{ + FILE* f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ } luaL_Stream; /* }====================================================== */ - /* compatibility with old module system */ #if defined(LUA_COMPAT_MODULE) @@ -258,7 +258,4 @@ LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, /* }============================================================ */ - #endif - - diff --git a/Lua/lbaselib.c b/Lua/lbaselib.c index 08523e6..f932bca 100644 --- a/Lua/lbaselib.c +++ b/Lua/lbaselib.c @@ -21,232 +21,279 @@ #include "lualib.h" -static int luaB_print (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int i; - lua_getglobal(L, "tostring"); - for (i=1; i<=n; i++) { - const char *s; - size_t l; - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); - s = lua_tolstring(L, -1, &l); /* get result */ - if (s == NULL) - return luaL_error(L, "'tostring' must return a string to 'print'"); - if (i>1) lua_writestring("\t", 1); - lua_writestring(s, l); - lua_pop(L, 1); /* pop result */ - } - lua_writeline(); - return 0; +static int luaB_print(lua_State* L) +{ + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i = 1; i <= n; i++) + { + const char* s; + size_t l; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tolstring(L, -1, &l); /* get result */ + if (s == NULL) + return luaL_error(L, "'tostring' must return a string to 'print'"); + if (i > 1) + lua_writestring("\t", 1); + lua_writestring(s, l); + lua_pop(L, 1); /* pop result */ + } + lua_writeline(); + return 0; } #define SPACECHARS " \f\n\r\t\v" -static const char *b_str2int (const char *s, int base, lua_Integer *pn) { - lua_Unsigned n = 0; - int neg = 0; - s += strspn(s, SPACECHARS); /* skip initial spaces */ - if (*s == '-') { s++; neg = 1; } /* handle signal */ - else if (*s == '+') s++; - if (!isalnum((unsigned char)*s)) /* no digit? */ - return NULL; - do { - int digit = (isdigit((unsigned char)*s)) ? *s - '0' - : (toupper((unsigned char)*s) - 'A') + 10; - if (digit >= base) return NULL; /* invalid numeral */ - n = n * base + digit; - s++; - } while (isalnum((unsigned char)*s)); - s += strspn(s, SPACECHARS); /* skip trailing spaces */ - *pn = (lua_Integer)((neg) ? (0u - n) : n); - return s; +static const char* b_str2int(const char* s, int base, lua_Integer* pn) +{ + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') + { + s++; + neg = 1; + } /* handle signal */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do + { + int digit = (isdigit((unsigned char)*s)) + ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } + while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; } -static int luaB_tonumber (lua_State *L) { - if (lua_isnoneornil(L, 2)) { /* standard conversion? */ - luaL_checkany(L, 1); - if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ - lua_settop(L, 1); /* yes; return it */ - return 1; - } - else { - size_t l; - const char *s = lua_tolstring(L, 1, &l); - if (s != NULL && lua_stringtonumber(L, s) == l + 1) - return 1; /* successful conversion to number */ - /* else not a number */ - } - } - else { - size_t l; - const char *s; - lua_Integer n = 0; /* to avoid warnings */ - lua_Integer base = luaL_checkinteger(L, 2); - luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ - s = lua_tolstring(L, 1, &l); - luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - if (b_str2int(s, (int)base, &n) == s + l) { - lua_pushinteger(L, n); - return 1; - } /* else not a number */ - } /* else not a number */ - lua_pushnil(L); /* not a number */ - return 1; +static int luaB_tonumber(lua_State* L) +{ + if (lua_isnoneornil(L, 2)) + { + /* standard conversion? */ + luaL_checkany(L, 1); + if (lua_type(L, 1) == LUA_TNUMBER) + { + /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else + { + size_t l; + const char* s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + } + } + else + { + size_t l; + const char* s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + if (b_str2int(s, (int)base, &n) == s + l) + { + lua_pushinteger(L, n); + return 1; + } /* else not a number */ + } /* else not a number */ + lua_pushnil(L); /* not a number */ + return 1; } -static int luaB_error (lua_State *L) { - int level = (int)luaL_optinteger(L, 2, 1); - lua_settop(L, 1); - if (lua_type(L, 1) == LUA_TSTRING && level > 0) { - luaL_where(L, level); /* add extra information */ - lua_pushvalue(L, 1); - lua_concat(L, 2); - } - return lua_error(L); +static int luaB_error(lua_State* L) +{ + int level = (int)luaL_optinteger(L, 2, 1); + lua_settop(L, 1); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) + { + luaL_where(L, level); /* add extra information */ + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); } -static int luaB_getmetatable (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - lua_pushnil(L); - return 1; /* no metatable */ - } - luaL_getmetafield(L, 1, "__metatable"); - return 1; /* returns either __metatable field (if present) or metatable */ +static int luaB_getmetatable(lua_State* L) +{ + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) + { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ } -static int luaB_setmetatable (lua_State *L) { - int t = lua_type(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) - return luaL_error(L, "cannot change a protected metatable"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; +static int luaB_setmetatable(lua_State* L) +{ + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) + return luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; } -static int luaB_rawequal (lua_State *L) { - luaL_checkany(L, 1); - luaL_checkany(L, 2); - lua_pushboolean(L, lua_rawequal(L, 1, 2)); - return 1; +static int luaB_rawequal(lua_State* L) +{ + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; } -static int luaB_rawlen (lua_State *L) { - int t = lua_type(L, 1); - luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, - "table or string expected"); - lua_pushinteger(L, lua_rawlen(L, 1)); - return 1; +static int luaB_rawlen(lua_State* L) +{ + int t = lua_type(L, 1); + luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, + "table or string expected"); + lua_pushinteger(L, lua_rawlen(L, 1)); + return 1; } -static int luaB_rawget (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_rawget(L, 1); - return 1; +static int luaB_rawget(lua_State* L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; } -static int luaB_rawset (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - luaL_checkany(L, 3); - lua_settop(L, 3); - lua_rawset(L, 1); - return 1; +static int luaB_rawset(lua_State* L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; } -static int luaB_collectgarbage (lua_State *L) { - static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", - "isrunning", NULL}; - static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCISRUNNING}; - int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; - int ex = (int)luaL_optinteger(L, 2, 0); - int res = lua_gc(L, o, ex); - switch (o) { - case LUA_GCCOUNT: { - int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); - return 1; - } - case LUA_GCSTEP: case LUA_GCISRUNNING: { - lua_pushboolean(L, res); - return 1; - } - default: { - lua_pushinteger(L, res); - return 1; - } - } +static int luaB_collectgarbage(lua_State* L) +{ + static const char* const opts[] = { + "stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", + "isrunning", NULL + }; + static const int optsnum[] = { + LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING + }; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + int ex = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, ex); + switch (o) + { + case LUA_GCCOUNT: + { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, (lua_Number)res + ((lua_Number)b / 1024)); + return 1; + } + case LUA_GCSTEP: + case LUA_GCISRUNNING: + { + lua_pushboolean(L, res); + return 1; + } + default: + { + lua_pushinteger(L, res); + return 1; + } + } } -static int luaB_type (lua_State *L) { - int t = lua_type(L, 1); - luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); - lua_pushstring(L, lua_typename(L, t)); - return 1; +static int luaB_type(lua_State* L) +{ + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); + return 1; } -static int pairsmeta (lua_State *L, const char *method, int iszero, - lua_CFunction iter) { - luaL_checkany(L, 1); - if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ - lua_pushcfunction(L, iter); /* will return generator, */ - lua_pushvalue(L, 1); /* state, */ - if (iszero) lua_pushinteger(L, 0); /* and initial value */ - else lua_pushnil(L); - } - else { - lua_pushvalue(L, 1); /* argument 'self' to metamethod */ - lua_call(L, 1, 3); /* get 3 values from metamethod */ - } - return 3; +static int pairsmeta(lua_State* L, const char* method, int iszero, + lua_CFunction iter) +{ + luaL_checkany(L, 1); + if (luaL_getmetafield(L, 1, method) == LUA_TNIL) + { + /* no metamethod? */ + lua_pushcfunction(L, iter); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + if (iszero) lua_pushinteger(L, 0); /* and initial value */ + else lua_pushnil(L); + } + else + { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_call(L, 1, 3); /* get 3 values from metamethod */ + } + return 3; } -static int luaB_next (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 2); /* create a 2nd argument if there isn't one */ - if (lua_next(L, 1)) - return 2; - else { - lua_pushnil(L); - return 1; - } +static int luaB_next(lua_State* L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else + { + lua_pushnil(L); + return 1; + } } -static int luaB_pairs (lua_State *L) { - return pairsmeta(L, "__pairs", 0, luaB_next); +static int luaB_pairs(lua_State* L) +{ + return pairsmeta(L, "__pairs", 0, luaB_next); } /* ** Traversal function for 'ipairs' */ -static int ipairsaux (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2) + 1; - lua_pushinteger(L, i); - return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +static int ipairsaux(lua_State* L) +{ + lua_Integer i = luaL_checkinteger(L, 2) + 1; + lua_pushinteger(L, i); + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; } @@ -254,42 +301,50 @@ static int ipairsaux (lua_State *L) { ** 'ipairs' function. Returns 'ipairsaux', given "table", 0. ** (The given "table" may not be a table.) */ -static int luaB_ipairs (lua_State *L) { +static int luaB_ipairs(lua_State* L) +{ #if defined(LUA_COMPAT_IPAIRS) return pairsmeta(L, "__ipairs", 1, ipairsaux); #else - luaL_checkany(L, 1); - lua_pushcfunction(L, ipairsaux); /* iteration function */ - lua_pushvalue(L, 1); /* state */ - lua_pushinteger(L, 0); /* initial value */ - return 3; + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; #endif } -static int load_aux (lua_State *L, int status, int envidx) { - if (status == LUA_OK) { - if (envidx != 0) { /* 'env' parameter? */ - lua_pushvalue(L, envidx); /* environment for loaded function */ - if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ - lua_pop(L, 1); /* remove 'env' if not used by previous call */ - } - return 1; - } - else { /* error (message is on top of the stack) */ - lua_pushnil(L); - lua_insert(L, -2); /* put before error message */ - return 2; /* return nil plus error message */ - } +static int load_aux(lua_State* L, int status, int envidx) +{ + if (status == LUA_OK) + { + if (envidx != 0) + { + /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } + return 1; + } + else + { + /* error (message is on top of the stack) */ + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } } -static int luaB_loadfile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - const char *mode = luaL_optstring(L, 2, NULL); - int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ - int status = luaL_loadfilex(L, fname, mode); - return load_aux(L, status, env); +static int luaB_loadfile(lua_State* L) +{ + const char* fname = luaL_optstring(L, 1, NULL); + const char* mode = luaL_optstring(L, 2, NULL); + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ + int status = luaL_loadfilex(L, fname, mode); + return load_aux(L, status, env); } @@ -314,87 +369,103 @@ static int luaB_loadfile (lua_State *L) { ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ -static const char *generic_reader (lua_State *L, void *ud, size_t *size) { - (void)(ud); /* not used */ - luaL_checkstack(L, 2, "too many nested functions"); - lua_pushvalue(L, 1); /* get function */ - lua_call(L, 0, 1); /* call it */ - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* pop result */ - *size = 0; - return NULL; - } - else if (!lua_isstring(L, -1)) - luaL_error(L, "reader function must return a string"); - lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ - return lua_tolstring(L, RESERVEDSLOT, size); +static const char* generic_reader(lua_State* L, void* ud, size_t* size) +{ + (void)(ud); /* not used */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); /* pop result */ + *size = 0; + return NULL; + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); } -static int luaB_load (lua_State *L) { - int status; - size_t l; - const char *s = lua_tolstring(L, 1, &l); - const char *mode = luaL_optstring(L, 3, "bt"); - int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ - if (s != NULL) { /* loading a string? */ - const char *chunkname = luaL_optstring(L, 2, s); - status = luaL_loadbufferx(L, s, l, chunkname, mode); - } - else { /* loading from a reader function */ - const char *chunkname = luaL_optstring(L, 2, "=(load)"); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, RESERVEDSLOT); /* create reserved slot */ - status = lua_load(L, generic_reader, NULL, chunkname, mode); - } - return load_aux(L, status, env); +static int luaB_load(lua_State* L) +{ + int status; + size_t l; + const char* s = lua_tolstring(L, 1, &l); + const char* mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ + if (s != NULL) + { + /* loading a string? */ + const char* chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else + { + /* loading from a reader function */ + const char* chunkname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, NULL, chunkname, mode); + } + return load_aux(L, status, env); } /* }====================================================== */ -static int dofilecont (lua_State *L, int d1, lua_KContext d2) { - (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ - return lua_gettop(L) - 1; +static int dofilecont(lua_State* L, int d1, lua_KContext d2) +{ + (void)d1; + (void)d2; /* only to match 'lua_Kfunction' prototype */ + return lua_gettop(L) - 1; } -static int luaB_dofile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) - return lua_error(L); - lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); - return dofilecont(L, 0, 0); +static int luaB_dofile(lua_State* L) +{ + const char* fname = luaL_optstring(L, 1, NULL); + lua_settop(L, 1); + if (luaL_loadfile(L, fname) != LUA_OK) + return lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L, 0, 0); } -static int luaB_assert (lua_State *L) { - if (lua_toboolean(L, 1)) /* condition is true? */ - return lua_gettop(L); /* return all arguments */ - else { /* error */ - luaL_checkany(L, 1); /* there must be a condition */ - lua_remove(L, 1); /* remove it */ - lua_pushliteral(L, "assertion failed!"); /* default message */ - lua_settop(L, 1); /* leave only message (default if no other one) */ - return luaB_error(L); /* call 'error' */ - } +static int luaB_assert(lua_State* L) +{ + if (lua_toboolean(L, 1)) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else + { + /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } } -static int luaB_select (lua_State *L) { - int n = lua_gettop(L); - if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { - lua_pushinteger(L, n-1); - return 1; - } - else { - lua_Integer i = luaL_checkinteger(L, 1); - if (i < 0) i = n + i; - else if (i > n) i = n; - luaL_argcheck(L, 1 <= i, 1, "index out of range"); - return n - (int)i; - } +static int luaB_select(lua_State* L) +{ + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') + { + lua_pushinteger(L, n - 1); + return 1; + } + else + { + lua_Integer i = luaL_checkinteger(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - (int)i; + } } @@ -405,24 +476,28 @@ static int luaB_select (lua_State *L) { ** 'extra' values (where 'extra' is exactly the number of items to be ** ignored). */ -static int finishpcall (lua_State *L, int status, lua_KContext extra) { - if (status != LUA_OK && status != LUA_YIELD) { /* error? */ - lua_pushboolean(L, 0); /* first result (false) */ - lua_pushvalue(L, -2); /* error message */ - return 2; /* return false, msg */ - } - else - return lua_gettop(L) - (int)extra; /* return all results */ +static int finishpcall(lua_State* L, int status, lua_KContext extra) +{ + if (status != LUA_OK && status != LUA_YIELD) + { + /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ + return 2; /* return false, msg */ + } + else + return lua_gettop(L) - (int)extra; /* return all results */ } -static int luaB_pcall (lua_State *L) { - int status; - luaL_checkany(L, 1); - lua_pushboolean(L, 1); /* first result if no errors */ - lua_insert(L, 1); /* put it in place */ - status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); - return finishpcall(L, status, 0); +static int luaB_pcall(lua_State* L) +{ + int status; + luaL_checkany(L, 1); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); } @@ -431,68 +506,70 @@ static int luaB_pcall (lua_State *L) { ** stack will have ; so, the function passes ** 2 to 'finishpcall' to skip the 2 first values when returning results. */ -static int luaB_xpcall (lua_State *L) { - int status; - int n = lua_gettop(L); - luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ - lua_pushboolean(L, 1); /* first result */ - lua_pushvalue(L, 1); /* function */ - lua_rotate(L, 3, 2); /* move them below function's arguments */ - status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); - return finishpcall(L, status, 2); +static int luaB_xpcall(lua_State* L) +{ + int status; + int n = lua_gettop(L); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); } -static int luaB_tostring (lua_State *L) { - luaL_checkany(L, 1); - luaL_tolstring(L, 1, NULL); - return 1; +static int luaB_tostring(lua_State* L) +{ + luaL_checkany(L, 1); + luaL_tolstring(L, 1, NULL); + return 1; } static const luaL_Reg base_funcs[] = { - {"assert", luaB_assert}, - {"collectgarbage", luaB_collectgarbage}, - {"dofile", luaB_dofile}, - {"error", luaB_error}, - {"getmetatable", luaB_getmetatable}, - {"ipairs", luaB_ipairs}, - {"loadfile", luaB_loadfile}, - {"load", luaB_load}, + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, #if defined(LUA_COMPAT_LOADSTRING) {"loadstring", luaB_load}, #endif - {"next", luaB_next}, - {"pairs", luaB_pairs}, - {"pcall", luaB_pcall}, - {"print", luaB_print}, - {"rawequal", luaB_rawequal}, - {"rawlen", luaB_rawlen}, - {"rawget", luaB_rawget}, - {"rawset", luaB_rawset}, - {"select", luaB_select}, - {"setmetatable", luaB_setmetatable}, - {"tonumber", luaB_tonumber}, - {"tostring", luaB_tostring}, - {"type", luaB_type}, - {"xpcall", luaB_xpcall}, - /* placeholders */ - {"_G", NULL}, - {"_VERSION", NULL}, - {NULL, NULL} + {"next", luaB_next}, + {"pairs", luaB_pairs}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawlen", luaB_rawlen}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"xpcall", luaB_xpcall}, + /* placeholders */ + {"_G", NULL}, + {"_VERSION", NULL}, + {NULL, NULL} }; -LUAMOD_API int luaopen_base (lua_State *L) { - /* open lib into global table */ - lua_pushglobaltable(L); - luaL_setfuncs(L, base_funcs, 0); - /* set global _G */ - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_G"); - /* set global _VERSION */ - lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); - return 1; +LUAMOD_API int luaopen_base(lua_State* L) +{ + /* open lib into global table */ + lua_pushglobaltable(L); + luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_G"); + /* set global _VERSION */ + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, "_VERSION"); + return 1; } - diff --git a/Lua/lbitlib.c b/Lua/lbitlib.c index 1cb1d5b..77a628a 100644 --- a/Lua/lbitlib.c +++ b/Lua/lbitlib.c @@ -226,8 +226,9 @@ LUAMOD_API int luaopen_bit32 (lua_State *L) { #else /* }{ */ -LUAMOD_API int luaopen_bit32 (lua_State *L) { - return luaL_error(L, "library 'bit32' has been deprecated"); +LUAMOD_API int luaopen_bit32(lua_State* L) +{ + return luaL_error(L, "library 'bit32' has been deprecated"); } #endif /* } */ diff --git a/Lua/lcode.c b/Lua/lcode.c index 0bb4142..8e18c9a 100644 --- a/Lua/lcode.c +++ b/Lua/lcode.c @@ -40,18 +40,20 @@ ** If expression is a numeric constant, fills 'v' with its value ** and returns 1. Otherwise, returns 0. */ -static int tonumeral(const expdesc *e, TValue *v) { - if (hasjumps(e)) - return 0; /* not a numeral */ - switch (e->k) { - case VKINT: - if (v) setivalue(v, e->u.ival); - return 1; - case VKFLT: - if (v) setfltvalue(v, e->u.nval); - return 1; - default: return 0; - } +static int tonumeral(const expdesc* e, TValue* v) +{ + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) + { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } } @@ -61,25 +63,32 @@ static int tonumeral(const expdesc *e, TValue *v) { ** range of previous instruction instead of emitting a new one. (For ** instance, 'local a; local b' will generate a single opcode.) */ -void luaK_nil (FuncState *fs, int from, int n) { - Instruction *previous; - int l = from + n - 1; /* last register to set nil */ - if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ - previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ - int pfrom = GETARG_A(*previous); /* get previous range */ - int pl = pfrom + GETARG_B(*previous); - if ((pfrom <= from && from <= pl + 1) || - (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ - if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ - if (pl > l) l = pl; /* l = max(l, pl) */ - SETARG_A(*previous, from); - SETARG_B(*previous, l - from); - return; - } - } /* else go through */ - } - luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ +void luaK_nil(FuncState* fs, int from, int n) +{ + Instruction* previous; + int l = from + n - 1; /* last register to set nil */ + if (fs->pc > fs->lasttarget) + { + /* no jumps to current position? */ + previous = &fs->f->code[fs->pc - 1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) + { + /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ + int pl = pfrom + GETARG_B(*previous); + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) + { + /* can connect both? */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); + return; + } + } /* else go through */ + } + luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ } @@ -87,12 +96,13 @@ void luaK_nil (FuncState *fs, int from, int n) { ** Gets the destination address of a jump instruction. Used to traverse ** a list of jumps. */ -static int getjump (FuncState *fs, int pc) { - int offset = GETARG_sBx(fs->f->code[pc]); - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ +static int getjump(FuncState* fs, int pc) +{ + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc + 1) + offset; /* turn offset into absolute position */ } @@ -100,30 +110,33 @@ static int getjump (FuncState *fs, int pc) { ** Fix jump instruction at position 'pc' to jump to 'dest'. ** (Jump addresses are relative in Lua) */ -static void fixjump (FuncState *fs, int pc, int dest) { - Instruction *jmp = &fs->f->code[pc]; - int offset = dest - (pc + 1); - lua_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sBx) - luaX_syntaxerror(fs->ls, "control structure too long"); - SETARG_sBx(*jmp, offset); +static void fixjump(FuncState* fs, int pc, int dest) +{ + Instruction* jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); } /* ** Concatenate jump-list 'l2' into jump-list 'l1' */ -void luaK_concat (FuncState *fs, int *l1, int l2) { - if (l2 == NO_JUMP) return; /* nothing to concatenate? */ - else if (*l1 == NO_JUMP) /* no original list? */ - *l1 = l2; /* 'l1' points to 'l2' */ - else { - int list = *l1; - int next; - while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, l2); /* last element links to 'l2' */ - } +void luaK_concat(FuncState* fs, int* l1, int l2) +{ + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else + { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } } @@ -133,21 +146,23 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { ** this position (kept in 'jpc'), link them all together so that ** 'patchlistaux' will fix all them directly to the final destination. */ -int luaK_jump (FuncState *fs) { - int jpc = fs->jpc; /* save list of jumps to here */ - int j; - fs->jpc = NO_JUMP; /* no more jumps to here */ - j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); - luaK_concat(fs, &j, jpc); /* keep them on hold */ - return j; +int luaK_jump(FuncState* fs) +{ + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + fs->jpc = NO_JUMP; /* no more jumps to here */ + j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + luaK_concat(fs, &j, jpc); /* keep them on hold */ + return j; } /* ** Code a 'return' instruction */ -void luaK_ret (FuncState *fs, int first, int nret) { - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +void luaK_ret(FuncState* fs, int first, int nret) +{ + luaK_codeABC(fs, OP_RETURN, first, nret + 1, 0); } @@ -155,9 +170,10 @@ void luaK_ret (FuncState *fs, int first, int nret) { ** Code a "conditional jump", that is, a test or comparison opcode ** followed by a jump. Return jump position. */ -static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { - luaK_codeABC(fs, op, A, B, C); - return luaK_jump(fs); +static int condjump(FuncState* fs, OpCode op, int A, int B, int C) +{ + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); } @@ -165,9 +181,10 @@ static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { ** returns current 'pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ -int luaK_getlabel (FuncState *fs) { - fs->lasttarget = fs->pc; - return fs->pc; +int luaK_getlabel(FuncState* fs) +{ + fs->lasttarget = fs->pc; + return fs->pc; } @@ -176,12 +193,13 @@ int luaK_getlabel (FuncState *fs) { ** jump (that is, its condition), or the jump itself if it is ** unconditional. */ -static Instruction *getjumpcontrol (FuncState *fs, int pc) { - Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) - return pi-1; - else - return pi; +static Instruction* getjumpcontrol(FuncState* fs, int pc) +{ + Instruction* pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi - 1; + else + return pi; } @@ -192,27 +210,30 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { ** register. Otherwise, change instruction to a simple 'TEST' (produces ** no register value) */ -static int patchtestreg (FuncState *fs, int node, int reg) { - Instruction *i = getjumpcontrol(fs, node); - if (GET_OPCODE(*i) != OP_TESTSET) - return 0; /* cannot patch other instructions */ - if (reg != NO_REG && reg != GETARG_B(*i)) - SETARG_A(*i, reg); - else { - /* no register to put value or register already has the value; - change instruction to simple test */ - *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); - } - return 1; +static int patchtestreg(FuncState* fs, int node, int reg) +{ + Instruction* i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else + { + /* no register to put value or register already has the value; + change instruction to simple test */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + } + return 1; } /* ** Traverse a list of tests ensuring no one produces a value */ -static void removevalues (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) - patchtestreg(fs, list, NO_REG); +static void removevalues(FuncState* fs, int list) +{ + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); } @@ -221,16 +242,18 @@ static void removevalues (FuncState *fs, int list) { ** registers: tests producing values jump to 'vtarget' (and put their ** values in 'reg'), other tests jump to 'dtarget'. */ -static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, - int dtarget) { - while (list != NO_JUMP) { - int next = getjump(fs, list); - if (patchtestreg(fs, list, reg)) - fixjump(fs, list, vtarget); - else - fixjump(fs, list, dtarget); /* jump to default target */ - list = next; - } +static void patchlistaux(FuncState* fs, int list, int vtarget, int reg, + int dtarget) +{ + while (list != NO_JUMP) + { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } } @@ -239,9 +262,10 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, ** to current position with no values) and reset list of pending ** jumps */ -static void dischargejpc (FuncState *fs) { - patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); - fs->jpc = NO_JUMP; +static void dischargejpc(FuncState* fs) +{ + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; } @@ -249,9 +273,10 @@ static void dischargejpc (FuncState *fs) { ** Add elements in 'list' to list of pending jumps to "here" ** (current position) */ -void luaK_patchtohere (FuncState *fs, int list) { - luaK_getlabel(fs); /* mark "here" as a jump target */ - luaK_concat(fs, &fs->jpc, list); +void luaK_patchtohere(FuncState* fs, int list) +{ + luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_concat(fs, &fs->jpc, list); } @@ -260,13 +285,15 @@ void luaK_patchtohere (FuncState *fs, int list) { ** (The assert means that we cannot fix a jump to a forward address ** because we only know addresses once code is generated.) */ -void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) /* 'target' is current position? */ - luaK_patchtohere(fs, list); /* add list to pending jumps */ - else { - lua_assert(target < fs->pc); - patchlistaux(fs, list, target, NO_REG, target); - } +void luaK_patchlist(FuncState* fs, int list, int target) +{ + if (target == fs->pc) /* 'target' is current position? */ + luaK_patchtohere(fs, list); /* add list to pending jumps */ + else + { + lua_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, target); + } } @@ -275,14 +302,16 @@ void luaK_patchlist (FuncState *fs, int list, int target) { ** (The assertion checks that jumps either were closing nothing ** or were closing higher levels, from inner blocks.) */ -void luaK_patchclose (FuncState *fs, int list, int level) { - level++; /* argument is +1 to reserve 0 as non-op */ - for (; list != NO_JUMP; list = getjump(fs, list)) { - lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && - (GETARG_A(fs->f->code[list]) == 0 || - GETARG_A(fs->f->code[list]) >= level)); - SETARG_A(fs->f->code[list], level); - } +void luaK_patchclose(FuncState* fs, int list, int level) +{ + level++; /* argument is +1 to reserve 0 as non-op */ + for (; list != NO_JUMP; list = getjump(fs, list)) + { + lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && + (GETARG_A(fs->f->code[list]) == 0 || + GETARG_A(fs->f->code[list]) >= level)); + SETARG_A(fs->f->code[list], level); + } } @@ -290,18 +319,19 @@ void luaK_patchclose (FuncState *fs, int list, int level) { ** Emit instruction 'i', checking for array sizes and saving also its ** line information. Return 'i' position. */ -static int luaK_code (FuncState *fs, Instruction i) { - Proto *f = fs->f; - dischargejpc(fs); /* 'pc' will change */ - /* put new instruction in code array */ - luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, - MAX_INT, "opcodes"); - f->code[fs->pc] = i; - /* save corresponding line information */ - luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, - MAX_INT, "opcodes"); - f->lineinfo[fs->pc] = fs->ls->lastline; - return fs->pc++; +static int luaK_code(FuncState* fs, Instruction i) +{ + Proto* f = fs->f; + dischargejpc(fs); /* 'pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "opcodes"); + f->lineinfo[fs->pc] = fs->ls->lastline; + return fs->pc++; } @@ -309,32 +339,35 @@ static int luaK_code (FuncState *fs, Instruction i) { ** Format and emit an 'iABC' instruction. (Assertions check consistency ** of parameters versus opcode.) */ -int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { - lua_assert(getOpMode(o) == iABC); - lua_assert(getBMode(o) != OpArgN || b == 0); - lua_assert(getCMode(o) != OpArgN || c == 0); - lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); - return luaK_code(fs, CREATE_ABC(o, a, b, c)); +int luaK_codeABC(FuncState* fs, OpCode o, int a, int b, int c) +{ + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); + return luaK_code(fs, CREATE_ABC(o, a, b, c)); } /* ** Format and emit an 'iABx' instruction. */ -int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { - lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); - lua_assert(getCMode(o) == OpArgN); - lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); - return luaK_code(fs, CREATE_ABx(o, a, bc)); +int luaK_codeABx(FuncState* fs, OpCode o, int a, unsigned int bc) +{ + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); } /* ** Emit an "extra argument" instruction (format 'iAx') */ -static int codeextraarg (FuncState *fs, int a) { - lua_assert(a <= MAXARG_Ax); - return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +static int codeextraarg(FuncState* fs, int a) +{ + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); } @@ -343,14 +376,16 @@ static int codeextraarg (FuncState *fs, int a) { ** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' ** instruction with "extra argument". */ -int luaK_codek (FuncState *fs, int reg, int k) { - if (k <= MAXARG_Bx) - return luaK_codeABx(fs, OP_LOADK, reg, k); - else { - int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); - codeextraarg(fs, k); - return p; - } +int luaK_codek(FuncState* fs, int reg, int k) +{ + if (k <= MAXARG_Bx) + return luaK_codeABx(fs, OP_LOADK, reg, k); + else + { + int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } } @@ -358,23 +393,26 @@ int luaK_codek (FuncState *fs, int reg, int k) { ** Check register-stack level, keeping track of its maximum size ** in field 'maxstacksize' */ -void luaK_checkstack (FuncState *fs, int n) { - int newstack = fs->freereg + n; - if (newstack > fs->f->maxstacksize) { - if (newstack >= MAXREGS) - luaX_syntaxerror(fs->ls, - "function or expression needs too many registers"); - fs->f->maxstacksize = cast_byte(newstack); - } +void luaK_checkstack(FuncState* fs, int n) +{ + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) + { + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); + fs->f->maxstacksize = cast_byte(newstack); + } } /* ** Reserve 'n' registers in register stack */ -void luaK_reserveregs (FuncState *fs, int n) { - luaK_checkstack(fs, n); - fs->freereg += n; +void luaK_reserveregs(FuncState* fs, int n) +{ + luaK_checkstack(fs, n); + fs->freereg += n; } @@ -383,20 +421,23 @@ void luaK_reserveregs (FuncState *fs, int n) { ** a local variable. ) */ -static void freereg (FuncState *fs, int reg) { - if (!ISK(reg) && reg >= fs->nactvar) { - fs->freereg--; - lua_assert(reg == fs->freereg); - } +static void freereg(FuncState* fs, int reg) +{ + if (!ISK(reg) && reg >= fs->nactvar) + { + fs->freereg--; + lua_assert(reg == fs->freereg); + } } /* ** Free register used by expression 'e' (if any) */ -static void freeexp (FuncState *fs, expdesc *e) { - if (e->k == VNONRELOC) - freereg(fs, e->u.info); +static void freeexp(FuncState* fs, expdesc* e) +{ + if (e->k == VNONRELOC) + freereg(fs, e->u.info); } @@ -404,17 +445,20 @@ static void freeexp (FuncState *fs, expdesc *e) { ** Free registers used by expressions 'e1' and 'e2' (if any) in proper ** order. */ -static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { - int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; - int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; - if (r1 > r2) { - freereg(fs, r1); - freereg(fs, r2); - } - else { - freereg(fs, r2); - freereg(fs, r1); - } +static void freeexps(FuncState* fs, expdesc* e1, expdesc* e2) +{ + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + if (r1 > r2) + { + freereg(fs, r1); + freereg(fs, r2); + } + else + { + freereg(fs, r2); + freereg(fs, r1); + } } @@ -425,40 +469,45 @@ static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { ** as keys (nil cannot be a key, integer keys can collapse with float ** keys), the caller must provide a useful 'key' for indexing the cache. */ -static int addk (FuncState *fs, TValue *key, TValue *v) { - lua_State *L = fs->ls->L; - Proto *f = fs->f; - TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ - int k, oldsize; - if (ttisinteger(idx)) { /* is there an index there? */ - k = cast_int(ivalue(idx)); - /* correct value? (warning: must distinguish floats from integers!) */ - if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && - luaV_rawequalobj(&f->k[k], v)) - return k; /* reuse index */ - } - /* constant not found; create a new entry */ - oldsize = f->sizek; - k = fs->nk; - /* numerical value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setivalue(idx, k); - luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); - while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); - setobj(L, &f->k[k], v); - fs->nk++; - luaC_barrier(L, f, v); - return k; +static int addk(FuncState* fs, TValue* key, TValue* v) +{ + lua_State* L = fs->ls->L; + Proto* f = fs->f; + TValue* idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ + int k, oldsize; + if (ttisinteger(idx)) + { + /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(idx, k); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) + setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; } /* ** Add a string to list of constants and return its index. */ -int luaK_stringK (FuncState *fs, TString *s) { - TValue o; - setsvalue(fs->ls->L, &o, s); - return addk(fs, &o, &o); /* use string itself as key */ +int luaK_stringK(FuncState* fs, TString* s) +{ + TValue o; + setsvalue(fs->ls->L, &o, s); + return addk(fs, &o, &o); /* use string itself as key */ } @@ -468,42 +517,46 @@ int luaK_stringK (FuncState *fs, TString *s) { ** same value; conversion to 'void*' is used only for hashing, so there ** are no "precision" problems. */ -int luaK_intK (FuncState *fs, lua_Integer n) { - TValue k, o; - setpvalue(&k, cast(void*, cast(size_t, n))); - setivalue(&o, n); - return addk(fs, &k, &o); +int luaK_intK(FuncState* fs, lua_Integer n) +{ + TValue k, o; + setpvalue(&k, cast(void*, cast(size_t, n))); + setivalue(&o, n); + return addk(fs, &k, &o); } /* ** Add a float to list of constants and return its index. */ -static int luaK_numberK (FuncState *fs, lua_Number r) { - TValue o; - setfltvalue(&o, r); - return addk(fs, &o, &o); /* use number itself as key */ +static int luaK_numberK(FuncState* fs, lua_Number r) +{ + TValue o; + setfltvalue(&o, r); + return addk(fs, &o, &o); /* use number itself as key */ } /* ** Add a boolean to list of constants and return its index. */ -static int boolK (FuncState *fs, int b) { - TValue o; - setbvalue(&o, b); - return addk(fs, &o, &o); /* use boolean itself as key */ +static int boolK(FuncState* fs, int b) +{ + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); /* use boolean itself as key */ } /* ** Add nil to list of constants and return its index. */ -static int nilK (FuncState *fs) { - TValue k, v; - setnilvalue(&v); - /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(fs->ls->L, &k, fs->ls->h); - return addk(fs, &k, &v); +static int nilK(FuncState* fs) +{ + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->ls->L, &k, fs->ls->h); + return addk(fs, &k, &v); } @@ -512,17 +565,22 @@ static int nilK (FuncState *fs) { ** Either 'e' is a multi-ret expression (function call or vararg) ** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). */ -void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { - if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getinstruction(fs, e), nresults + 1); - } - else if (e->k == VVARARG) { - Instruction *pc = &getinstruction(fs, e); - SETARG_B(*pc, nresults + 1); - SETARG_A(*pc, fs->freereg); - luaK_reserveregs(fs, 1); - } - else lua_assert(nresults == LUA_MULTRET); +void luaK_setreturns(FuncState* fs, expdesc* e, int nresults) +{ + if (e->k == VCALL) + { + /* expression is an open function call? */ + SETARG_C(getinstruction(fs, e), nresults + 1); + } + else if (e->k == VVARARG) + { + Instruction* pc = &getinstruction(fs, e); + SETARG_B(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); + luaK_reserveregs(fs, 1); + } + else + lua_assert(nresults == LUA_MULTRET); } @@ -536,55 +594,71 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { ** (Calls are created returning one result, so that does not need ** to be fixed.) */ -void luaK_setoneret (FuncState *fs, expdesc *e) { - if (e->k == VCALL) { /* expression is an open function call? */ - /* already returns 1 value */ - lua_assert(GETARG_C(getinstruction(fs, e)) == 2); - e->k = VNONRELOC; /* result has fixed position */ - e->u.info = GETARG_A(getinstruction(fs, e)); - } - else if (e->k == VVARARG) { - SETARG_B(getinstruction(fs, e), 2); - e->k = VRELOCABLE; /* can relocate its simple result */ - } +void luaK_setoneret(FuncState* fs, expdesc* e) +{ + if (e->k == VCALL) + { + /* expression is an open function call? */ + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); + } + else if (e->k == VVARARG) + { + SETARG_B(getinstruction(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ + } } /* ** Ensure that expression 'e' is not a variable. */ -void luaK_dischargevars (FuncState *fs, expdesc *e) { - switch (e->k) { - case VLOCAL: { /* already in a register */ - e->k = VNONRELOC; /* becomes a non-relocatable value */ - break; - } - case VUPVAL: { /* move value to some (pending) register */ - e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - case VINDEXED: { - OpCode op; - freereg(fs, e->u.ind.idx); - if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ - freereg(fs, e->u.ind.t); - op = OP_GETTABLE; - } - else { - lua_assert(e->u.ind.vt == VUPVAL); - op = OP_GETTABUP; /* 't' is in an upvalue */ - } - e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; - break; - } - case VVARARG: case VCALL: { - luaK_setoneret(fs, e); - break; - } - default: break; /* there is one value available (somewhere) */ - } +void luaK_dischargevars(FuncState* fs, expdesc* e) +{ + switch (e->k) + { + case VLOCAL: + { + /* already in a register */ + e->k = VNONRELOC; /* becomes a non-relocatable value */ + break; + } + case VUPVAL: + { + /* move value to some (pending) register */ + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + case VINDEXED: + { + OpCode op; + freereg(fs, e->u.ind.idx); + if (e->u.ind.vt == VLOCAL) + { + /* is 't' in a register? */ + freereg(fs, e->u.ind.t); + op = OP_GETTABLE; + } + else + { + lua_assert(e->u.ind.vt == VUPVAL); + op = OP_GETTABUP; /* 't' is in an upvalue */ + } + e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOCABLE; + break; + } + case VVARARG: + case VCALL: + { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } } @@ -592,63 +666,78 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { ** Ensures expression value is in register 'reg' (and therefore ** 'e' will become a non-relocatable expression). */ -static void discharge2reg (FuncState *fs, expdesc *e, int reg) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: { - luaK_nil(fs, reg, 1); - break; - } - case VFALSE: case VTRUE: { - luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); - break; - } - case VK: { - luaK_codek(fs, reg, e->u.info); - break; - } - case VKFLT: { - luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); - break; - } - case VKINT: { - luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); - break; - } - case VRELOCABLE: { - Instruction *pc = &getinstruction(fs, e); - SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ - break; - } - case VNONRELOC: { - if (reg != e->u.info) - luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); - break; - } - default: { - lua_assert(e->k == VJMP); - return; /* nothing to do... */ - } - } - e->u.info = reg; - e->k = VNONRELOC; +static void discharge2reg(FuncState* fs, expdesc* e, int reg) +{ + luaK_dischargevars(fs, e); + switch (e->k) + { + case VNIL: + { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: + case VTRUE: + { + luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VK: + { + luaK_codek(fs, reg, e->u.info); + break; + } + case VKFLT: + { + luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); + break; + } + case VKINT: + { + luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); + break; + } + case VRELOCABLE: + { + Instruction* pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ + break; + } + case VNONRELOC: + { + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: + { + lua_assert(e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.info = reg; + e->k = VNONRELOC; } /* ** Ensures expression value is in any register. */ -static void discharge2anyreg (FuncState *fs, expdesc *e) { - if (e->k != VNONRELOC) { /* no fixed register yet? */ - luaK_reserveregs(fs, 1); /* get a register */ - discharge2reg(fs, e, fs->freereg-1); /* put value there */ - } +static void discharge2anyreg(FuncState* fs, expdesc* e) +{ + if (e->k != VNONRELOC) + { + /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg - 1); /* put value there */ + } } -static int code_loadbool (FuncState *fs, int A, int b, int jump) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +static int code_loadbool(FuncState* fs, int A, int b, int jump) +{ + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); } @@ -656,12 +745,14 @@ static int code_loadbool (FuncState *fs, int A, int b, int jump) { ** check whether list has any jump that do not produce a value ** or produce an inverted value */ -static int need_value (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TESTSET) return 1; - } - return 0; /* not found */ +static int need_value(FuncState* fs, int list) +{ + for (; list != NO_JUMP; list = getjump(fs, list)) + { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ } @@ -672,27 +763,30 @@ static int need_value (FuncState *fs, int list) { ** its final position or to "load" instructions (for those tests ** that do not produce values). */ -static void exp2reg (FuncState *fs, expdesc *e, int reg) { - discharge2reg(fs, e, reg); - if (e->k == VJMP) /* expression itself is a test? */ - luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ - if (hasjumps(e)) { - int final; /* position after whole expression */ - int p_f = NO_JUMP; /* position of an eventual LOAD false */ - int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e->t) || need_value(fs, e->f)) { - int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); - p_f = code_loadbool(fs, reg, 0, 1); - p_t = code_loadbool(fs, reg, 1, 0); - luaK_patchtohere(fs, fj); - } - final = luaK_getlabel(fs); - patchlistaux(fs, e->f, final, reg, p_f); - patchlistaux(fs, e->t, final, reg, p_t); - } - e->f = e->t = NO_JUMP; - e->u.info = reg; - e->k = VNONRELOC; +static void exp2reg(FuncState* fs, expdesc* e, int reg) +{ + discharge2reg(fs, e, reg); + if (e->k == VJMP) /* expression itself is a test? */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ + if (hasjumps(e)) + { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) + { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_loadbool(fs, reg, 0, 1); + p_t = code_loadbool(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; } @@ -700,11 +794,12 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { ** Ensures final expression result (including results from its jump ** lists) is in next available register. */ -void luaK_exp2nextreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - freeexp(fs, e); - luaK_reserveregs(fs, 1); - exp2reg(fs, e, fs->freereg - 1); +void luaK_exp2nextreg(FuncState* fs, expdesc* e) +{ + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); } @@ -712,18 +807,23 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { ** Ensures final expression result (including results from its jump ** lists) is in some (any) register and return that register. */ -int luaK_exp2anyreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - if (e->k == VNONRELOC) { /* expression already has a register? */ - if (!hasjumps(e)) /* no jumps? */ - return e->u.info; /* result is already in a register */ - if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->u.info); /* put final result in it */ - return e->u.info; - } - } - luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ - return e->u.info; +int luaK_exp2anyreg(FuncState* fs, expdesc* e) +{ + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) + { + /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ + if (e->u.info >= fs->nactvar) + { + /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put final result in it */ + return e->u.info; + } + } + luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ + return e->u.info; } @@ -731,9 +831,10 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { ** Ensures final expression result is either in a register or in an ** upvalue. */ -void luaK_exp2anyregup (FuncState *fs, expdesc *e) { - if (e->k != VUPVAL || hasjumps(e)) - luaK_exp2anyreg(fs, e); +void luaK_exp2anyregup(FuncState* fs, expdesc* e) +{ + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); } @@ -741,11 +842,12 @@ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { ** Ensures final expression result is either in a register or it is ** a constant. */ -void luaK_exp2val (FuncState *fs, expdesc *e) { - if (hasjumps(e)) - luaK_exp2anyreg(fs, e); - else - luaK_dischargevars(fs, e); +void luaK_exp2val(FuncState* fs, expdesc* e) +{ + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); } @@ -755,78 +857,93 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { ** in the range of R/K indices). ** Returns R/K index. */ -int luaK_exp2RK (FuncState *fs, expdesc *e) { - luaK_exp2val(fs, e); - switch (e->k) { /* move constants to 'k' */ - case VTRUE: e->u.info = boolK(fs, 1); goto vk; - case VFALSE: e->u.info = boolK(fs, 0); goto vk; - case VNIL: e->u.info = nilK(fs); goto vk; - case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; - case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; - case VK: - vk: - e->k = VK; - if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ - return RKASK(e->u.info); - else break; - default: break; - } - /* not a constant in the right range: put it in a register */ - return luaK_exp2anyreg(fs, e); +int luaK_exp2RK(FuncState* fs, expdesc* e) +{ + luaK_exp2val(fs, e); + switch (e->k) + { + /* move constants to 'k' */ + case VTRUE: e->u.info = boolK(fs, 1); + goto vk; + case VFALSE: e->u.info = boolK(fs, 0); + goto vk; + case VNIL: e->u.info = nilK(fs); + goto vk; + case VKINT: e->u.info = luaK_intK(fs, e->u.ival); + goto vk; + case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); + goto vk; + case VK: + vk: + e->k = VK; + if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ + return RKASK(e->u.info); + else break; + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); } /* ** Generate code to store result of expression 'ex' into variable 'var'. */ -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { - switch (var->k) { - case VLOCAL: { - freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ - return; - } - case VUPVAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); - break; - } - case VINDEXED: { - OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; - int e = luaK_exp2RK(fs, ex); - luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); - break; - } - default: lua_assert(0); /* invalid var kind to store */ - } - freeexp(fs, ex); +void luaK_storevar(FuncState* fs, expdesc* var, expdesc* ex) +{ + switch (var->k) + { + case VLOCAL: + { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ + return; + } + case VUPVAL: + { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } + case VINDEXED: + { + OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); + break; + } + default: lua_assert(0); /* invalid var kind to store */ + } + freeexp(fs, ex); } /* ** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). */ -void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { - int ereg; - luaK_exp2anyreg(fs, e); - ereg = e->u.info; /* register where 'e' was placed */ - freeexp(fs, e); - e->u.info = fs->freereg; /* base register for op_self */ - e->k = VNONRELOC; /* self expression has a fixed register */ - luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ - luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); - freeexp(fs, key); +void luaK_self(FuncState* fs, expdesc* e, expdesc* key) +{ + int ereg; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; /* self expression has a fixed register */ + luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); + freeexp(fs, key); } /* ** Negate condition 'e' (where 'e' is a comparison). */ -static void negatecondition (FuncState *fs, expdesc *e) { - Instruction *pc = getjumpcontrol(fs, e->u.info); - lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && - GET_OPCODE(*pc) != OP_TEST); - SETARG_A(*pc, !(GETARG_A(*pc))); +static void negatecondition(FuncState* fs, expdesc* e) +{ + Instruction* pc = getjumpcontrol(fs, e->u.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); } @@ -836,106 +953,138 @@ static void negatecondition (FuncState *fs, expdesc *e) { ** Optimize when 'e' is 'not' something, inverting the condition ** and removing the 'not'. */ -static int jumponcond (FuncState *fs, expdesc *e, int cond) { - if (e->k == VRELOCABLE) { - Instruction ie = getinstruction(fs, e); - if (GET_OPCODE(ie) == OP_NOT) { - fs->pc--; /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); - } - /* else go through */ - } - discharge2anyreg(fs, e); - freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); +static int jumponcond(FuncState* fs, expdesc* e, int cond) +{ + if (e->k == VRELOCABLE) + { + Instruction ie = getinstruction(fs, e); + if (GET_OPCODE(ie) == OP_NOT) + { + fs->pc--; /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); } /* ** Emit code to go through if 'e' is true, jump otherwise. */ -void luaK_goiftrue (FuncState *fs, expdesc *e) { - int pc; /* pc of new jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VJMP: { /* condition? */ - negatecondition(fs, e); /* jump when it is false */ - pc = e->u.info; /* save jump position */ - break; - } - case VK: case VKFLT: case VKINT: case VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } - default: { - pc = jumponcond(fs, e, 0); /* jump when false */ - break; - } - } - luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ - luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ - e->t = NO_JUMP; +void luaK_goiftrue(FuncState* fs, expdesc* e) +{ + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) + { + case VJMP: + { + /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ + break; + } + case VK: + case VKFLT: + case VKINT: + case VTRUE: + { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: + { + pc = jumponcond(fs, e, 0); /* jump when false */ + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ + e->t = NO_JUMP; } /* ** Emit code to go through if 'e' is false, jump otherwise. */ -void luaK_goiffalse (FuncState *fs, expdesc *e) { - int pc; /* pc of new jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VJMP: { - pc = e->u.info; /* already jump if true */ - break; - } - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } - default: { - pc = jumponcond(fs, e, 1); /* jump if true */ - break; - } - } - luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ - luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ - e->f = NO_JUMP; +void luaK_goiffalse(FuncState* fs, expdesc* e) +{ + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) + { + case VJMP: + { + pc = e->u.info; /* already jump if true */ + break; + } + case VNIL: + case VFALSE: + { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: + { + pc = jumponcond(fs, e, 1); /* jump if true */ + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ + e->f = NO_JUMP; } /* ** Code 'not e', doing constant folding. */ -static void codenot (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: case VFALSE: { - e->k = VTRUE; /* true == not nil == not false */ - break; - } - case VK: case VKFLT: case VKINT: case VTRUE: { - e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ - break; - } - case VJMP: { - negatecondition(fs, e); - break; - } - case VRELOCABLE: - case VNONRELOC: { - discharge2anyreg(fs, e); - freeexp(fs, e); - e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - default: lua_assert(0); /* cannot happen */ - } - /* interchange true and false lists */ - { int temp = e->f; e->f = e->t; e->t = temp; } - removevalues(fs, e->f); /* values are useless when negated */ - removevalues(fs, e->t); +static void codenot(FuncState* fs, expdesc* e) +{ + luaK_dischargevars(fs, e); + switch (e->k) + { + case VNIL: + case VFALSE: + { + e->k = VTRUE; /* true == not nil == not false */ + break; + } + case VK: + case VKFLT: + case VKINT: + case VTRUE: + { + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ + break; + } + case VJMP: + { + negatecondition(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: + { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + default: lua_assert(0); /* cannot happen */ + } + /* interchange true and false lists */ + { + int temp = e->f; + e->f = e->t; + e->t = temp; + } + removevalues(fs, e->f); /* values are useless when negated */ + removevalues(fs, e->t); } @@ -943,12 +1092,13 @@ static void codenot (FuncState *fs, expdesc *e) { ** Create expression 't[k]'. 't' must have its final result already in a ** register or upvalue. */ -void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); - t->u.ind.t = t->u.info; /* register or upvalue index */ - t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ - t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; - t->k = VINDEXED; +void luaK_indexed(FuncState* fs, expdesc* t, expdesc* k) +{ + lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); + t->u.ind.t = t->u.info; /* register or upvalue index */ + t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; + t->k = VINDEXED; } @@ -957,17 +1107,27 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { ** Bitwise operations need operands convertible to integers; division ** operations cannot have 0 as divisor. */ -static int validop (int op, TValue *v1, TValue *v2) { - switch (op) { - case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: - case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ - lua_Integer i; - return (tointeger(v1, &i) && tointeger(v2, &i)); - } - case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ - return (nvalue(v2) != 0); - default: return 1; /* everything else is valid */ - } +static int validop(int op, TValue* v1, TValue* v2) +{ + switch (op) + { + case LUA_OPBAND: + case LUA_OPBOR: + case LUA_OPBXOR: + case LUA_OPSHL: + case LUA_OPSHR: + case LUA_OPBNOT: + { + /* conversion errors */ + lua_Integer i; + return (tointeger(v1, &i) && tointeger(v2, &i)); + } + case LUA_OPDIV: + case LUA_OPIDIV: + case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } } @@ -975,24 +1135,28 @@ static int validop (int op, TValue *v1, TValue *v2) { ** Try to "constant-fold" an operation; return 1 iff successful. ** (In this case, 'e1' has the final result.) */ -static int constfolding (FuncState *fs, int op, expdesc *e1, - const expdesc *e2) { - TValue v1, v2, res; - if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) - return 0; /* non-numeric operands or not safe to fold */ - luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ - if (ttisinteger(&res)) { - e1->k = VKINT; - e1->u.ival = ivalue(&res); - } - else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ - lua_Number n = fltvalue(&res); - if (luai_numisnan(n) || n == 0) - return 0; - e1->k = VKFLT; - e1->u.nval = n; - } - return 1; +static int constfolding(FuncState* fs, int op, expdesc* e1, + const expdesc* e2) +{ + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) + { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else + { + /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } + return 1; } @@ -1001,12 +1165,13 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, ** (everything but 'not'). ** Expression to produce final result will be encoded in 'e'. */ -static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { - int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ - freeexp(fs, e); - e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ - e->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); +static void codeunexpval(FuncState* fs, OpCode op, expdesc* e, int line) +{ + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); } @@ -1019,14 +1184,15 @@ static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { ** in "stack order" (that is, first on 'e2', which may have more ** recent registers to be released). */ -static void codebinexpval (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { - int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ - int rk1 = luaK_exp2RK(fs, e1); - freeexps(fs, e1, e2); - e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); +static void codebinexpval(FuncState* fs, OpCode op, + expdesc* e1, expdesc* e2, int line) +{ + int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ + int rk1 = luaK_exp2RK(fs, e1); + freeexps(fs, e1, e2); + e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ + e1->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); } @@ -1034,48 +1200,61 @@ static void codebinexpval (FuncState *fs, OpCode op, ** Emit code for comparisons. ** 'e1' was already put in R/K form by 'luaK_infix'. */ -static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { - int rk1 = (e1->k == VK) ? RKASK(e1->u.info) - : check_exp(e1->k == VNONRELOC, e1->u.info); - int rk2 = luaK_exp2RK(fs, e2); - freeexps(fs, e1, e2); - switch (opr) { - case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ - e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); - break; - } - case OPR_GT: case OPR_GE: { - /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ - OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); - e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ - break; - } - default: { /* '==', '<', '<=' use their own opcodes */ - OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); - e1->u.info = condjump(fs, op, 1, rk1, rk2); - break; - } - } - e1->k = VJMP; +static void codecomp(FuncState* fs, BinOpr opr, expdesc* e1, expdesc* e2) +{ + int rk1 = (e1->k == VK) + ? RKASK(e1->u.info) + : check_exp(e1->k == VNONRELOC, e1->u.info); + int rk2 = luaK_exp2RK(fs, e2); + freeexps(fs, e1, e2); + switch (opr) + { + case OPR_NE: + { + /* '(a ~= b)' ==> 'not (a == b)' */ + e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); + break; + } + case OPR_GT: + case OPR_GE: + { + /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ + break; + } + default: + { + /* '==', '<', '<=' use their own opcodes */ + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk1, rk2); + break; + } + } + e1->k = VJMP; } /* ** Aplly prefix operation 'op' to expression 'e'. */ -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { - static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; - switch (op) { - case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ - if (constfolding(fs, op + LUA_OPUNM, e, &ef)) - break; - /* FALLTHROUGH */ - case OPR_LEN: - codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); - break; - case OPR_NOT: codenot(fs, e); break; - default: lua_assert(0); - } +void luaK_prefix(FuncState* fs, UnOpr op, expdesc* e, int line) +{ + static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; + switch (op) + { + case OPR_MINUS: + case OPR_BNOT: /* use 'ef' as fake 2nd operand */ + if (constfolding(fs, op + LUA_OPUNM, e, &ef)) + break; + /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); + break; + case OPR_NOT: codenot(fs, e); + break; + default: lua_assert(0); + } } @@ -1083,35 +1262,49 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { ** Process 1st operand 'v' of binary operation 'op' before reading ** 2nd operand. */ -void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { - switch (op) { - case OPR_AND: { - luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ - break; - } - case OPR_OR: { - luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ - break; - } - case OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ - break; - } - case OPR_ADD: case OPR_SUB: - case OPR_MUL: case OPR_DIV: case OPR_IDIV: - case OPR_MOD: case OPR_POW: - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - if (!tonumeral(v, NULL)) - luaK_exp2RK(fs, v); - /* else keep numeral, which may be folded with 2nd operand */ - break; - } - default: { - luaK_exp2RK(fs, v); - break; - } - } +void luaK_infix(FuncState* fs, BinOpr op, expdesc* v) +{ + switch (op) + { + case OPR_AND: + { + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ + break; + } + case OPR_OR: + { + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ + break; + } + case OPR_CONCAT: + { + luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ + break; + } + case OPR_ADD: + case OPR_SUB: + case OPR_MUL: + case OPR_DIV: + case OPR_IDIV: + case OPR_MOD: + case OPR_POW: + case OPR_BAND: + case OPR_BOR: + case OPR_BXOR: + case OPR_SHL: + case OPR_SHR: + { + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be folded with 2nd operand */ + break; + } + default: + { + luaK_exp2RK(fs, v); + break; + } + } } @@ -1121,61 +1314,84 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { ** concatenation is right associative), merge second CONCAT into first ** one. */ -void luaK_posfix (FuncState *fs, BinOpr op, - expdesc *e1, expdesc *e2, int line) { - switch (op) { - case OPR_AND: { - lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, &e2->f, e1->f); - *e1 = *e2; - break; - } - case OPR_OR: { - lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, &e2->t, e1->t); - *e1 = *e2; - break; - } - case OPR_CONCAT: { - luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && - GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { - lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); - freeexp(fs, e1); - SETARG_B(getinstruction(fs, e2), e1->u.info); - e1->k = VRELOCABLE; e1->u.info = e2->u.info; - } - else { - luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codebinexpval(fs, OP_CONCAT, e1, e2, line); - } - break; - } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_IDIV: case OPR_MOD: case OPR_POW: - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); - break; - } - case OPR_EQ: case OPR_LT: case OPR_LE: - case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, op, e1, e2); - break; - } - default: lua_assert(0); - } +void luaK_posfix(FuncState* fs, BinOpr op, + expdesc* e1, expdesc* e2, int line) +{ + switch (op) + { + case OPR_AND: + { + lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: + { + lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: + { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && + GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) + { + lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getinstruction(fs, e2), e1->u.info); + e1->k = VRELOCABLE; + e1->u.info = e2->u.info; + } + else + { + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codebinexpval(fs, OP_CONCAT, e1, e2, line); + } + break; + } + case OPR_ADD: + case OPR_SUB: + case OPR_MUL: + case OPR_DIV: + case OPR_IDIV: + case OPR_MOD: + case OPR_POW: + case OPR_BAND: + case OPR_BOR: + case OPR_BXOR: + case OPR_SHL: + case OPR_SHR: + { + if (!constfolding(fs, op + LUA_OPADD, e1, e2)) + codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + break; + } + case OPR_EQ: + case OPR_LT: + case OPR_LE: + case OPR_NE: + case OPR_GT: + case OPR_GE: + { + codecomp(fs, op, e1, e2); + break; + } + default: lua_assert(0); + } } /* ** Change line information associated with current position. */ -void luaK_fixline (FuncState *fs, int line) { - fs->f->lineinfo[fs->pc - 1] = line; +void luaK_fixline(FuncState* fs, int line) +{ + fs->f->lineinfo[fs->pc - 1] = line; } @@ -1186,18 +1402,19 @@ void luaK_fixline (FuncState *fs, int line) { ** 'tostore' is number of values (in registers 'base + 1',...) to add to ** table (or LUA_MULTRET to add up to stack top). */ -void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { - int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; - int b = (tostore == LUA_MULTRET) ? 0 : tostore; - lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); - if (c <= MAXARG_C) - luaK_codeABC(fs, OP_SETLIST, base, b, c); - else if (c <= MAXARG_Ax) { - luaK_codeABC(fs, OP_SETLIST, base, b, 0); - codeextraarg(fs, c); - } - else - luaX_syntaxerror(fs->ls, "constructor too long"); - fs->freereg = base + 1; /* free registers with list values */ +void luaK_setlist(FuncState* fs, int base, int nelems, int tostore) +{ + int c = (nelems - 1) / LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else if (c <= MAXARG_Ax) + { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + codeextraarg(fs, c); + } + else + luaX_syntaxerror(fs->ls, "constructor too long"); + fs->freereg = base + 1; /* free registers with list values */ } - diff --git a/Lua/lcode.h b/Lua/lcode.h index cd306d5..69fb5b7 100644 --- a/Lua/lcode.h +++ b/Lua/lcode.h @@ -23,17 +23,30 @@ /* ** grep "ORDER OPR" if you change these enums (ORDER OP) */ -typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, - OPR_DIV, - OPR_IDIV, - OPR_BAND, OPR_BOR, OPR_BXOR, - OPR_SHL, OPR_SHR, - OPR_CONCAT, - OPR_EQ, OPR_LT, OPR_LE, - OPR_NE, OPR_GT, OPR_GE, - OPR_AND, OPR_OR, - OPR_NOBINOPR +typedef enum BinOpr +{ + OPR_ADD, + OPR_SUB, + OPR_MUL, + OPR_MOD, + OPR_POW, + OPR_DIV, + OPR_IDIV, + OPR_BAND, + OPR_BOR, + OPR_BXOR, + OPR_SHL, + OPR_SHR, + OPR_CONCAT, + OPR_EQ, + OPR_LT, + OPR_LE, + OPR_NE, + OPR_GT, + OPR_GE, + OPR_AND, + OPR_OR, + OPR_NOBINOPR } BinOpr; @@ -49,40 +62,40 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) -LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); -LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); -LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); -LUAI_FUNC void luaK_fixline (FuncState *fs, int line); -LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); -LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); -LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); -LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); -LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); -LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); -LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); -LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); -LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); -LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_jump (FuncState *fs); -LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); -LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); -LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); -LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); -LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); -LUAI_FUNC int luaK_getlabel (FuncState *fs); -LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); -LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); -LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, - expdesc *v2, int line); -LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); +LUAI_FUNC int luaK_codeABx(FuncState* fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeABC(FuncState* fs, OpCode o, int A, int B, int C); +LUAI_FUNC int luaK_codek(FuncState* fs, int reg, int k); +LUAI_FUNC void luaK_fixline(FuncState* fs, int line); +LUAI_FUNC void luaK_nil(FuncState* fs, int from, int n); +LUAI_FUNC void luaK_reserveregs(FuncState* fs, int n); +LUAI_FUNC void luaK_checkstack(FuncState* fs, int n); +LUAI_FUNC int luaK_stringK(FuncState* fs, TString* s); +LUAI_FUNC int luaK_intK(FuncState* fs, lua_Integer n); +LUAI_FUNC void luaK_dischargevars(FuncState* fs, expdesc* e); +LUAI_FUNC int luaK_exp2anyreg(FuncState* fs, expdesc* e); +LUAI_FUNC void luaK_exp2anyregup(FuncState* fs, expdesc* e); +LUAI_FUNC void luaK_exp2nextreg(FuncState* fs, expdesc* e); +LUAI_FUNC void luaK_exp2val(FuncState* fs, expdesc* e); +LUAI_FUNC int luaK_exp2RK(FuncState* fs, expdesc* e); +LUAI_FUNC void luaK_self(FuncState* fs, expdesc* e, expdesc* key); +LUAI_FUNC void luaK_indexed(FuncState* fs, expdesc* t, expdesc* k); +LUAI_FUNC void luaK_goiftrue(FuncState* fs, expdesc* e); +LUAI_FUNC void luaK_goiffalse(FuncState* fs, expdesc* e); +LUAI_FUNC void luaK_storevar(FuncState* fs, expdesc* var, expdesc* e); +LUAI_FUNC void luaK_setreturns(FuncState* fs, expdesc* e, int nresults); +LUAI_FUNC void luaK_setoneret(FuncState* fs, expdesc* e); +LUAI_FUNC int luaK_jump(FuncState* fs); +LUAI_FUNC void luaK_ret(FuncState* fs, int first, int nret); +LUAI_FUNC void luaK_patchlist(FuncState* fs, int list, int target); +LUAI_FUNC void luaK_patchtohere(FuncState* fs, int list); +LUAI_FUNC void luaK_patchclose(FuncState* fs, int list, int level); +LUAI_FUNC void luaK_concat(FuncState* fs, int* l1, int l2); +LUAI_FUNC int luaK_getlabel(FuncState* fs); +LUAI_FUNC void luaK_prefix(FuncState* fs, UnOpr op, expdesc* v, int line); +LUAI_FUNC void luaK_infix(FuncState* fs, BinOpr op, expdesc* v); +LUAI_FUNC void luaK_posfix(FuncState* fs, BinOpr op, expdesc* v1, + expdesc* v2, int line); +LUAI_FUNC void luaK_setlist(FuncState* fs, int base, int nelems, int tostore); #endif diff --git a/Lua/lcorolib.c b/Lua/lcorolib.c index 2303429..df822dc 100644 --- a/Lua/lcorolib.c +++ b/Lua/lcorolib.c @@ -18,151 +18,174 @@ #include "lualib.h" -static lua_State *getco (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "thread expected"); - return co; +static lua_State* getco(lua_State* L) +{ + lua_State* co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "thread expected"); + return co; } -static int auxresume (lua_State *L, lua_State *co, int narg) { - int status; - if (!lua_checkstack(co, narg)) { - lua_pushliteral(L, "too many arguments to resume"); - return -1; /* error flag */ - } - if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { - lua_pushliteral(L, "cannot resume dead coroutine"); - return -1; /* error flag */ - } - lua_xmove(L, co, narg); - status = lua_resume(co, L, narg); - if (status == LUA_OK || status == LUA_YIELD) { - int nres = lua_gettop(co); - if (!lua_checkstack(L, nres + 1)) { - lua_pop(co, nres); /* remove results anyway */ - lua_pushliteral(L, "too many results to resume"); - return -1; /* error flag */ - } - lua_xmove(co, L, nres); /* move yielded values */ - return nres; - } - else { - lua_xmove(co, L, 1); /* move error message */ - return -1; /* error flag */ - } +static int auxresume(lua_State* L, lua_State* co, int narg) +{ + int status; + if (!lua_checkstack(co, narg)) + { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) + { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, L, narg); + if (status == LUA_OK || status == LUA_YIELD) + { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) + { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else + { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } } -static int luaB_coresume (lua_State *L) { - lua_State *co = getco(L); - int r; - r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - lua_insert(L, -(r + 1)); - return r + 1; /* return true + 'resume' returns */ - } +static int luaB_coresume(lua_State* L) +{ + lua_State* co = getco(L); + int r; + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) + { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else + { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + 'resume' returns */ + } } -static int luaB_auxwrap (lua_State *L) { - lua_State *co = lua_tothread(L, lua_upvalueindex(1)); - int r = auxresume(L, co, lua_gettop(L)); - if (r < 0) { - if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ - luaL_where(L, 1); /* add extra info */ - lua_insert(L, -2); - lua_concat(L, 2); - } - return lua_error(L); /* propagate error */ - } - return r; +static int luaB_auxwrap(lua_State* L) +{ + lua_State* co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) + { + if (lua_type(L, -1) == LUA_TSTRING) + { + /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + return lua_error(L); /* propagate error */ + } + return r; } -static int luaB_cocreate (lua_State *L) { - lua_State *NL; - luaL_checktype(L, 1, LUA_TFUNCTION); - NL = lua_newthread(L); - lua_pushvalue(L, 1); /* move function to top */ - lua_xmove(L, NL, 1); /* move function from L to NL */ - return 1; +static int luaB_cocreate(lua_State* L) +{ + lua_State* NL; + luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; } -static int luaB_cowrap (lua_State *L) { - luaB_cocreate(L); - lua_pushcclosure(L, luaB_auxwrap, 1); - return 1; +static int luaB_cowrap(lua_State* L) +{ + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; } -static int luaB_yield (lua_State *L) { - return lua_yield(L, lua_gettop(L)); +static int luaB_yield(lua_State* L) +{ + return lua_yield(L, lua_gettop(L)); } -static int luaB_costatus (lua_State *L) { - lua_State *co = getco(L); - if (L == co) lua_pushliteral(L, "running"); - else { - switch (lua_status(co)) { - case LUA_YIELD: - lua_pushliteral(L, "suspended"); - break; - case LUA_OK: { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ - lua_pushliteral(L, "normal"); /* it is running */ - else if (lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); /* initial state */ - break; - } - default: /* some error occurred */ - lua_pushliteral(L, "dead"); - break; - } - } - return 1; +static int luaB_costatus(lua_State* L) +{ + lua_State* co = getco(L); + if (L == co) + lua_pushliteral(L, "running"); + else + { + switch (lua_status(co)) + { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case LUA_OK: + { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occurred */ + lua_pushliteral(L, "dead"); + break; + } + } + return 1; } -static int luaB_yieldable (lua_State *L) { - lua_pushboolean(L, lua_isyieldable(L)); - return 1; +static int luaB_yieldable(lua_State* L) +{ + lua_pushboolean(L, lua_isyieldable(L)); + return 1; } -static int luaB_corunning (lua_State *L) { - int ismain = lua_pushthread(L); - lua_pushboolean(L, ismain); - return 2; +static int luaB_corunning(lua_State* L) +{ + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; } static const luaL_Reg co_funcs[] = { - {"create", luaB_cocreate}, - {"resume", luaB_coresume}, - {"running", luaB_corunning}, - {"status", luaB_costatus}, - {"wrap", luaB_cowrap}, - {"yield", luaB_yield}, - {"isyieldable", luaB_yieldable}, - {NULL, NULL} + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, + {NULL, NULL} }; - -LUAMOD_API int luaopen_coroutine (lua_State *L) { - luaL_newlib(L, co_funcs); - return 1; +LUAMOD_API int luaopen_coroutine(lua_State* L) +{ + luaL_newlib(L, co_funcs); + return 1; } - diff --git a/Lua/lctype.c b/Lua/lctype.c index ae9367e..863615c 100644 --- a/Lua/lctype.c +++ b/Lua/lctype.c @@ -17,39 +17,39 @@ #include LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { - 0x00, /* EOZ */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ - 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ - 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif /* } */ diff --git a/Lua/lctype.h b/Lua/lctype.h index 99c7d12..8c2d56a 100644 --- a/Lua/lctype.h +++ b/Lua/lctype.h @@ -92,4 +92,3 @@ LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; #endif /* } */ #endif - diff --git a/Lua/ldblib.c b/Lua/ldblib.c index 786f6cd..e47c726 100644 --- a/Lua/ldblib.c +++ b/Lua/ldblib.c @@ -32,52 +32,59 @@ static const int HOOKKEY = 0; ** guarantees about its stack space; any push in L1 must be ** checked. */ -static void checkstack (lua_State *L, lua_State *L1, int n) { - if (L != L1 && !lua_checkstack(L1, n)) - luaL_error(L, "stack overflow"); +static void checkstack(lua_State* L, lua_State* L1, int n) +{ + if (L != L1 && !lua_checkstack(L1, n)) + luaL_error(L, "stack overflow"); } -static int db_getregistry (lua_State *L) { - lua_pushvalue(L, LUA_REGISTRYINDEX); - return 1; +static int db_getregistry(lua_State* L) +{ + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; } -static int db_getmetatable (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - lua_pushnil(L); /* no metatable */ - } - return 1; +static int db_getmetatable(lua_State* L) +{ + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) + { + lua_pushnil(L); /* no metatable */ + } + return 1; } -static int db_setmetatable (lua_State *L) { - int t = lua_type(L, 2); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; /* return 1st argument */ +static int db_setmetatable(lua_State* L) +{ + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ } -static int db_getuservalue (lua_State *L) { - if (lua_type(L, 1) != LUA_TUSERDATA) - lua_pushnil(L); - else - lua_getuservalue(L, 1); - return 1; +static int db_getuservalue(lua_State* L) +{ + if (lua_type(L, 1) != LUA_TUSERDATA) + lua_pushnil(L); + else + lua_getuservalue(L, 1); + return 1; } -static int db_setuservalue (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_setuservalue(L, 1); - return 1; +static int db_setuservalue(lua_State* L) +{ + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_setuservalue(L, 1); + return 1; } @@ -87,15 +94,18 @@ static int db_setuservalue (lua_State *L) { ** 1 if this argument is present (so that functions can skip it to ** access their other arguments) */ -static lua_State *getthread (lua_State *L, int *arg) { - if (lua_isthread(L, 1)) { - *arg = 1; - return lua_tothread(L, 1); - } - else { - *arg = 0; - return L; /* function will operate over current thread */ - } +static lua_State* getthread(lua_State* L, int* arg) +{ + if (lua_isthread(L, 1)) + { + *arg = 1; + return lua_tothread(L, 1); + } + else + { + *arg = 0; + return L; /* function will operate over current thread */ + } } @@ -104,19 +114,22 @@ static lua_State *getthread (lua_State *L, int *arg) { ** from 'lua_getinfo' into result table. Key is always a string; ** value can be a string, an int, or a boolean. */ -static void settabss (lua_State *L, const char *k, const char *v) { - lua_pushstring(L, v); - lua_setfield(L, -2, k); +static void settabss(lua_State* L, const char* k, const char* v) +{ + lua_pushstring(L, v); + lua_setfield(L, -2, k); } -static void settabsi (lua_State *L, const char *k, int v) { - lua_pushinteger(L, v); - lua_setfield(L, -2, k); +static void settabsi(lua_State* L, const char* k, int v) +{ + lua_pushinteger(L, v); + lua_setfield(L, -2, k); } -static void settabsb (lua_State *L, const char *k, int v) { - lua_pushboolean(L, v); - lua_setfield(L, -2, k); +static void settabsb(lua_State* L, const char* k, int v) +{ + lua_pushboolean(L, v); + lua_setfield(L, -2, k); } @@ -127,12 +140,13 @@ static void settabsb (lua_State *L, const char *k, int v) { ** 'lua_getinfo' on top of the result table so that it can call ** 'lua_setfield'. */ -static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { - if (L == L1) - lua_rotate(L, -2, 1); /* exchange object and table */ - else - lua_xmove(L1, L, 1); /* move object to the "main" stack */ - lua_setfield(L, -2, fname); /* put object into table */ +static void treatstackoption(lua_State* L, lua_State* L1, const char* fname) +{ + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ + else + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ } @@ -142,129 +156,149 @@ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { ** two optional outputs (function and line table) from function ** 'lua_getinfo'. */ -static int db_getinfo (lua_State *L) { - lua_Debug ar; - int arg; - lua_State *L1 = getthread(L, &arg); - const char *options = luaL_optstring(L, arg+2, "flnStu"); - checkstack(L, L1, 3); - if (lua_isfunction(L, arg + 1)) { /* info about a function? */ - options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ - lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ - lua_xmove(L, L1, 1); - } - else { /* stack level */ - if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { - lua_pushnil(L); /* level out of range */ - return 1; - } - } - if (!lua_getinfo(L1, options, &ar)) - return luaL_argerror(L, arg+2, "invalid option"); - lua_newtable(L); /* table to collect results */ - if (strchr(options, 'S')) { - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabsi(L, "lastlinedefined", ar.lastlinedefined); - settabss(L, "what", ar.what); - } - if (strchr(options, 'l')) - settabsi(L, "currentline", ar.currentline); - if (strchr(options, 'u')) { - settabsi(L, "nups", ar.nups); - settabsi(L, "nparams", ar.nparams); - settabsb(L, "isvararg", ar.isvararg); - } - if (strchr(options, 'n')) { - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - } - if (strchr(options, 't')) - settabsb(L, "istailcall", ar.istailcall); - if (strchr(options, 'L')) - treatstackoption(L, L1, "activelines"); - if (strchr(options, 'f')) - treatstackoption(L, L1, "func"); - return 1; /* return table */ +static int db_getinfo(lua_State* L) +{ + lua_Debug ar; + int arg; + lua_State* L1 = getthread(L, &arg); + const char* options = luaL_optstring(L, arg+2, "flnStu"); + checkstack(L, L1, 3); + if (lua_isfunction(L, arg + 1)) + { + /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else + { + /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) + { + lua_pushnil(L); /* level out of range */ + return 1; + } + } + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg + 2, "invalid option"); + lua_newtable(L); /* table to collect results */ + if (strchr(options, 'S')) + { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) + { + settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } + if (strchr(options, 'n')) + { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ } -static int db_getlocal (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - const char *name; - int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ - if (lua_isfunction(L, arg + 1)) { /* function argument? */ - lua_pushvalue(L, arg + 1); /* push function */ - lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ - return 1; /* return only name (there is no value) */ - } - else { /* stack-level argument */ - int level = (int)luaL_checkinteger(L, arg + 1); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - checkstack(L, L1, 1); - name = lua_getlocal(L1, &ar, nvar); - if (name) { - lua_xmove(L1, L, 1); /* move local value */ - lua_pushstring(L, name); /* push name */ - lua_rotate(L, -2, 1); /* re-order */ - return 2; - } - else { - lua_pushnil(L); /* no name (nor value) */ - return 1; - } - } +static int db_getlocal(lua_State* L) +{ + int arg; + lua_State* L1 = getthread(L, &arg); + lua_Debug ar; + const char* name; + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) + { + /* function argument? */ + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ + return 1; /* return only name (there is no value) */ + } + else + { + /* stack-level argument */ + int level = (int)luaL_checkinteger(L, arg + 1); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ + return luaL_argerror(L, arg + 1, "level out of range"); + checkstack(L, L1, 1); + name = lua_getlocal(L1, &ar, nvar); + if (name) + { + lua_xmove(L1, L, 1); /* move local value */ + lua_pushstring(L, name); /* push name */ + lua_rotate(L, -2, 1); /* re-order */ + return 2; + } + else + { + lua_pushnil(L); /* no name (nor value) */ + return 1; + } + } } -static int db_setlocal (lua_State *L) { - int arg; - const char *name; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - int level = (int)luaL_checkinteger(L, arg + 1); - int nvar = (int)luaL_checkinteger(L, arg + 2); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - luaL_checkany(L, arg+3); - lua_settop(L, arg+3); - checkstack(L, L1, 1); - lua_xmove(L, L1, 1); - name = lua_setlocal(L1, &ar, nvar); - if (name == NULL) - lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ - lua_pushstring(L, name); - return 1; +static int db_setlocal(lua_State* L) +{ + int arg; + const char* name; + lua_State* L1 = getthread(L, &arg); + lua_Debug ar; + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ + return luaL_argerror(L, arg + 1, "level out of range"); + luaL_checkany(L, arg + 3); + lua_settop(L, arg + 3); + checkstack(L, L1, 1); + lua_xmove(L, L1, 1); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); + return 1; } /* ** get (if 'get' is true) or set an upvalue from a closure */ -static int auxupvalue (lua_State *L, int get) { - const char *name; - int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ - luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ - name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - lua_insert(L, -(get+1)); /* no-op if get is false */ - return get + 1; +static int auxupvalue(lua_State* L, int get) +{ + const char* name; + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); /* no-op if get is false */ + return get + 1; } -static int db_getupvalue (lua_State *L) { - return auxupvalue(L, 1); +static int db_getupvalue(lua_State* L) +{ + return auxupvalue(L, 1); } -static int db_setupvalue (lua_State *L) { - luaL_checkany(L, 3); - return auxupvalue(L, 0); +static int db_setupvalue(lua_State* L) +{ + luaL_checkany(L, 3); + return auxupvalue(L, 0); } @@ -272,29 +306,32 @@ static int db_setupvalue (lua_State *L) { ** Check whether a given upvalue from a given closure exists and ** returns its index */ -static int checkupval (lua_State *L, int argf, int argnup) { - int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ - luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ - luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, - "invalid upvalue index"); - return nup; +static int checkupval(lua_State* L, int argf, int argnup) +{ + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, + "invalid upvalue index"); + return nup; } -static int db_upvalueid (lua_State *L) { - int n = checkupval(L, 1, 2); - lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); - return 1; +static int db_upvalueid(lua_State* L) +{ + int n = checkupval(L, 1, 2); + lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); + return 1; } -static int db_upvaluejoin (lua_State *L) { - int n1 = checkupval(L, 1, 2); - int n2 = checkupval(L, 3, 4); - luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); - luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); - lua_upvaluejoin(L, 1, n1, 3, n2); - return 0; +static int db_upvaluejoin(lua_State* L) +{ + int n1 = checkupval(L, 1, 2); + int n2 = checkupval(L, 3, 4); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; } @@ -302,155 +339,177 @@ static int db_upvaluejoin (lua_State *L) { ** Call hook function registered at hook table for the current ** thread (if there is one) */ -static void hookf (lua_State *L, lua_Debug *ar) { - static const char *const hooknames[] = - {"call", "return", "line", "count", "tail call"}; - lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); - lua_pushthread(L); - if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ - lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ - if (ar->currentline >= 0) - lua_pushinteger(L, ar->currentline); /* push current line */ - else lua_pushnil(L); - lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); /* call hook function */ - } +static void hookf(lua_State* L, lua_Debug* ar) +{ + static const char* const hooknames[] = + {"call", "return", "line", "count", "tail call"}; + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + lua_pushthread(L); + if (lua_rawget(L, -2) == LUA_TFUNCTION) + { + /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); /* push current line */ + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); /* call hook function */ + } } /* ** Convert a string mask (for 'sethook') into a bit mask */ -static int makemask (const char *smask, int count) { - int mask = 0; - if (strchr(smask, 'c')) mask |= LUA_MASKCALL; - if (strchr(smask, 'r')) mask |= LUA_MASKRET; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - return mask; +static int makemask(const char* smask, int count) +{ + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; } /* ** Convert a bit mask (for 'gethook') into a string mask */ -static char *unmakemask (int mask, char *smask) { - int i = 0; - if (mask & LUA_MASKCALL) smask[i++] = 'c'; - if (mask & LUA_MASKRET) smask[i++] = 'r'; - if (mask & LUA_MASKLINE) smask[i++] = 'l'; - smask[i] = '\0'; - return smask; +static char* unmakemask(int mask, char* smask) +{ + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; } -static int db_sethook (lua_State *L) { - int arg, mask, count; - lua_Hook func; - lua_State *L1 = getthread(L, &arg); - if (lua_isnoneornil(L, arg+1)) { /* no hook? */ - lua_settop(L, arg+1); - func = NULL; mask = 0; count = 0; /* turn off hooks */ - } - else { - const char *smask = luaL_checkstring(L, arg+2); - luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = (int)luaL_optinteger(L, arg + 3, 0); - func = hookf; mask = makemask(smask, count); - } - if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { - lua_createtable(L, 0, 2); /* create a hook table */ - lua_pushvalue(L, -1); - lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ - lua_pushstring(L, "k"); - lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ - lua_pushvalue(L, -1); - lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ - } - checkstack(L, L1, 1); - lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ - lua_pushvalue(L, arg + 1); /* value (hook function) */ - lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ - lua_sethook(L1, func, mask, count); - return 0; +static int db_sethook(lua_State* L) +{ + int arg, mask, count; + lua_Hook func; + lua_State* L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) + { + /* no hook? */ + lua_settop(L, arg + 1); + func = NULL; + mask = 0; + count = 0; /* turn off hooks */ + } + else + { + const char* smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg + 1, LUA_TFUNCTION); + count = (int)luaL_optinteger(L, arg + 3, 0); + func = hookf; + mask = makemask(smask, count); + } + if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) + { + lua_createtable(L, 0, 2); /* create a hook table */ + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + } + checkstack(L, L1, 1); + lua_pushthread(L1); + lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); + return 0; } -static int db_gethook (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - char buff[5]; - int mask = lua_gethookmask(L1); - lua_Hook hook = lua_gethook(L1); - if (hook == NULL) /* no hook? */ - lua_pushnil(L); - else if (hook != hookf) /* external hook? */ - lua_pushliteral(L, "external hook"); - else { /* hook table must exist */ - lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); - checkstack(L, L1, 1); - lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_rawget(L, -2); /* 1st result = hooktable[L1] */ - lua_remove(L, -2); /* remove hook table */ - } - lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ - lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ - return 3; +static int db_gethook(lua_State* L) +{ + int arg; + lua_State* L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook == NULL) /* no hook? */ + lua_pushnil(L); + else if (hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else + { + /* hook table must exist */ + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + checkstack(L, L1, 1); + lua_pushthread(L1); + lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ + return 3; } -static int db_debug (lua_State *L) { - for (;;) { - char buffer[250]; - lua_writestringerror("%s", "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || - strcmp(buffer, "cont\n") == 0) - return 0; - if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || - lua_pcall(L, 0, 0, 0)) - lua_writestringerror("%s\n", lua_tostring(L, -1)); - lua_settop(L, 0); /* remove eventual returns */ - } +static int db_debug(lua_State* L) +{ + for (;;) + { + char buffer[250]; + lua_writestringerror("%s", "lua_debug> "); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) + lua_writestringerror("%s\n", lua_tostring(L, -1)); + lua_settop(L, 0); /* remove eventual returns */ + } } -static int db_traceback (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - const char *msg = lua_tostring(L, arg + 1); - if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ - lua_pushvalue(L, arg + 1); /* return it untouched */ - else { - int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); - luaL_traceback(L, L1, msg, level); - } - return 1; +static int db_traceback(lua_State* L) +{ + int arg; + lua_State* L1 = getthread(L, &arg); + const char* msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else + { + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); + } + return 1; } static const luaL_Reg dblib[] = { - {"debug", db_debug}, - {"getuservalue", db_getuservalue}, - {"gethook", db_gethook}, - {"getinfo", db_getinfo}, - {"getlocal", db_getlocal}, - {"getregistry", db_getregistry}, - {"getmetatable", db_getmetatable}, - {"getupvalue", db_getupvalue}, - {"upvaluejoin", db_upvaluejoin}, - {"upvalueid", db_upvalueid}, - {"setuservalue", db_setuservalue}, - {"sethook", db_sethook}, - {"setlocal", db_setlocal}, - {"setmetatable", db_setmetatable}, - {"setupvalue", db_setupvalue}, - {"traceback", db_traceback}, - {NULL, NULL} + {"debug", db_debug}, + {"getuservalue", db_getuservalue}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_traceback}, + {NULL, NULL} }; -LUAMOD_API int luaopen_debug (lua_State *L) { - luaL_newlib(L, dblib); - return 1; +LUAMOD_API int luaopen_debug(lua_State* L) +{ + luaL_newlib(L, dblib); + return 1; } - diff --git a/Lua/ldebug.c b/Lua/ldebug.c index 239affb..90a17a7 100644 --- a/Lua/ldebug.c +++ b/Lua/ldebug.c @@ -30,7 +30,6 @@ #include "lvm.h" - #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) @@ -38,18 +37,20 @@ #define ci_func(ci) (clLvalue((ci)->func)) -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, - const char **name); +static const char* funcnamefromcode(lua_State* L, CallInfo* ci, + const char** name); -static int currentpc (CallInfo *ci) { - lua_assert(isLua(ci)); - return pcRel(ci->u.l.savedpc, ci_func(ci)->p); +static int currentpc(CallInfo* ci) +{ + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); } -static int currentline (CallInfo *ci) { - return getfuncline(ci_func(ci)->p, currentpc(ci)); +static int currentline(CallInfo* ci) +{ + return getfuncline(ci_func(ci)->p, currentpc(ci)); } @@ -59,13 +60,15 @@ static int currentline (CallInfo *ci) { ** purposes. (It exchanges 'func' and 'extra'; so, when called again, ** after debugging, it also "re-restores" ** 'func' to its altered value. */ -static void swapextra (lua_State *L) { - if (L->status == LUA_YIELD) { - CallInfo *ci = L->ci; /* get function that yielded */ - StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ - ci->func = restorestack(L, ci->extra); - ci->extra = savestack(L, temp); - } +static void swapextra(lua_State* L) +{ + if (L->status == LUA_YIELD) + { + CallInfo* ci = L->ci; /* get function that yielded */ + StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ + ci->func = restorestack(L, ci->extra); + ci->extra = savestack(L, temp); + } } @@ -78,264 +81,313 @@ static void swapextra (lua_State *L) { ** ensures that for all platforms where it runs). Moreover, 'hook' is ** always checked before being called (see 'luaD_hook'). */ -LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { - if (func == NULL || mask == 0) { /* turn off hooks? */ - mask = 0; - func = NULL; - } - if (isLua(L->ci)) - L->oldpc = L->ci->u.l.savedpc; - L->hook = func; - L->basehookcount = count; - resethookcount(L); - L->hookmask = cast_byte(mask); +LUA_API void lua_sethook(lua_State* L, lua_Hook func, int mask, int count) +{ + if (func == NULL || mask == 0) + { + /* turn off hooks? */ + mask = 0; + func = NULL; + } + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); } -LUA_API lua_Hook lua_gethook (lua_State *L) { - return L->hook; +LUA_API lua_Hook lua_gethook(lua_State* L) +{ + return L->hook; } -LUA_API int lua_gethookmask (lua_State *L) { - return L->hookmask; +LUA_API int lua_gethookmask(lua_State* L) +{ + return L->hookmask; } -LUA_API int lua_gethookcount (lua_State *L) { - return L->basehookcount; +LUA_API int lua_gethookcount(lua_State* L) +{ + return L->basehookcount; } -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { - int status; - CallInfo *ci; - if (level < 0) return 0; /* invalid (negative) level */ - lua_lock(L); - for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) - level--; - if (level == 0 && ci != &L->base_ci) { /* level found? */ - status = 1; - ar->i_ci = ci; - } - else status = 0; /* no such level */ - lua_unlock(L); - return status; +LUA_API int lua_getstack(lua_State* L, int level, lua_Debug* ar) +{ + int status; + CallInfo* ci; + if (level < 0) return 0; /* invalid (negative) level */ + lua_lock(L); + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) + level--; + if (level == 0 && ci != &L->base_ci) + { + /* level found? */ + status = 1; + ar->i_ci = ci; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; } -static const char *upvalname (Proto *p, int uv) { - TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); - if (s == NULL) return "?"; - else return getstr(s); +static const char* upvalname(Proto* p, int uv) +{ + TString* s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + if (s == NULL) return "?"; + else return getstr(s); } -static const char *findvararg (CallInfo *ci, int n, StkId *pos) { - int nparams = clLvalue(ci->func)->p->numparams; - if (n >= cast_int(ci->u.l.base - ci->func) - nparams) - return NULL; /* no such vararg */ - else { - *pos = ci->func + nparams + n; - return "(*vararg)"; /* generic name for any vararg */ - } +static const char* findvararg(CallInfo* ci, int n, StkId* pos) +{ + int nparams = clLvalue(ci->func)->p->numparams; + if (n >= cast_int(ci->u.l.base - ci->func) - nparams) + return NULL; /* no such vararg */ + else + { + *pos = ci->func + nparams + n; + return "(*vararg)"; /* generic name for any vararg */ + } } -static const char *findlocal (lua_State *L, CallInfo *ci, int n, - StkId *pos) { - const char *name = NULL; - StkId base; - if (isLua(ci)) { - if (n < 0) /* access to vararg values? */ - return findvararg(ci, -n, pos); - else { - base = ci->u.l.base; - name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); - } - } - else - base = ci->func + 1; - if (name == NULL) { /* no 'standard' name? */ - StkId limit = (ci == L->ci) ? L->top : ci->next->func; - if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ - name = "(*temporary)"; /* generic name for any valid slot */ - else - return NULL; /* no name */ - } - *pos = base + (n - 1); - return name; +static const char* findlocal(lua_State* L, CallInfo* ci, int n, + StkId* pos) +{ + const char* name = NULL; + StkId base; + if (isLua(ci)) + { + if (n < 0) /* access to vararg values? */ + return findvararg(ci, -n, pos); + else + { + base = ci->u.l.base; + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + } + } + else + base = ci->func + 1; + if (name == NULL) + { + /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top : ci->next->func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + name = "(*temporary)"; /* generic name for any valid slot */ + else + return NULL; /* no name */ + } + *pos = base + (n - 1); + return name; } -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { - const char *name; - lua_lock(L); - swapextra(L); - if (ar == NULL) { /* information about non-active function? */ - if (!isLfunction(L->top - 1)) /* not a Lua function? */ - name = NULL; - else /* consider live variables at function start (parameters) */ - name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); - } - else { /* active function; get information through 'ar' */ - StkId pos = NULL; /* to avoid warnings */ - name = findlocal(L, ar->i_ci, n, &pos); - if (name) { - setobj2s(L, L->top, pos); - api_incr_top(L); - } - } - swapextra(L); - lua_unlock(L); - return name; +LUA_API const char* lua_getlocal(lua_State* L, const lua_Debug* ar, int n) +{ + const char* name; + lua_lock(L); + swapextra(L); + if (ar == NULL) + { + /* information about non-active function? */ + if (!isLfunction(L->top - 1)) /* not a Lua function? */ + name = NULL; + else /* consider live variables at function start (parameters) */ + name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); + } + else + { + /* active function; get information through 'ar' */ + StkId pos = NULL; /* to avoid warnings */ + name = findlocal(L, ar->i_ci, n, &pos); + if (name) + { + setobj2s(L, L->top, pos); + api_incr_top(L); + } + } + swapextra(L); + lua_unlock(L); + return name; } -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos = NULL; /* to avoid warnings */ - const char *name; - lua_lock(L); - swapextra(L); - name = findlocal(L, ar->i_ci, n, &pos); - if (name) { - setobjs2s(L, pos, L->top - 1); - L->top--; /* pop value */ - } - swapextra(L); - lua_unlock(L); - return name; +LUA_API const char* lua_setlocal(lua_State* L, const lua_Debug* ar, int n) +{ + StkId pos = NULL; /* to avoid warnings */ + const char* name; + lua_lock(L); + swapextra(L); + name = findlocal(L, ar->i_ci, n, &pos); + if (name) + { + setobjs2s(L, pos, L->top - 1); + L->top--; /* pop value */ + } + swapextra(L); + lua_unlock(L); + return name; } -static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { - ar->source = "=[C]"; - ar->linedefined = -1; - ar->lastlinedefined = -1; - ar->what = "C"; - } - else { - Proto *p = cl->l.p; - ar->source = p->source ? getstr(p->source) : "=?"; - ar->linedefined = p->linedefined; - ar->lastlinedefined = p->lastlinedefined; - ar->what = (ar->linedefined == 0) ? "main" : "Lua"; - } - luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); +static void funcinfo(lua_Debug* ar, Closure* cl) +{ + if (noLuaClosure(cl)) + { + ar->source = "=[C]"; + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else + { + Proto* p = cl->l.p; + ar->source = p->source ? getstr(p->source) : "=?"; + ar->linedefined = p->linedefined; + ar->lastlinedefined = p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } -static void collectvalidlines (lua_State *L, Closure *f) { - if (noLuaClosure(f)) { - setnilvalue(L->top); - api_incr_top(L); - } - else { - int i; - TValue v; - int *lineinfo = f->l.p->lineinfo; - Table *t = luaH_new(L); /* new table to store active lines */ - sethvalue(L, L->top, t); /* push it on stack */ - api_incr_top(L); - setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ - for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ - luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ - } +static void collectvalidlines(lua_State* L, Closure* f) +{ + if (noLuaClosure(f)) + { + setnilvalue(L->top); + api_incr_top(L); + } + else + { + int i; + TValue v; + int* lineinfo = f->l.p->lineinfo; + Table* t = luaH_new(L); /* new table to store active lines */ + sethvalue(L, L->top, t); /* push it on stack */ + api_incr_top(L); + setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ + for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ + luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ + } } -static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { - if (ci == NULL) /* no 'ci'? */ - return NULL; /* no info */ - else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ - *name = "__gc"; - return "metamethod"; /* report it as such */ - } - /* calling function is a known Lua function? */ - else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) - return funcnamefromcode(L, ci->previous, name); - else return NULL; /* no way to find a name */ +static const char* getfuncname(lua_State* L, CallInfo* ci, const char** name) +{ + if (ci == NULL) /* no 'ci'? */ + return NULL; /* no info */ + else if (ci->callstatus & CIST_FIN) + { + /* is this a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + /* calling function is a known Lua function? */ + else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) + return funcnamefromcode(L, ci->previous, name); + else return NULL; /* no way to find a name */ } -static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - Closure *f, CallInfo *ci) { - int status = 1; - for (; *what; what++) { - switch (*what) { - case 'S': { - funcinfo(ar, f); - break; - } - case 'l': { - ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; - break; - } - case 'u': { - ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { - ar->isvararg = 1; - ar->nparams = 0; - } - else { - ar->isvararg = f->l.p->is_vararg; - ar->nparams = f->l.p->numparams; - } - break; - } - case 't': { - ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; - break; - } - case 'n': { - ar->namewhat = getfuncname(L, ci, &ar->name); - if (ar->namewhat == NULL) { - ar->namewhat = ""; /* not found */ - ar->name = NULL; - } - break; - } - case 'L': - case 'f': /* handled by lua_getinfo */ - break; - default: status = 0; /* invalid option */ - } - } - return status; +static int auxgetinfo(lua_State* L, const char* what, lua_Debug* ar, + Closure* f, CallInfo* ci) +{ + int status = 1; + for (; *what; what++) + { + switch (*what) + { + case 'S': + { + funcinfo(ar, f); + break; + } + case 'l': + { + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; + break; + } + case 'u': + { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) + { + ar->isvararg = 1; + ar->nparams = 0; + } + else + { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': + { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; + break; + } + case 'n': + { + ar->namewhat = getfuncname(L, ci, &ar->name); + if (ar->namewhat == NULL) + { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; } -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - int status; - Closure *cl; - CallInfo *ci; - StkId func; - lua_lock(L); - swapextra(L); - if (*what == '>') { - ci = NULL; - func = L->top - 1; - api_check(L, ttisfunction(func), "function expected"); - what++; /* skip the '>' */ - L->top--; /* pop function */ - } - else { - ci = ar->i_ci; - func = ci->func; - lua_assert(ttisfunction(ci->func)); - } - cl = ttisclosure(func) ? clvalue(func) : NULL; - status = auxgetinfo(L, what, ar, cl, ci); - if (strchr(what, 'f')) { - setobjs2s(L, L->top, func); - api_incr_top(L); - } - swapextra(L); /* correct before option 'L', which can raise a mem. error */ - if (strchr(what, 'L')) - collectvalidlines(L, cl); - lua_unlock(L); - return status; +LUA_API int lua_getinfo(lua_State* L, const char* what, lua_Debug* ar) +{ + int status; + Closure* cl; + CallInfo* ci; + StkId func; + lua_lock(L); + swapextra(L); + if (*what == '>') + { + ci = NULL; + func = L->top - 1; + api_check(L, ttisfunction(func), "function expected"); + what++; /* skip the '>' */ + L->top--; /* pop function */ + } + else + { + ci = ar->i_ci; + func = ci->func; + lua_assert(ttisfunction(ci->func)); + } + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); + if (strchr(what, 'f')) + { + setobjs2s(L, L->top, func); + api_incr_top(L); + } + swapextra(L); /* correct before option 'L', which can raise a mem. error */ + if (strchr(what, 'L')) + collectvalidlines(L, cl); + lua_unlock(L); + return status; } @@ -345,140 +397,169 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { ** ======================================================= */ -static const char *getobjname (Proto *p, int lastpc, int reg, - const char **name); +static const char* getobjname(Proto* p, int lastpc, int reg, + const char** name); /* ** find a "name" for the RK value 'c' */ -static void kname (Proto *p, int pc, int c, const char **name) { - if (ISK(c)) { /* is 'c' a constant? */ - TValue *kvalue = &p->k[INDEXK(c)]; - if (ttisstring(kvalue)) { /* literal constant? */ - *name = svalue(kvalue); /* it is its own name */ - return; - } - /* else no reasonable name found */ - } - else { /* 'c' is a register */ - const char *what = getobjname(p, pc, c, name); /* search for 'c' */ - if (what && *what == 'c') { /* found a constant name? */ - return; /* 'name' already filled */ - } - /* else no reasonable name found */ - } - *name = "?"; /* no reasonable name found */ +static void kname(Proto* p, int pc, int c, const char** name) +{ + if (ISK(c)) + { + /* is 'c' a constant? */ + TValue* kvalue = &p->k[INDEXK(c)]; + if (ttisstring(kvalue)) + { + /* literal constant? */ + *name = svalue(kvalue); /* it is its own name */ + return; + } + /* else no reasonable name found */ + } + else + { + /* 'c' is a register */ + const char* what = getobjname(p, pc, c, name); /* search for 'c' */ + if (what && *what == 'c') + { + /* found a constant name? */ + return; /* 'name' already filled */ + } + /* else no reasonable name found */ + } + *name = "?"; /* no reasonable name found */ } -static int filterpc (int pc, int jmptarget) { - if (pc < jmptarget) /* is code conditional (inside a jump)? */ - return -1; /* cannot know who sets that register */ - else return pc; /* current position sets that register */ +static int filterpc(int pc, int jmptarget) +{ + if (pc < jmptarget) /* is code conditional (inside a jump)? */ + return -1; /* cannot know who sets that register */ + else return pc; /* current position sets that register */ } /* ** try to find last instruction before 'lastpc' that modified register 'reg' */ -static int findsetreg (Proto *p, int lastpc, int reg) { - int pc; - int setreg = -1; /* keep last instruction that changed 'reg' */ - int jmptarget = 0; /* any code before this address is conditional */ - for (pc = 0; pc < lastpc; pc++) { - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); - int a = GETARG_A(i); - switch (op) { - case OP_LOADNIL: { - int b = GETARG_B(i); - if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_TFORCALL: { - if (reg >= a + 2) /* affect all regs above its base */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_CALL: - case OP_TAILCALL: { - if (reg >= a) /* affect all registers above base */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_JMP: { - int b = GETARG_sBx(i); - int dest = pc + 1 + b; - /* jump is forward and do not skip 'lastpc'? */ - if (pc < dest && dest <= lastpc) { - if (dest > jmptarget) - jmptarget = dest; /* update 'jmptarget' */ - } - break; - } - default: - if (testAMode(op) && reg == a) /* any instruction that set A */ - setreg = filterpc(pc, jmptarget); - break; - } - } - return setreg; +static int findsetreg(Proto* p, int lastpc, int reg) +{ + int pc; + int setreg = -1; /* keep last instruction that changed 'reg' */ + int jmptarget = 0; /* any code before this address is conditional */ + for (pc = 0; pc < lastpc; pc++) + { + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + switch (op) + { + case OP_LOADNIL: + { + int b = GETARG_B(i); + if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_TFORCALL: + { + if (reg >= a + 2) /* affect all regs above its base */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_CALL: + case OP_TAILCALL: + { + if (reg >= a) /* affect all registers above base */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_JMP: + { + int b = GETARG_sBx(i); + int dest = pc + 1 + b; + /* jump is forward and do not skip 'lastpc'? */ + if (pc < dest && dest <= lastpc) + { + if (dest > jmptarget) + jmptarget = dest; /* update 'jmptarget' */ + } + break; + } + default: + if (testAMode(op) && reg == a) /* any instruction that set A */ + setreg = filterpc(pc, jmptarget); + break; + } + } + return setreg; } -static const char *getobjname (Proto *p, int lastpc, int reg, - const char **name) { - int pc; - *name = luaF_getlocalname(p, reg + 1, lastpc); - if (*name) /* is a local? */ - return "local"; - /* else try symbolic execution */ - pc = findsetreg(p, lastpc, reg); - if (pc != -1) { /* could find instruction? */ - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); - switch (op) { - case OP_MOVE: { - int b = GETARG_B(i); /* move from 'b' to 'a' */ - if (b < GETARG_A(i)) - return getobjname(p, pc, b, name); /* get name for 'b' */ - break; - } - case OP_GETTABUP: - case OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - int t = GETARG_B(i); /* table index */ - const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ - ? luaF_getlocalname(p, t + 1, pc) - : upvalname(p, t); - kname(p, pc, k, name); - return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; - } - case OP_GETUPVAL: { - *name = upvalname(p, GETARG_B(i)); - return "upvalue"; - } - case OP_LOADK: - case OP_LOADKX: { - int b = (op == OP_LOADK) ? GETARG_Bx(i) - : GETARG_Ax(p->code[pc + 1]); - if (ttisstring(&p->k[b])) { - *name = svalue(&p->k[b]); - return "constant"; - } - break; - } - case OP_SELF: { - int k = GETARG_C(i); /* key index */ - kname(p, pc, k, name); - return "method"; - } - default: break; /* go through to return NULL */ - } - } - return NULL; /* could not find reasonable name */ +static const char* getobjname(Proto* p, int lastpc, int reg, + const char** name) +{ + int pc; + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ + pc = findsetreg(p, lastpc, reg); + if (pc != -1) + { + /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + switch (op) + { + case OP_MOVE: + { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) + return getobjname(p, pc, b, name); /* get name for 'b' */ + break; + } + case OP_GETTABUP: + case OP_GETTABLE: + { + int k = GETARG_C(i); /* key index */ + int t = GETARG_B(i); /* table index */ + const char* vn = (op == OP_GETTABLE) /* name of indexed variable */ + ? luaF_getlocalname(p, t + 1, pc) + : upvalname(p, t); + kname(p, pc, k, name); + return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; + } + case OP_GETUPVAL: + { + *name = upvalname(p, GETARG_B(i)); + return "upvalue"; + } + case OP_LOADK: + case OP_LOADKX: + { + int b = (op == OP_LOADK) + ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) + { + *name = svalue(&p->k[b]); + return "constant"; + } + break; + } + case OP_SELF: + { + int k = GETARG_C(i); /* key index */ + kname(p, pc, k, name); + return "method"; + } + default: break; /* go through to return NULL */ + } + } + return NULL; /* could not find reasonable name */ } @@ -488,64 +569,90 @@ static const char *getobjname (Proto *p, int lastpc, int reg, ** Returns what the name is (e.g., "for iterator", "method", ** "metamethod") and sets '*name' to point to the name. */ -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, - const char **name) { - TMS tm = (TMS)0; /* (initial value avoids warnings) */ - Proto *p = ci_func(ci)->p; /* calling function */ - int pc = currentpc(ci); /* calling instruction index */ - Instruction i = p->code[pc]; /* calling instruction */ - if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ - *name = "?"; - return "hook"; - } - switch (GET_OPCODE(i)) { - case OP_CALL: - case OP_TAILCALL: - return getobjname(p, pc, GETARG_A(i), name); /* get function name */ - case OP_TFORCALL: { /* for iterator */ - *name = "for iterator"; - return "for iterator"; - } - /* other instructions can do calls through metamethods */ - case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: - tm = TM_INDEX; - break; - case OP_SETTABUP: case OP_SETTABLE: - tm = TM_NEWINDEX; - break; - case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: - case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: - case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { - int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ - tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ - break; - } - case OP_UNM: tm = TM_UNM; break; - case OP_BNOT: tm = TM_BNOT; break; - case OP_LEN: tm = TM_LEN; break; - case OP_CONCAT: tm = TM_CONCAT; break; - case OP_EQ: tm = TM_EQ; break; - case OP_LT: tm = TM_LT; break; - case OP_LE: tm = TM_LE; break; - default: - return NULL; /* cannot find a reasonable name */ - } - *name = getstr(G(L)->tmname[tm]); - return "metamethod"; +static const char* funcnamefromcode(lua_State* L, CallInfo* ci, + const char** name) +{ + TMS tm = (TMS)0; /* (initial value avoids warnings) */ + Proto* p = ci_func(ci)->p; /* calling function */ + int pc = currentpc(ci); /* calling instruction index */ + Instruction i = p->code[pc]; /* calling instruction */ + if (ci->callstatus & CIST_HOOKED) + { + /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + switch (GET_OPCODE(i)) + { + case OP_CALL: + case OP_TAILCALL: + return getobjname(p, pc, GETARG_A(i), name); /* get function name */ + case OP_TFORCALL: + { + /* for iterator */ + *name = "for iterator"; + return "for iterator"; + } + /* other instructions can do calls through metamethods */ + case OP_SELF: + case OP_GETTABUP: + case OP_GETTABLE: + tm = TM_INDEX; + break; + case OP_SETTABUP: + case OP_SETTABLE: + tm = TM_NEWINDEX; + break; + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_MOD: + case OP_POW: + case OP_DIV: + case OP_IDIV: + case OP_BAND: + case OP_BOR: + case OP_BXOR: + case OP_SHL: + case OP_SHR: + { + int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ + tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ + break; + } + case OP_UNM: tm = TM_UNM; + break; + case OP_BNOT: tm = TM_BNOT; + break; + case OP_LEN: tm = TM_LEN; + break; + case OP_CONCAT: tm = TM_CONCAT; + break; + case OP_EQ: tm = TM_EQ; + break; + case OP_LT: tm = TM_LT; + break; + case OP_LE: tm = TM_LE; + break; + default: + return NULL; /* cannot find a reasonable name */ + } + *name = getstr(G(L)->tmname[tm]); + return "metamethod"; } /* }====================================================== */ - /* ** The subtraction of two potentially unrelated pointers is ** not ISO C, but it should not crash a program; the subsequent ** checks are ISO C and ensure a correct result. */ -static int isinstack (CallInfo *ci, const TValue *o) { - ptrdiff_t i = o - ci->u.l.base; - return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); +static int isinstack(CallInfo* ci, const TValue* o) +{ + ptrdiff_t i = o - ci->u.l.base; + return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); } @@ -554,145 +661,168 @@ static int isinstack (CallInfo *ci, const TValue *o) { ** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on ** upvalues.) */ -static const char *getupvalname (CallInfo *ci, const TValue *o, - const char **name) { - LClosure *c = ci_func(ci); - int i; - for (i = 0; i < c->nupvalues; i++) { - if (c->upvals[i]->v == o) { - *name = upvalname(c->p, i); - return "upvalue"; - } - } - return NULL; +static const char* getupvalname(CallInfo* ci, const TValue* o, + const char** name) +{ + LClosure* c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) + { + if (c->upvals[i]->v == o) + { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; } -static const char *varinfo (lua_State *L, const TValue *o) { - const char *name = NULL; /* to avoid warnings */ - CallInfo *ci = L->ci; - const char *kind = NULL; - if (isLua(ci)) { - kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ - if (!kind && isinstack(ci, o)) /* no? try a register */ - kind = getobjname(ci_func(ci)->p, currentpc(ci), - cast_int(o - ci->u.l.base), &name); - } - return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; +static const char* varinfo(lua_State* L, const TValue* o) +{ + const char* name = NULL; /* to avoid warnings */ + CallInfo* ci = L->ci; + const char* kind = NULL; + if (isLua(ci)) + { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind && isinstack(ci, o)) /* no? try a register */ + kind = getobjname(ci_func(ci)->p, currentpc(ci), + cast_int(o - ci->u.l.base), &name); + } + return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; } -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { - const char *t = luaT_objtypename(L, o); - luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); +l_noret luaG_typeerror(lua_State* L, const TValue* o, const char* op) +{ + const char* t = luaT_objtypename(L, o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); } -l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { - if (ttisstring(p1) || cvt2str(p1)) p1 = p2; - luaG_typeerror(L, p1, "concatenate"); +l_noret luaG_concaterror(lua_State* L, const TValue* p1, const TValue* p2) +{ + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; + luaG_typeerror(L, p1, "concatenate"); } -l_noret luaG_opinterror (lua_State *L, const TValue *p1, - const TValue *p2, const char *msg) { - lua_Number temp; - if (!tonumber(p1, &temp)) /* first operand is wrong? */ - p2 = p1; /* now second is wrong */ - luaG_typeerror(L, p2, msg); +l_noret luaG_opinterror(lua_State* L, const TValue* p1, + const TValue* p2, const char* msg) +{ + lua_Number temp; + if (!tonumber(p1, &temp)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); } /* ** Error when both values are convertible to numbers, but not to integers */ -l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { - lua_Integer temp; - if (!tointeger(p1, &temp)) - p2 = p1; - luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); +l_noret luaG_tointerror(lua_State* L, const TValue* p1, const TValue* p2) +{ + lua_Integer temp; + if (!tointeger(p1, &temp)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); } -l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = luaT_objtypename(L, p1); - const char *t2 = luaT_objtypename(L, p2); - if (strcmp(t1, t2) == 0) - luaG_runerror(L, "attempt to compare two %s values", t1); - else - luaG_runerror(L, "attempt to compare %s with %s", t1, t2); +l_noret luaG_ordererror(lua_State* L, const TValue* p1, const TValue* p2) +{ + const char* t1 = luaT_objtypename(L, p1); + const char* t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); } /* add src:line information to 'msg' */ -const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, - int line) { - char buff[LUA_IDSIZE]; - if (src) - luaO_chunkid(buff, getstr(src), LUA_IDSIZE); - else { /* no source available; use "?" instead */ - buff[0] = '?'; buff[1] = '\0'; - } - return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +const char* luaG_addinfo(lua_State* L, const char* msg, TString* src, + int line) +{ + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), LUA_IDSIZE); + else + { + /* no source available; use "?" instead */ + buff[0] = '?'; + buff[1] = '\0'; + } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } -l_noret luaG_errormsg (lua_State *L) { - if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); - setobjs2s(L, L->top, L->top - 1); /* move argument */ - setobjs2s(L, L->top - 1, errfunc); /* push function */ - L->top++; /* assume EXTRA_STACK */ - luaD_callnoyield(L, L->top - 2, 1); /* call it */ - } - luaD_throw(L, LUA_ERRRUN); +l_noret luaG_errormsg(lua_State* L) +{ + if (L->errfunc != 0) + { + /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ + L->top++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); } -l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { - CallInfo *ci = L->ci; - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); /* format message */ - va_end(argp); - if (isLua(ci)) /* if Lua function, add source:line information */ - luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); - luaG_errormsg(L); +l_noret luaG_runerror(lua_State* L, const char* fmt, ...) +{ + CallInfo* ci = L->ci; + const char* msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ + va_end(argp); + if (isLua(ci)) /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); + luaG_errormsg(L); } -void luaG_traceexec (lua_State *L) { - CallInfo *ci = L->ci; - lu_byte mask = L->hookmask; - int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); - if (counthook) - resethookcount(L); /* reset count */ - else if (!(mask & LUA_MASKLINE)) - return; /* no line hook and count != 0; nothing to be done */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ - ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ - return; /* do not call hook again (VM yielded, so it did not move) */ - } - if (counthook) - luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ - if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->p; - int npc = pcRel(ci->u.l.savedpc, p); - int newline = getfuncline(p, npc); - if (npc == 0 || /* call linehook when enter a new function, */ - ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ - newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ - luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ - } - L->oldpc = ci->u.l.savedpc; - if (L->status == LUA_YIELD) { /* did hook yield? */ - if (counthook) - L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ - ci->func = L->top - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); - } +void luaG_traceexec(lua_State* L) +{ + CallInfo* ci = L->ci; + lu_byte mask = L->hookmask; + int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return; /* no line hook and count != 0; nothing to be done */ + if (ci->callstatus & CIST_HOOKYIELD) + { + /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ + } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) + { + Proto* p = ci_func(ci)->p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) + { + /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } } - diff --git a/Lua/ldebug.h b/Lua/ldebug.h index 0e31546..36ee35e 100644 --- a/Lua/ldebug.h +++ b/Lua/ldebug.h @@ -18,22 +18,22 @@ #define resethookcount(L) (L->hookcount = L->basehookcount) -LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, - const char *opname); -LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, - const TValue *p2, - const char *msg); -LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); -LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, - TString *src, int line); -LUAI_FUNC l_noret luaG_errormsg (lua_State *L); -LUAI_FUNC void luaG_traceexec (lua_State *L); +LUAI_FUNC l_noret luaG_typeerror(lua_State* L, const TValue* o, + const char* opname); +LUAI_FUNC l_noret luaG_concaterror(lua_State* L, const TValue* p1, + const TValue* p2); +LUAI_FUNC l_noret luaG_opinterror(lua_State* L, const TValue* p1, + const TValue* p2, + const char* msg); +LUAI_FUNC l_noret luaG_tointerror(lua_State* L, const TValue* p1, + const TValue* p2); +LUAI_FUNC l_noret luaG_ordererror(lua_State* L, const TValue* p1, + const TValue* p2); +LUAI_FUNC l_noret luaG_runerror(lua_State* L, const char* fmt, ...); +LUAI_FUNC const char* luaG_addinfo(lua_State* L, const char* msg, + TString* src, int line); +LUAI_FUNC l_noret luaG_errormsg(lua_State* L); +LUAI_FUNC void luaG_traceexec(lua_State* L); #endif diff --git a/Lua/ldo.c b/Lua/ldo.c index 90b695f..316e4ce 100644 --- a/Lua/ldo.c +++ b/Lua/ldo.c @@ -34,7 +34,6 @@ #include "lzio.h" - #define errorstatus(s) ((s) > LUA_YIELD) @@ -79,72 +78,90 @@ #endif /* } */ - /* chain list of long jump buffers */ -struct lua_longjmp { - struct lua_longjmp *previous; - luai_jmpbuf b; - volatile int status; /* error code */ +struct lua_longjmp +{ + struct lua_longjmp* previous; + luai_jmpbuf b; + volatile int status; /* error code */ }; -static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { - switch (errcode) { - case LUA_ERRMEM: { /* memory error? */ - setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ - break; - } - case LUA_ERRERR: { - setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); - break; - } - default: { - setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ - break; - } - } - L->top = oldtop + 1; +static void seterrorobj(lua_State* L, int errcode, StkId oldtop) +{ + switch (errcode) + { + case LUA_ERRMEM: + { + /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ + break; + } + case LUA_ERRERR: + { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + default: + { + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ + break; + } + } + L->top = oldtop + 1; } -l_noret luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { /* thread has an error handler? */ - L->errorJmp->status = errcode; /* set status */ - LUAI_THROW(L, L->errorJmp); /* jump to it */ - } - else { /* thread has no error handler */ - global_State *g = G(L); - L->status = cast_byte(errcode); /* mark it as dead */ - if (g->mainthread->errorJmp) { /* main thread has a handler? */ - setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ - luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ - } - else { /* no handler at all; abort */ - if (g->panic) { /* panic function? */ - seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ - if (L->ci->top < L->top) - L->ci->top = L->top; /* pushing msg. can break this invariant */ - lua_unlock(L); - g->panic(L); /* call panic function (last chance to jump out) */ - } - abort(); - } - } +l_noret luaD_throw(lua_State* L, int errcode) +{ + if (L->errorJmp) + { + /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ + } + else + { + /* thread has no error handler */ + global_State* g = G(L); + L->status = cast_byte(errcode); /* mark it as dead */ + if (g->mainthread->errorJmp) + { + /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ + } + else + { + /* no handler at all; abort */ + if (g->panic) + { + /* panic function? */ + seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ + if (L->ci->top < L->top) + L->ci->top = L->top; /* pushing msg. can break this invariant */ + lua_unlock(L); + g->panic(L); /* call panic function (last chance to jump out) */ + } + abort(); + } + } } -int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - unsigned short oldnCcalls = L->nCcalls; - struct lua_longjmp lj; - lj.status = LUA_OK; - lj.previous = L->errorJmp; /* chain new error handler */ - L->errorJmp = &lj; - LUAI_TRY(L, &lj, - (*f)(L, ud); - ); - L->errorJmp = lj.previous; /* restore old error handler */ - L->nCcalls = oldnCcalls; - return lj.status; +int luaD_rawrunprotected(lua_State* L, Pfunc f, void* ud) +{ + unsigned short oldnCcalls = L->nCcalls; + struct lua_longjmp lj; + lj.status = LUA_OK; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + L->nCcalls = oldnCcalls; + return lj.status; } /* }====================================================== */ @@ -155,18 +172,20 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { ** Stack reallocation ** =================================================================== */ -static void correctstack (lua_State *L, TValue *oldstack) { - CallInfo *ci; - UpVal *up; - L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->u.open.next) - up->v = (up->v - oldstack) + L->stack; - for (ci = L->ci; ci != NULL; ci = ci->previous) { - ci->top = (ci->top - oldstack) + L->stack; - ci->func = (ci->func - oldstack) + L->stack; - if (isLua(ci)) - ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; - } +static void correctstack(lua_State* L, TValue* oldstack) +{ + CallInfo* ci; + UpVal* up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v = (up->v - oldstack) + L->stack; + for (ci = L->ci; ci != NULL; ci = ci->previous) + { + ci->top = (ci->top - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + if (isLua(ci)) + ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; + } } @@ -174,72 +193,81 @@ static void correctstack (lua_State *L, TValue *oldstack) { #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) -void luaD_reallocstack (lua_State *L, int newsize) { - TValue *oldstack = L->stack; - int lim = L->stacksize; - lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); - for (; lim < newsize; lim++) - setnilvalue(L->stack + lim); /* erase new segment */ - L->stacksize = newsize; - L->stack_last = L->stack + newsize - EXTRA_STACK; - correctstack(L, oldstack); +void luaD_reallocstack(lua_State* L, int newsize) +{ + TValue* oldstack = L->stack; + int lim = L->stacksize; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); + for (; lim < newsize; lim++) + setnilvalue(L->stack + lim); /* erase new segment */ + L->stacksize = newsize; + L->stack_last = L->stack + newsize - EXTRA_STACK; + correctstack(L, oldstack); } -void luaD_growstack (lua_State *L, int n) { - int size = L->stacksize; - if (size > LUAI_MAXSTACK) /* error after extra size? */ - luaD_throw(L, LUA_ERRERR); - else { - int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; - int newsize = 2 * size; - if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; - if (newsize < needed) newsize = needed; - if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ - luaD_reallocstack(L, ERRORSTACKSIZE); - luaG_runerror(L, "stack overflow"); - } - else - luaD_reallocstack(L, newsize); - } +void luaD_growstack(lua_State* L, int n) +{ + int size = L->stacksize; + if (size > LUAI_MAXSTACK) /* error after extra size? */ + luaD_throw(L, LUA_ERRERR); + else + { + int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; + int newsize = 2 * size; + if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > LUAI_MAXSTACK) + { + /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } } -static int stackinuse (lua_State *L) { - CallInfo *ci; - StkId lim = L->top; - for (ci = L->ci; ci != NULL; ci = ci->previous) { - if (lim < ci->top) lim = ci->top; - } - lua_assert(lim <= L->stack_last); - return cast_int(lim - L->stack) + 1; /* part of stack in use */ +static int stackinuse(lua_State* L) +{ + CallInfo* ci; + StkId lim = L->top; + for (ci = L->ci; ci != NULL; ci = ci->previous) + { + if (lim < ci->top) lim = ci->top; + } + lua_assert(lim <= L->stack_last); + return cast_int(lim - L->stack) + 1; /* part of stack in use */ } -void luaD_shrinkstack (lua_State *L) { - int inuse = stackinuse(L); - int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; - if (goodsize > LUAI_MAXSTACK) - goodsize = LUAI_MAXSTACK; /* respect stack limit */ - if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ - luaE_freeCI(L); /* free all CIs (list grew because of an error) */ - else - luaE_shrinkCI(L); /* shrink list */ - /* if thread is currently not handling a stack overflow and its - good size is smaller than current size, shrink its stack */ - if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && - goodsize < L->stacksize) - luaD_reallocstack(L, goodsize); - else /* don't change stack */ - condmovestack(L,{},{}); /* (change only for debugging) */ +void luaD_shrinkstack(lua_State* L) +{ + int inuse = stackinuse(L); + int goodsize = inuse + (inuse / 8) + 2 * EXTRA_STACK; + if (goodsize > LUAI_MAXSTACK) + goodsize = LUAI_MAXSTACK; /* respect stack limit */ + if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ + luaE_freeCI(L); /* free all CIs (list grew because of an error) */ + else + luaE_shrinkCI(L); /* shrink list */ + /* if thread is currently not handling a stack overflow and its + good size is smaller than current size, shrink its stack */ + if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && + goodsize < L->stacksize) + luaD_reallocstack(L, goodsize); + else /* don't change stack */ + condmovestack(L, {}, {}); /* (change only for debugging) */ } -void luaD_inctop (lua_State *L) { - luaD_checkstack(L, 1); - L->top++; +void luaD_inctop(lua_State* L) +{ + luaD_checkstack(L, 1); + L->top++; } /* }================================================================== */ @@ -250,60 +278,67 @@ void luaD_inctop (lua_State *L) { ** called. (Both 'L->hook' and 'L->hookmask', which triggers this ** function, can be changed asynchronously by signals.) */ -void luaD_hook (lua_State *L, int event, int line) { - lua_Hook hook = L->hook; - if (hook && L->allowhook) { /* make sure there is a hook */ - CallInfo *ci = L->ci; - ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, ci->top); - lua_Debug ar; - ar.event = event; - ar.currentline = line; - ar.i_ci = ci; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - L->allowhook = 0; /* cannot call hooks inside a hook */ - ci->callstatus |= CIST_HOOKED; - lua_unlock(L); - (*hook)(L, &ar); - lua_lock(L); - lua_assert(!L->allowhook); - L->allowhook = 1; - ci->top = restorestack(L, ci_top); - L->top = restorestack(L, top); - ci->callstatus &= ~CIST_HOOKED; - } +void luaD_hook(lua_State* L, int event, int line) +{ + lua_Hook hook = L->hook; + if (hook && L->allowhook) + { + /* make sure there is a hook */ + CallInfo* ci = L->ci; + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, ci->top); + lua_Debug ar; + ar.event = event; + ar.currentline = line; + ar.i_ci = ci; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= CIST_HOOKED; + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); + ci->callstatus &= ~CIST_HOOKED; + } } -static void callhook (lua_State *L, CallInfo *ci) { - int hook = LUA_HOOKCALL; - ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ - if (isLua(ci->previous) && - GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { - ci->callstatus |= CIST_TAIL; - hook = LUA_HOOKTAILCALL; - } - luaD_hook(L, hook, -1); - ci->u.l.savedpc--; /* correct 'pc' */ +static void callhook(lua_State* L, CallInfo* ci) +{ + int hook = LUA_HOOKCALL; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + if (isLua(ci->previous) && + GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) + { + ci->callstatus |= CIST_TAIL; + hook = LUA_HOOKTAILCALL; + } + luaD_hook(L, hook, -1); + ci->u.l.savedpc--; /* correct 'pc' */ } -static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { - int i; - int nfixargs = p->numparams; - StkId base, fixed; - /* move fixed parameters to final position */ - fixed = L->top - actual; /* first fixed argument */ - base = L->top; /* final position of first argument */ - for (i = 0; i < nfixargs && i < actual; i++) { - setobjs2s(L, L->top++, fixed + i); - setnilvalue(fixed + i); /* erase original copy (for GC) */ - } - for (; i < nfixargs; i++) - setnilvalue(L->top++); /* complete missing arguments */ - return base; +static StkId adjust_varargs(lua_State* L, Proto* p, int actual) +{ + int i; + int nfixargs = p->numparams; + StkId base, fixed; + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i = 0; i < nfixargs && i < actual; i++) + { + setobjs2s(L, L->top++, fixed + i); + setnilvalue(fixed + i); /* erase original copy (for GC) */ + } + for (; i < nfixargs; i++) + setnilvalue(L->top++); /* complete missing arguments */ + return base; } @@ -312,16 +347,17 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { ** it in stack below original 'func' so that 'luaD_precall' can call ** it. Raise an error if __call metafield is not a function. */ -static void tryfuncTM (lua_State *L, StkId func) { - const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); - StkId p; - if (!ttisfunction(tm)) - luaG_typeerror(L, func, "call"); - /* Open a hole inside the stack at 'func' */ - for (p = L->top; p > func; p--) - setobjs2s(L, p, p-1); - L->top++; /* slot ensured by caller */ - setobj2s(L, func, tm); /* tag method is the new function to be called */ +static void tryfuncTM(lua_State* L, StkId func) +{ + const TValue* tm = luaT_gettmbyobj(L, func, TM_CALL); + StkId p; + if (!ttisfunction(tm)) + luaG_typeerror(L, func, "call"); + /* Open a hole inside the stack at 'func' */ + for (p = L->top; p > func; p--) + setobjs2s(L, p, p-1); + L->top++; /* slot ensured by caller */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ } @@ -331,40 +367,51 @@ static void tryfuncTM (lua_State *L, StkId func) { ** expressions, multiple results for tail calls/single parameters) ** separated. */ -static int moveresults (lua_State *L, const TValue *firstResult, StkId res, - int nres, int wanted) { - switch (wanted) { /* handle typical cases separately */ - case 0: break; /* nothing to move */ - case 1: { /* one result needed */ - if (nres == 0) /* no results? */ - firstResult = luaO_nilobject; /* adjust with nil */ - setobjs2s(L, res, firstResult); /* move it to proper place */ - break; - } - case LUA_MULTRET: { - int i; - for (i = 0; i < nres; i++) /* move all results to correct place */ - setobjs2s(L, res + i, firstResult + i); - L->top = res + nres; - return 0; /* wanted == LUA_MULTRET */ - } - default: { - int i; - if (wanted <= nres) { /* enough results? */ - for (i = 0; i < wanted; i++) /* move wanted results to correct place */ - setobjs2s(L, res + i, firstResult + i); - } - else { /* not enough results; use all of them plus nils */ - for (i = 0; i < nres; i++) /* move all results to correct place */ - setobjs2s(L, res + i, firstResult + i); - for (; i < wanted; i++) /* complete wanted number of results */ - setnilvalue(res + i); - } - break; - } - } - L->top = res + wanted; /* top points after the last result */ - return 1; +static int moveresults(lua_State* L, const TValue* firstResult, StkId res, + int nres, int wanted) +{ + switch (wanted) + { + /* handle typical cases separately */ + case 0: break; /* nothing to move */ + case 1: + { + /* one result needed */ + if (nres == 0) /* no results? */ + firstResult = luaO_nilobject; /* adjust with nil */ + setobjs2s(L, res, firstResult); /* move it to proper place */ + break; + } + case LUA_MULTRET: + { + int i; + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + L->top = res + nres; + return 0; /* wanted == LUA_MULTRET */ + } + default: + { + int i; + if (wanted <= nres) + { + /* enough results? */ + for (i = 0; i < wanted; i++) /* move wanted results to correct place */ + setobjs2s(L, res + i, firstResult + i); + } + else + { + /* not enough results; use all of them plus nils */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(res + i); + } + break; + } + } + L->top = res + wanted; /* top points after the last result */ + return 1; } @@ -373,25 +420,27 @@ static int moveresults (lua_State *L, const TValue *firstResult, StkId res, ** moves current number of results to proper place; returns 0 iff call ** wanted multiple (variable number of) results. */ -int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { - StkId res; - int wanted = ci->nresults; - if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { - if (L->hookmask & LUA_MASKRET) { - ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ - luaD_hook(L, LUA_HOOKRET, -1); - firstResult = restorestack(L, fr); - } - L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ - } - res = ci->func; /* res == final position of 1st result */ - L->ci = ci->previous; /* back to caller */ - /* move results to proper place */ - return moveresults(L, firstResult, res, nres, wanted); +int luaD_poscall(lua_State* L, CallInfo* ci, StkId firstResult, int nres) +{ + StkId res; + int wanted = ci->nresults; + if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) + { + if (L->hookmask & LUA_MASKRET) + { + ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + luaD_hook(L, LUA_HOOKRET, -1); + firstResult = restorestack(L, fr); + } + L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ + } + res = ci->func; /* res == final position of 1st result */ + L->ci = ci->previous; /* back to caller */ + /* move results to proper place */ + return moveresults(L, firstResult, res, nres, wanted); } - #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) @@ -410,64 +459,73 @@ int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { ** the execution ('luaV_execute') to the caller, to allow stackless ** calls.) Returns true iff function has been executed (C function). */ -int luaD_precall (lua_State *L, StkId func, int nresults) { - lua_CFunction f; - CallInfo *ci; - switch (ttype(func)) { - case LUA_TCCL: /* C closure */ - f = clCvalue(func)->f; - goto Cfunc; - case LUA_TLCF: /* light C function */ - f = fvalue(func); - Cfunc: { - int n; /* number of returns */ - checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ - ci = next_ci(L); /* now 'enter' new function */ - ci->nresults = nresults; - ci->func = func; - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); - lua_unlock(L); - n = (*f)(L); /* do the actual call */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, ci, L->top - n, n); - return 1; - } - case LUA_TLCL: { /* Lua function: prepare its call */ - StkId base; - Proto *p = clLvalue(func)->p; - int n = cast_int(L->top - func) - 1; /* number of real arguments */ - int fsize = p->maxstacksize; /* frame size */ - checkstackp(L, fsize, func); - if (p->is_vararg) - base = adjust_varargs(L, p, n); - else { /* non vararg function */ - for (; n < p->numparams; n++) - setnilvalue(L->top++); /* complete missing arguments */ - base = func + 1; - } - ci = next_ci(L); /* now 'enter' new function */ - ci->nresults = nresults; - ci->func = func; - ci->u.l.base = base; - L->top = ci->top = base + fsize; - lua_assert(ci->top <= L->stack_last); - ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus = CIST_LUA; - if (L->hookmask & LUA_MASKCALL) - callhook(L, ci); - return 0; - } - default: { /* not a function */ - checkstackp(L, 1, func); /* ensure space for metamethod */ - tryfuncTM(L, func); /* try to get '__call' metamethod */ - return luaD_precall(L, func, nresults); /* now it must be a function */ - } - } +int luaD_precall(lua_State* L, StkId func, int nresults) +{ + lua_CFunction f; + CallInfo* ci; + switch (ttype(func)) + { + case LUA_TCCL: /* C closure */ + f = clCvalue(func)->f; + goto Cfunc; + case LUA_TLCF: /* light C function */ + f = fvalue(func); + Cfunc: + { + int n; /* number of returns */ + checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; + if (L->hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, L->top - n, n); + return 1; + } + case LUA_TLCL: + { + /* Lua function: prepare its call */ + StkId base; + Proto* p = clLvalue(func)->p; + int n = cast_int(L->top - func) - 1; /* number of real arguments */ + int fsize = p->maxstacksize; /* frame size */ + checkstackp(L, fsize, func); + if (p->is_vararg) + base = adjust_varargs(L, p, n); + else + { + /* non vararg function */ + for (; n < p->numparams; n++) + setnilvalue(L->top++); /* complete missing arguments */ + base = func + 1; + } + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->u.l.base = base; + L->top = ci->top = base + fsize; + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; + if (L->hookmask & LUA_MASKCALL) + callhook(L, ci); + return 0; + } + default: + { + /* not a function */ + checkstackp(L, 1, func); /* ensure space for metamethod */ + tryfuncTM(L, func); /* try to get '__call' metamethod */ + return luaD_precall(L, func, nresults); /* now it must be a function */ + } + } } @@ -478,11 +536,12 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to ** allow overflow handling to work) */ -static void stackerror (lua_State *L) { - if (L->nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ +static void stackerror(lua_State* L) +{ + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS >> 3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } @@ -492,22 +551,24 @@ static void stackerror (lua_State *L) { ** When returns, all the results are on the stack, starting at the original ** function position. */ -void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls >= LUAI_MAXCCALLS) - stackerror(L); - if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ - luaV_execute(L); /* call it */ - L->nCcalls--; +void luaD_call(lua_State* L, StkId func, int nResults) +{ + if (++L->nCcalls >= LUAI_MAXCCALLS) + stackerror(L); + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ + luaV_execute(L); /* call it */ + L->nCcalls--; } /* ** Similar to 'luaD_call', but does not allow yields during the call */ -void luaD_callnoyield (lua_State *L, StkId func, int nResults) { - L->nny++; - luaD_call(L, func, nResults); - L->nny--; +void luaD_callnoyield(lua_State* L, StkId func, int nResults) +{ + L->nny++; + luaD_call(L, func, nResults); + L->nny--; } @@ -515,25 +576,28 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) { ** Completes the execution of an interrupted C function, calling its ** continuation function. */ -static void finishCcall (lua_State *L, int status) { - CallInfo *ci = L->ci; - int n; - /* must have a continuation and must be able to call it */ - lua_assert(ci->u.c.k != NULL && L->nny == 0); - /* error status can only happen in a protected call */ - lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); - if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ - ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ - L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ - } - /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already - handled */ - adjustresults(L, ci->nresults); - lua_unlock(L); - n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ +static void finishCcall(lua_State* L, int status) +{ + CallInfo* ci = L->ci; + int n; + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && L->nny == 0); + /* error status can only happen in a protected call */ + lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); + if (ci->callstatus & CIST_YPCALL) + { + /* was inside a pcall? */ + ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ + L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ + } + /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already + handled */ + adjustresults(L, ci->nresults); + lua_unlock(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ } @@ -545,17 +609,22 @@ static void finishCcall (lua_State *L, int status) { ** be passed to the first continuation function (otherwise the default ** status is LUA_YIELD). */ -static void unroll (lua_State *L, void *ud) { - if (ud != NULL) /* error status? */ - finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ - while (L->ci != &L->base_ci) { /* something in the stack */ - if (!isLua(L->ci)) /* C function? */ - finishCcall(L, LUA_YIELD); /* complete its execution */ - else { /* Lua function */ - luaV_finishOp(L); /* finish interrupted instruction */ - luaV_execute(L); /* execute down to higher C 'boundary' */ - } - } +static void unroll(lua_State* L, void* ud) +{ + if (ud != NULL) /* error status? */ + finishCcall(L, *(int*)ud); /* finish 'lua_pcallk' callee */ + while (L->ci != &L->base_ci) + { + /* something in the stack */ + if (!isLua(L->ci)) /* C function? */ + finishCcall(L, LUA_YIELD); /* complete its execution */ + else + { + /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L); /* execute down to higher C 'boundary' */ + } + } } @@ -563,13 +632,16 @@ static void unroll (lua_State *L, void *ud) { ** Try to find a suspended protected call (a "recover point") for the ** given thread. */ -static CallInfo *findpcall (lua_State *L) { - CallInfo *ci; - for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ - if (ci->callstatus & CIST_YPCALL) - return ci; - } - return NULL; /* no pending pcall */ +static CallInfo* findpcall(lua_State* L) +{ + CallInfo* ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) + { + /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ } @@ -578,20 +650,21 @@ static CallInfo *findpcall (lua_State *L) { ** there is one) and completes the execution of the interrupted ** 'luaD_pcall'. If there is no recover point, returns zero. */ -static int recover (lua_State *L, int status) { - StkId oldtop; - CallInfo *ci = findpcall(L); - if (ci == NULL) return 0; /* no recovery point */ - /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->extra); - luaF_close(L, oldtop); - seterrorobj(L, status, oldtop); - L->ci = ci; - L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ - L->nny = 0; /* should be zero to be yieldable */ - luaD_shrinkstack(L); - L->errfunc = ci->u.c.old_errfunc; - return 1; /* continue running the coroutine */ +static int recover(lua_State* L, int status) +{ + StkId oldtop; + CallInfo* ci = findpcall(L); + if (ci == NULL) return 0; /* no recovery point */ + /* "finish" luaD_pcall */ + oldtop = restorestack(L, ci->extra); + luaF_close(L, oldtop); + seterrorobj(L, status, oldtop); + L->ci = ci; + L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ + L->nny = 0; /* should be zero to be yieldable */ + luaD_shrinkstack(L); + L->errfunc = ci->u.c.old_errfunc; + return 1; /* continue running the coroutine */ } @@ -600,12 +673,13 @@ static int recover (lua_State *L, int status) { ** of the coroutine itself. (Such errors should not be handled by any ** coroutine error handler and should not kill the coroutine.) */ -static int resume_error (lua_State *L, const char *msg, int narg) { - L->top -= narg; /* remove args from the stack */ - setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ - api_incr_top(L); - lua_unlock(L); - return LUA_ERRRUN; +static int resume_error(lua_State* L, const char* msg, int narg) +{ + L->top -= narg; /* remove args from the stack */ + setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ + api_incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; } @@ -616,187 +690,224 @@ static int resume_error (lua_State *L, const char *msg, int narg) { ** function), plus erroneous cases: non-suspended coroutine or dead ** coroutine. */ -static void resume (lua_State *L, void *ud) { - int n = *(cast(int*, ud)); /* number of arguments */ - StkId firstArg = L->top - n; /* first argument */ - CallInfo *ci = L->ci; - if (L->status == LUA_OK) { /* starting a coroutine? */ - if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ - luaV_execute(L); /* call it */ - } - else { /* resuming from previous yield */ - lua_assert(L->status == LUA_YIELD); - L->status = LUA_OK; /* mark that it is running (again) */ - ci->func = restorestack(L, ci->extra); - if (isLua(ci)) /* yielded inside a hook? */ - luaV_execute(L); /* just continue running Lua code */ - else { /* 'common' yield */ - if (ci->u.c.k != NULL) { /* does it have a continuation function? */ - lua_unlock(L); - n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ - lua_lock(L); - api_checknelems(L, n); - firstArg = L->top - n; /* yield results come from continuation */ - } - luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ - } - unroll(L, NULL); /* run continuation */ - } +static void resume(lua_State* L, void* ud) +{ + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top - n; /* first argument */ + CallInfo* ci = L->ci; + if (L->status == LUA_OK) + { + /* starting a coroutine? */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ + luaV_execute(L); /* call it */ + } + else + { + /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = LUA_OK; /* mark that it is running (again) */ + ci->func = restorestack(L, ci->extra); + if (isLua(ci)) /* yielded inside a hook? */ + luaV_execute(L); /* just continue running Lua code */ + else + { + /* 'common' yield */ + if (ci->u.c.k != NULL) + { + /* does it have a continuation function? */ + lua_unlock(L); + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + firstArg = L->top - n; /* yield results come from continuation */ + } + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ + } + unroll(L, NULL); /* run continuation */ + } } -LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { - int status; - unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ - lua_lock(L); - if (L->status == LUA_OK) { /* may be starting a coroutine */ - if (L->ci != &L->base_ci) /* not in base level? */ - return resume_error(L, "cannot resume non-suspended coroutine", nargs); - } - else if (L->status != LUA_YIELD) - return resume_error(L, "cannot resume dead coroutine", nargs); - L->nCcalls = (from) ? from->nCcalls + 1 : 1; - if (L->nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow", nargs); - luai_userstateresume(L, nargs); - L->nny = 0; /* allow yields */ - api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); - status = luaD_rawrunprotected(L, resume, &nargs); - if (status == -1) /* error calling 'lua_resume'? */ - status = LUA_ERRRUN; - else { /* continue running after recoverable errors */ - while (errorstatus(status) && recover(L, status)) { - /* unroll continuation */ - status = luaD_rawrunprotected(L, unroll, &status); - } - if (errorstatus(status)) { /* unrecoverable error? */ - L->status = cast_byte(status); /* mark thread as 'dead' */ - seterrorobj(L, status, L->top); /* push error message */ - L->ci->top = L->top; - } - else lua_assert(status == L->status); /* normal end or yield */ - } - L->nny = oldnny; /* restore 'nny' */ - L->nCcalls--; - lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); - lua_unlock(L); - return status; +LUA_API int lua_resume(lua_State* L, lua_State* from, int nargs) +{ + int status; + unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ + lua_lock(L); + if (L->status == LUA_OK) + { + /* may be starting a coroutine */ + if (L->ci != &L->base_ci) /* not in base level? */ + return resume_error(L, "cannot resume non-suspended coroutine", nargs); + } + else if (L->status != LUA_YIELD) + return resume_error(L, "cannot resume dead coroutine", nargs); + L->nCcalls = (from) ? from->nCcalls + 1 : 1; + if (L->nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow", nargs); + luai_userstateresume(L, nargs); + L->nny = 0; /* allow yields */ + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); + status = luaD_rawrunprotected(L, resume, &nargs); + if (status == -1) /* error calling 'lua_resume'? */ + status = LUA_ERRRUN; + else + { + /* continue running after recoverable errors */ + while (errorstatus(status) && recover(L, status)) + { + /* unroll continuation */ + status = luaD_rawrunprotected(L, unroll, &status); + } + if (errorstatus(status)) + { + /* unrecoverable error? */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + seterrorobj(L, status, L->top); /* push error message */ + L->ci->top = L->top; + } + else + lua_assert(status == L->status); /* normal end or yield */ + } + L->nny = oldnny; /* restore 'nny' */ + L->nCcalls--; + lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); + lua_unlock(L); + return status; } -LUA_API int lua_isyieldable (lua_State *L) { - return (L->nny == 0); +LUA_API int lua_isyieldable(lua_State* L) +{ + return (L->nny == 0); } -LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k) { - CallInfo *ci = L->ci; - luai_userstateyield(L, nresults); - lua_lock(L); - api_checknelems(L, nresults); - if (L->nny > 0) { - if (L != G(L)->mainthread) - luaG_runerror(L, "attempt to yield across a C-call boundary"); - else - luaG_runerror(L, "attempt to yield from outside a coroutine"); - } - L->status = LUA_YIELD; - ci->extra = savestack(L, ci->func); /* save current 'func' */ - if (isLua(ci)) { /* inside a hook? */ - api_check(L, k == NULL, "hooks cannot continue after yielding"); - } - else { - if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ - ci->u.c.ctx = ctx; /* save context */ - ci->func = L->top - nresults - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); - } - lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ - lua_unlock(L); - return 0; /* return to 'luaD_hook' */ +LUA_API int lua_yieldk(lua_State* L, int nresults, lua_KContext ctx, + lua_KFunction k) +{ + CallInfo* ci = L->ci; + luai_userstateyield(L, nresults); + lua_lock(L); + api_checknelems(L, nresults); + if (L->nny > 0) + { + if (L != G(L)->mainthread) + luaG_runerror(L, "attempt to yield across a C-call boundary"); + else + luaG_runerror(L, "attempt to yield from outside a coroutine"); + } + L->status = LUA_YIELD; + ci->extra = savestack(L, ci->func); /* save current 'func' */ + if (isLua(ci)) + { + /* inside a hook? */ + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else + { + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + ci->func = L->top - nresults - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ + lua_unlock(L); + return 0; /* return to 'luaD_hook' */ } -int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t old_top, ptrdiff_t ef) { - int status; - CallInfo *old_ci = L->ci; - lu_byte old_allowhooks = L->allowhook; - unsigned short old_nny = L->nny; - ptrdiff_t old_errfunc = L->errfunc; - L->errfunc = ef; - status = luaD_rawrunprotected(L, func, u); - if (status != LUA_OK) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close possible pending closures */ - seterrorobj(L, status, oldtop); - L->ci = old_ci; - L->allowhook = old_allowhooks; - L->nny = old_nny; - luaD_shrinkstack(L); - } - L->errfunc = old_errfunc; - return status; +int luaD_pcall(lua_State* L, Pfunc func, void* u, + ptrdiff_t old_top, ptrdiff_t ef) +{ + int status; + CallInfo* old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + unsigned short old_nny = L->nny; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != LUA_OK) + { + /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close possible pending closures */ + seterrorobj(L, status, oldtop); + L->ci = old_ci; + L->allowhook = old_allowhooks; + L->nny = old_nny; + luaD_shrinkstack(L); + } + L->errfunc = old_errfunc; + return status; } - /* ** Execute a protected parser. */ -struct SParser { /* data to 'f_parser' */ - ZIO *z; - Mbuffer buff; /* dynamic structure used by the scanner */ - Dyndata dyd; /* dynamic structures used by the parser */ - const char *mode; - const char *name; +struct SParser +{ + /* data to 'f_parser' */ + ZIO* z; + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char* mode; + const char* name; }; -static void checkmode (lua_State *L, const char *mode, const char *x) { - if (mode && strchr(mode, x[0]) == NULL) { - luaO_pushfstring(L, - "attempt to load a %s chunk (mode is '%s')", x, mode); - luaD_throw(L, LUA_ERRSYNTAX); - } +static void checkmode(lua_State* L, const char* mode, const char* x) +{ + if (mode && strchr(mode, x[0]) == NULL) + { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is '%s')", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } } -static void f_parser (lua_State *L, void *ud) { - LClosure *cl; - struct SParser *p = cast(struct SParser *, ud); - int c = zgetc(p->z); /* read first character */ - if (c == LUA_SIGNATURE[0]) { - checkmode(L, p->mode, "binary"); - cl = luaU_undump(L, p->z, p->name); - } - else { - checkmode(L, p->mode, "text"); - cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); - } - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luaF_initupvals(L, cl); +static void f_parser(lua_State* L, void* ud) +{ + LClosure* cl; + struct SParser* p = cast(struct SParser *, ud); + int c = zgetc(p->z); /* read first character */ + if (c == LUA_SIGNATURE[0]) + { + checkmode(L, p->mode, "binary"); + cl = luaU_undump(L, p->z, p->name); + } + else + { + checkmode(L, p->mode, "text"); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); } -int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, - const char *mode) { - struct SParser p; - int status; - L->nny++; /* cannot yield during parsing */ - p.z = z; p.name = name; p.mode = mode; - p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; - p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; - p.dyd.label.arr = NULL; p.dyd.label.size = 0; - luaZ_initbuffer(L, &p.buff); - status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); - luaZ_freebuffer(L, &p.buff); - luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); - luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); - luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); - L->nny--; - return status; +int luaD_protectedparser(lua_State* L, ZIO* z, const char* name, + const char* mode) +{ + struct SParser p; + int status; + L->nny++; /* cannot yield during parsing */ + p.z = z; + p.name = name; + p.mode = mode; + p.dyd.actvar.arr = NULL; + p.dyd.actvar.size = 0; + p.dyd.gt.arr = NULL; + p.dyd.gt.size = 0; + p.dyd.label.arr = NULL; + p.dyd.label.size = 0; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); + luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); + luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); + luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); + L->nny--; + return status; } - - diff --git a/Lua/ldo.h b/Lua/ldo.h index 4f5d51c..8685894 100644 --- a/Lua/ldo.h +++ b/Lua/ldo.h @@ -28,31 +28,29 @@ #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) - #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) /* type of protected functions, to be ran by 'runprotected' */ -typedef void (*Pfunc) (lua_State *L, void *ud); +typedef void (*Pfunc)(lua_State* L, void* ud); -LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, - const char *mode); -LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); -LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); -LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); -LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, - int nres); -LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); -LUAI_FUNC void luaD_growstack (lua_State *L, int n); -LUAI_FUNC void luaD_shrinkstack (lua_State *L); -LUAI_FUNC void luaD_inctop (lua_State *L); +LUAI_FUNC int luaD_protectedparser(lua_State* L, ZIO* z, const char* name, + const char* mode); +LUAI_FUNC void luaD_hook(lua_State* L, int event, int line); +LUAI_FUNC int luaD_precall(lua_State* L, StkId func, int nresults); +LUAI_FUNC void luaD_call(lua_State* L, StkId func, int nResults); +LUAI_FUNC void luaD_callnoyield(lua_State* L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall(lua_State* L, Pfunc func, void* u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC int luaD_poscall(lua_State* L, CallInfo* ci, StkId firstResult, + int nres); +LUAI_FUNC void luaD_reallocstack(lua_State* L, int newsize); +LUAI_FUNC void luaD_growstack(lua_State* L, int n); +LUAI_FUNC void luaD_shrinkstack(lua_State* L); +LUAI_FUNC void luaD_inctop(lua_State* L); -LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); -LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); +LUAI_FUNC l_noret luaD_throw(lua_State* L, int errcode); +LUAI_FUNC int luaD_rawrunprotected(lua_State* L, Pfunc f, void* ud); #endif - diff --git a/Lua/ldump.c b/Lua/ldump.c index 016e300..ae6b4fb 100644 --- a/Lua/ldump.c +++ b/Lua/ldump.c @@ -19,12 +19,13 @@ #include "lundump.h" -typedef struct { - lua_State *L; - lua_Writer writer; - void *data; - int strip; - int status; +typedef struct +{ + lua_State* L; + lua_Writer writer; + void* data; + int strip; + int status; } DumpState; @@ -37,179 +38,199 @@ typedef struct { #define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) -static void DumpBlock (const void *b, size_t size, DumpState *D) { - if (D->status == 0 && size > 0) { - lua_unlock(D->L); - D->status = (*D->writer)(D->L, b, size, D->data); - lua_lock(D->L); - } +static void DumpBlock(const void* b, size_t size, DumpState* D) +{ + if (D->status == 0 && size > 0) + { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } } #define DumpVar(x,D) DumpVector(&x,1,D) -static void DumpByte (int y, DumpState *D) { - lu_byte x = (lu_byte)y; - DumpVar(x, D); +static void DumpByte(int y, DumpState* D) +{ + lu_byte x = (lu_byte)y; + DumpVar(x, D); } -static void DumpInt (int x, DumpState *D) { - DumpVar(x, D); +static void DumpInt(int x, DumpState* D) +{ + DumpVar(x, D); } -static void DumpNumber (lua_Number x, DumpState *D) { - DumpVar(x, D); +static void DumpNumber(lua_Number x, DumpState* D) +{ + DumpVar(x, D); } -static void DumpInteger (lua_Integer x, DumpState *D) { - DumpVar(x, D); +static void DumpInteger(lua_Integer x, DumpState* D) +{ + DumpVar(x, D); } -static void DumpString (const TString *s, DumpState *D) { - if (s == NULL) - DumpByte(0, D); - else { - size_t size = tsslen(s) + 1; /* include trailing '\0' */ - const char *str = getstr(s); - if (size < 0xFF) - DumpByte(cast_int(size), D); - else { - DumpByte(0xFF, D); - DumpVar(size, D); - } - DumpVector(str, size - 1, D); /* no need to save '\0' */ - } +static void DumpString(const TString* s, DumpState* D) +{ + if (s == NULL) + DumpByte(0, D); + else + { + size_t size = tsslen(s) + 1; /* include trailing '\0' */ + const char* str = getstr(s); + if (size < 0xFF) + DumpByte(cast_int(size), D); + else + { + DumpByte(0xFF, D); + DumpVar(size, D); + } + DumpVector(str, size - 1, D); /* no need to save '\0' */ + } } -static void DumpCode (const Proto *f, DumpState *D) { - DumpInt(f->sizecode, D); - DumpVector(f->code, f->sizecode, D); +static void DumpCode(const Proto* f, DumpState* D) +{ + DumpInt(f->sizecode, D); + DumpVector(f->code, f->sizecode, D); } -static void DumpFunction(const Proto *f, TString *psource, DumpState *D); +static void DumpFunction(const Proto* f, TString* psource, DumpState* D); -static void DumpConstants (const Proto *f, DumpState *D) { - int i; - int n = f->sizek; - DumpInt(n, D); - for (i = 0; i < n; i++) { - const TValue *o = &f->k[i]; - DumpByte(ttype(o), D); - switch (ttype(o)) { - case LUA_TNIL: - break; - case LUA_TBOOLEAN: - DumpByte(bvalue(o), D); - break; - case LUA_TNUMFLT: - DumpNumber(fltvalue(o), D); - break; - case LUA_TNUMINT: - DumpInteger(ivalue(o), D); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - DumpString(tsvalue(o), D); - break; - default: - lua_assert(0); - } - } +static void DumpConstants(const Proto* f, DumpState* D) +{ + int i; + int n = f->sizek; + DumpInt(n, D); + for (i = 0; i < n; i++) + { + const TValue* o = &f->k[i]; + DumpByte(ttype(o), D); + switch (ttype(o)) + { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o), D); + break; + case LUA_TNUMFLT: + DumpNumber(fltvalue(o), D); + break; + case LUA_TNUMINT: + DumpInteger(ivalue(o), D); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + DumpString(tsvalue(o), D); + break; + default: + lua_assert(0); + } + } } -static void DumpProtos (const Proto *f, DumpState *D) { - int i; - int n = f->sizep; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpFunction(f->p[i], f->source, D); +static void DumpProtos(const Proto* f, DumpState* D) +{ + int i; + int n = f->sizep; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpFunction(f->p[i], f->source, D); } -static void DumpUpvalues (const Proto *f, DumpState *D) { - int i, n = f->sizeupvalues; - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpByte(f->upvalues[i].instack, D); - DumpByte(f->upvalues[i].idx, D); - } +static void DumpUpvalues(const Proto* f, DumpState* D) +{ + int i, n = f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + { + DumpByte(f->upvalues[i].instack, D); + DumpByte(f->upvalues[i].idx, D); + } } -static void DumpDebug (const Proto *f, DumpState *D) { - int i, n; - n = (D->strip) ? 0 : f->sizelineinfo; - DumpInt(n, D); - DumpVector(f->lineinfo, n, D); - n = (D->strip) ? 0 : f->sizelocvars; - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpString(f->locvars[i].varname, D); - DumpInt(f->locvars[i].startpc, D); - DumpInt(f->locvars[i].endpc, D); - } - n = (D->strip) ? 0 : f->sizeupvalues; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpString(f->upvalues[i].name, D); +static void DumpDebug(const Proto* f, DumpState* D) +{ + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + DumpInt(n, D); + DumpVector(f->lineinfo, n, D); + n = (D->strip) ? 0 : f->sizelocvars; + DumpInt(n, D); + for (i = 0; i < n; i++) + { + DumpString(f->locvars[i].varname, D); + DumpInt(f->locvars[i].startpc, D); + DumpInt(f->locvars[i].endpc, D); + } + n = (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpString(f->upvalues[i].name, D); } -static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { - if (D->strip || f->source == psource) - DumpString(NULL, D); /* no debug info or same source as its parent */ - else - DumpString(f->source, D); - DumpInt(f->linedefined, D); - DumpInt(f->lastlinedefined, D); - DumpByte(f->numparams, D); - DumpByte(f->is_vararg, D); - DumpByte(f->maxstacksize, D); - DumpCode(f, D); - DumpConstants(f, D); - DumpUpvalues(f, D); - DumpProtos(f, D); - DumpDebug(f, D); +static void DumpFunction(const Proto* f, TString* psource, DumpState* D) +{ + if (D->strip || f->source == psource) + DumpString(NULL, D); /* no debug info or same source as its parent */ + else + DumpString(f->source, D); + DumpInt(f->linedefined, D); + DumpInt(f->lastlinedefined, D); + DumpByte(f->numparams, D); + DumpByte(f->is_vararg, D); + DumpByte(f->maxstacksize, D); + DumpCode(f, D); + DumpConstants(f, D); + DumpUpvalues(f, D); + DumpProtos(f, D); + DumpDebug(f, D); } -static void DumpHeader (DumpState *D) { - DumpLiteral(LUA_SIGNATURE, D); - DumpByte(LUAC_VERSION, D); - DumpByte(LUAC_FORMAT, D); - DumpLiteral(LUAC_DATA, D); - DumpByte(sizeof(int), D); - DumpByte(sizeof(size_t), D); - DumpByte(sizeof(Instruction), D); - DumpByte(sizeof(lua_Integer), D); - DumpByte(sizeof(lua_Number), D); - DumpInteger(LUAC_INT, D); - DumpNumber(LUAC_NUM, D); +static void DumpHeader(DumpState* D) +{ + DumpLiteral(LUA_SIGNATURE, D); + DumpByte(LUAC_VERSION, D); + DumpByte(LUAC_FORMAT, D); + DumpLiteral(LUAC_DATA, D); + DumpByte(sizeof(int), D); + DumpByte(sizeof(size_t), D); + DumpByte(sizeof(Instruction), D); + DumpByte(sizeof(lua_Integer), D); + DumpByte(sizeof(lua_Number), D); + DumpInteger(LUAC_INT, D); + DumpNumber(LUAC_NUM, D); } /* ** dump Lua function as precompiled chunk */ -int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, - int strip) { - DumpState D; - D.L = L; - D.writer = w; - D.data = data; - D.strip = strip; - D.status = 0; - DumpHeader(&D); - DumpByte(f->sizeupvalues, &D); - DumpFunction(f, NULL, &D); - return D.status; +int luaU_dump(lua_State* L, const Proto* f, lua_Writer w, void* data, + int strip) +{ + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + DumpHeader(&D); + DumpByte(f->sizeupvalues, &D); + DumpFunction(f, NULL, &D); + return D.status; } - diff --git a/Lua/lfunc.c b/Lua/lfunc.c index 67967da..38f1f54 100644 --- a/Lua/lfunc.c +++ b/Lua/lfunc.c @@ -21,115 +21,127 @@ #include "lstate.h" - -CClosure *luaF_newCclosure (lua_State *L, int n) { - GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); - CClosure *c = gco2ccl(o); - c->nupvalues = cast_byte(n); - return c; +CClosure* luaF_newCclosure(lua_State* L, int n) +{ + GCObject* o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); + CClosure* c = gco2ccl(o); + c->nupvalues = cast_byte(n); + return c; } -LClosure *luaF_newLclosure (lua_State *L, int n) { - GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); - LClosure *c = gco2lcl(o); - c->p = NULL; - c->nupvalues = cast_byte(n); - while (n--) c->upvals[n] = NULL; - return c; +LClosure* luaF_newLclosure(lua_State* L, int n) +{ + GCObject* o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); + LClosure* c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(n); + while (n--) c->upvals[n] = NULL; + return c; } /* ** fill a closure with new closed upvalues */ -void luaF_initupvals (lua_State *L, LClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) { - UpVal *uv = luaM_new(L, UpVal); - uv->refcount = 1; - uv->v = &uv->u.value; /* make it closed */ - setnilvalue(uv->v); - cl->upvals[i] = uv; - } +void luaF_initupvals(lua_State* L, LClosure* cl) +{ + int i; + for (i = 0; i < cl->nupvalues; i++) + { + UpVal* uv = luaM_new(L, UpVal); + uv->refcount = 1; + uv->v = &uv->u.value; /* make it closed */ + setnilvalue(uv->v); + cl->upvals[i] = uv; + } } -UpVal *luaF_findupval (lua_State *L, StkId level) { - UpVal **pp = &L->openupval; - UpVal *p; - UpVal *uv; - lua_assert(isintwups(L) || L->openupval == NULL); - while (*pp != NULL && (p = *pp)->v >= level) { - lua_assert(upisopen(p)); - if (p->v == level) /* found a corresponding upvalue? */ - return p; /* return it */ - pp = &p->u.open.next; - } - /* not found: create a new upvalue */ - uv = luaM_new(L, UpVal); - uv->refcount = 0; - uv->u.open.next = *pp; /* link it to list of open upvalues */ - uv->u.open.touched = 1; - *pp = uv; - uv->v = level; /* current value lives in the stack */ - if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ - L->twups = G(L)->twups; /* link it to the list */ - G(L)->twups = L; - } - return uv; +UpVal* luaF_findupval(lua_State* L, StkId level) +{ + UpVal** pp = &L->openupval; + UpVal* p; + UpVal* uv; + lua_assert(isintwups(L) || L->openupval == NULL); + while (*pp != NULL && (p = *pp)->v >= level) + { + lua_assert(upisopen(p)); + if (p->v == level) /* found a corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; + } + /* not found: create a new upvalue */ + uv = luaM_new(L, UpVal); + uv->refcount = 0; + uv->u.open.next = *pp; /* link it to list of open upvalues */ + uv->u.open.touched = 1; + *pp = uv; + uv->v = level; /* current value lives in the stack */ + if (!isintwups(L)) + { + /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } + return uv; } -void luaF_close (lua_State *L, StkId level) { - UpVal *uv; - while (L->openupval != NULL && (uv = L->openupval)->v >= level) { - lua_assert(upisopen(uv)); - L->openupval = uv->u.open.next; /* remove from 'open' list */ - if (uv->refcount == 0) /* no references? */ - luaM_free(L, uv); /* free upvalue */ - else { - setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ - uv->v = &uv->u.value; /* now current value lives here */ - luaC_upvalbarrier(L, uv); - } - } +void luaF_close(lua_State* L, StkId level) +{ + UpVal* uv; + while (L->openupval != NULL && (uv = L->openupval)->v >= level) + { + lua_assert(upisopen(uv)); + L->openupval = uv->u.open.next; /* remove from 'open' list */ + if (uv->refcount == 0) /* no references? */ + luaM_free(L, uv); /* free upvalue */ + else + { + setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ + uv->v = &uv->u.value; /* now current value lives here */ + luaC_upvalbarrier(L, uv); + } + } } -Proto *luaF_newproto (lua_State *L) { - GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); - Proto *f = gco2p(o); - f->k = NULL; - f->sizek = 0; - f->p = NULL; - f->sizep = 0; - f->code = NULL; - f->cache = NULL; - f->sizecode = 0; - f->lineinfo = NULL; - f->sizelineinfo = 0; - f->upvalues = NULL; - f->sizeupvalues = 0; - f->numparams = 0; - f->is_vararg = 0; - f->maxstacksize = 0; - f->locvars = NULL; - f->sizelocvars = 0; - f->linedefined = 0; - f->lastlinedefined = 0; - f->source = NULL; - return f; +Proto* luaF_newproto(lua_State* L) +{ + GCObject* o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); + Proto* f = gco2p(o); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->cache = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; } -void luaF_freeproto (lua_State *L, Proto *f) { - luaM_freearray(L, f->code, f->sizecode); - luaM_freearray(L, f->p, f->sizep); - luaM_freearray(L, f->k, f->sizek); - luaM_freearray(L, f->lineinfo, f->sizelineinfo); - luaM_freearray(L, f->locvars, f->sizelocvars); - luaM_freearray(L, f->upvalues, f->sizeupvalues); - luaM_free(L, f); +void luaF_freeproto(lua_State* L, Proto* f) +{ + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); + luaM_free(L, f); } @@ -137,15 +149,18 @@ void luaF_freeproto (lua_State *L, Proto *f) { ** Look for n-th local variable at line 'line' in function 'func'. ** Returns NULL if not found. */ -const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { - int i; - for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { - if (pc < f->locvars[i].endpc) { /* is variable active? */ - local_number--; - if (local_number == 0) - return getstr(f->locvars[i].varname); - } - } - return NULL; /* not found */ +const char* luaF_getlocalname(const Proto* f, int local_number, int pc) +{ + int i; + for (i = 0; i < f->sizelocvars && f->locvars[i].startpc <= pc; i++) + { + if (pc < f->locvars[i].endpc) + { + /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ } - diff --git a/Lua/lfunc.h b/Lua/lfunc.h index 2eeb0d5..4720113 100644 --- a/Lua/lfunc.h +++ b/Lua/lfunc.h @@ -32,30 +32,35 @@ /* ** Upvalues for Lua closures */ -struct UpVal { - TValue *v; /* points to stack or to its own value */ - lu_mem refcount; /* reference counter */ - union { - struct { /* (when open) */ - UpVal *next; /* linked list */ - int touched; /* mark to avoid cycles with dead threads */ - } open; - TValue value; /* the value (when closed) */ - } u; +struct UpVal +{ + TValue* v; /* points to stack or to its own value */ + lu_mem refcount; /* reference counter */ + union + { + struct + { + /* (when open) */ + UpVal* next; /* linked list */ + int touched; /* mark to avoid cycles with dead threads */ + } open; + + TValue value; /* the value (when closed) */ + } u; }; #define upisopen(up) ((up)->v != &(up)->u.value) -LUAI_FUNC Proto *luaF_newproto (lua_State *L); -LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); -LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); -LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); -LUAI_FUNC void luaF_close (lua_State *L, StkId level); -LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, - int pc); +LUAI_FUNC Proto* luaF_newproto(lua_State* L); +LUAI_FUNC CClosure* luaF_newCclosure(lua_State* L, int nelems); +LUAI_FUNC LClosure* luaF_newLclosure(lua_State* L, int nelems); +LUAI_FUNC void luaF_initupvals(lua_State* L, LClosure* cl); +LUAI_FUNC UpVal* luaF_findupval(lua_State* L, StkId level); +LUAI_FUNC void luaF_close(lua_State* L, StkId level); +LUAI_FUNC void luaF_freeproto(lua_State* L, Proto* f); +LUAI_FUNC const char* luaF_getlocalname(const Proto* func, int local_number, + int pc); #endif diff --git a/Lua/lgc.c b/Lua/lgc.c index ba2c19e..d0aa5e6 100644 --- a/Lua/lgc.c +++ b/Lua/lgc.c @@ -91,7 +91,7 @@ */ #define markobjectN(g,t) { if (t) markobject(g,t); } -static void reallymarkobject (global_State *g, GCObject *o); +static void reallymarkobject(global_State* g, GCObject* o); /* @@ -122,10 +122,11 @@ static void reallymarkobject (global_State *g, GCObject *o); ** associated nil value is enough to signal that the entry is logically ** empty. */ -static void removeentry (Node *n) { - lua_assert(ttisnil(gval(n))); - if (valiswhite(gkey(n))) - setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ +static void removeentry(Node* n) +{ + lua_assert(ttisnil(gval(n))); + if (valiswhite(gkey(n))) + setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ } @@ -136,13 +137,15 @@ static void removeentry (Node *n) { ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ -static int iscleared (global_State *g, const TValue *o) { - if (!iscollectable(o)) return 0; - else if (ttisstring(o)) { - markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ - return 0; - } - else return iswhite(gcvalue(o)); +static int iscleared(global_State* g, const TValue* o) +{ + if (!iscollectable(o)) return 0; + else if (ttisstring(o)) + { + markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ + return 0; + } + else return iswhite(gcvalue(o)); } @@ -152,15 +155,18 @@ static int iscleared (global_State *g, const TValue *o) { ** object to white [sweep it] to avoid other barrier calls for this ** same object.) */ -void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { - global_State *g = G(L); - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - if (keepinvariant(g)) /* must keep invariant? */ - reallymarkobject(g, v); /* restore invariant */ - else { /* sweep phase */ - lua_assert(issweepphase(g)); - makewhite(g, o); /* mark main obj. as white to avoid other barriers */ - } +void luaC_barrier_(lua_State* L, GCObject* o, GCObject* v) +{ + global_State* g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + if (keepinvariant(g)) /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + else + { + /* sweep phase */ + lua_assert(issweepphase(g)); + makewhite(g, o); /* mark main obj. as white to avoid other barriers */ + } } @@ -168,11 +174,12 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { ** barrier that moves collector backward, that is, mark the black object ** pointing to a white object as gray again. */ -void luaC_barrierback_ (lua_State *L, Table *t) { - global_State *g = G(L); - lua_assert(isblack(t) && !isdead(g, t)); - black2gray(t); /* make table gray (again) */ - linkgclist(t, g->grayagain); +void luaC_barrierback_(lua_State* L, Table* t) +{ + global_State* g = G(L); + lua_assert(isblack(t) && !isdead(g, t)); + black2gray(t); /* make table gray (again) */ + linkgclist(t, g->grayagain); } @@ -182,22 +189,24 @@ void luaC_barrierback_ (lua_State *L, Table *t) { ** closures pointing to it. So, we assume that the object being assigned ** must be marked. */ -void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = gcvalue(uv->v); - lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ - if (keepinvariant(g)) - markobject(g, o); +void luaC_upvalbarrier_(lua_State* L, UpVal* uv) +{ + global_State* g = G(L); + GCObject* o = gcvalue(uv->v); + lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ + if (keepinvariant(g)) + markobject(g, o); } -void luaC_fix (lua_State *L, GCObject *o) { - global_State *g = G(L); - lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ - white2gray(o); /* they will be gray forever */ - g->allgc = o->next; /* remove object from 'allgc' list */ - o->next = g->fixedgc; /* link it to 'fixedgc' list */ - g->fixedgc = o; +void luaC_fix(lua_State* L, GCObject* o) +{ + global_State* g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + white2gray(o); /* they will be gray forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; } @@ -205,20 +214,20 @@ void luaC_fix (lua_State *L, GCObject *o) { ** create a new collectable object (with given type and size) and link ** it to 'allgc' list. */ -GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { - global_State *g = G(L); - GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); - o->marked = luaC_white(g); - o->tt = tt; - o->next = g->allgc; - g->allgc = o; - return o; +GCObject* luaC_newobj(lua_State* L, int tt, size_t sz) +{ + global_State* g = G(L); + GCObject* o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; + return o; } /* }====================================================== */ - /* ** {====================================================== ** Mark functions @@ -232,74 +241,89 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { ** to appropriate list to be visited (and turned black) later. (Open ** upvalues are already linked in 'headuv' list.) */ -static void reallymarkobject (global_State *g, GCObject *o) { - reentry: - white2gray(o); - switch (o->tt) { - case LUA_TSHRSTR: { - gray2black(o); - g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); - break; - } - case LUA_TLNGSTR: { - gray2black(o); - g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); - break; - } - case LUA_TUSERDATA: { - TValue uvalue; - markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ - gray2black(o); - g->GCmemtrav += sizeudata(gco2u(o)); - getuservalue(g->mainthread, gco2u(o), &uvalue); - if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ - o = gcvalue(&uvalue); - goto reentry; - } - break; - } - case LUA_TLCL: { - linkgclist(gco2lcl(o), g->gray); - break; - } - case LUA_TCCL: { - linkgclist(gco2ccl(o), g->gray); - break; - } - case LUA_TTABLE: { - linkgclist(gco2t(o), g->gray); - break; - } - case LUA_TTHREAD: { - linkgclist(gco2th(o), g->gray); - break; - } - case LUA_TPROTO: { - linkgclist(gco2p(o), g->gray); - break; - } - default: lua_assert(0); break; - } +static void reallymarkobject(global_State* g, GCObject* o) +{ +reentry: + white2gray(o); + switch (o->tt) + { + case LUA_TSHRSTR: + { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); + break; + } + case LUA_TLNGSTR: + { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); + break; + } + case LUA_TUSERDATA: + { + TValue uvalue; + markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ + gray2black(o); + g->GCmemtrav += sizeudata(gco2u(o)); + getuservalue(g->mainthread, gco2u(o), &uvalue); + if (valiswhite(&uvalue)) + { + /* markvalue(g, &uvalue); */ + o = gcvalue(&uvalue); + goto reentry; + } + break; + } + case LUA_TLCL: + { + linkgclist(gco2lcl(o), g->gray); + break; + } + case LUA_TCCL: + { + linkgclist(gco2ccl(o), g->gray); + break; + } + case LUA_TTABLE: + { + linkgclist(gco2t(o), g->gray); + break; + } + case LUA_TTHREAD: + { + linkgclist(gco2th(o), g->gray); + break; + } + case LUA_TPROTO: + { + linkgclist(gco2p(o), g->gray); + break; + } + default: lua_assert(0); + break; + } } /* ** mark metamethods for basic types */ -static void markmt (global_State *g) { - int i; - for (i=0; i < LUA_NUMTAGS; i++) - markobjectN(g, g->mt[i]); +static void markmt(global_State* g) +{ + int i; + for (i = 0; i < LUA_NUMTAGS; i++) + markobjectN(g, g->mt[i]); } /* ** mark all objects in list of being-finalized */ -static void markbeingfnz (global_State *g) { - GCObject *o; - for (o = g->tobefnz; o != NULL; o = o->next) - markobject(g, o); +static void markbeingfnz(global_State* g) +{ + GCObject* o; + for (o = g->tobefnz; o != NULL; o = o->next) + markobject(g, o); } @@ -309,38 +333,45 @@ static void markbeingfnz (global_State *g) { ** thread.) Remove from the list threads that no longer have upvalues and ** not-marked threads. */ -static void remarkupvals (global_State *g) { - lua_State *thread; - lua_State **p = &g->twups; - while ((thread = *p) != NULL) { - lua_assert(!isblack(thread)); /* threads are never black */ - if (isgray(thread) && thread->openupval != NULL) - p = &thread->twups; /* keep marked thread with upvalues in the list */ - else { /* thread is not marked or without upvalues */ - UpVal *uv; - *p = thread->twups; /* remove thread from the list */ - thread->twups = thread; /* mark that it is out of list */ - for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { - if (uv->u.open.touched) { - markvalue(g, uv->v); /* remark upvalue's value */ - uv->u.open.touched = 0; - } - } - } - } +static void remarkupvals(global_State* g) +{ + lua_State* thread; + lua_State** p = &g->twups; + while ((thread = *p) != NULL) + { + lua_assert(!isblack(thread)); /* threads are never black */ + if (isgray(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else + { + /* thread is not marked or without upvalues */ + UpVal* uv; + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) + { + if (uv->u.open.touched) + { + markvalue(g, uv->v); /* remark upvalue's value */ + uv->u.open.touched = 0; + } + } + } + } } /* ** mark root set and reset all gray lists, to start a new collection */ -static void restartcollection (global_State *g) { - g->gray = g->grayagain = NULL; - g->weak = g->allweak = g->ephemeron = NULL; - markobject(g, g->mainthread); - markvalue(g, &g->l_registry); - markmt(g); - markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +static void restartcollection(global_State* g) +{ + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ } /* }====================================================== */ @@ -358,26 +389,30 @@ static void restartcollection (global_State *g) { ** atomic phase. In the atomic phase, if table has any white value, ** put it in 'weak' list, to be cleared. */ -static void traverseweakvalue (global_State *g, Table *h) { - Node *n, *limit = gnodelast(h); - /* if there is array part, assume it may have white values (it is not - worth traversing it now just to check) */ - int hasclears = (h->sizearray > 0); - for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else { - lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); /* mark key */ - if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ - hasclears = 1; /* table will have to be cleared */ - } - } - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasclears) - linkgclist(h, g->weak); /* has to be cleared later */ +static void traverseweakvalue(global_State* g, Table* h) +{ + Node *n, *limit = gnodelast(h); + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ + int hasclears = (h->sizearray > 0); + for (n = gnode(h, 0); n < limit; n++) + { + /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else + { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ + hasclears = 1; /* table will have to be cleared */ + } + } + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ } @@ -391,83 +426,98 @@ static void traverseweakvalue (global_State *g, Table *h) { ** black). Otherwise, if it has any white key, table has to be cleared ** (in the atomic phase). */ -static int traverseephemeron (global_State *g, Table *h) { - int marked = 0; /* true if an object is marked in this traversal */ - int hasclears = 0; /* true if table has white keys */ - int hasww = 0; /* true if table has entry "white-key -> white-value" */ - Node *n, *limit = gnodelast(h); - unsigned int i; - /* traverse array part */ - for (i = 0; i < h->sizearray; i++) { - if (valiswhite(&h->array[i])) { - marked = 1; - reallymarkobject(g, gcvalue(&h->array[i])); - } - } - /* traverse hash part */ - for (n = gnode(h, 0); n < limit; n++) { - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ - hasclears = 1; /* table must be cleared */ - if (valiswhite(gval(n))) /* value not marked yet? */ - hasww = 1; /* white-white entry */ - } - else if (valiswhite(gval(n))) { /* value not marked yet? */ - marked = 1; - reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ - } - } - /* link table into proper list */ - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasww) /* table has white->white entries? */ - linkgclist(h, g->ephemeron); /* have to propagate again */ - else if (hasclears) /* table has white keys? */ - linkgclist(h, g->allweak); /* may have to clean white keys */ - return marked; +static int traverseephemeron(global_State* g, Table* h) +{ + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has white keys */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ + Node *n, *limit = gnodelast(h); + unsigned int i; + /* traverse array part */ + for (i = 0; i < h->sizearray; i++) + { + if (valiswhite(&h->array[i])) + { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); + } + } + /* traverse hash part */ + for (n = gnode(h, 0); n < limit; n++) + { + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else if (iscleared(g, gkey(n))) + { + /* key is not marked (yet)? */ + hasclears = 1; /* table must be cleared */ + if (valiswhite(gval(n))) /* value not marked yet? */ + hasww = 1; /* white-white entry */ + } + else if (valiswhite(gval(n))) + { + /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } + } + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ + return marked; } -static void traversestrongtable (global_State *g, Table *h) { - Node *n, *limit = gnodelast(h); - unsigned int i; - for (i = 0; i < h->sizearray; i++) /* traverse array part */ - markvalue(g, &h->array[i]); - for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else { - lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); /* mark key */ - markvalue(g, gval(n)); /* mark value */ - } - } +static void traversestrongtable(global_State* g, Table* h) +{ + Node *n, *limit = gnodelast(h); + unsigned int i; + for (i = 0; i < h->sizearray; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) + { + /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else + { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ + } + } } -static lu_mem traversetable (global_State *g, Table *h) { - const char *weakkey, *weakvalue; - const TValue *mode = gfasttm(g, h->metatable, TM_MODE); - markobjectN(g, h->metatable); - if (mode && ttisstring(mode) && /* is there a weak mode? */ - ((weakkey = strchr(svalue(mode), 'k')), - (weakvalue = strchr(svalue(mode), 'v')), - (weakkey || weakvalue))) { /* is really weak? */ - black2gray(h); /* keep table gray */ - if (!weakkey) /* strong keys? */ - traverseweakvalue(g, h); - else if (!weakvalue) /* strong values? */ - traverseephemeron(g, h); - else /* all weak */ - linkgclist(h, g->allweak); /* nothing to traverse now */ - } - else /* not weak */ - traversestrongtable(g, h); - return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * cast(size_t, allocsizenode(h)); +static lu_mem traversetable(global_State* g, Table* h) +{ + const char *weakkey, *weakvalue; + const TValue* mode = gfasttm(g, h->metatable, TM_MODE); + markobjectN(g, h->metatable); + if (mode && ttisstring(mode) && /* is there a weak mode? */ + ((weakkey = strchr(svalue(mode), 'k')), + (weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) + { + /* is really weak? */ + black2gray(h); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else /* all weak */ + linkgclist(h, g->allweak); /* nothing to traverse now */ + } + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * cast(size_t, allocsizenode(h)); } @@ -476,33 +526,35 @@ static lu_mem traversetable (global_State *g, Table *h) { ** arrays can be larger than needed; the extra slots are filled with ** NULL, so the use of 'markobjectN') */ -static int traverseproto (global_State *g, Proto *f) { - int i; - if (f->cache && iswhite(f->cache)) - f->cache = NULL; /* allow cache to be collected */ - markobjectN(g, f->source); - for (i = 0; i < f->sizek; i++) /* mark literals */ - markvalue(g, &f->k[i]); - for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ - markobjectN(g, f->upvalues[i].name); - for (i = 0; i < f->sizep; i++) /* mark nested protos */ - markobjectN(g, f->p[i]); - for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ - markobjectN(g, f->locvars[i].varname); - return sizeof(Proto) + sizeof(Instruction) * f->sizecode + - sizeof(Proto *) * f->sizep + - sizeof(TValue) * f->sizek + - sizeof(int) * f->sizelineinfo + - sizeof(LocVar) * f->sizelocvars + - sizeof(Upvaldesc) * f->sizeupvalues; +static int traverseproto(global_State* g, Proto* f) +{ + int i; + if (f->cache && iswhite(f->cache)) + f->cache = NULL; /* allow cache to be collected */ + markobjectN(g, f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + markobjectN(g, f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ + markobjectN(g, f->p[i]); + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + markobjectN(g, f->locvars[i].varname); + return sizeof(Proto) + sizeof(Instruction) * f->sizecode + + sizeof(Proto*) * f->sizep + + sizeof(TValue) * f->sizek + + sizeof(int) * f->sizelineinfo + + sizeof(LocVar) * f->sizelocvars + + sizeof(Upvaldesc) * f->sizeupvalues; } -static lu_mem traverseCclosure (global_State *g, CClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ - markvalue(g, &cl->upvalue[i]); - return sizeCclosure(cl->nupvalues); +static lu_mem traverseCclosure(global_State* g, CClosure* cl) +{ + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return sizeCclosure(cl->nupvalues); } /* @@ -511,44 +563,52 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { ** (because then the value cannot be changed by the thread and the ** thread may not be traversed again) */ -static lu_mem traverseLclosure (global_State *g, LClosure *cl) { - int i; - markobjectN(g, cl->p); /* mark its prototype */ - for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ - UpVal *uv = cl->upvals[i]; - if (uv != NULL) { - if (upisopen(uv) && g->gcstate != GCSinsideatomic) - uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ - else - markvalue(g, uv->v); - } - } - return sizeLclosure(cl->nupvalues); +static lu_mem traverseLclosure(global_State* g, LClosure* cl) +{ + int i; + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) + { + /* mark its upvalues */ + UpVal* uv = cl->upvals[i]; + if (uv != NULL) + { + if (upisopen(uv) && g->gcstate != GCSinsideatomic) + uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ + else + markvalue(g, uv->v); + } + } + return sizeLclosure(cl->nupvalues); } -static lu_mem traversethread (global_State *g, lua_State *th) { - StkId o = th->stack; - if (o == NULL) - return 1; /* stack not completely built yet */ - lua_assert(g->gcstate == GCSinsideatomic || - th->openupval == NULL || isintwups(th)); - for (; o < th->top; o++) /* mark live elements in the stack */ - markvalue(g, o); - if (g->gcstate == GCSinsideatomic) { /* final traversal? */ - StkId lim = th->stack + th->stacksize; /* real end of stack */ - for (; o < lim; o++) /* clear not-marked stack slice */ - setnilvalue(o); - /* 'remarkupvals' may have removed thread from 'twups' list */ - if (!isintwups(th) && th->openupval != NULL) { - th->twups = g->twups; /* link it back to the list */ - g->twups = th; - } - } - else if (g->gckind != KGC_EMERGENCY) - luaD_shrinkstack(th); /* do not change stack in emergency cycle */ - return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * th->nci); +static lu_mem traversethread(global_State* g, lua_State* th) +{ + StkId o = th->stack; + if (o == NULL) + return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSinsideatomic || + th->openupval == NULL || isintwups(th)); + for (; o < th->top; o++) /* mark live elements in the stack */ + markvalue(g, o); + if (g->gcstate == GCSinsideatomic) + { + /* final traversal? */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) + { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } + } + else if (g->gckind != KGC_EMERGENCY) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->nci); } @@ -556,70 +616,85 @@ static lu_mem traversethread (global_State *g, lua_State *th) { ** traverse one gray object, turning it to black (except for threads, ** which are always gray). */ -static void propagatemark (global_State *g) { - lu_mem size; - GCObject *o = g->gray; - lua_assert(isgray(o)); - gray2black(o); - switch (o->tt) { - case LUA_TTABLE: { - Table *h = gco2t(o); - g->gray = h->gclist; /* remove from 'gray' list */ - size = traversetable(g, h); - break; - } - case LUA_TLCL: { - LClosure *cl = gco2lcl(o); - g->gray = cl->gclist; /* remove from 'gray' list */ - size = traverseLclosure(g, cl); - break; - } - case LUA_TCCL: { - CClosure *cl = gco2ccl(o); - g->gray = cl->gclist; /* remove from 'gray' list */ - size = traverseCclosure(g, cl); - break; - } - case LUA_TTHREAD: { - lua_State *th = gco2th(o); - g->gray = th->gclist; /* remove from 'gray' list */ - linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ - black2gray(o); - size = traversethread(g, th); - break; - } - case LUA_TPROTO: { - Proto *p = gco2p(o); - g->gray = p->gclist; /* remove from 'gray' list */ - size = traverseproto(g, p); - break; - } - default: lua_assert(0); return; - } - g->GCmemtrav += size; +static void propagatemark(global_State* g) +{ + lu_mem size; + GCObject* o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->tt) + { + case LUA_TTABLE: + { + Table* h = gco2t(o); + g->gray = h->gclist; /* remove from 'gray' list */ + size = traversetable(g, h); + break; + } + case LUA_TLCL: + { + LClosure* cl = gco2lcl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; + } + case LUA_TCCL: + { + CClosure* cl = gco2ccl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseCclosure(g, cl); + break; + } + case LUA_TTHREAD: + { + lua_State* th = gco2th(o); + g->gray = th->gclist; /* remove from 'gray' list */ + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + black2gray(o); + size = traversethread(g, th); + break; + } + case LUA_TPROTO: + { + Proto* p = gco2p(o); + g->gray = p->gclist; /* remove from 'gray' list */ + size = traverseproto(g, p); + break; + } + default: lua_assert(0); + return; + } + g->GCmemtrav += size; } -static void propagateall (global_State *g) { - while (g->gray) propagatemark(g); +static void propagateall(global_State* g) +{ + while (g->gray) propagatemark(g); } -static void convergeephemerons (global_State *g) { - int changed; - do { - GCObject *w; - GCObject *next = g->ephemeron; /* get ephemeron list */ - g->ephemeron = NULL; /* tables may return to this list when traversed */ - changed = 0; - while ((w = next) != NULL) { - next = gco2t(w)->gclist; - if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ - propagateall(g); /* propagate changes */ - changed = 1; /* will have to revisit all ephemeron tables */ - } - } - } while (changed); +static void convergeephemerons(global_State* g) +{ + int changed; + do + { + GCObject* w; + GCObject* next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ + changed = 0; + while ((w = next) != NULL) + { + next = gco2t(w)->gclist; + if (traverseephemeron(g, gco2t(w))) + { + /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + } + while (changed); } /* }====================================================== */ @@ -636,17 +711,21 @@ static void convergeephemerons (global_State *g) { ** clear entries with unmarked keys from all weaktables in list 'l' up ** to element 'f' */ -static void clearkeys (global_State *g, GCObject *l, GCObject *f) { - for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); - Node *n, *limit = gnodelast(h); - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { - setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* and remove entry from table */ - } - } - } +static void clearkeys(global_State* g, GCObject* l, GCObject* f) +{ + for (; l != f; l = gco2t(l)->gclist) + { + Table* h = gco2t(l); + Node *n, *limit = gnodelast(h); + for (n = gnode(h, 0); n < limit; n++) + { + if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) + { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ + } + } + } } @@ -654,74 +733,91 @@ static void clearkeys (global_State *g, GCObject *l, GCObject *f) { ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ -static void clearvalues (global_State *g, GCObject *l, GCObject *f) { - for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); - Node *n, *limit = gnodelast(h); - unsigned int i; - for (i = 0; i < h->sizearray; i++) { - TValue *o = &h->array[i]; - if (iscleared(g, o)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { - setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* and remove entry from table */ - } - } - } +static void clearvalues(global_State* g, GCObject* l, GCObject* f) +{ + for (; l != f; l = gco2t(l)->gclist) + { + Table* h = gco2t(l); + Node *n, *limit = gnodelast(h); + unsigned int i; + for (i = 0; i < h->sizearray; i++) + { + TValue* o = &h->array[i]; + if (iscleared(g, o)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + for (n = gnode(h, 0); n < limit; n++) + { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) + { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ + } + } + } } -void luaC_upvdeccount (lua_State *L, UpVal *uv) { - lua_assert(uv->refcount > 0); - uv->refcount--; - if (uv->refcount == 0 && !upisopen(uv)) - luaM_free(L, uv); +void luaC_upvdeccount(lua_State* L, UpVal* uv) +{ + lua_assert(uv->refcount > 0); + uv->refcount--; + if (uv->refcount == 0 && !upisopen(uv)) + luaM_free(L, uv); } -static void freeLclosure (lua_State *L, LClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) { - UpVal *uv = cl->upvals[i]; - if (uv) - luaC_upvdeccount(L, uv); - } - luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); +static void freeLclosure(lua_State* L, LClosure* cl) +{ + int i; + for (i = 0; i < cl->nupvalues; i++) + { + UpVal* uv = cl->upvals[i]; + if (uv) + luaC_upvdeccount(L, uv); + } + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); } -static void freeobj (lua_State *L, GCObject *o) { - switch (o->tt) { - case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; - case LUA_TLCL: { - freeLclosure(L, gco2lcl(o)); - break; - } - case LUA_TCCL: { - luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); - break; - } - case LUA_TTABLE: luaH_free(L, gco2t(o)); break; - case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; - case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; - case LUA_TSHRSTR: - luaS_remove(L, gco2ts(o)); /* remove it from hash table */ - luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); - break; - case LUA_TLNGSTR: { - luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); - break; - } - default: lua_assert(0); - } +static void freeobj(lua_State* L, GCObject* o) +{ + switch (o->tt) + { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); + break; + case LUA_TLCL: + { + freeLclosure(L, gco2lcl(o)); + break; + } + case LUA_TCCL: + { + luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); + break; + } + case LUA_TTABLE: luaH_free(L, gco2t(o)); + break; + case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); + break; + case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); + break; + case LUA_TSHRSTR: + luaS_remove(L, gco2ts(o)); /* remove it from hash table */ + luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); + break; + case LUA_TLNGSTR: + { + luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); + break; + } + default: lua_assert(0); + } } #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) -static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); +static GCObject** sweeplist(lua_State* L, GCObject** p, lu_mem count); /* @@ -731,35 +827,44 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); ** collection cycle. Return where to continue the traversal or NULL if ** list is finished. */ -static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { - global_State *g = G(L); - int ow = otherwhite(g); - int white = luaC_white(g); /* current white */ - while (*p != NULL && count-- > 0) { - GCObject *curr = *p; - int marked = curr->marked; - if (isdeadm(ow, marked)) { /* is 'curr' dead? */ - *p = curr->next; /* remove 'curr' from list */ - freeobj(L, curr); /* erase 'curr' */ - } - else { /* change mark to 'white' */ - curr->marked = cast_byte((marked & maskcolors) | white); - p = &curr->next; /* go to next element */ - } - } - return (*p == NULL) ? NULL : p; +static GCObject** sweeplist(lua_State* L, GCObject** p, lu_mem count) +{ + global_State* g = G(L); + int ow = otherwhite(g); + int white = luaC_white(g); /* current white */ + while (*p != NULL && count-- > 0) + { + GCObject* curr = *p; + int marked = curr->marked; + if (isdeadm(ow, marked)) + { + /* is 'curr' dead? */ + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else + { + /* change mark to 'white' */ + curr->marked = cast_byte((marked & maskcolors) | white); + p = &curr->next; /* go to next element */ + } + } + return (*p == NULL) ? NULL : p; } /* ** sweep a list until a live object (or end of list) */ -static GCObject **sweeptolive (lua_State *L, GCObject **p) { - GCObject **old = p; - do { - p = sweeplist(L, p, 1); - } while (p == old); - return p; +static GCObject** sweeptolive(lua_State* L, GCObject** p) +{ + GCObject** old = p; + do + { + p = sweeplist(L, p, 1); + } + while (p == old); + return p; } /* }====================================================== */ @@ -774,101 +879,116 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) { /* ** If possible, shrink string table */ -static void checkSizes (lua_State *L, global_State *g) { - if (g->gckind != KGC_EMERGENCY) { - l_mem olddebt = g->GCdebt; - if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ - luaS_resize(L, g->strt.size / 2); /* shrink it a little */ - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ - } +static void checkSizes(lua_State* L, global_State* g) +{ + if (g->gckind != KGC_EMERGENCY) + { + l_mem olddebt = g->GCdebt; + if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ + luaS_resize(L, g->strt.size / 2); /* shrink it a little */ + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + } } -static GCObject *udata2finalize (global_State *g) { - GCObject *o = g->tobefnz; /* get first element */ - lua_assert(tofinalize(o)); - g->tobefnz = o->next; /* remove it from 'tobefnz' list */ - o->next = g->allgc; /* return it to 'allgc' list */ - g->allgc = o; - resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ - if (issweepphase(g)) - makewhite(g, o); /* "sweep" object */ - return o; +static GCObject* udata2finalize(global_State* g) +{ + GCObject* o = g->tobefnz; /* get first element */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) + makewhite(g, o); /* "sweep" object */ + return o; } -static void dothecall (lua_State *L, void *ud) { - UNUSED(ud); - luaD_callnoyield(L, L->top - 2, 0); +static void dothecall(lua_State* L, void* ud) +{ + UNUSED(ud); + luaD_callnoyield(L, L->top - 2, 0); } -static void GCTM (lua_State *L, int propagateerrors) { - global_State *g = G(L); - const TValue *tm; - TValue v; - setgcovalue(L, &v, udata2finalize(g)); - tm = luaT_gettmbyobj(L, &v, TM_GC); - if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ - int status; - lu_byte oldah = L->allowhook; - int running = g->gcrunning; - L->allowhook = 0; /* stop debug hooks during GC metamethod */ - g->gcrunning = 0; /* avoid GC steps */ - setobj2s(L, L->top, tm); /* push finalizer... */ - setobj2s(L, L->top + 1, &v); /* ... and its argument */ - L->top += 2; /* and (next line) call the finalizer */ - L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ - status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); - L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ - L->allowhook = oldah; /* restore hooks */ - g->gcrunning = running; /* restore state */ - if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ - if (status == LUA_ERRRUN) { /* is there an error object? */ - const char *msg = (ttisstring(L->top - 1)) - ? svalue(L->top - 1) - : "no message"; - luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); - status = LUA_ERRGCMM; /* error in __gc metamethod */ - } - luaD_throw(L, status); /* re-throw error */ - } - } +static void GCTM(lua_State* L, int propagateerrors) +{ + global_State* g = G(L); + const TValue* tm; + TValue v; + setgcovalue(L, &v, udata2finalize(g)); + tm = luaT_gettmbyobj(L, &v, TM_GC); + if (tm != NULL && ttisfunction(tm)) + { + /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; + int running = g->gcrunning; + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + setobj2s(L, L->top + 1, &v); /* ... and its argument */ + L->top += 2; /* and (next line) call the finalizer */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ + g->gcrunning = running; /* restore state */ + if (status != LUA_OK && propagateerrors) + { + /* error while running __gc? */ + if (status == LUA_ERRRUN) + { + /* is there an error object? */ + const char* msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-throw error */ + } + } } /* ** call a few (up to 'g->gcfinnum') finalizers */ -static int runafewfinalizers (lua_State *L) { - global_State *g = G(L); - unsigned int i; - lua_assert(!g->tobefnz || g->gcfinnum > 0); - for (i = 0; g->tobefnz && i < g->gcfinnum; i++) - GCTM(L, 1); /* call one finalizer */ - g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ - : g->gcfinnum * 2; /* else call a few more next time */ - return i; +static int runafewfinalizers(lua_State* L) +{ + global_State* g = G(L); + unsigned int i; + lua_assert(!g->tobefnz || g->gcfinnum > 0); + for (i = 0; g->tobefnz && i < g->gcfinnum; i++) + GCTM(L, 1); /* call one finalizer */ + g->gcfinnum = (!g->tobefnz) + ? 0 /* nothing more to finalize? */ + : g->gcfinnum * 2; /* else call a few more next time */ + return i; } /* ** call all pending finalizers */ -static void callallpendingfinalizers (lua_State *L) { - global_State *g = G(L); - while (g->tobefnz) - GCTM(L, 0); +static void callallpendingfinalizers(lua_State* L) +{ + global_State* g = G(L); + while (g->tobefnz) + GCTM(L, 0); } /* ** find last 'next' field in list 'p' list (to add elements in its end) */ -static GCObject **findlast (GCObject **p) { - while (*p != NULL) - p = &(*p)->next; - return p; +static GCObject** findlast(GCObject** p) +{ + while (*p != NULL) + p = &(*p)->next; + return p; } @@ -876,21 +996,25 @@ static GCObject **findlast (GCObject **p) { ** move all unreachable objects (or 'all' objects) that need ** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ -static void separatetobefnz (global_State *g, int all) { - GCObject *curr; - GCObject **p = &g->finobj; - GCObject **lastnext = findlast(&g->tobefnz); - while ((curr = *p) != NULL) { /* traverse all finalizable objects */ - lua_assert(tofinalize(curr)); - if (!(iswhite(curr) || all)) /* not being collected? */ - p = &curr->next; /* don't bother with it */ - else { - *p = curr->next; /* remove 'curr' from 'finobj' list */ - curr->next = *lastnext; /* link at the end of 'tobefnz' list */ - *lastnext = curr; - lastnext = &curr->next; - } - } +static void separatetobefnz(global_State* g, int all) +{ + GCObject* curr; + GCObject** p = &g->finobj; + GCObject** lastnext = findlast(&g->tobefnz); + while ((curr = *p) != NULL) + { + /* traverse all finalizable objects */ + lua_assert(tofinalize(curr)); + if (!(iswhite(curr) || all)) /* not being collected? */ + p = &curr->next; /* don't bother with it */ + else + { + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &curr->next; + } + } } @@ -898,31 +1022,34 @@ static void separatetobefnz (global_State *g, int all) { ** if object 'o' has a finalizer, remove it from 'allgc' list (must ** search the list to find it) and link it in 'finobj' list. */ -void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { - global_State *g = G(L); - if (tofinalize(o) || /* obj. is already marked... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ - return; /* nothing to be done */ - else { /* move 'o' to 'finobj' list */ - GCObject **p; - if (issweepphase(g)) { - makewhite(g, o); /* "sweep" object 'o' */ - if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ - g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ - } - /* search for pointer pointing to 'o' */ - for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } - *p = o->next; /* remove 'o' from 'allgc' list */ - o->next = g->finobj; /* link it in 'finobj' list */ - g->finobj = o; - l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ - } +void luaC_checkfinalizer(lua_State* L, GCObject* o, Table* mt) +{ + global_State* g = G(L); + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + return; /* nothing to be done */ + else + { + /* move 'o' to 'finobj' list */ + GCObject** p; + if (issweepphase(g)) + { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ + } + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ + g->finobj = o; + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ + } } /* }====================================================== */ - /* ** {====================================================== ** GC control @@ -936,15 +1063,16 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** should be OK: it cannot be zero (because Lua cannot even start with ** less than PAUSEADJ bytes). */ -static void setpause (global_State *g) { - l_mem threshold, debt; - l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ - lua_assert(estimate > 0); - threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ - ? estimate * g->gcpause /* no overflow */ - : MAX_LMEM; /* overflow; truncate to maximum */ - debt = gettotalbytes(g) - threshold; - luaE_setdebt(g, debt); +static void setpause(global_State* g) +{ + l_mem threshold, debt; + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); + threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * g->gcpause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = gettotalbytes(g) - threshold; + luaE_setdebt(g, debt); } @@ -955,144 +1083,170 @@ static void setpause (global_State *g) { ** not need to skip objects created between "now" and the start of the ** real sweep. */ -static void entersweep (lua_State *L) { - global_State *g = G(L); - g->gcstate = GCSswpallgc; - lua_assert(g->sweepgc == NULL); - g->sweepgc = sweeplist(L, &g->allgc, 1); +static void entersweep(lua_State* L) +{ + global_State* g = G(L); + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); + g->sweepgc = sweeplist(L, &g->allgc, 1); } -void luaC_freeallobjects (lua_State *L) { - global_State *g = G(L); - separatetobefnz(g, 1); /* separate all objects with finalizers */ - lua_assert(g->finobj == NULL); - callallpendingfinalizers(L); - lua_assert(g->tobefnz == NULL); - g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ - g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); - sweepwholelist(L, &g->allgc); - sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ - lua_assert(g->strt.nuse == 0); +void luaC_freeallobjects(lua_State* L) +{ + global_State* g = G(L); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L); + lua_assert(g->tobefnz == NULL); + g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->finobj); + sweepwholelist(L, &g->allgc); + sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ + lua_assert(g->strt.nuse == 0); } -static l_mem atomic (lua_State *L) { - global_State *g = G(L); - l_mem work; - GCObject *origweak, *origall; - GCObject *grayagain = g->grayagain; /* save original list */ - lua_assert(g->ephemeron == NULL && g->weak == NULL); - lua_assert(!iswhite(g->mainthread)); - g->gcstate = GCSinsideatomic; - g->GCmemtrav = 0; /* start counting work */ - markobject(g, L); /* mark running thread */ - /* registry and global metatables may be changed by API */ - markvalue(g, &g->l_registry); - markmt(g); /* mark global metatables */ - /* remark occasional upvalues of (maybe) dead threads */ - remarkupvals(g); - propagateall(g); /* propagate changes */ - work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ - g->gray = grayagain; - propagateall(g); /* traverse 'grayagain' list */ - g->GCmemtrav = 0; /* restart counting */ - convergeephemerons(g); - /* at this point, all strongly accessible objects are marked. */ - /* Clear values from weak tables, before checking finalizers */ - clearvalues(g, g->weak, NULL); - clearvalues(g, g->allweak, NULL); - origweak = g->weak; origall = g->allweak; - work += g->GCmemtrav; /* stop counting (objects being finalized) */ - separatetobefnz(g, 0); /* separate objects to be finalized */ - g->gcfinnum = 1; /* there may be objects to be finalized */ - markbeingfnz(g); /* mark objects that will be finalized */ - propagateall(g); /* remark, to propagate 'resurrection' */ - g->GCmemtrav = 0; /* restart counting */ - convergeephemerons(g); - /* at this point, all resurrected objects are marked. */ - /* remove dead objects from weak tables */ - clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ - /* clear values from resurrected weak tables */ - clearvalues(g, g->weak, origweak); - clearvalues(g, g->allweak, origall); - luaS_clearcache(g); - g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - work += g->GCmemtrav; /* complete counting */ - return work; /* estimate of memory marked by 'atomic' */ +static l_mem atomic(lua_State* L) +{ + global_State* g = G(L); + l_mem work; + GCObject *origweak, *origall; + GCObject* grayagain = g->grayagain; /* save original list */ + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSinsideatomic; + g->GCmemtrav = 0; /* start counting work */ + markobject(g, L); /* mark running thread */ + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark global metatables */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + propagateall(g); /* propagate changes */ + work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ + g->gray = grayagain; + propagateall(g); /* traverse 'grayagain' list */ + g->GCmemtrav = 0; /* restart counting */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* Clear values from weak tables, before checking finalizers */ + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); + origweak = g->weak; + origall = g->allweak; + work += g->GCmemtrav; /* stop counting (objects being finalized) */ + separatetobefnz(g, 0); /* separate objects to be finalized */ + g->gcfinnum = 1; /* there may be objects to be finalized */ + markbeingfnz(g); /* mark objects that will be finalized */ + propagateall(g); /* remark, to propagate 'resurrection' */ + g->GCmemtrav = 0; /* restart counting */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak tables */ + clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ + /* clear values from resurrected weak tables */ + clearvalues(g, g->weak, origweak); + clearvalues(g, g->allweak, origall); + luaS_clearcache(g); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ } -static lu_mem sweepstep (lua_State *L, global_State *g, - int nextstate, GCObject **nextlist) { - if (g->sweepgc) { - l_mem olddebt = g->GCdebt; - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ - if (g->sweepgc) /* is there still something to sweep? */ - return (GCSWEEPMAX * GCSWEEPCOST); - } - /* else enter next state */ - g->gcstate = nextstate; - g->sweepgc = nextlist; - return 0; +static lu_mem sweepstep(lua_State* L, global_State* g, + int nextstate, GCObject** nextlist) +{ + if (g->sweepgc) + { + l_mem olddebt = g->GCdebt; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + if (g->sweepgc) /* is there still something to sweep? */ + return (GCSWEEPMAX * GCSWEEPCOST); + } + /* else enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; } -static lu_mem singlestep (lua_State *L) { - global_State *g = G(L); - switch (g->gcstate) { - case GCSpause: { - g->GCmemtrav = g->strt.size * sizeof(GCObject*); - restartcollection(g); - g->gcstate = GCSpropagate; - return g->GCmemtrav; - } - case GCSpropagate: { - g->GCmemtrav = 0; - lua_assert(g->gray); - propagatemark(g); - if (g->gray == NULL) /* no more gray objects? */ - g->gcstate = GCSatomic; /* finish propagate phase */ - return g->GCmemtrav; /* memory traversed in this step */ - } - case GCSatomic: { - lu_mem work; - propagateall(g); /* make sure gray list is empty */ - work = atomic(L); /* work is what was traversed by 'atomic' */ - entersweep(L); - g->GCestimate = gettotalbytes(g); /* first estimate */; - return work; - } - case GCSswpallgc: { /* sweep "regular" objects */ - return sweepstep(L, g, GCSswpfinobj, &g->finobj); - } - case GCSswpfinobj: { /* sweep objects with finalizers */ - return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); - } - case GCSswptobefnz: { /* sweep objects to be finalized */ - return sweepstep(L, g, GCSswpend, NULL); - } - case GCSswpend: { /* finish sweeps */ - makewhite(g, g->mainthread); /* sweep main thread */ - checkSizes(L, g); - g->gcstate = GCScallfin; - return 0; - } - case GCScallfin: { /* call remaining finalizers */ - if (g->tobefnz && g->gckind != KGC_EMERGENCY) { - int n = runafewfinalizers(L); - return (n * GCFINALIZECOST); - } - else { /* emergency mode or no more finalizers */ - g->gcstate = GCSpause; /* finish collection */ - return 0; - } - } - default: lua_assert(0); return 0; - } +static lu_mem singlestep(lua_State* L) +{ + global_State* g = G(L); + switch (g->gcstate) + { + case GCSpause: + { + g->GCmemtrav = g->strt.size * sizeof(GCObject*); + restartcollection(g); + g->gcstate = GCSpropagate; + return g->GCmemtrav; + } + case GCSpropagate: + { + g->GCmemtrav = 0; + lua_assert(g->gray); + propagatemark(g); + if (g->gray == NULL) /* no more gray objects? */ + g->gcstate = GCSatomic; /* finish propagate phase */ + return g->GCmemtrav; /* memory traversed in this step */ + } + case GCSatomic: + { + lu_mem work; + propagateall(g); /* make sure gray list is empty */ + work = atomic(L); /* work is what was traversed by 'atomic' */ + entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */ + ; + return work; + } + case GCSswpallgc: + { + /* sweep "regular" objects */ + return sweepstep(L, g, GCSswpfinobj, &g->finobj); + } + case GCSswpfinobj: + { + /* sweep objects with finalizers */ + return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + } + case GCSswptobefnz: + { + /* sweep objects to be finalized */ + return sweepstep(L, g, GCSswpend, NULL); + } + case GCSswpend: + { + /* finish sweeps */ + makewhite(g, g->mainthread); /* sweep main thread */ + checkSizes(L, g); + g->gcstate = GCScallfin; + return 0; + } + case GCScallfin: + { + /* call remaining finalizers */ + if (g->tobefnz && g->gckind != KGC_EMERGENCY) + { + int n = runafewfinalizers(L); + return (n * GCFINALIZECOST); + } + else + { + /* emergency mode or no more finalizers */ + g->gcstate = GCSpause; /* finish collection */ + return 0; + } + } + default: lua_assert(0); + return 0; + } } @@ -1100,10 +1254,11 @@ static lu_mem singlestep (lua_State *L) { ** advances the garbage collector until it reaches a state allowed ** by 'statemask' */ -void luaC_runtilstate (lua_State *L, int statesmask) { - global_State *g = G(L); - while (!testbit(statesmask, g->gcstate)) - singlestep(L); +void luaC_runtilstate(lua_State* L, int statesmask) +{ + global_State* g = G(L); + while (!testbit(statesmask, g->gcstate)) + singlestep(L); } @@ -1111,38 +1266,47 @@ void luaC_runtilstate (lua_State *L, int statesmask) { ** get GC debt and convert it from Kb to 'work units' (avoid zero debt ** and overflows) */ -static l_mem getdebt (global_State *g) { - l_mem debt = g->GCdebt; - int stepmul = g->gcstepmul; - if (debt <= 0) return 0; /* minimal debt */ - else { - debt = (debt / STEPMULADJ) + 1; - debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; - return debt; - } +static l_mem getdebt(global_State* g) +{ + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (debt <= 0) return 0; /* minimal debt */ + else + { + debt = (debt / STEPMULADJ) + 1; + debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; + return debt; + } } /* ** performs a basic GC step when collector is running */ -void luaC_step (lua_State *L) { - global_State *g = G(L); - l_mem debt = getdebt(g); /* GC deficit (be paid now) */ - if (!g->gcrunning) { /* not running? */ - luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ - return; - } - do { /* repeat until pause or enough "credit" (negative debt) */ - lu_mem work = singlestep(L); /* perform one single step */ - debt -= work; - } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); - if (g->gcstate == GCSpause) - setpause(g); /* pause until next cycle */ - else { - debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ - luaE_setdebt(g, debt); - runafewfinalizers(L); - } +void luaC_step(lua_State* L) +{ + global_State* g = G(L); + l_mem debt = getdebt(g); /* GC deficit (be paid now) */ + if (!g->gcrunning) + { + /* not running? */ + luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ + return; + } + do + { + /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ + debt -= work; + } + while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + setpause(g); /* pause until next cycle */ + else + { + debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + luaE_setdebt(g, debt); + runafewfinalizers(L); + } } @@ -1155,24 +1319,25 @@ void luaC_step (lua_State *L) { ** to sweep all objects to turn them back to white (as white has not ** changed, nothing will be collected). */ -void luaC_fullgc (lua_State *L, int isemergency) { - global_State *g = G(L); - lua_assert(g->gckind == KGC_NORMAL); - if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ - if (keepinvariant(g)) { /* black objects? */ - entersweep(L); /* sweep everything to turn them back to white */ - } - /* finish any pending sweep phase to start a new cycle */ - luaC_runtilstate(L, bitmask(GCSpause)); - luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ - luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ - /* estimate must be correct after a full GC cycle */ - lua_assert(g->GCestimate == gettotalbytes(g)); - luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ - g->gckind = KGC_NORMAL; - setpause(g); +void luaC_fullgc(lua_State* L, int isemergency) +{ + global_State* g = G(L); + lua_assert(g->gckind == KGC_NORMAL); + if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ + if (keepinvariant(g)) + { + /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ + } + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + g->gckind = KGC_NORMAL; + setpause(g); } /* }====================================================== */ - - diff --git a/Lua/lgc.h b/Lua/lgc.h index aed3e18..3a2a27c 100644 --- a/Lua/lgc.h +++ b/Lua/lgc.h @@ -25,7 +25,6 @@ */ - /* how much to allocate before next GC step */ #if !defined(GCSTEPSIZE) /* ~100 small strings */ @@ -131,17 +130,17 @@ (iscollectable((uv)->v) && !upisopen(uv)) ? \ luaC_upvalbarrier_(L,uv) : cast_void(0)) -LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); -LUAI_FUNC void luaC_freeallobjects (lua_State *L); -LUAI_FUNC void luaC_step (lua_State *L); -LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); -LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); -LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); -LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); -LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); -LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); -LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_fix(lua_State* L, GCObject* o); +LUAI_FUNC void luaC_freeallobjects(lua_State* L); +LUAI_FUNC void luaC_step(lua_State* L); +LUAI_FUNC void luaC_runtilstate(lua_State* L, int statesmask); +LUAI_FUNC void luaC_fullgc(lua_State* L, int isemergency); +LUAI_FUNC GCObject* luaC_newobj(lua_State* L, int tt, size_t sz); +LUAI_FUNC void luaC_barrier_(lua_State* L, GCObject* o, GCObject* v); +LUAI_FUNC void luaC_barrierback_(lua_State* L, Table* o); +LUAI_FUNC void luaC_upvalbarrier_(lua_State* L, UpVal* uv); +LUAI_FUNC void luaC_checkfinalizer(lua_State* L, GCObject* o, Table* mt); +LUAI_FUNC void luaC_upvdeccount(lua_State* L, UpVal* uv); #endif diff --git a/Lua/linit.c b/Lua/linit.c index afcaf98..9abd109 100644 --- a/Lua/linit.c +++ b/Lua/linit.c @@ -40,29 +40,30 @@ ** program */ static const luaL_Reg loadedlibs[] = { - {"_G", luaopen_base}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_COLIBNAME, luaopen_coroutine}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_OSLIBNAME, luaopen_os}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_UTF8LIBNAME, luaopen_utf8}, - {LUA_DBLIBNAME, luaopen_debug}, + {"_G", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, + {LUA_DBLIBNAME, luaopen_debug}, #if defined(LUA_COMPAT_BITLIB) {LUA_BITLIBNAME, luaopen_bit32}, #endif - {NULL, NULL} + {NULL, NULL} }; -LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_Reg *lib; - /* "require" functions from 'loadedlibs' and set results to global table */ - for (lib = loadedlibs; lib->func; lib++) { - luaL_requiref(L, lib->name, lib->func, 1); - lua_pop(L, 1); /* remove lib */ - } +LUALIB_API void luaL_openlibs(lua_State* L) +{ + const luaL_Reg* lib; + /* "require" functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) + { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } } - diff --git a/Lua/liolib.c b/Lua/liolib.c index 1568403..cbc6743 100644 --- a/Lua/liolib.c +++ b/Lua/liolib.c @@ -23,8 +23,6 @@ #include "lualib.h" - - /* ** Change this macro to accept other modes for 'fopen' besides ** the standard ones. @@ -37,10 +35,11 @@ #endif /* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ -static int l_checkmode (const char *mode) { - return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && - (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ - (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ +static int l_checkmode(const char* mode) +{ + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && + (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ + (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ } #endif @@ -147,36 +146,39 @@ typedef luaL_Stream LStream; #define isclosed(p) ((p)->closef == NULL) -static int io_type (lua_State *L) { - LStream *p; - luaL_checkany(L, 1); - p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); - if (p == NULL) - lua_pushnil(L); /* not a file */ - else if (isclosed(p)) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; +static int io_type(lua_State* L) +{ + LStream* p; + luaL_checkany(L, 1); + p = (LStream*)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + lua_pushnil(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; } -static int f_tostring (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - lua_pushliteral(L, "file (closed)"); - else - lua_pushfstring(L, "file (%p)", p->f); - return 1; +static int f_tostring(lua_State* L) +{ + LStream* p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; } -static FILE *tofile (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - luaL_error(L, "attempt to use a closed file"); - lua_assert(p->f); - return p->f; +static FILE* tofile(lua_State* L) +{ + LStream* p = tolstream(L); + if (isclosed(p)) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; } @@ -185,11 +187,12 @@ static FILE *tofile (lua_State *L) { ** before opening the actual file; so, if there is a memory error, the ** handle is in a consistent state. */ -static LStream *newprefile (lua_State *L) { - LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); - p->closef = NULL; /* mark file handle as 'closed' */ - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; +static LStream* newprefile(lua_State* L) +{ + LStream* p = (LStream*)lua_newuserdata(L, sizeof(LStream)); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; } @@ -198,131 +201,147 @@ static LStream *newprefile (lua_State *L) { ** a bug in some versions of the Clang compiler (e.g., clang 3.0 for ** 32 bits). */ -static int aux_close (lua_State *L) { - LStream *p = tolstream(L); - volatile lua_CFunction cf = p->closef; - p->closef = NULL; /* mark stream as closed */ - return (*cf)(L); /* close it */ +static int aux_close(lua_State* L) +{ + LStream* p = tolstream(L); + volatile lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ } -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ - tofile(L); /* make sure argument is an open stream */ - return aux_close(L); +static int io_close(lua_State* L) +{ + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); } -static int f_gc (lua_State *L) { - LStream *p = tolstream(L); - if (!isclosed(p) && p->f != NULL) - aux_close(L); /* ignore closed and incompletely open files */ - return 0; +static int f_gc(lua_State* L) +{ + LStream* p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; } /* ** function to close regular files */ -static int io_fclose (lua_State *L) { - LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); +static int io_fclose(lua_State* L) +{ + LStream* p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); } -static LStream *newfile (lua_State *L) { - LStream *p = newprefile(L); - p->f = NULL; - p->closef = &io_fclose; - return p; +static LStream* newfile(lua_State* L) +{ + LStream* p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; } -static void opencheck (lua_State *L, const char *fname, const char *mode) { - LStream *p = newfile(L); - p->f = fopen(fname, mode); - if (p->f == NULL) - luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); +static void opencheck(lua_State* L, const char* fname, const char* mode) +{ + LStream* p = newfile(L); + p->f = fopen(fname, mode); + if (p->f == NULL) + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); } -static int io_open (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newfile(L); - const char *md = mode; /* to traverse/check mode */ - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - p->f = fopen(filename, mode); - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +static int io_open(lua_State* L) +{ + const char* filename = luaL_checkstring(L, 1); + const char* mode = luaL_optstring(L, 2, "r"); + LStream* p = newfile(L); + const char* md = mode; /* to traverse/check mode */ + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + p->f = fopen(filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } /* ** function to close 'popen' files */ -static int io_pclose (lua_State *L) { - LStream *p = tolstream(L); - return luaL_execresult(L, l_pclose(L, p->f)); +static int io_pclose(lua_State* L) +{ + LStream* p = tolstream(L); + return luaL_execresult(L, l_pclose(L, p->f)); } -static int io_popen (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newprefile(L); - p->f = l_popen(L, filename, mode); - p->closef = &io_pclose; - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +static int io_popen(lua_State* L) +{ + const char* filename = luaL_checkstring(L, 1); + const char* mode = luaL_optstring(L, 2, "r"); + LStream* p = newprefile(L); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } -static int io_tmpfile (lua_State *L) { - LStream *p = newfile(L); - p->f = tmpfile(); - return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +static int io_tmpfile(lua_State* L) +{ + LStream* p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } -static FILE *getiofile (lua_State *L, const char *findex) { - LStream *p; - lua_getfield(L, LUA_REGISTRYINDEX, findex); - p = (LStream *)lua_touserdata(L, -1); - if (isclosed(p)) - luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); - return p->f; +static FILE* getiofile(lua_State* L, const char* findex) +{ + LStream* p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream*)lua_touserdata(L, -1); + if (isclosed(p)) + luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); + return p->f; } -static int g_iofile (lua_State *L, const char *f, const char *mode) { - if (!lua_isnoneornil(L, 1)) { - const char *filename = lua_tostring(L, 1); - if (filename) - opencheck(L, filename, mode); - else { - tofile(L); /* check that it's a valid file handle */ - lua_pushvalue(L, 1); - } - lua_setfield(L, LUA_REGISTRYINDEX, f); - } - /* return current value */ - lua_getfield(L, LUA_REGISTRYINDEX, f); - return 1; +static int g_iofile(lua_State* L, const char* f, const char* mode) +{ + if (!lua_isnoneornil(L, 1)) + { + const char* filename = lua_tostring(L, 1); + if (filename) + opencheck(L, filename, mode); + else + { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; } -static int io_input (lua_State *L) { - return g_iofile(L, IO_INPUT, "r"); +static int io_input(lua_State* L) +{ + return g_iofile(L, IO_INPUT, "r"); } -static int io_output (lua_State *L) { - return g_iofile(L, IO_OUTPUT, "w"); +static int io_output(lua_State* L) +{ + return g_iofile(L, IO_OUTPUT, "w"); } -static int io_readline (lua_State *L); +static int io_readline(lua_State* L); /* @@ -331,40 +350,47 @@ static int io_readline (lua_State *L); */ #define MAXARGLINE 250 -static void aux_lines (lua_State *L, int toclose) { - int n = lua_gettop(L) - 1; /* number of arguments to read */ - luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); - lua_pushinteger(L, n); /* number of arguments to read */ - lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ - lua_pushcclosure(L, io_readline, 3 + n); +static void aux_lines(lua_State* L, int toclose) +{ + int n = lua_gettop(L) - 1; /* number of arguments to read */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); + lua_pushinteger(L, n); /* number of arguments to read */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ + lua_pushcclosure(L, io_readline, 3 + n); } -static int f_lines (lua_State *L) { - tofile(L); /* check that it's a valid file handle */ - aux_lines(L, 0); - return 1; +static int f_lines(lua_State* L) +{ + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 0); + return 1; } -static int io_lines (lua_State *L) { - int toclose; - if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ - if (lua_isnil(L, 1)) { /* no file name? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ - lua_replace(L, 1); /* put it at index 1 */ - tofile(L); /* check that it's a valid file handle */ - toclose = 0; /* do not close it after iteration */ - } - else { /* open a new file */ - const char *filename = luaL_checkstring(L, 1); - opencheck(L, filename, "r"); - lua_replace(L, 1); /* put file at index 1 */ - toclose = 1; /* close it after iteration */ - } - aux_lines(L, toclose); - return 1; +static int io_lines(lua_State* L) +{ + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) + { + /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ + } + else + { + /* open a new file */ + const char* filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); + return 1; } @@ -382,48 +408,55 @@ static int io_lines (lua_State *L) { /* auxiliary structure used by 'read_number' */ -typedef struct { - FILE *f; /* file being read */ - int c; /* current character (look ahead) */ - int n; /* number of elements in buffer 'buff' */ - char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +typedef struct +{ + FILE* f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ } RN; /* ** Add current char to buffer (if not out of space) and read next one */ -static int nextc (RN *rn) { - if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ - rn->buff[0] = '\0'; /* invalidate result */ - return 0; /* fail */ - } - else { - rn->buff[rn->n++] = rn->c; /* save current char */ - rn->c = l_getc(rn->f); /* read next one */ - return 1; - } +static int nextc(RN* rn) +{ + if (rn->n >= L_MAXLENNUM) + { + /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ + } + else + { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } } /* ** Accept current char if it is in 'set' (of size 2) */ -static int test2 (RN *rn, const char *set) { - if (rn->c == set[0] || rn->c == set[1]) - return nextc(rn); - else return 0; +static int test2(RN* rn, const char* set) +{ + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; } /* ** Read a sequence of (hex)digits */ -static int readdigits (RN *rn, int hex) { - int count = 0; - while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) - count++; - return count; +static int readdigits(RN* rn, int hex) +{ + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; } @@ -432,260 +465,306 @@ static int readdigits (RN *rn, int hex) { ** Then it calls 'lua_stringtonumber' to check whether the format is ** correct and to convert it to a Lua number */ -static int read_number (lua_State *L, FILE *f) { - RN rn; - int count = 0; - int hex = 0; - char decp[2]; - rn.f = f; rn.n = 0; - decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ - decp[1] = '.'; /* always accept a dot */ - l_lockfile(rn.f); - do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ - test2(&rn, "-+"); /* optional signal */ - if (test2(&rn, "00")) { - if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ - else count = 1; /* count initial '0' as a valid digit */ - } - count += readdigits(&rn, hex); /* integral part */ - if (test2(&rn, decp)) /* decimal point? */ - count += readdigits(&rn, hex); /* fractional part */ - if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ - test2(&rn, "-+"); /* exponent signal */ - readdigits(&rn, 0); /* exponent digits */ - } - ungetc(rn.c, rn.f); /* unread look-ahead char */ - l_unlockfile(rn.f); - rn.buff[rn.n] = '\0'; /* finish string */ - if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ - return 1; /* ok */ - else { /* invalid format */ - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ - } +static int read_number(lua_State* L, FILE* f) +{ + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; + rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } + while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "00")) + { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) + { + /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else + { + /* invalid format */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } } -static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); - ungetc(c, f); /* no-op when c == EOF */ - lua_pushliteral(L, ""); - return (c != EOF); +static int test_eof(lua_State* L, FILE* f) +{ + int c = getc(f); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); + return (c != EOF); } -static int read_line (lua_State *L, FILE *f, int chop) { - luaL_Buffer b; - int c = '\0'; - luaL_buffinit(L, &b); - while (c != EOF && c != '\n') { /* repeat until end of line */ - char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ - int i = 0; - l_lockfile(f); /* no memory errors can happen inside the lock */ - while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') - buff[i++] = c; - l_unlockfile(f); - luaL_addsize(&b, i); - } - if (!chop && c == '\n') /* want a newline and have one? */ - luaL_addchar(&b, c); /* add ending newline to result */ - luaL_pushresult(&b); /* close buffer */ - /* return ok if read something (either a newline or something else) */ - return (c == '\n' || lua_rawlen(L, -1) > 0); +static int read_line(lua_State* L, FILE* f, int chop) +{ + luaL_Buffer b; + int c = '\0'; + luaL_buffinit(L, &b); + while (c != EOF && c != '\n') + { + /* repeat until end of line */ + char* buff = luaL_prepbuffer(&b); /* preallocate buffer */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; + l_unlockfile(f); + luaL_addsize(&b, i); + } + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); } -static void read_all (lua_State *L, FILE *f) { - size_t nr; - luaL_Buffer b; - luaL_buffinit(L, &b); - do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ - char *p = luaL_prepbuffer(&b); - nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); - luaL_addsize(&b, nr); - } while (nr == LUAL_BUFFERSIZE); - luaL_pushresult(&b); /* close buffer */ +static void read_all(lua_State* L, FILE* f) +{ + size_t nr; + luaL_Buffer b; + luaL_buffinit(L, &b); + do + { + /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char* p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); + luaL_addsize(&b, nr); + } + while (nr == LUAL_BUFFERSIZE); + luaL_pushresult(&b); /* close buffer */ } -static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t nr; /* number of chars actually read */ - char *p; - luaL_Buffer b; - luaL_buffinit(L, &b); - p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ - nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ - luaL_addsize(&b, nr); - luaL_pushresult(&b); /* close buffer */ - return (nr > 0); /* true iff read something */ +static int read_chars(lua_State* L, FILE* f, size_t n) +{ + size_t nr; /* number of chars actually read */ + char* p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); + luaL_pushresult(&b); /* close buffer */ + return (nr > 0); /* true iff read something */ } -static int g_read (lua_State *L, FILE *f, int first) { - int nargs = lua_gettop(L) - 1; - int success; - int n; - clearerr(f); - if (nargs == 0) { /* no arguments? */ - success = read_line(L, f, 1); - n = first+1; /* to return 1 result */ - } - else { /* ensure stack space for all results and for auxlib's buffer */ - luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); - success = 1; - for (n = first; nargs-- && success; n++) { - if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)luaL_checkinteger(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - const char *p = luaL_checkstring(L, n); - if (*p == '*') p++; /* skip optional '*' (for compatibility) */ - switch (*p) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f, 1); - break; - case 'L': /* line with end-of-line */ - success = read_line(L, f, 0); - break; - case 'a': /* file */ - read_all(L, f); /* read entire file */ - success = 1; /* always success */ - break; - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - if (ferror(f)) - return luaL_fileresult(L, 0, NULL); - if (!success) { - lua_pop(L, 1); /* remove last result */ - lua_pushnil(L); /* push nil instead */ - } - return n - first; +static int g_read(lua_State* L, FILE* f, int first) +{ + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) + { + /* no arguments? */ + success = read_line(L, f, 1); + n = first + 1; /* to return 1 result */ + } + else + { + /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs + LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) + { + if (lua_type(L, n) == LUA_TNUMBER) + { + size_t l = (size_t)luaL_checkinteger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else + { + const char* p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) + { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); + break; + case 'a': /* file */ + read_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + if (!success) + { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; } -static int io_read (lua_State *L) { - return g_read(L, getiofile(L, IO_INPUT), 1); +static int io_read(lua_State* L) +{ + return g_read(L, getiofile(L, IO_INPUT), 1); } -static int f_read (lua_State *L) { - return g_read(L, tofile(L), 2); +static int f_read(lua_State* L) +{ + return g_read(L, tofile(L), 2); } -static int io_readline (lua_State *L) { - LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); - int i; - int n = (int)lua_tointeger(L, lua_upvalueindex(2)); - if (isclosed(p)) /* file is already closed? */ - return luaL_error(L, "file is already closed"); - lua_settop(L , 1); - luaL_checkstack(L, n, "too many arguments"); - for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ - lua_pushvalue(L, lua_upvalueindex(3 + i)); - n = g_read(L, p->f, 2); /* 'n' is number of results */ - lua_assert(n > 0); /* should return at least a nil */ - if (lua_toboolean(L, -n)) /* read at least one value? */ - return n; /* return them */ - else { /* first result is nil: EOF or error */ - if (n > 1) { /* is there error information? */ - /* 2nd result is error message */ - return luaL_error(L, "%s", lua_tostring(L, -n + 1)); - } - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ - lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(1)); - aux_close(L); /* close it */ - } - return 0; - } +static int io_readline(lua_State* L) +{ + LStream* p = (LStream*)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + lua_settop(L, 1); + luaL_checkstack(L, n, "too many arguments"); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, p->f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (lua_toboolean(L, -n)) /* read at least one value? */ + return n; /* return them */ + else + { + /* first result is nil: EOF or error */ + if (n > 1) + { + /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } + if (lua_toboolean(L, lua_upvalueindex(3))) + { + /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } } /* }====================================================== */ -static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - arg; - int status = 1; - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - int len = lua_isinteger(L, arg) - ? fprintf(f, LUA_INTEGER_FMT, - (LUAI_UACINT)lua_tointeger(L, arg)) - : fprintf(f, LUA_NUMBER_FMT, - (LUAI_UACNUMBER)lua_tonumber(L, arg)); - status = status && (len > 0); - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - if (status) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); +static int g_write(lua_State* L, FILE* f, int arg) +{ + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) + { + if (lua_type(L, arg) == LUA_TNUMBER) + { + /* optimization: could be done exactly as for strings */ + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, + (LUAI_UACINT)lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, + (LUAI_UACNUMBER)lua_tonumber(L, arg)); + status = status && (len > 0); + } + else + { + size_t l; + const char* s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (status) return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); } -static int io_write (lua_State *L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); +static int io_write(lua_State* L) +{ + return g_write(L, getiofile(L, IO_OUTPUT), 1); } -static int f_write (lua_State *L) { - FILE *f = tofile(L); - lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ - return g_write(L, f, 2); +static int f_write(lua_State* L) +{ + FILE* f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); } -static int f_seek (lua_State *L) { - static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; - static const char *const modenames[] = {"set", "cur", "end", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Integer p3 = luaL_optinteger(L, 3, 0); - l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Integer)offset == p3, 3, - "not an integer in proper range"); - op = l_fseek(f, offset, mode[op]); - if (op) - return luaL_fileresult(L, 0, NULL); /* error */ - else { - lua_pushinteger(L, (lua_Integer)l_ftell(f)); - return 1; - } +static int f_seek(lua_State* L) +{ + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char* const modenames[] = {"set", "cur", "end", NULL}; + FILE* f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + lua_Integer p3 = luaL_optinteger(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Integer)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); + if (op) + return luaL_fileresult(L, 0, NULL); /* error */ + else + { + lua_pushinteger(L, (lua_Integer)l_ftell(f)); + return 1; + } } -static int f_setvbuf (lua_State *L) { - static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; - static const char *const modenames[] = {"no", "full", "line", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); - return luaL_fileresult(L, res == 0, NULL); +static int f_setvbuf(lua_State* L) +{ + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char* const modenames[] = {"no", "full", "line", NULL}; + FILE* f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); + return luaL_fileresult(L, res == 0, NULL); } - -static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +static int io_flush(lua_State* L) +{ + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } -static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +static int f_flush(lua_State* L) +{ + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); } @@ -693,18 +772,18 @@ static int f_flush (lua_State *L) { ** functions for 'io' library */ static const luaL_Reg iolib[] = { - {"close", io_close}, - {"flush", io_flush}, - {"input", io_input}, - {"lines", io_lines}, - {"open", io_open}, - {"output", io_output}, - {"popen", io_popen}, - {"read", io_read}, - {"tmpfile", io_tmpfile}, - {"type", io_type}, - {"write", io_write}, - {NULL, NULL} + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} }; @@ -712,60 +791,64 @@ static const luaL_Reg iolib[] = { ** methods for file handles */ static const luaL_Reg flib[] = { - {"close", io_close}, - {"flush", f_flush}, - {"lines", f_lines}, - {"read", f_read}, - {"seek", f_seek}, - {"setvbuf", f_setvbuf}, - {"write", f_write}, - {"__gc", f_gc}, - {"__tostring", f_tostring}, - {NULL, NULL} + {"close", io_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} }; -static void createmeta (lua_State *L) { - luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ - lua_pop(L, 1); /* pop new metatable */ +static void createmeta(lua_State* L) +{ + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ } /* ** function to (not) close the standard files stdin, stdout, and stderr */ -static int io_noclose (lua_State *L) { - LStream *p = tolstream(L); - p->closef = &io_noclose; /* keep file opened */ - lua_pushnil(L); - lua_pushliteral(L, "cannot close standard file"); - return 2; +static int io_noclose(lua_State* L) +{ + LStream* p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; } -static void createstdfile (lua_State *L, FILE *f, const char *k, - const char *fname) { - LStream *p = newprefile(L); - p->f = f; - p->closef = &io_noclose; - if (k != NULL) { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ - } - lua_setfield(L, -2, fname); /* add file to module */ +static void createstdfile(lua_State* L, FILE* f, const char* k, + const char* fname) +{ + LStream* p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) + { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ } -LUAMOD_API int luaopen_io (lua_State *L) { - luaL_newlib(L, iolib); /* new module */ - createmeta(L); - /* create (and set) default files */ - createstdfile(L, stdin, IO_INPUT, "stdin"); - createstdfile(L, stdout, IO_OUTPUT, "stdout"); - createstdfile(L, stderr, NULL, "stderr"); - return 1; +LUAMOD_API int luaopen_io(lua_State* L) +{ + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; } - diff --git a/Lua/llex.c b/Lua/llex.c index 7032827..d0b6dbd 100644 --- a/Lua/llex.c +++ b/Lua/llex.c @@ -28,94 +28,106 @@ #include "lzio.h" - #define next(ls) (ls->current = zgetc(ls->z)) - #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ -static const char *const luaX_tokens [] = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "goto", "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", - "//", "..", "...", "==", ">=", "<=", "~=", - "<<", ">>", "::", "", - "", "", "", "" +static const char* const luaX_tokens[] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "", + "", "", "", "" }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) -static l_noret lexerror (LexState *ls, const char *msg, int token); +static l_noret lexerror(LexState* ls, const char* msg, int token); -static void save (LexState *ls, int c) { - Mbuffer *b = ls->buff; - if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { - size_t newsize; - if (luaZ_sizebuffer(b) >= MAX_SIZE/2) - lexerror(ls, "lexical element too long", 0); - newsize = luaZ_sizebuffer(b) * 2; - luaZ_resizebuffer(ls->L, b, newsize); - } - b->buffer[luaZ_bufflen(b)++] = cast(char, c); +static void save(LexState* ls, int c) +{ + Mbuffer* b = ls->buff; + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) + { + size_t newsize; + if (luaZ_sizebuffer(b) >= MAX_SIZE / 2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[luaZ_bufflen(b)++] = cast(char, c); } -void luaX_init (lua_State *L) { - int i; - TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ - luaC_fix(L, obj2gco(e)); /* never collect this name */ - for (i=0; iextra = cast_byte(i+1); /* reserved word */ - } +void luaX_init(lua_State* L) +{ + int i; + TString* e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ + for (i = 0; i < NUM_RESERVED; i++) + { + TString* ts = luaS_new(L, luaX_tokens[i]); + luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */ + ts->extra = cast_byte(i+1); /* reserved word */ + } } -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { /* single-byte symbols? */ - lua_assert(token == cast_uchar(token)); - return luaO_pushfstring(ls->L, "'%c'", token); - } - else { - const char *s = luaX_tokens[token - FIRST_RESERVED]; - if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ - return luaO_pushfstring(ls->L, "'%s'", s); - else /* names, strings, and numerals */ - return s; - } +const char* luaX_token2str(LexState* ls, int token) +{ + if (token < FIRST_RESERVED) + { + /* single-byte symbols? */ + lua_assert(token == cast_uchar(token)); + return luaO_pushfstring(ls->L, "'%c'", token); + } + else + { + const char* s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ + return luaO_pushfstring(ls->L, "'%s'", s); + else /* names, strings, and numerals */ + return s; + } } -static const char *txtToken (LexState *ls, int token) { - switch (token) { - case TK_NAME: case TK_STRING: - case TK_FLT: case TK_INT: - save(ls, '\0'); - return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); - default: - return luaX_token2str(ls, token); - } +static const char* txtToken(LexState* ls, int token) +{ + switch (token) + { + case TK_NAME: + case TK_STRING: + case TK_FLT: + case TK_INT: + save(ls, '\0'); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); + default: + return luaX_token2str(ls, token); + } } -static l_noret lexerror (LexState *ls, const char *msg, int token) { - msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); - if (token) - luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); - luaD_throw(ls->L, LUA_ERRSYNTAX); +static l_noret lexerror(LexState* ls, const char* msg, int token) +{ + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); + if (token) + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); } -l_noret luaX_syntaxerror (LexState *ls, const char *msg) { - lexerror(ls, msg, ls->t.token); +l_noret luaX_syntaxerror(LexState* ls, const char* msg) +{ + lexerror(ls, msg, ls->t.token); } @@ -124,23 +136,28 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { ** it will not be collected until the end of the compilation ** (by that time it should be anchored somewhere) */ -TString *luaX_newstring (LexState *ls, const char *str, size_t l) { - lua_State *L = ls->L; - TValue *o; /* entry for 'str' */ - TString *ts = luaS_newlstr(L, str, l); /* create new string */ - setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, ls->h, L->top - 1); - if (ttisnil(o)) { /* not in use yet? */ - /* boolean value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setbvalue(o, 1); /* t[string] = true */ - luaC_checkGC(L); - } - else { /* string already present */ - ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ - } - L->top--; /* remove string from stack */ - return ts; +TString* luaX_newstring(LexState* ls, const char* str, size_t l) +{ + lua_State* L = ls->L; + TValue* o; /* entry for 'str' */ + TString* ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_set(L, ls->h, L->top - 1); + if (ttisnil(o)) + { + /* not in use yet? */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setbvalue(o, 1); /* t[string] = true */ + luaC_checkGC(L); + } + else + { + /* string already present */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ + } + L->top--; /* remove string from stack */ + return ts; } @@ -148,34 +165,35 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { ** increment line number and skips newline sequence (any of ** \n, \r, \n\r, or \r\n) */ -static void inclinenumber (LexState *ls) { - int old = ls->current; - lua_assert(currIsNewline(ls)); - next(ls); /* skip '\n' or '\r' */ - if (currIsNewline(ls) && ls->current != old) - next(ls); /* skip '\n\r' or '\r\n' */ - if (++ls->linenumber >= MAX_INT) - lexerror(ls, "chunk has too many lines", 0); +static void inclinenumber(LexState* ls) +{ + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip '\n' or '\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip '\n\r' or '\r\n' */ + if (++ls->linenumber >= MAX_INT) + lexerror(ls, "chunk has too many lines", 0); } -void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, - int firstchar) { - ls->t.token = 0; - ls->L = L; - ls->current = firstchar; - ls->lookahead.token = TK_EOS; /* no look-ahead token */ - ls->z = z; - ls->fs = NULL; - ls->linenumber = 1; - ls->lastline = 1; - ls->source = source; - ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ - luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ +void luaX_setinput(lua_State* L, LexState* ls, ZIO* z, TString* source, + int firstchar) +{ + ls->t.token = 0; + ls->L = L; + ls->current = firstchar; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ } - /* ** ======================================================= ** LEXICAL ANALYZER @@ -183,12 +201,14 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, */ -static int check_next1 (LexState *ls, int c) { - if (ls->current == c) { - next(ls); - return 1; - } - else return 0; +static int check_next1(LexState* ls, int c) +{ + if (ls->current == c) + { + next(ls); + return 1; + } + else return 0; } @@ -196,13 +216,15 @@ static int check_next1 (LexState *ls, int c) { ** Check whether current char is in set 'set' (with two chars) and ** saves it */ -static int check_next2 (LexState *ls, const char *set) { - lua_assert(set[2] == '\0'); - if (ls->current == set[0] || ls->current == set[1]) { - save_and_next(ls); - return 1; - } - else return 0; +static int check_next2(LexState* ls, const char* set) +{ + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) + { + save_and_next(ls); + return 1; + } + else return 0; } @@ -211,35 +233,39 @@ static int check_next2 (LexState *ls, const char *set) { ** this function is quite liberal in what it accepts, as 'luaO_str2num' ** will reject ill-formed numerals. */ -static int read_numeral (LexState *ls, SemInfo *seminfo) { - TValue obj; - const char *expo = "Ee"; - int first = ls->current; - lua_assert(lisdigit(ls->current)); - save_and_next(ls); - if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ - expo = "Pp"; - for (;;) { - if (check_next2(ls, expo)) /* exponent part? */ - check_next2(ls, "-+"); /* optional exponent sign */ - if (lisxdigit(ls->current)) - save_and_next(ls); - else if (ls->current == '.') - save_and_next(ls); - else break; - } - save(ls, '\0'); - if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ - lexerror(ls, "malformed number", TK_FLT); - if (ttisinteger(&obj)) { - seminfo->i = ivalue(&obj); - return TK_INT; - } - else { - lua_assert(ttisfloat(&obj)); - seminfo->r = fltvalue(&obj); - return TK_FLT; - } +static int read_numeral(LexState* ls, SemInfo* seminfo) +{ + TValue obj; + const char* expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ + expo = "Pp"; + for (;;) + { + if (check_next2(ls, expo)) /* exponent part? */ + check_next2(ls, "-+"); /* optional exponent sign */ + if (lisxdigit(ls->current)) + save_and_next(ls); + else if (ls->current == '.') + save_and_next(ls); + else break; + } + save(ls, '\0'); + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + lexerror(ls, "malformed number", TK_FLT); + if (ttisinteger(&obj)) + { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else + { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } } @@ -248,318 +274,422 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) { ** its number of '='s; otherwise, return a negative number (-1 iff there ** are no '='s after initial bracket) */ -static int skip_sep (LexState *ls) { - int count = 0; - int s = ls->current; - lua_assert(s == '[' || s == ']'); - save_and_next(ls); - while (ls->current == '=') { - save_and_next(ls); - count++; - } - return (ls->current == s) ? count : (-count) - 1; +static int skip_sep(LexState* ls) +{ + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') + { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; } -static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { - int line = ls->linenumber; /* initial line (for error message) */ - save_and_next(ls); /* skip 2nd '[' */ - if (currIsNewline(ls)) /* string starts with a newline? */ - inclinenumber(ls); /* skip it */ - for (;;) { - switch (ls->current) { - case EOZ: { /* error */ - const char *what = (seminfo ? "string" : "comment"); - const char *msg = luaO_pushfstring(ls->L, - "unfinished long %s (starting at line %d)", what, line); - lexerror(ls, msg, TK_EOS); - break; /* to avoid warnings */ - } - case ']': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd ']' */ - goto endloop; - } - break; - } - case '\n': case '\r': { - save(ls, '\n'); - inclinenumber(ls); - if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ - break; - } - default: { - if (seminfo) save_and_next(ls); - else next(ls); - } - } - } endloop: - if (seminfo) - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), - luaZ_bufflen(ls->buff) - 2*(2 + sep)); +static void read_long_string(LexState* ls, SemInfo* seminfo, int sep) +{ + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) + { + switch (ls->current) + { + case EOZ: + { + /* error */ + const char* what = (seminfo ? "string" : "comment"); + const char* msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); + break; /* to avoid warnings */ + } + case ']': + { + if (skip_sep(ls) == sep) + { + save_and_next(ls); /* skip 2nd ']' */ + goto endloop; + } + break; + } + case '\n': + case '\r': + { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) + luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: + { + if (seminfo) + save_and_next(ls); + else + next(ls); + } + } + } +endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2 * (2 + sep)); } -static void esccheck (LexState *ls, int c, const char *msg) { - if (!c) { - if (ls->current != EOZ) - save_and_next(ls); /* add current to buffer for error message */ - lexerror(ls, msg, TK_STRING); - } +static void esccheck(LexState* ls, int c, const char* msg) +{ + if (!c) + { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } } -static int gethexa (LexState *ls) { - save_and_next(ls); - esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); - return luaO_hexavalue(ls->current); +static int gethexa(LexState* ls) +{ + save_and_next(ls); + esccheck(ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); } -static int readhexaesc (LexState *ls) { - int r = gethexa(ls); - r = (r << 4) + gethexa(ls); - luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ - return r; +static int readhexaesc(LexState* ls) +{ + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; } -static unsigned long readutf8esc (LexState *ls) { - unsigned long r; - int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ - save_and_next(ls); /* skip 'u' */ - esccheck(ls, ls->current == '{', "missing '{'"); - r = gethexa(ls); /* must have at least one digit */ - while ((save_and_next(ls), lisxdigit(ls->current))) { - i++; - r = (r << 4) + luaO_hexavalue(ls->current); - esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); - } - esccheck(ls, ls->current == '}', "missing '}'"); - next(ls); /* skip '}' */ - luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ - return r; +static unsigned long readutf8esc(LexState* ls) +{ + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while ((save_and_next(ls), lisxdigit(ls->current))) + { + i++; + r = (r << 4) + luaO_hexavalue(ls->current); + esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); + } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ + return r; } -static void utf8esc (LexState *ls) { - char buff[UTF8BUFFSZ]; - int n = luaO_utf8esc(buff, readutf8esc(ls)); - for (; n > 0; n--) /* add 'buff' to string */ - save(ls, buff[UTF8BUFFSZ - n]); +static void utf8esc(LexState* ls) +{ + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); } -static int readdecesc (LexState *ls) { - int i; - int r = 0; /* result accumulator */ - for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ - r = 10*r + ls->current - '0'; - save_and_next(ls); - } - esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); - luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ - return r; +static int readdecesc(LexState* ls) +{ + int i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && lisdigit(ls->current); i++) + { + /* read up to 3 digits */ + r = 10 * r + ls->current - '0'; + save_and_next(ls); + } + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ + return r; } -static void read_string (LexState *ls, int del, SemInfo *seminfo) { - save_and_next(ls); /* keep delimiter (for error messages) */ - while (ls->current != del) { - switch (ls->current) { - case EOZ: - lexerror(ls, "unfinished string", TK_EOS); - break; /* to avoid warnings */ - case '\n': - case '\r': - lexerror(ls, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': { /* escape sequences */ - int c; /* final character to be saved */ - save_and_next(ls); /* keep '\\' for error messages */ - switch (ls->current) { - case 'a': c = '\a'; goto read_save; - case 'b': c = '\b'; goto read_save; - case 'f': c = '\f'; goto read_save; - case 'n': c = '\n'; goto read_save; - case 'r': c = '\r'; goto read_save; - case 't': c = '\t'; goto read_save; - case 'v': c = '\v'; goto read_save; - case 'x': c = readhexaesc(ls); goto read_save; - case 'u': utf8esc(ls); goto no_save; - case '\n': case '\r': - inclinenumber(ls); c = '\n'; goto only_save; - case '\\': case '\"': case '\'': - c = ls->current; goto read_save; - case EOZ: goto no_save; /* will raise an error next loop */ - case 'z': { /* zap following span of spaces */ - luaZ_buffremove(ls->buff, 1); /* remove '\\' */ - next(ls); /* skip the 'z' */ - while (lisspace(ls->current)) { - if (currIsNewline(ls)) inclinenumber(ls); - else next(ls); - } - goto no_save; - } - default: { - esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); - c = readdecesc(ls); /* digital escape '\ddd' */ - goto only_save; - } - } - read_save: - next(ls); - /* go through */ - only_save: - luaZ_buffremove(ls->buff, 1); /* remove '\\' */ - save(ls, c); - /* go through */ - no_save: break; - } - default: - save_and_next(ls); - } - } - save_and_next(ls); /* skip delimiter */ - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, - luaZ_bufflen(ls->buff) - 2); +static void read_string(LexState* ls, int del, SemInfo* seminfo) +{ + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) + { + switch (ls->current) + { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': + { + /* escape sequences */ + int c; /* final character to be saved */ + save_and_next(ls); /* keep '\\' for error messages */ + switch (ls->current) + { + case 'a': c = '\a'; + goto read_save; + case 'b': c = '\b'; + goto read_save; + case 'f': c = '\f'; + goto read_save; + case 'n': c = '\n'; + goto read_save; + case 'r': c = '\r'; + goto read_save; + case 't': c = '\t'; + goto read_save; + case 'v': c = '\v'; + goto read_save; + case 'x': c = readhexaesc(ls); + goto read_save; + case 'u': utf8esc(ls); + goto no_save; + case '\n': + case '\r': + inclinenumber(ls); + c = '\n'; + goto only_save; + case '\\': + case '\"': + case '\'': + c = ls->current; + goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ + case 'z': + { + /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + next(ls); /* skip the 'z' */ + while (lisspace(ls->current)) + { + if (currIsNewline(ls)) inclinenumber(ls); + else + next(ls); + } + goto no_save; + } + default: + { + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ + goto only_save; + } + } + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ + no_save: break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); } -static int llex (LexState *ls, SemInfo *seminfo) { - luaZ_resetbuffer(ls->buff); - for (;;) { - switch (ls->current) { - case '\n': case '\r': { /* line breaks */ - inclinenumber(ls); - break; - } - case ' ': case '\f': case '\t': case '\v': { /* spaces */ - next(ls); - break; - } - case '-': { /* '-' or '--' (comment) */ - next(ls); - if (ls->current != '-') return '-'; - /* else is a comment */ - next(ls); - if (ls->current == '[') { /* long comment? */ - int sep = skip_sep(ls); - luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ - if (sep >= 0) { - read_long_string(ls, NULL, sep); /* skip long comment */ - luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ - break; - } - } - /* else short comment */ - while (!currIsNewline(ls) && ls->current != EOZ) - next(ls); /* skip until end of line (or end of file) */ - break; - } - case '[': { /* long string or simply '[' */ - int sep = skip_sep(ls); - if (sep >= 0) { - read_long_string(ls, seminfo, sep); - return TK_STRING; - } - else if (sep != -1) /* '[=...' missing second bracket */ - lexerror(ls, "invalid long string delimiter", TK_STRING); - return '['; - } - case '=': { - next(ls); - if (check_next1(ls, '=')) return TK_EQ; - else return '='; - } - case '<': { - next(ls); - if (check_next1(ls, '=')) return TK_LE; - else if (check_next1(ls, '<')) return TK_SHL; - else return '<'; - } - case '>': { - next(ls); - if (check_next1(ls, '=')) return TK_GE; - else if (check_next1(ls, '>')) return TK_SHR; - else return '>'; - } - case '/': { - next(ls); - if (check_next1(ls, '/')) return TK_IDIV; - else return '/'; - } - case '~': { - next(ls); - if (check_next1(ls, '=')) return TK_NE; - else return '~'; - } - case ':': { - next(ls); - if (check_next1(ls, ':')) return TK_DBCOLON; - else return ':'; - } - case '"': case '\'': { /* short literal strings */ - read_string(ls, ls->current, seminfo); - return TK_STRING; - } - case '.': { /* '.', '..', '...', or number */ - save_and_next(ls); - if (check_next1(ls, '.')) { - if (check_next1(ls, '.')) - return TK_DOTS; /* '...' */ - else return TK_CONCAT; /* '..' */ - } - else if (!lisdigit(ls->current)) return '.'; - else return read_numeral(ls, seminfo); - } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - return read_numeral(ls, seminfo); - } - case EOZ: { - return TK_EOS; - } - default: { - if (lislalpha(ls->current)) { /* identifier or reserved word? */ - TString *ts; - do { - save_and_next(ls); - } while (lislalnum(ls->current)); - ts = luaX_newstring(ls, luaZ_buffer(ls->buff), - luaZ_bufflen(ls->buff)); - seminfo->ts = ts; - if (isreserved(ts)) /* reserved word? */ - return ts->extra - 1 + FIRST_RESERVED; - else { - return TK_NAME; - } - } - else { /* single-char tokens (+ - / ...) */ - int c = ls->current; - next(ls); - return c; - } - } - } - } +static int llex(LexState* ls, SemInfo* seminfo) +{ + luaZ_resetbuffer(ls->buff); + for (;;) + { + switch (ls->current) + { + case '\n': + case '\r': + { + /* line breaks */ + inclinenumber(ls); + break; + } + case ' ': + case '\f': + case '\t': + case '\v': + { + /* spaces */ + next(ls); + break; + } + case '-': + { + /* '-' or '--' (comment) */ + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') + { + /* long comment? */ + int sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ + if (sep >= 0) + { + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + case '[': + { + /* long string or simply '[' */ + int sep = skip_sep(ls); + if (sep >= 0) + { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep != -1) /* '[=...' missing second bracket */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; + } + case '=': + { + next(ls); + if (check_next1(ls, '=')) return TK_EQ; + else return '='; + } + case '<': + { + next(ls); + if (check_next1(ls, '=')) return TK_LE; + else if (check_next1(ls, '<')) return TK_SHL; + else return '<'; + } + case '>': + { + next(ls); + if (check_next1(ls, '=')) return TK_GE; + else if (check_next1(ls, '>')) return TK_SHR; + else return '>'; + } + case '/': + { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; + else return '/'; + } + case '~': + { + next(ls); + if (check_next1(ls, '=')) return TK_NE; + else return '~'; + } + case ':': + { + next(ls); + if (check_next1(ls, ':')) return TK_DBCOLON; + else return ':'; + } + case '"': + case '\'': + { + /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': + { + /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next1(ls, '.')) + { + if (check_next1(ls, '.')) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ + } + else if (!lisdigit(ls->current)) return '.'; + else return read_numeral(ls, seminfo); + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + return read_numeral(ls, seminfo); + } + case EOZ: + { + return TK_EOS; + } + default: + { + if (lislalpha(ls->current)) + { + /* identifier or reserved word? */ + TString* ts; + do + { + save_and_next(ls); + } + while (lislalnum(ls->current)); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->extra - 1 + FIRST_RESERVED; + else + { + return TK_NAME; + } + } + else + { + /* single-char tokens (+ - / ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } } -void luaX_next (LexState *ls) { - ls->lastline = ls->linenumber; - if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ - ls->t = ls->lookahead; /* use this one */ - ls->lookahead.token = TK_EOS; /* and discharge it */ - } - else - ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +void luaX_next(LexState* ls) +{ + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) + { + /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ } -int luaX_lookahead (LexState *ls) { - lua_assert(ls->lookahead.token == TK_EOS); - ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); - return ls->lookahead.token; +int luaX_lookahead(LexState* ls) +{ + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; } - diff --git a/Lua/llex.h b/Lua/llex.h index 2363d87..23304f2 100644 --- a/Lua/llex.h +++ b/Lua/llex.h @@ -23,63 +23,96 @@ * WARNING: if you change the order of this enumeration, * grep "ORDER RESERVED" */ -enum RESERVED { - /* terminal symbols denoted by reserved words */ - TK_AND = FIRST_RESERVED, TK_BREAK, - TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, - TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, - TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, - /* other terminal symbols */ - TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, - TK_SHL, TK_SHR, - TK_DBCOLON, TK_EOS, - TK_FLT, TK_INT, TK_NAME, TK_STRING +enum RESERVED +{ + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, + TK_BREAK, + TK_DO, + TK_ELSE, + TK_ELSEIF, + TK_END, + TK_FALSE, + TK_FOR, + TK_FUNCTION, + TK_GOTO, + TK_IF, + TK_IN, + TK_LOCAL, + TK_NIL, + TK_NOT, + TK_OR, + TK_REPEAT, + TK_RETURN, + TK_THEN, + TK_TRUE, + TK_UNTIL, + TK_WHILE, + /* other terminal symbols */ + TK_IDIV, + TK_CONCAT, + TK_DOTS, + TK_EQ, + TK_GE, + TK_LE, + TK_NE, + TK_SHL, + TK_SHR, + TK_DBCOLON, + TK_EOS, + TK_FLT, + TK_INT, + TK_NAME, + TK_STRING }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) -typedef union { - lua_Number r; - lua_Integer i; - TString *ts; -} SemInfo; /* semantics information */ +typedef union +{ + lua_Number r; + lua_Integer i; + TString* ts; +} SemInfo; /* semantics information */ -typedef struct Token { - int token; - SemInfo seminfo; +typedef struct Token +{ + int token; + SemInfo seminfo; } Token; /* state of the lexer plus state of the parser when shared by all functions */ -typedef struct LexState { - int current; /* current character (charint) */ - int linenumber; /* input line counter */ - int lastline; /* line of last token 'consumed' */ - Token t; /* current token */ - Token lookahead; /* look ahead token */ - struct FuncState *fs; /* current function (parser) */ - struct lua_State *L; - ZIO *z; /* input stream */ - Mbuffer *buff; /* buffer for tokens */ - Table *h; /* to avoid collection/reuse strings */ - struct Dyndata *dyd; /* dynamic structures used by the parser */ - TString *source; /* current source name */ - TString *envn; /* environment variable name */ +typedef struct LexState +{ + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token 'consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState* fs; /* current function (parser) */ + struct lua_State* L; + ZIO* z; /* input stream */ + Mbuffer* buff; /* buffer for tokens */ + Table* h; /* to avoid collection/reuse strings */ + struct Dyndata* dyd; /* dynamic structures used by the parser */ + TString* source; /* current source name */ + TString* envn; /* environment variable name */ } LexState; -LUAI_FUNC void luaX_init (lua_State *L); -LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, - TString *source, int firstchar); -LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); -LUAI_FUNC void luaX_next (LexState *ls); -LUAI_FUNC int luaX_lookahead (LexState *ls); -LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); -LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); +LUAI_FUNC void luaX_init(lua_State* L); +LUAI_FUNC void luaX_setinput(lua_State* L, LexState* ls, ZIO* z, + TString* source, int firstchar); +LUAI_FUNC TString* luaX_newstring(LexState* ls, const char* str, size_t l); +LUAI_FUNC void luaX_next(LexState* ls); +LUAI_FUNC int luaX_lookahead(LexState* ls); +LUAI_FUNC l_noret luaX_syntaxerror(LexState* ls, const char* s); +LUAI_FUNC const char* luaX_token2str(LexState* ls, int token); #endif diff --git a/Lua/llimits.h b/Lua/llimits.h index f21377f..a0db4d3 100644 --- a/Lua/llimits.h +++ b/Lua/llimits.h @@ -59,22 +59,21 @@ typedef unsigned char lu_byte; #define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) - /* type to ensure maximum alignment */ #if defined(LUAI_USER_ALIGNMENT_T) typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; #else -typedef union { - lua_Number n; - double u; - void *s; - lua_Integer i; - long l; +typedef union +{ + lua_Number n; + double u; + void* s; + lua_Integer i; + long l; } L_Umaxalign; #endif - /* types of 'usual argument conversions' for lua_Number and lua_Integer */ typedef LUAI_UACNUMBER l_uacNumber; typedef LUAI_UACINT l_uacInt; @@ -144,7 +143,6 @@ typedef LUAI_UACINT l_uacInt; #endif - /* ** maximum depth for nested C calls and syntactical nested non-terminals ** in a program. (Value must fit in an unsigned short int.) @@ -154,7 +152,6 @@ typedef LUAI_UACINT l_uacInt; #endif - /* ** type for virtual-machine instructions; ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) @@ -166,7 +163,6 @@ typedef unsigned long Instruction; #endif - /* ** Maximum length for short strings, that is, strings that are ** internalized. (Cannot be smaller than reserved words or tags for @@ -254,7 +250,6 @@ typedef unsigned long Instruction; #endif - /* ** The luai_num* macros define the primitive operations over numbers. */ @@ -299,9 +294,6 @@ typedef unsigned long Instruction; #endif - - - /* ** macro to control inclusion of some hard tests on stack reallocation */ diff --git a/Lua/lmathlib.c b/Lua/lmathlib.c index b7f8bae..fcad850 100644 --- a/Lua/lmathlib.c +++ b/Lua/lmathlib.c @@ -36,108 +36,127 @@ #endif /* } */ -static int math_abs (lua_State *L) { - if (lua_isinteger(L, 1)) { - lua_Integer n = lua_tointeger(L, 1); - if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); - lua_pushinteger(L, n); - } - else - lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); - return 1; +static int math_abs(lua_State* L) +{ + if (lua_isinteger(L, 1)) + { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + return 1; } -static int math_sin (lua_State *L) { - lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); - return 1; +static int math_sin(lua_State* L) +{ + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); + return 1; } -static int math_cos (lua_State *L) { - lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); - return 1; +static int math_cos(lua_State* L) +{ + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); + return 1; } -static int math_tan (lua_State *L) { - lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); - return 1; +static int math_tan(lua_State* L) +{ + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); + return 1; } -static int math_asin (lua_State *L) { - lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); - return 1; +static int math_asin(lua_State* L) +{ + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); + return 1; } -static int math_acos (lua_State *L) { - lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); - return 1; +static int math_acos(lua_State* L) +{ + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); + return 1; } -static int math_atan (lua_State *L) { - lua_Number y = luaL_checknumber(L, 1); - lua_Number x = luaL_optnumber(L, 2, 1); - lua_pushnumber(L, l_mathop(atan2)(y, x)); - return 1; +static int math_atan(lua_State* L) +{ + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); + return 1; } -static int math_toint (lua_State *L) { - int valid; - lua_Integer n = lua_tointegerx(L, 1, &valid); - if (valid) - lua_pushinteger(L, n); - else { - luaL_checkany(L, 1); - lua_pushnil(L); /* value is not convertible to integer */ - } - return 1; +static int math_toint(lua_State* L) +{ + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (valid) + lua_pushinteger(L, n); + else + { + luaL_checkany(L, 1); + lua_pushnil(L); /* value is not convertible to integer */ + } + return 1; } -static void pushnumint (lua_State *L, lua_Number d) { - lua_Integer n; - if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ - lua_pushinteger(L, n); /* result is integer */ - else - lua_pushnumber(L, d); /* result is float */ +static void pushnumint(lua_State* L, lua_Number d) +{ + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ } -static int math_floor (lua_State *L) { - if (lua_isinteger(L, 1)) - lua_settop(L, 1); /* integer is its own floor */ - else { - lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); - pushnumint(L, d); - } - return 1; +static int math_floor(lua_State* L) +{ + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else + { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; } -static int math_ceil (lua_State *L) { - if (lua_isinteger(L, 1)) - lua_settop(L, 1); /* integer is its own ceil */ - else { - lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); - pushnumint(L, d); - } - return 1; +static int math_ceil(lua_State* L) +{ + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else + { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; } -static int math_fmod (lua_State *L) { - if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { - lua_Integer d = lua_tointeger(L, 2); - if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ - luaL_argcheck(L, d != 0, 2, "zero"); - lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ - } - else - lua_pushinteger(L, lua_tointeger(L, 1) % d); - } - else - lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); - return 1; +static int math_fmod(lua_State* L) +{ + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) + { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) + { + /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); + return 1; } @@ -146,97 +165,111 @@ static int math_fmod (lua_State *L) { ** (which is not compatible with 'float*') when lua_Number is not ** 'double'. */ -static int math_modf (lua_State *L) { - if (lua_isinteger(L ,1)) { - lua_settop(L, 1); /* number is its own integer part */ - lua_pushnumber(L, 0); /* no fractional part */ - } - else { - lua_Number n = luaL_checknumber(L, 1); - /* integer part (rounds toward zero) */ - lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); - pushnumint(L, ip); - /* fractional part (test needed for inf/-inf) */ - lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); - } - return 2; +static int math_modf(lua_State* L) +{ + if (lua_isinteger(L, 1)) + { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else + { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } + return 2; } -static int math_sqrt (lua_State *L) { - lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); - return 1; +static int math_sqrt(lua_State* L) +{ + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); + return 1; } -static int math_ult (lua_State *L) { - lua_Integer a = luaL_checkinteger(L, 1); - lua_Integer b = luaL_checkinteger(L, 2); - lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); - return 1; +static int math_ult(lua_State* L) +{ + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); + return 1; } -static int math_log (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number res; - if (lua_isnoneornil(L, 2)) - res = l_mathop(log)(x); - else { - lua_Number base = luaL_checknumber(L, 2); +static int math_log(lua_State* L) +{ + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = l_mathop(log)(x); + else + { + lua_Number base = luaL_checknumber(L, 2); #if !defined(LUA_USE_C89) if (base == l_mathop(2.0)) res = l_mathop(log2)(x); else #endif - if (base == l_mathop(10.0)) - res = l_mathop(log10)(x); - else - res = l_mathop(log)(x)/l_mathop(log)(base); - } - lua_pushnumber(L, res); - return 1; + if (base == l_mathop(10.0)) + res = l_mathop(log10)(x); + else + res = l_mathop(log)(x) / l_mathop(log)(base); + } + lua_pushnumber(L, res); + return 1; } -static int math_exp (lua_State *L) { - lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); - return 1; +static int math_exp(lua_State* L) +{ + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); + return 1; } -static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); - return 1; +static int math_deg(lua_State* L) +{ + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); + return 1; } -static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); - return 1; +static int math_rad(lua_State* L) +{ + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); + return 1; } -static int math_min (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int imin = 1; /* index of current minimum value */ - int i; - luaL_argcheck(L, n >= 1, 1, "value expected"); - for (i = 2; i <= n; i++) { - if (lua_compare(L, i, imin, LUA_OPLT)) - imin = i; - } - lua_pushvalue(L, imin); - return 1; +static int math_min(lua_State* L) +{ + int n = lua_gettop(L); /* number of arguments */ + int imin = 1; /* index of current minimum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) + { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; + } + lua_pushvalue(L, imin); + return 1; } -static int math_max (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int imax = 1; /* index of current maximum value */ - int i; - luaL_argcheck(L, n >= 1, 1, "value expected"); - for (i = 2; i <= n; i++) { - if (lua_compare(L, imax, i, LUA_OPLT)) - imax = i; - } - lua_pushvalue(L, imax); - return 1; +static int math_max(lua_State* L) +{ + int n = lua_gettop(L); /* number of arguments */ + int imax = 1; /* index of current maximum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) + { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; + } + lua_pushvalue(L, imax); + return 1; } /* @@ -244,55 +277,68 @@ static int math_max (lua_State *L) { ** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' ** will keep full precision (ensuring that 'r' is always less than 1.0.) */ -static int math_random (lua_State *L) { - lua_Integer low, up; - double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); - switch (lua_gettop(L)) { /* check number of arguments */ - case 0: { /* no arguments */ - lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ - return 1; - } - case 1: { /* only upper limit */ - low = 1; - up = luaL_checkinteger(L, 1); - break; - } - case 2: { /* lower and upper limits */ - low = luaL_checkinteger(L, 1); - up = luaL_checkinteger(L, 2); - break; - } - default: return luaL_error(L, "wrong number of arguments"); - } - /* random integer in the interval [low, up] */ - luaL_argcheck(L, low <= up, 1, "interval is empty"); - luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, - "interval too large"); - r *= (double)(up - low) + 1.0; - lua_pushinteger(L, (lua_Integer)r + low); - return 1; +static int math_random(lua_State* L) +{ + lua_Integer low, up; + double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); + switch (lua_gettop(L)) + { + /* check number of arguments */ + case 0: + { + /* no arguments */ + lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ + return 1; + } + case 1: + { + /* only upper limit */ + low = 1; + up = luaL_checkinteger(L, 1); + break; + } + case 2: + { + /* lower and upper limits */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, + "interval too large"); + r *= (double)(up - low) + 1.0; + lua_pushinteger(L, (lua_Integer)r + low); + return 1; } -static int math_randomseed (lua_State *L) { - l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); - (void)l_rand(); /* discard first value to avoid undesirable correlations */ - return 0; +static int math_randomseed(lua_State* L) +{ + l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); + (void)l_rand(); /* discard first value to avoid undesirable correlations */ + return 0; } -static int math_type (lua_State *L) { - if (lua_type(L, 1) == LUA_TNUMBER) { - if (lua_isinteger(L, 1)) - lua_pushliteral(L, "integer"); - else - lua_pushliteral(L, "float"); - } - else { - luaL_checkany(L, 1); - lua_pushnil(L); - } - return 1; +static int math_type(lua_State* L) +{ + if (lua_type(L, 1) == LUA_TNUMBER) + { + if (lua_isinteger(L, 1)) + lua_pushliteral(L, "integer"); + else + lua_pushliteral(L, "float"); + } + else + { + luaL_checkany(L, 1); + lua_pushnil(L); + } + return 1; } @@ -348,31 +394,30 @@ static int math_log10 (lua_State *L) { /* }================================================================== */ - static const luaL_Reg mathlib[] = { - {"abs", math_abs}, - {"acos", math_acos}, - {"asin", math_asin}, - {"atan", math_atan}, - {"ceil", math_ceil}, - {"cos", math_cos}, - {"deg", math_deg}, - {"exp", math_exp}, - {"tointeger", math_toint}, - {"floor", math_floor}, - {"fmod", math_fmod}, - {"ult", math_ult}, - {"log", math_log}, - {"max", math_max}, - {"min", math_min}, - {"modf", math_modf}, - {"rad", math_rad}, - {"random", math_random}, - {"randomseed", math_randomseed}, - {"sin", math_sin}, - {"sqrt", math_sqrt}, - {"tan", math_tan}, - {"type", math_type}, + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"tointeger", math_toint}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"ult", math_ult}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"rad", math_rad}, + {"random", math_random}, + {"randomseed", math_randomseed}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"type", math_type}, #if defined(LUA_COMPAT_MATHLIB) {"atan2", math_atan}, {"cosh", math_cosh}, @@ -383,28 +428,28 @@ static const luaL_Reg mathlib[] = { {"ldexp", math_ldexp}, {"log10", math_log10}, #endif - /* placeholders */ - {"pi", NULL}, - {"huge", NULL}, - {"maxinteger", NULL}, - {"mininteger", NULL}, - {NULL, NULL} + /* placeholders */ + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, + {NULL, NULL} }; /* ** Open math library */ -LUAMOD_API int luaopen_math (lua_State *L) { - luaL_newlib(L, mathlib); - lua_pushnumber(L, PI); - lua_setfield(L, -2, "pi"); - lua_pushnumber(L, (lua_Number)HUGE_VAL); - lua_setfield(L, -2, "huge"); - lua_pushinteger(L, LUA_MAXINTEGER); - lua_setfield(L, -2, "maxinteger"); - lua_pushinteger(L, LUA_MININTEGER); - lua_setfield(L, -2, "mininteger"); - return 1; +LUAMOD_API int luaopen_math(lua_State* L) +{ + luaL_newlib(L, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, (lua_Number)HUGE_VAL); + lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); + return 1; } - diff --git a/Lua/lmem.c b/Lua/lmem.c index 0a0476c..ea62ccd 100644 --- a/Lua/lmem.c +++ b/Lua/lmem.c @@ -22,7 +22,6 @@ #include "lstate.h" - /* ** About the realloc function: ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); @@ -41,60 +40,66 @@ */ - #define MINSIZEARRAY 4 -void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, - int limit, const char *what) { - void *newblock; - int newsize; - if (*size >= limit/2) { /* cannot double it? */ - if (*size >= limit) /* cannot grow even a little? */ - luaG_runerror(L, "too many %s (limit is %d)", what, limit); - newsize = limit; /* still have at least one free place */ - } - else { - newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - } - newblock = luaM_reallocv(L, block, *size, newsize, size_elems); - *size = newsize; /* update only when everything else is OK */ - return newblock; +void* luaM_growaux_(lua_State* L, void* block, int* size, size_t size_elems, + int limit, const char* what) +{ + void* newblock; + int newsize; + if (*size >= limit / 2) + { + /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, "too many %s (limit is %d)", what, limit); + newsize = limit; /* still have at least one free place */ + } + else + { + newsize = (*size) * 2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; } -l_noret luaM_toobig (lua_State *L) { - luaG_runerror(L, "memory allocation error: block too big"); +l_noret luaM_toobig(lua_State* L) +{ + luaG_runerror(L, "memory allocation error: block too big"); } - /* ** generic allocation routine. */ -void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { - void *newblock; - global_State *g = G(L); - size_t realosize = (block) ? osize : 0; - lua_assert((realosize == 0) == (block == NULL)); +void* luaM_realloc_(lua_State* L, void* block, size_t osize, size_t nsize) +{ + void* newblock; + global_State* g = G(L); + size_t realosize = (block) ? osize : 0; + lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) if (nsize > realosize && g->gcrunning) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif - newblock = (*g->frealloc)(g->ud, block, osize, nsize); - if (newblock == NULL && nsize > 0) { - lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ - if (g->version) { /* is state fully built? */ - luaC_fullgc(L, 1); /* try to free some memory... */ - newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ - } - if (newblock == NULL) - luaD_throw(L, LUA_ERRMEM); - } - lua_assert((nsize == 0) == (newblock == NULL)); - g->GCdebt = (g->GCdebt + nsize) - realosize; - return newblock; + newblock = (*g->frealloc)(g->ud, block, osize, nsize); + if (newblock == NULL && nsize > 0) + { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->version) + { + /* is state fully built? */ + luaC_fullgc(L, 1); /* try to free some memory... */ + newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ + } + if (newblock == NULL) + luaD_throw(L, LUA_ERRMEM); + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->GCdebt = (g->GCdebt + nsize) - realosize; + return newblock; } - diff --git a/Lua/lmem.h b/Lua/lmem.h index 30f4848..55343f7 100644 --- a/Lua/lmem.h +++ b/Lua/lmem.h @@ -56,14 +56,13 @@ #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) -LUAI_FUNC l_noret luaM_toobig (lua_State *L); +LUAI_FUNC l_noret luaM_toobig(lua_State* L); /* not to be called directly */ -LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, - size_t size); -LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, - size_t size_elem, int limit, - const char *what); +LUAI_FUNC void* luaM_realloc_(lua_State* L, void* block, size_t oldsize, + size_t size); +LUAI_FUNC void* luaM_growaux_(lua_State* L, void* block, int* size, + size_t size_elem, int limit, + const char* what); #endif - diff --git a/Lua/loadlib.c b/Lua/loadlib.c index 4791e74..016057b 100644 --- a/Lua/loadlib.c +++ b/Lua/loadlib.c @@ -74,7 +74,7 @@ static const int CLIBS = 0; /* ** unload library 'lib' */ -static void lsys_unloadlib (void *lib); +static void lsys_unloadlib(void* lib); /* ** load C library in file 'path'. If 'seeglb', load with all names in @@ -82,16 +82,14 @@ static void lsys_unloadlib (void *lib); ** Returns the library; in case of error, returns NULL plus an ** error string in the stack. */ -static void *lsys_load (lua_State *L, const char *path, int seeglb); +static void* lsys_load(lua_State* L, const char* path, int seeglb); /* ** Try to find a function named 'sym' in library 'lib'. ** Returns the function; in case of error, returns NULL plus an ** error string in the stack. */ -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); - - +static lua_CFunction lsys_sym(lua_State* L, void* lib, const char* sym); #if defined(LUA_USE_DLOPEN) /* { */ @@ -139,7 +137,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { /* }====================================================== */ - #elif defined(LUA_DL_DLL) /* }{ */ /* ** {====================================================================== @@ -165,50 +162,54 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { ** Replace in the path (on the top of the stack) any occurrence ** of LUA_EXEC_DIR with the executable's path. */ -static void setprogdir (lua_State *L) { - char buff[MAX_PATH + 1]; - char *lb; - DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ - if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) - luaL_error(L, "unable to get ModuleFileName"); - else { - *lb = '\0'; /* cut name on the last '\\' to get the path */ - luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); - lua_remove(L, -2); /* remove original string */ - } +static void setprogdir(lua_State* L) +{ + char buff[MAX_PATH + 1]; + char* lb; + DWORD nsize = sizeof(buff) / sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else + { + *lb = '\0'; /* cut name on the last '\\' to get the path */ + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); + lua_remove(L, -2); /* remove original string */ + } } - - -static void pusherror (lua_State *L) { - int error = GetLastError(); - char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) - lua_pushstring(L, buffer); - else - lua_pushfstring(L, "system error %d\n", error); +static void pusherror(lua_State* L) +{ + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer) / sizeof(char), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); } -static void lsys_unloadlib (void *lib) { - FreeLibrary((HMODULE)lib); +static void lsys_unloadlib(void* lib) +{ + FreeLibrary((HMODULE)lib); } -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); - (void)(seeglb); /* not used: symbols are 'global' by default */ - if (lib == NULL) pusherror(L); - return lib; +static void* lsys_load(lua_State* L, const char* path, int seeglb) +{ + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ + if (lib == NULL) pusherror(L); + return lib; } -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); - if (f == NULL) pusherror(L); - return f; +static lua_CFunction lsys_sym(lua_State* L, void* lib, const char* sym) +{ + lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); + if (f == NULL) pusherror(L); + return f; } /* }====================================================== */ @@ -275,37 +276,40 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { /* ** return registry.LUA_NOENV as a boolean */ -static int noenv (lua_State *L) { - int b; - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - b = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - return b; +static int noenv(lua_State* L) +{ + int b; + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + return b; } /* ** Set a path */ -static void setpath (lua_State *L, const char *fieldname, - const char *envname, - const char *dft) { - const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); - const char *path = getenv(nver); /* use versioned name */ - if (path == NULL) /* no environment variable? */ - path = getenv(envname); /* try unversioned name */ - if (path == NULL || noenv(L)) /* no environment variable? */ - lua_pushstring(L, dft); /* use default */ - else { - /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ - path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, - LUA_PATH_SEP AUXMARK LUA_PATH_SEP); - luaL_gsub(L, path, AUXMARK, dft); - lua_remove(L, -2); /* remove result from 1st 'gsub' */ - } - setprogdir(L); - lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ - lua_pop(L, 1); /* pop versioned variable name */ +static void setpath(lua_State* L, const char* fieldname, + const char* envname, + const char* dft) +{ + const char* nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); + const char* path = getenv(nver); /* use versioned name */ + if (path == NULL) /* no environment variable? */ + path = getenv(envname); /* try unversioned name */ + if (path == NULL || noenv(L)) /* no environment variable? */ + lua_pushstring(L, dft); /* use default */ + else + { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, + LUA_PATH_SEP AUXMARK LUA_PATH_SEP); + luaL_gsub(L, path, AUXMARK, dft); + lua_remove(L, -2); /* remove result from 1st 'gsub' */ + } + setprogdir(L); + lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ + lua_pop(L, 1); /* pop versioned variable name */ } /* }================================================================== */ @@ -314,13 +318,14 @@ static void setpath (lua_State *L, const char *fieldname, /* ** return registry.CLIBS[path] */ -static void *checkclib (lua_State *L, const char *path) { - void *plib; - lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); - lua_getfield(L, -1, path); - plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ - lua_pop(L, 2); /* pop CLIBS table and 'plib' */ - return plib; +static void* checkclib(lua_State* L, const char* path) +{ + void* plib; + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ + return plib; } @@ -328,13 +333,14 @@ static void *checkclib (lua_State *L, const char *path) { ** registry.CLIBS[path] = plib -- for queries ** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries */ -static void addtoclib (lua_State *L, const char *path, void *plib) { - lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); - lua_pushlightuserdata(L, plib); - lua_pushvalue(L, -1); - lua_setfield(L, -3, path); /* CLIBS[path] = plib */ - lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ - lua_pop(L, 1); /* pop CLIBS table */ +static void addtoclib(lua_State* L, const char* path, void* plib) +{ + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ } @@ -342,18 +348,20 @@ static void addtoclib (lua_State *L, const char *path, void *plib) { ** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib ** handles in list CLIBS */ -static int gctm (lua_State *L) { - lua_Integer n = luaL_len(L, 1); - for (; n >= 1; n--) { /* for each handle, in reverse order */ - lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ - lsys_unloadlib(lua_touserdata(L, -1)); - lua_pop(L, 1); /* pop handle */ - } - return 0; +static int gctm(lua_State* L) +{ + lua_Integer n = luaL_len(L, 1); + for (; n >= 1; n--) + { + /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + lsys_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } + return 0; } - /* error codes for 'lookforfunc' */ #define ERRLIB 1 #define ERRFUNC 2 @@ -369,43 +377,51 @@ static int gctm (lua_State *L) { ** Return 0 and 'true' or a function in the stack; in case of ** errors, return an error code and an error message in the stack. */ -static int lookforfunc (lua_State *L, const char *path, const char *sym) { - void *reg = checkclib(L, path); /* check loaded C libraries */ - if (reg == NULL) { /* must load library? */ - reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ - if (reg == NULL) return ERRLIB; /* unable to load library */ - addtoclib(L, path, reg); - } - if (*sym == '*') { /* loading only library (no function)? */ - lua_pushboolean(L, 1); /* return 'true' */ - return 0; /* no errors */ - } - else { - lua_CFunction f = lsys_sym(L, reg, sym); - if (f == NULL) - return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function */ - return 0; /* no errors */ - } +static int lookforfunc(lua_State* L, const char* path, const char* sym) +{ + void* reg = checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) + { + /* must load library? */ + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ + if (reg == NULL) return ERRLIB; /* unable to load library */ + addtoclib(L, path, reg); + } + if (*sym == '*') + { + /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } + else + { + lua_CFunction f = lsys_sym(L, reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ + } } -static int ll_loadlib (lua_State *L) { - const char *path = luaL_checkstring(L, 1); - const char *init = luaL_checkstring(L, 2); - int stat = lookforfunc(L, path, init); - if (stat == 0) /* no errors? */ - return 1; /* return the loaded function */ - else { /* error; error message is on stack top */ - lua_pushnil(L); - lua_insert(L, -2); - lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); - return 3; /* return nil, error message, and where */ - } +static int ll_loadlib(lua_State* L) +{ + const char* path = luaL_checkstring(L, 1); + const char* init = luaL_checkstring(L, 2); + int stat = lookforfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else + { + /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } } - /* ** {====================================================== ** 'require' function @@ -413,91 +429,103 @@ static int ll_loadlib (lua_State *L) { */ -static int readable (const char *filename) { - FILE *f = fopen(filename, "r"); /* try to open file */ - if (f == NULL) return 0; /* open failed */ - fclose(f); - return 1; +static int readable(const char* filename) +{ + FILE* f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; } -static const char *pushnexttemplate (lua_State *L, const char *path) { - const char *l; - while (*path == *LUA_PATH_SEP) path++; /* skip separators */ - if (*path == '\0') return NULL; /* no more templates */ - l = strchr(path, *LUA_PATH_SEP); /* find next separator */ - if (l == NULL) l = path + strlen(path); - lua_pushlstring(L, path, l - path); /* template */ - return l; +static const char* pushnexttemplate(lua_State* L, const char* path) +{ + const char* l; + while (*path == *LUA_PATH_SEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATH_SEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; } -static const char *searchpath (lua_State *L, const char *name, - const char *path, - const char *sep, - const char *dirsep) { - luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); - if (*sep != '\0') /* non-empty separator? */ - name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ - while ((path = pushnexttemplate(L, path)) != NULL) { - const char *filename = luaL_gsub(L, lua_tostring(L, -1), - LUA_PATH_MARK, name); - lua_remove(L, -2); /* remove path template */ - if (readable(filename)) /* does file exist and is readable? */ - return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file '%s'", filename); - lua_remove(L, -2); /* remove file name */ - luaL_addvalue(&msg); /* concatenate error msg. entry */ - } - luaL_pushresult(&msg); /* create error message */ - return NULL; /* not found */ +static const char* searchpath(lua_State* L, const char* name, + const char* path, + const char* sep, + const char* dirsep) +{ + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + if (*sep != '\0') /* non-empty separator? */ + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + while ((path = pushnexttemplate(L, path)) != NULL) + { + const char* filename = luaL_gsub(L, lua_tostring(L, -1), + LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file '%s'", filename); + lua_remove(L, -2); /* remove file name */ + luaL_addvalue(&msg); /* concatenate error msg. entry */ + } + luaL_pushresult(&msg); /* create error message */ + return NULL; /* not found */ } -static int ll_searchpath (lua_State *L) { - const char *f = searchpath(L, luaL_checkstring(L, 1), - luaL_checkstring(L, 2), - luaL_optstring(L, 3, "."), - luaL_optstring(L, 4, LUA_DIRSEP)); - if (f != NULL) return 1; - else { /* error message is on top of the stack */ - lua_pushnil(L); - lua_insert(L, -2); - return 2; /* return nil + error message */ - } +static int ll_searchpath(lua_State* L) +{ + const char* f = searchpath(L, luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, "."), + luaL_optstring(L, 4, LUA_DIRSEP)); + if (f != NULL) return 1; + else + { + /* error message is on top of the stack */ + lua_pushnil(L); + lua_insert(L, -2); + return 2; /* return nil + error message */ + } } -static const char *findfile (lua_State *L, const char *name, - const char *pname, - const char *dirsep) { - const char *path; - lua_getfield(L, lua_upvalueindex(1), pname); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, "'package.%s' must be a string", pname); - return searchpath(L, name, path, ".", dirsep); +static const char* findfile(lua_State* L, const char* name, + const char* pname, + const char* dirsep) +{ + const char* path; + lua_getfield(L, lua_upvalueindex(1), pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, "'package.%s' must be a string", pname); + return searchpath(L, name, path, ".", dirsep); } -static int checkload (lua_State *L, int stat, const char *filename) { - if (stat) { /* module loaded successfully? */ - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; /* return open function and file name */ - } - else - return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); +static int checkload(lua_State* L, int stat, const char* filename) +{ + if (stat) + { + /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); } -static int searcher_Lua (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - filename = findfile(L, name, "path", LUA_LSUBSEP); - if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); +static int searcher_Lua(lua_State* L) +{ + const char* filename; + const char* name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path", LUA_LSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); } @@ -509,118 +537,134 @@ static int searcher_Lua (lua_State *L) { ** fails, it also tries "luaopen_Y".) If there is no ignore mark, ** look for a function named "luaopen_modname". */ -static int loadfunc (lua_State *L, const char *filename, const char *modname) { - const char *openfunc; - const char *mark; - modname = luaL_gsub(L, modname, ".", LUA_OFSEP); - mark = strchr(modname, *LUA_IGMARK); - if (mark) { - int stat; - openfunc = lua_pushlstring(L, modname, mark - modname); - openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); - stat = lookforfunc(L, filename, openfunc); - if (stat != ERRFUNC) return stat; - modname = mark + 1; /* else go ahead and try old-style name */ - } - openfunc = lua_pushfstring(L, LUA_POF"%s", modname); - return lookforfunc(L, filename, openfunc); +static int loadfunc(lua_State* L, const char* filename, const char* modname) +{ + const char* openfunc; + const char* mark; + modname = luaL_gsub(L, modname, ".", LUA_OFSEP); + mark = strchr(modname, *LUA_IGMARK); + if (mark) + { + int stat; + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); + if (stat != ERRFUNC) return stat; + modname = mark + 1; /* else go ahead and try old-style name */ + } + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); } -static int searcher_C (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); - if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (loadfunc(L, filename, name) == 0), filename); +static int searcher_C(lua_State* L) +{ + const char* name = luaL_checkstring(L, 1); + const char* filename = findfile(L, name, "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (loadfunc(L, filename, name) == 0), filename); } -static int searcher_Croot (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - const char *p = strchr(name, '.'); - int stat; - if (p == NULL) return 0; /* is root */ - lua_pushlstring(L, name, p - name); - filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); - if (filename == NULL) return 1; /* root not found */ - if ((stat = loadfunc(L, filename, name)) != 0) { - if (stat != ERRFUNC) - return checkload(L, 0, filename); /* real error */ - else { /* open function not found */ - lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); - return 1; - } - } - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; +static int searcher_Croot(lua_State* L) +{ + const char* filename; + const char* name = luaL_checkstring(L, 1); + const char* p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* root not found */ + if ((stat = loadfunc(L, filename, name)) != 0) + { + if (stat != ERRFUNC) + return checkload(L, 0, filename); /* real error */ + else + { + /* open function not found */ + lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); + return 1; + } + } + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; } -static int searcher_preload (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ - lua_pushfstring(L, "\n\tno field package.preload['%s']", name); - return 1; +static int searcher_preload(lua_State* L) +{ + const char* name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; } -static void findloader (lua_State *L, const char *name) { - int i; - luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); - /* push 'package.searchers' to index 3 in the stack */ - if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) - luaL_error(L, "'package.searchers' must be a table"); - /* iterate over available searchers to find a loader */ - for (i = 1; ; i++) { - if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ - lua_pop(L, 1); /* remove nil */ - luaL_pushresult(&msg); /* create error message */ - luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); - } - lua_pushstring(L, name); - lua_call(L, 1, 2); /* call it */ - if (lua_isfunction(L, -2)) /* did it find a loader? */ - return; /* module loader found */ - else if (lua_isstring(L, -2)) { /* searcher returned error message? */ - lua_pop(L, 1); /* remove extra return */ - luaL_addvalue(&msg); /* concatenate error message */ - } - else - lua_pop(L, 2); /* remove both returns */ - } +static void findloader(lua_State* L, const char* name) +{ + int i; + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + /* push 'package.searchers' to index 3 in the stack */ + if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) + luaL_error(L, "'package.searchers' must be a table"); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) + { + if (lua_rawgeti(L, 3, i) == LUA_TNIL) + { + /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_pushresult(&msg); /* create error message */ + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) + { + /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(&msg); /* concatenate error message */ + } + else + lua_pop(L, 2); /* remove both returns */ + } } -static int ll_require (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_settop(L, 1); /* LOADED table will be at index 2 */ - lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_getfield(L, 2, name); /* LOADED[name] */ - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded */ - /* else must load package */ - lua_pop(L, 1); /* remove 'getfield' result */ - findloader(L, name); - lua_pushstring(L, name); /* pass name as argument to module loader */ - lua_insert(L, -2); /* name is 1st argument (before search data) */ - lua_call(L, 2, 1); /* run loader to load module */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* LOADED[name] = returned value */ - if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ - lua_pushboolean(L, 1); /* use true as result */ - lua_pushvalue(L, -1); /* extra copy to be returned */ - lua_setfield(L, 2, name); /* LOADED[name] = true */ - } - return 1; +static int ll_require(lua_State* L) +{ + const char* name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded */ + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); + lua_pushstring(L, name); /* pass name as argument to module loader */ + lua_insert(L, -2); /* name is 1st argument (before search data) */ + lua_call(L, 2, 1); /* run loader to load module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + if (lua_getfield(L, 2, name) == LUA_TNIL) + { + /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ + } + return 1; } /* }====================================================== */ - /* ** {====================================================== ** 'module' function @@ -704,20 +748,19 @@ static int ll_seeall (lua_State *L) { /* }====================================================== */ - static const luaL_Reg pk_funcs[] = { - {"loadlib", ll_loadlib}, - {"searchpath", ll_searchpath}, + {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, #if defined(LUA_COMPAT_MODULE) {"seeall", ll_seeall}, #endif - /* placeholders */ - {"preload", NULL}, - {"cpath", NULL}, - {"path", NULL}, - {"searchers", NULL}, - {"loaded", NULL}, - {NULL, NULL} + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, + {NULL, NULL} }; @@ -725,28 +768,30 @@ static const luaL_Reg ll_funcs[] = { #if defined(LUA_COMPAT_MODULE) {"module", ll_module}, #endif - {"require", ll_require}, - {NULL, NULL} + {"require", ll_require}, + {NULL, NULL} }; -static void createsearcherstable (lua_State *L) { - static const lua_CFunction searchers[] = - {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; - int i; - /* create 'searchers' table */ - lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); - /* fill it with predefined searchers */ - for (i=0; searchers[i] != NULL; i++) { - lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ - lua_pushcclosure(L, searchers[i], 1); - lua_rawseti(L, -2, i+1); - } +static void createsearcherstable(lua_State* L) +{ + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers) / sizeof(searchers[0]) - 1, 0); + /* fill it with predefined searchers */ + for (i = 0; searchers[i] != NULL; i++) + { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i + 1); + } #if defined(LUA_COMPAT_LOADERS) lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ #endif - lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ } @@ -754,37 +799,38 @@ static void createsearcherstable (lua_State *L) { ** create table CLIBS to keep track of loaded C libraries, ** setting a finalizer to close all libraries when closing state. */ -static void createclibstable (lua_State *L) { - lua_newtable(L); /* create CLIBS table */ - lua_createtable(L, 0, 1); /* create metatable for CLIBS */ - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ - lua_setmetatable(L, -2); - lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ +static void createclibstable(lua_State* L) +{ + lua_newtable(L); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); + lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ } -LUAMOD_API int luaopen_package (lua_State *L) { - createclibstable(L); - luaL_newlib(L, pk_funcs); /* create 'package' table */ - createsearcherstable(L); - /* set paths */ - setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); - setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); - /* store config information */ - lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" - LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); - lua_setfield(L, -2, "config"); - /* set field 'loaded' */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_setfield(L, -2, "loaded"); - /* set field 'preload' */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - lua_setfield(L, -2, "preload"); - lua_pushglobaltable(L); - lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ - luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ - lua_pop(L, 1); /* pop global table */ - return 1; /* return 'package' table */ +LUAMOD_API int luaopen_package(lua_State* L) +{ + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ + createsearcherstable(L); + /* set paths */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); + lua_setfield(L, -2, "config"); + /* set field 'loaded' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, "loaded"); + /* set field 'preload' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, "preload"); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ + return 1; /* return 'package' table */ } - diff --git a/Lua/lobject.c b/Lua/lobject.c index 2da7689..53c3e3f 100644 --- a/Lua/lobject.c +++ b/Lua/lobject.c @@ -29,7 +29,6 @@ #include "lvm.h" - LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; @@ -38,142 +37,185 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ -int luaO_int2fb (unsigned int x) { - int e = 0; /* exponent */ - if (x < 8) return x; - while (x >= (8 << 4)) { /* coarse steps */ - x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ - e += 4; - } - while (x >= (8 << 1)) { /* fine steps */ - x = (x + 1) >> 1; /* x = ceil(x / 2) */ - e++; - } - return ((e+1) << 3) | (cast_int(x) - 8); +int luaO_int2fb(unsigned int x) +{ + int e = 0; /* exponent */ + if (x < 8) return x; + while (x >= (8 << 4)) + { + /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) + { + /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ + e++; + } + return ((e + 1) << 3) | (cast_int(x) - 8); } /* converts back */ -int luaO_fb2int (int x) { - return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); +int luaO_fb2int(int x) +{ + return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); } /* ** Computes ceil(log2(x)) */ -int luaO_ceillog2 (unsigned int x) { - static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - }; - int l = 0; - x--; - while (x >= 256) { l += 8; x >>= 8; } - return l + log_2[x]; +int luaO_ceillog2(unsigned int x) +{ + static const lu_byte log_2[256] = { + /* log_2[i] = ceil(log2(i - 1)) */ + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 + }; + int l = 0; + x--; + while (x >= 256) + { + l += 8; + x >>= 8; + } + return l + log_2[x]; } -static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, - lua_Integer v2) { - switch (op) { - case LUA_OPADD: return intop(+, v1, v2); - case LUA_OPSUB:return intop(-, v1, v2); - case LUA_OPMUL:return intop(*, v1, v2); - case LUA_OPMOD: return luaV_mod(L, v1, v2); - case LUA_OPIDIV: return luaV_div(L, v1, v2); - case LUA_OPBAND: return intop(&, v1, v2); - case LUA_OPBOR: return intop(|, v1, v2); - case LUA_OPBXOR: return intop(^, v1, v2); - case LUA_OPSHL: return luaV_shiftl(v1, v2); - case LUA_OPSHR: return luaV_shiftl(v1, -v2); - case LUA_OPUNM: return intop(-, 0, v1); - case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); - default: lua_assert(0); return 0; - } +static lua_Integer intarith(lua_State* L, int op, lua_Integer v1, + lua_Integer v2) +{ + switch (op) + { + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB: return intop(-, v1, v2); + case LUA_OPMUL: return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_div(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftl(v1, -v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); + default: lua_assert(0); + return 0; + } } -static lua_Number numarith (lua_State *L, int op, lua_Number v1, - lua_Number v2) { - switch (op) { - case LUA_OPADD: return luai_numadd(L, v1, v2); - case LUA_OPSUB: return luai_numsub(L, v1, v2); - case LUA_OPMUL: return luai_nummul(L, v1, v2); - case LUA_OPDIV: return luai_numdiv(L, v1, v2); - case LUA_OPPOW: return luai_numpow(L, v1, v2); - case LUA_OPIDIV: return luai_numidiv(L, v1, v2); - case LUA_OPUNM: return luai_numunm(L, v1); - case LUA_OPMOD: { - lua_Number m; - luai_nummod(L, v1, v2, m); - return m; - } - default: lua_assert(0); return 0; - } +static lua_Number numarith(lua_State* L, int op, lua_Number v1, + lua_Number v2) +{ + switch (op) + { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: + { + lua_Number m; + luai_nummod(L, v1, v2, m); + return m; + } + default: lua_assert(0); + return 0; + } } -void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, - TValue *res) { - switch (op) { - case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: - case LUA_OPSHL: case LUA_OPSHR: - case LUA_OPBNOT: { /* operate only on integers */ - lua_Integer i1; lua_Integer i2; - if (tointeger(p1, &i1) && tointeger(p2, &i2)) { - setivalue(res, intarith(L, op, i1, i2)); - return; - } - else break; /* go to the end */ - } - case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ - lua_Number n1; lua_Number n2; - if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setfltvalue(res, numarith(L, op, n1, n2)); - return; - } - else break; /* go to the end */ - } - default: { /* other operations */ - lua_Number n1; lua_Number n2; - if (ttisinteger(p1) && ttisinteger(p2)) { - setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); - return; - } - else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setfltvalue(res, numarith(L, op, n1, n2)); - return; - } - else break; /* go to the end */ - } - } - /* could not perform raw operation; try metamethod */ - lua_assert(L != NULL); /* should not fail when folding (compile time) */ - luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); +void luaO_arith(lua_State* L, int op, const TValue* p1, const TValue* p2, + TValue* res) +{ + switch (op) + { + case LUA_OPBAND: + case LUA_OPBOR: + case LUA_OPBXOR: + case LUA_OPSHL: + case LUA_OPSHR: + case LUA_OPBNOT: + { + /* operate only on integers */ + lua_Integer i1; + lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) + { + setivalue(res, intarith(L, op, i1, i2)); + return; + } + else break; /* go to the end */ + } + case LUA_OPDIV: + case LUA_OPPOW: + { + /* operate only on floats */ + lua_Number n1; + lua_Number n2; + if (tonumber(p1, &n1) && tonumber(p2, &n2)) + { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + default: + { + /* other operations */ + lua_Number n1; + lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) + { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) + { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + } + /* could not perform raw operation; try metamethod */ + lua_assert(L != NULL); /* should not fail when folding (compile time) */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); } -int luaO_hexavalue (int c) { - if (lisdigit(c)) return c - '0'; - else return (ltolower(c) - 'a') + 10; +int luaO_hexavalue(int c) +{ + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; } -static int isneg (const char **s) { - if (**s == '-') { (*s)++; return 1; } - else if (**s == '+') (*s)++; - return 0; +static int isneg(const char** s) +{ + if (**s == '-') + { + (*s)++; + return 1; + } + else if (**s == '+') (*s)++; + return 0; } - /* ** {================================================================== ** Lua's implementation for 'lua_strx2number' @@ -190,53 +232,60 @@ static int isneg (const char **s) { ** convert an hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ -static lua_Number lua_strx2number (const char *s, char **endptr) { - int dot = lua_getlocaledecpoint(); - lua_Number r = 0.0; /* result (accumulator) */ - int sigdig = 0; /* number of significant digits */ - int nosigdig = 0; /* number of non-significant digits */ - int e = 0; /* exponent correction */ - int neg; /* 1 if number is negative */ - int hasdot = 0; /* true after seen a dot */ - *endptr = cast(char *, s); /* nothing is valid yet */ - while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ - neg = isneg(&s); /* check signal */ - if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ - return 0.0; /* invalid format (no '0x') */ - for (s += 2; ; s++) { /* skip '0x' and read numeral */ - if (*s == dot) { - if (hasdot) break; /* second dot? stop loop */ - else hasdot = 1; - } - else if (lisxdigit(cast_uchar(*s))) { - if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ - nosigdig++; - else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ - r = (r * cast_num(16.0)) + luaO_hexavalue(*s); - else e++; /* too many digits; ignore, but still count for exponent */ - if (hasdot) e--; /* decimal digit? correct exponent */ - } - else break; /* neither a dot nor a digit */ - } - if (nosigdig + sigdig == 0) /* no digits? */ - return 0.0; /* invalid format */ - *endptr = cast(char *, s); /* valid up to here */ - e *= 4; /* each digit multiplies/divides value by 2^4 */ - if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; /* exponent value */ - int neg1; /* exponent signal */ - s++; /* skip 'p' */ - neg1 = isneg(&s); /* signal */ - if (!lisdigit(cast_uchar(*s))) - return 0.0; /* invalid; must have at least one digit */ - while (lisdigit(cast_uchar(*s))) /* read exponent */ - exp1 = exp1 * 10 + *(s++) - '0'; - if (neg1) exp1 = -exp1; - e += exp1; - *endptr = cast(char *, s); /* valid up to here */ - } - if (neg) r = -r; - return l_mathop(ldexp)(r, e); +static lua_Number lua_strx2number(const char* s, char** endptr) +{ + int dot = lua_getlocaledecpoint(); + lua_Number r = 0.0; /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ + *endptr = cast(char *, s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check signal */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return 0.0; /* invalid format (no '0x') */ + for (s += 2; ; s++) + { + /* skip '0x' and read numeral */ + if (*s == dot) + { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) + { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ + } + if (nosigdig + sigdig == 0) /* no digits? */ + return 0.0; /* invalid format */ + *endptr = cast(char *, s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ + if (*s == 'p' || *s == 'P') + { + /* exponent part? */ + int exp1 = 0; /* exponent value */ + int neg1; /* exponent signal */ + s++; /* skip 'p' */ + neg1 = isneg(&s); /* signal */ + if (!lisdigit(cast_uchar(*s))) + return 0.0; /* invalid; must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + *endptr = cast(char *, s); /* valid up to here */ + } + if (neg) r = -r; + return l_mathop(ldexp)(r, e); } #endif @@ -248,13 +297,15 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { #define L_MAXLENNUM 200 #endif -static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { - char *endptr; - *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ - : lua_str2number(s, &endptr); - if (endptr == s) return NULL; /* nothing recognized? */ - while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ - return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ +static const char* l_str2dloc(const char* s, lua_Number* result, int mode) +{ + char* endptr; + *result = (mode == 'x') + ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ } @@ -271,93 +322,116 @@ static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { ** to a buffer (because 's' is read-only), changes the dot to the ** current locale radix mark, and tries to convert again. */ -static const char *l_str2d (const char *s, lua_Number *result) { - const char *endptr; - const char *pmode = strpbrk(s, ".xXnN"); - int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; - if (mode == 'n') /* reject 'inf' and 'nan' */ - return NULL; - endptr = l_str2dloc(s, result, mode); /* try to convert */ - if (endptr == NULL) { /* failed? may be a different locale */ - char buff[L_MAXLENNUM + 1]; - const char *pdot = strchr(s, '.'); - if (strlen(s) > L_MAXLENNUM || pdot == NULL) - return NULL; /* string too long or no dot; fail */ - strcpy(buff, s); /* copy string to buffer */ - buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ - endptr = l_str2dloc(buff, result, mode); /* try again */ - if (endptr != NULL) - endptr = s + (endptr - buff); /* make relative to 's' */ - } - return endptr; +static const char* l_str2d(const char* s, lua_Number* result) +{ + const char* endptr; + const char* pmode = strpbrk(s, ".xXnN"); + int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; + if (mode == 'n') /* reject 'inf' and 'nan' */ + return NULL; + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) + { + /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + const char* pdot = strchr(s, '.'); + if (strlen(s) > L_MAXLENNUM || pdot == NULL) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; } #define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) #define MAXLASTD cast_int(LUA_MAXINTEGER % 10) -static const char *l_str2int (const char *s, lua_Integer *result) { - lua_Unsigned a = 0; - int empty = 1; - int neg; - while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ - neg = isneg(&s); - if (s[0] == '0' && - (s[1] == 'x' || s[1] == 'X')) { /* hex? */ - s += 2; /* skip '0x' */ - for (; lisxdigit(cast_uchar(*s)); s++) { - a = a * 16 + luaO_hexavalue(*s); - empty = 0; - } - } - else { /* decimal */ - for (; lisdigit(cast_uchar(*s)); s++) { - int d = *s - '0'; - if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ - return NULL; /* do not accept it (as integer) */ - a = a * 10 + d; - empty = 0; - } - } - while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ - if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ - else { - *result = l_castU2S((neg) ? 0u - a : a); - return s; - } +static const char* l_str2int(const char* s, lua_Integer* result) +{ + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) + { + /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) + { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else + { + /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) + { + int d = *s - '0'; + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return NULL; /* do not accept it (as integer) */ + a = a * 10 + d; + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else + { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } } -size_t luaO_str2num (const char *s, TValue *o) { - lua_Integer i; lua_Number n; - const char *e; - if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ - setivalue(o, i); - } - else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ - setfltvalue(o, n); - } - else - return 0; /* conversion failed */ - return (e - s) + 1; /* success; return string size */ +size_t luaO_str2num(const char* s, TValue* o) +{ + lua_Integer i; + lua_Number n; + const char* e; + if ((e = l_str2int(s, &i)) != NULL) + { + /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) + { + /* else try as a float */ + setfltvalue(o, n); + } + else + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ } -int luaO_utf8esc (char *buff, unsigned long x) { - int n = 1; /* number of bytes put in buffer (backwards) */ - lua_assert(x <= 0x10FFFF); - if (x < 0x80) /* ascii? */ - buff[UTF8BUFFSZ - 1] = cast(char, x); - else { /* need continuation bytes */ - unsigned int mfb = 0x3f; /* maximum that fits in first byte */ - do { /* add continuation bytes */ - buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); - x >>= 6; /* remove added bits */ - mfb >>= 1; /* now there is one less bit available in first byte */ - } while (x > mfb); /* still needs continuation byte? */ - buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ - } - return n; +int luaO_utf8esc(char* buff, unsigned long x) +{ + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x10FFFF); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast(char, x); + else + { + /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do + { + /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } + while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ + } + return n; } @@ -368,28 +442,33 @@ int luaO_utf8esc (char *buff, unsigned long x) { /* ** Convert a number object to a string */ -void luaO_tostring (lua_State *L, StkId obj) { - char buff[MAXNUMBER2STR]; - size_t len; - lua_assert(ttisnumber(obj)); - if (ttisinteger(obj)) - len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); - else { - len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); +void luaO_tostring(lua_State* L, StkId obj) +{ + char buff[MAXNUMBER2STR]; + size_t len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); + else + { + len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); #if !defined(LUA_COMPAT_FLOATSTRING) - if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ - buff[len++] = lua_getlocaledecpoint(); - buff[len++] = '0'; /* adds '.0' to result */ - } + if (buff[strspn(buff, "-0123456789")] == '\0') + { + /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } #endif - } - setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); + } + setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); } -static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); - luaD_inctop(L); +static void pushstr(lua_State* L, const char* str, size_t l) +{ + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); + luaD_inctop(L); } @@ -397,80 +476,100 @@ static void pushstr (lua_State *L, const char *str, size_t l) { ** this function handles only '%d', '%c', '%f', '%p', and '%s' conventional formats, plus Lua-specific '%I' and '%U' */ -const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - int n = 0; - for (;;) { - const char *e = strchr(fmt, '%'); - if (e == NULL) break; - pushstr(L, fmt, e - fmt); - switch (*(e+1)) { - case 's': { /* zero-terminated string */ - const char *s = va_arg(argp, char *); - if (s == NULL) s = "(null)"; - pushstr(L, s, strlen(s)); - break; - } - case 'c': { /* an 'int' as a character */ - char buff = cast(char, va_arg(argp, int)); - if (lisprint(cast_uchar(buff))) - pushstr(L, &buff, 1); - else /* non-printable character; print its code */ - luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); - break; - } - case 'd': { /* an 'int' */ - setivalue(L->top, va_arg(argp, int)); - goto top2str; - } - case 'I': { /* a 'lua_Integer' */ - setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); - goto top2str; - } - case 'f': { /* a 'lua_Number' */ - setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); - top2str: /* convert the top element to a string */ - luaD_inctop(L); - luaO_tostring(L, L->top - 1); - break; - } - case 'p': { /* a pointer */ - char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ - int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); - pushstr(L, buff, l); - break; - } - case 'U': { /* an 'int' as a UTF-8 sequence */ - char buff[UTF8BUFFSZ]; - int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); - pushstr(L, buff + UTF8BUFFSZ - l, l); - break; - } - case '%': { - pushstr(L, "%", 1); - break; - } - default: { - luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", - *(e + 1)); - } - } - n += 2; - fmt = e+2; - } - luaD_checkstack(L, 1); - pushstr(L, fmt, strlen(fmt)); - if (n > 0) luaV_concat(L, n + 1); - return svalue(L->top - 1); +const char* luaO_pushvfstring(lua_State* L, const char* fmt, va_list argp) +{ + int n = 0; + for (;;) + { + const char* e = strchr(fmt, '%'); + if (e == NULL) break; + pushstr(L, fmt, e - fmt); + switch (*(e + 1)) + { + case 's': + { + /* zero-terminated string */ + const char* s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s, strlen(s)); + break; + } + case 'c': + { + /* an 'int' as a character */ + char buff = cast(char, va_arg(argp, int)); + if (lisprint(cast_uchar(buff))) + pushstr(L, &buff, 1); + else /* non-printable character; print its code */ + luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); + break; + } + case 'd': + { + /* an 'int' */ + setivalue(L->top, va_arg(argp, int)); + goto top2str; + } + case 'I': + { + /* a 'lua_Integer' */ + setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); + goto top2str; + } + case 'f': + { + /* a 'lua_Number' */ + setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + top2str: /* convert the top element to a string */ + luaD_inctop(L); + luaO_tostring(L, L->top - 1); + break; + } + case 'p': + { + /* a pointer */ + char buff[4 * sizeof(void*) + 8]; /* should be enough space for a '%p' */ + int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); + pushstr(L, buff, l); + break; + } + case 'U': + { + /* an 'int' as a UTF-8 sequence */ + char buff[UTF8BUFFSZ]; + int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); + pushstr(L, buff + UTF8BUFFSZ - l, l); + break; + } + case '%': + { + pushstr(L, "%", 1); + break; + } + default: + { + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); + } + } + n += 2; + fmt = e + 2; + } + luaD_checkstack(L, 1); + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); + return svalue(L->top - 1); } -const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - return msg; +const char* luaO_pushfstring(lua_State* L, const char* fmt, ...) +{ + const char* msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; } @@ -483,39 +582,52 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { #define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) -void luaO_chunkid (char *out, const char *source, size_t bufflen) { - size_t l = strlen(source); - if (*source == '=') { /* 'literal' source */ - if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l * sizeof(char)); - else { /* truncate it */ - addstr(out, source + 1, bufflen - 1); - *out = '\0'; - } - } - else if (*source == '@') { /* file name */ - if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l * sizeof(char)); - else { /* add '...' before rest of name */ - addstr(out, RETS, LL(RETS)); - bufflen -= LL(RETS); - memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); - } - } - else { /* string; format as [string "source"] */ - const char *nl = strchr(source, '\n'); /* find first new line (if any) */ - addstr(out, PRE, LL(PRE)); /* add prefix */ - bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ - if (l < bufflen && nl == NULL) { /* small one-line source? */ - addstr(out, source, l); /* keep it */ - } - else { - if (nl != NULL) l = nl - source; /* stop at first newline */ - if (l > bufflen) l = bufflen; - addstr(out, source, l); - addstr(out, RETS, LL(RETS)); - } - memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); - } +void luaO_chunkid(char* out, const char* source, size_t bufflen) +{ + size_t l = strlen(source); + if (*source == '=') + { + /* 'literal' source */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else + { + /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } + else if (*source == '@') + { + /* file name */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else + { + /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); + } + } + else + { + /* string; format as [string "source"] */ + const char* nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ + if (l < bufflen && nl == NULL) + { + /* small one-line source? */ + addstr(out, source, l); /* keep it */ + } + else + { + if (nl != NULL) l = nl - source; /* stop at first newline */ + if (l > bufflen) l = bufflen; + addstr(out, source, l); + addstr(out, RETS, LL(RETS)); + } + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); + } } - diff --git a/Lua/lobject.h b/Lua/lobject.h index 3c04228..539c2a1 100644 --- a/Lua/lobject.h +++ b/Lua/lobject.h @@ -82,13 +82,12 @@ typedef struct GCObject GCObject; /* ** Common type has only the common header */ -struct GCObject { - CommonHeader; +struct GCObject +{ + CommonHeader; }; - - /* ** Tagged Values. This is the basic representation of values in Lua, ** an actual value plus a tag with its type. @@ -97,25 +96,26 @@ struct GCObject { /* ** Union of all Lua values */ -typedef union Value { - GCObject *gc; /* collectable objects */ - void *p; /* light userdata */ - int b; /* booleans */ - lua_CFunction f; /* light C functions */ - lua_Integer i; /* integer numbers */ - lua_Number n; /* float numbers */ +typedef union Value +{ + GCObject* gc; /* collectable objects */ + void* p; /* light userdata */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ } Value; #define TValuefields Value value_; int tt_ -typedef struct lua_TValue { - TValuefields; +typedef struct lua_TValue +{ + TValuefields; } TValue; - /* macro defining a nil value */ #define NILCONSTANT {NULL}, LUA_TNIL @@ -255,7 +255,6 @@ typedef struct lua_TValue { #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) - #define setobj(L,obj1,obj2) \ { TValue *io1=(obj1); *io1 = *(obj2); \ (void)L; checkliveness(L,io1); } @@ -282,8 +281,6 @@ typedef struct lua_TValue { #define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) - - /* ** {====================================================== ** types and prototypes @@ -291,33 +288,35 @@ typedef struct lua_TValue { */ -typedef TValue *StkId; /* index to stack elements */ - - +typedef TValue* StkId; /* index to stack elements */ /* ** Header for string value; string bytes follow the end of this structure ** (aligned according to 'UTString'; see next). */ -typedef struct TString { - CommonHeader; - lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - lu_byte shrlen; /* length for short strings */ - unsigned int hash; - union { - size_t lnglen; /* length for long strings */ - struct TString *hnext; /* linked list for hash table */ - } u; +typedef struct TString +{ + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + + union + { + size_t lnglen; /* length for long strings */ + struct TString* hnext; /* linked list for hash table */ + } u; } TString; /* ** Ensures that address after this type is always fully aligned. */ -typedef union UTString { - L_Umaxalign dummy; /* ensures maximum alignment for strings */ - TString tsv; +typedef union UTString +{ + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + TString tsv; } UTString; @@ -343,21 +342,23 @@ typedef union UTString { ** Header for userdata; memory area follows the end of this structure ** (aligned according to 'UUdata'; see next). */ -typedef struct Udata { - CommonHeader; - lu_byte ttuv_; /* user value's tag */ - struct Table *metatable; - size_t len; /* number of bytes */ - union Value user_; /* user value */ +typedef struct Udata +{ + CommonHeader; + lu_byte ttuv_; /* user value's tag */ + struct Table* metatable; + size_t len; /* number of bytes */ + union Value user_; /* user value */ } Udata; /* ** Ensures that address after this type is always fully aligned. */ -typedef union UUdata { - L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ - Udata uv; +typedef union UUdata +{ + L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ + Udata uv; } UUdata; @@ -383,10 +384,11 @@ typedef union UUdata { /* ** Description of an upvalue for function prototypes */ -typedef struct Upvaldesc { - TString *name; /* upvalue name (for debug information) */ - lu_byte instack; /* whether it is in stack (register) */ - lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ +typedef struct Upvaldesc +{ + TString* name; /* upvalue name (for debug information) */ + lu_byte instack; /* whether it is in stack (register) */ + lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ } Upvaldesc; @@ -394,42 +396,43 @@ typedef struct Upvaldesc { ** Description of a local variable for function prototypes ** (used for debug information) */ -typedef struct LocVar { - TString *varname; - int startpc; /* first point where variable is active */ - int endpc; /* first point where variable is dead */ +typedef struct LocVar +{ + TString* varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ } LocVar; /* ** Function Prototypes */ -typedef struct Proto { - CommonHeader; - lu_byte numparams; /* number of fixed parameters */ - lu_byte is_vararg; - lu_byte maxstacksize; /* number of registers needed by this function */ - int sizeupvalues; /* size of 'upvalues' */ - int sizek; /* size of 'k' */ - int sizecode; - int sizelineinfo; - int sizep; /* size of 'p' */ - int sizelocvars; - int linedefined; /* debug information */ - int lastlinedefined; /* debug information */ - TValue *k; /* constants used by the function */ - Instruction *code; /* opcodes */ - struct Proto **p; /* functions defined inside the function */ - int *lineinfo; /* map from opcodes to source lines (debug information) */ - LocVar *locvars; /* information about local variables (debug information) */ - Upvaldesc *upvalues; /* upvalue information */ - struct LClosure *cache; /* last-created closure with this prototype */ - TString *source; /* used for debug information */ - GCObject *gclist; +typedef struct Proto +{ + CommonHeader; + lu_byte numparams; /* number of fixed parameters */ + lu_byte is_vararg; + lu_byte maxstacksize; /* number of registers needed by this function */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of 'k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of 'p' */ + int sizelocvars; + int linedefined; /* debug information */ + int lastlinedefined; /* debug information */ + TValue* k; /* constants used by the function */ + Instruction* code; /* opcodes */ + struct Proto** p; /* functions defined inside the function */ + int* lineinfo; /* map from opcodes to source lines (debug information) */ + LocVar* locvars; /* information about local variables (debug information) */ + Upvaldesc* upvalues; /* upvalue information */ + struct LClosure* cache; /* last-created closure with this prototype */ + TString* source; /* used for debug information */ + GCObject* gclist; } Proto; - /* ** Lua Upvalues */ @@ -443,23 +446,26 @@ typedef struct UpVal UpVal; #define ClosureHeader \ CommonHeader; lu_byte nupvalues; GCObject *gclist -typedef struct CClosure { - ClosureHeader; - lua_CFunction f; - TValue upvalue[1]; /* list of upvalues */ +typedef struct CClosure +{ + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; /* list of upvalues */ } CClosure; -typedef struct LClosure { - ClosureHeader; - struct Proto *p; - UpVal *upvals[1]; /* list of upvalues */ +typedef struct LClosure +{ + ClosureHeader; + struct Proto* p; + UpVal* upvals[1]; /* list of upvalues */ } LClosure; -typedef union Closure { - CClosure c; - LClosure l; +typedef union Closure +{ + CClosure c; + LClosure l; } Closure; @@ -472,12 +478,15 @@ typedef union Closure { ** Tables */ -typedef union TKey { - struct { - TValuefields; - int next; /* for chaining (offset for next node) */ - } nk; - TValue tvk; +typedef union TKey +{ + struct + { + TValuefields; + int next; /* for chaining (offset for next node) */ + } nk; + + TValue tvk; } TKey; @@ -488,26 +497,27 @@ typedef union TKey { (void)L; checkliveness(L,io_); } -typedef struct Node { - TValue i_val; - TKey i_key; +typedef struct Node +{ + TValue i_val; + TKey i_key; } Node; -typedef struct Table { - CommonHeader; - lu_byte flags; /* 1<

> RK(C) */ -OP_UNM,/* A B R(A) := -R(B) */ -OP_BNOT,/* A B R(A) := ~R(B) */ -OP_NOT,/* A B R(A) := not R(B) */ -OP_LEN,/* A B R(A) := length of R(B) */ + OP_ADD, + /* A B C R(A) := RK(B) + RK(C) */ + OP_SUB, + /* A B C R(A) := RK(B) - RK(C) */ + OP_MUL, + /* A B C R(A) := RK(B) * RK(C) */ + OP_MOD, + /* A B C R(A) := RK(B) % RK(C) */ + OP_POW, + /* A B C R(A) := RK(B) ^ RK(C) */ + OP_DIV, + /* A B C R(A) := RK(B) / RK(C) */ + OP_IDIV, + /* A B C R(A) := RK(B) // RK(C) */ + OP_BAND, + /* A B C R(A) := RK(B) & RK(C) */ + OP_BOR, + /* A B C R(A) := RK(B) | RK(C) */ + OP_BXOR, + /* A B C R(A) := RK(B) ~ RK(C) */ + OP_SHL, + /* A B C R(A) := RK(B) << RK(C) */ + OP_SHR, + /* A B C R(A) := RK(B) >> RK(C) */ + OP_UNM, + /* A B R(A) := -R(B) */ + OP_BNOT, + /* A B R(A) := ~R(B) */ + OP_NOT, + /* A B R(A) := not R(B) */ + OP_LEN, + /* A B R(A) := length of R(B) */ -OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ + OP_CONCAT, + /* A B C R(A) := R(B).. ... ..R(C) */ -OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ -OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ -OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ -OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ + OP_JMP, + /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ + OP_EQ, + /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ + OP_LT, + /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ + OP_LE, + /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ -OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ -OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + OP_TEST, + /* A C if not (R(A) <=> C) then pc++ */ + OP_TESTSET, + /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ -OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ -OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ -OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + OP_CALL, + /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ + OP_TAILCALL, + /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ + OP_RETURN, + /* A B return R(A), ... ,R(A+B-2) (see note) */ -OP_FORLOOP,/* A sBx R(A)+=R(A+2); - if R(A) tm_sec); - setfield(L, "min", stm->tm_min); - setfield(L, "hour", stm->tm_hour); - setfield(L, "day", stm->tm_mday); - setfield(L, "month", stm->tm_mon + 1); - setfield(L, "year", stm->tm_year + 1900); - setfield(L, "wday", stm->tm_wday + 1); - setfield(L, "yday", stm->tm_yday + 1); - setboolfield(L, "isdst", stm->tm_isdst); +static void setallfields(lua_State* L, struct tm* stm) +{ + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon + 1); + setfield(L, "year", stm->tm_year + 1900); + setfield(L, "wday", stm->tm_wday + 1); + setfield(L, "yday", stm->tm_yday + 1); + setboolfield(L, "isdst", stm->tm_isdst); } -static int getboolfield (lua_State *L, const char *key) { - int res; - res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); - lua_pop(L, 1); - return res; +static int getboolfield(lua_State* L, const char* key) +{ + int res; + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; } @@ -236,43 +246,51 @@ static int getboolfield (lua_State *L, const char *key) { #define L_MAXDATEFIELD (INT_MAX / 2) #endif -static int getfield (lua_State *L, const char *key, int d, int delta) { - int isnum; - int t = lua_getfield(L, -1, key); /* get field and its type */ - lua_Integer res = lua_tointegerx(L, -1, &isnum); - if (!isnum) { /* field is not an integer? */ - if (t != LUA_TNIL) /* some other value? */ - return luaL_error(L, "field '%s' is not an integer", key); - else if (d < 0) /* absent field; no default? */ - return luaL_error(L, "field '%s' missing in date table", key); - res = d; - } - else { - if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) - return luaL_error(L, "field '%s' is out-of-bound", key); - res -= delta; - } - lua_pop(L, 1); - return (int)res; +static int getfield(lua_State* L, const char* key, int d, int delta) +{ + int isnum; + int t = lua_getfield(L, -1, key); /* get field and its type */ + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) + { + /* field is not an integer? */ + if (t != LUA_TNIL) /* some other value? */ + return luaL_error(L, "field '%s' is not an integer", key); + else if (d < 0) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); + res = d; + } + else + { + if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) + return luaL_error(L, "field '%s' is out-of-bound", key); + res -= delta; + } + lua_pop(L, 1); + return (int)res; } -static const char *checkoption (lua_State *L, const char *conv, - ptrdiff_t convlen, char *buff) { - const char *option = LUA_STRFTIMEOPTIONS; - int oplen = 1; /* length of options being checked */ - for (; *option != '\0' && oplen <= convlen; option += oplen) { - if (*option == '|') /* next block? */ - oplen++; /* will check options with next length (+1) */ - else if (memcmp(conv, option, oplen) == 0) { /* match? */ - memcpy(buff, conv, oplen); /* copy valid option to buffer */ - buff[oplen] = '\0'; - return conv + oplen; /* return next item */ - } - } - luaL_argerror(L, 1, - lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); - return conv; /* to avoid warnings */ +static const char* checkoption(lua_State* L, const char* conv, + ptrdiff_t convlen, char* buff) +{ + const char* option = LUA_STRFTIMEOPTIONS; + int oplen = 1; /* length of options being checked */ + for (; *option != '\0' && oplen <= convlen; option += oplen) + { + if (*option == '|') /* next block? */ + oplen++; /* will check options with next length (+1) */ + else if (memcmp(conv, option, oplen) == 0) + { + /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ } @@ -280,128 +298,143 @@ static const char *checkoption (lua_State *L, const char *conv, #define SIZETIMEFMT 250 -static int os_date (lua_State *L) { - size_t slen; - const char *s = luaL_optlstring(L, 1, "%c", &slen); - time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); - const char *se = s + slen; /* 's' end */ - struct tm tmr, *stm; - if (*s == '!') { /* UTC? */ - stm = l_gmtime(&t, &tmr); - s++; /* skip '!' */ - } - else - stm = l_localtime(&t, &tmr); - if (stm == NULL) /* invalid date? */ - luaL_error(L, "time result cannot be represented in this installation"); - if (strcmp(s, "*t") == 0) { - lua_createtable(L, 0, 9); /* 9 = number of fields */ - setallfields(L, stm); - } - else { - char cc[4]; /* buffer for individual conversion specifiers */ - luaL_Buffer b; - cc[0] = '%'; - luaL_buffinit(L, &b); - while (s < se) { - if (*s != '%') /* not a conversion specifier? */ - luaL_addchar(&b, *s++); - else { - size_t reslen; - char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); - s++; /* skip '%' */ - s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ - reslen = strftime(buff, SIZETIMEFMT, cc, stm); - luaL_addsize(&b, reslen); - } - } - luaL_pushresult(&b); - } - return 1; +static int os_date(lua_State* L) +{ + size_t slen; + const char* s = luaL_optlstring(L, 1, "%c", &slen); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); + const char* se = s + slen; /* 's' end */ + struct tm tmr, *stm; + if (*s == '!') + { + /* UTC? */ + stm = l_gmtime(&t, &tmr); + s++; /* skip '!' */ + } + else + stm = l_localtime(&t, &tmr); + if (stm == NULL) /* invalid date? */ + luaL_error(L, "time result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) + { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setallfields(L, stm); + } + else + { + char cc[4]; /* buffer for individual conversion specifiers */ + luaL_Buffer b; + cc[0] = '%'; + luaL_buffinit(L, &b); + while (s < se) + { + if (*s != '%') /* not a conversion specifier? */ + luaL_addchar(&b, *s++); + else + { + size_t reslen; + char* buff = luaL_prepbuffsize(&b, SIZETIMEFMT); + s++; /* skip '%' */ + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); + } + } + luaL_pushresult(&b); + } + return 1; } -static int os_time (lua_State *L) { - time_t t; - if (lua_isnoneornil(L, 1)) /* called without args? */ - t = time(NULL); /* get current time */ - else { - struct tm ts; - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0, 0); - ts.tm_min = getfield(L, "min", 0, 0); - ts.tm_hour = getfield(L, "hour", 12, 0); - ts.tm_mday = getfield(L, "day", -1, 0); - ts.tm_mon = getfield(L, "month", -1, 1); - ts.tm_year = getfield(L, "year", -1, 1900); - ts.tm_isdst = getboolfield(L, "isdst"); - t = mktime(&ts); - setallfields(L, &ts); /* update fields with normalized values */ - } - if (t != (time_t)(l_timet)t || t == (time_t)(-1)) - luaL_error(L, "time result cannot be represented in this installation"); - l_pushtime(L, t); - return 1; +static int os_time(lua_State* L) +{ + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else + { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_year = getfield(L, "year", -1, 1900); + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ + } + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + luaL_error(L, "time result cannot be represented in this installation"); + l_pushtime(L, t); + return 1; } -static int os_difftime (lua_State *L) { - time_t t1 = l_checktime(L, 1); - time_t t2 = l_checktime(L, 2); - lua_pushnumber(L, (lua_Number)difftime(t1, t2)); - return 1; +static int os_difftime(lua_State* L) +{ + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); + return 1; } /* }====================================================== */ -static int os_setlocale (lua_State *L) { - static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static const char *const catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", NULL}; - const char *l = luaL_optstring(L, 1, NULL); - int op = luaL_checkoption(L, 2, "all", catnames); - lua_pushstring(L, setlocale(cat[op], l)); - return 1; +static int os_setlocale(lua_State* L) +{ + static const int cat[] = { + LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME + }; + static const char* const catnames[] = { + "all", "collate", "ctype", "monetary", + "numeric", "time", NULL + }; + const char* l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; } -static int os_exit (lua_State *L) { - int status; - if (lua_isboolean(L, 1)) - status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); - else - status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); - if (lua_toboolean(L, 2)) - lua_close(L); - if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ - return 0; +static int os_exit(lua_State* L) +{ + int status; + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); + else + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; } static const luaL_Reg syslib[] = { - {"clock", os_clock}, - {"date", os_date}, - {"difftime", os_difftime}, - {"execute", os_execute}, - {"exit", os_exit}, - {"getenv", os_getenv}, - {"remove", os_remove}, - {"rename", os_rename}, - {"setlocale", os_setlocale}, - {"time", os_time}, - {"tmpname", os_tmpname}, - {NULL, NULL} + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} }; /* }====================================================== */ - -LUAMOD_API int luaopen_os (lua_State *L) { - luaL_newlib(L, syslib); - return 1; +LUAMOD_API int luaopen_os(lua_State* L) +{ + luaL_newlib(L, syslib); + return 1; } - diff --git a/Lua/lparser.c b/Lua/lparser.c index cd4512d..6a81824 100644 --- a/Lua/lparser.c +++ b/Lua/lparser.c @@ -28,7 +28,6 @@ #include "ltable.h" - /* maximum number of local variables per function (must be smaller than 250, due to the bytecode format) */ #define MAXVARS 200 @@ -45,209 +44,235 @@ /* ** nodes for block list (list of active blocks) */ -typedef struct BlockCnt { - struct BlockCnt *previous; /* chain */ - int firstlabel; /* index of first label in this block */ - int firstgoto; /* index of first pending goto in this block */ - lu_byte nactvar; /* # active locals outside the block */ - lu_byte upval; /* true if some variable in the block is an upvalue */ - lu_byte isloop; /* true if 'block' is a loop */ +typedef struct BlockCnt +{ + struct BlockCnt* previous; /* chain */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ + lu_byte nactvar; /* # active locals outside the block */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isloop; /* true if 'block' is a loop */ } BlockCnt; - /* ** prototypes for recursive non-terminal functions */ -static void statement (LexState *ls); -static void expr (LexState *ls, expdesc *v); +static void statement(LexState* ls); +static void expr(LexState* ls, expdesc* v); /* semantic error */ -static l_noret semerror (LexState *ls, const char *msg) { - ls->t.token = 0; /* remove "near " from final message */ - luaX_syntaxerror(ls, msg); +static l_noret semerror(LexState* ls, const char* msg) +{ + ls->t.token = 0; /* remove "near " from final message */ + luaX_syntaxerror(ls, msg); } -static l_noret error_expected (LexState *ls, int token) { - luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); +static l_noret error_expected(LexState* ls, int token) +{ + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); } -static l_noret errorlimit (FuncState *fs, int limit, const char *what) { - lua_State *L = fs->ls->L; - const char *msg; - int line = fs->f->linedefined; - const char *where = (line == 0) - ? "main function" - : luaO_pushfstring(L, "function at line %d", line); - msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", - what, limit, where); - luaX_syntaxerror(fs->ls, msg); +static l_noret errorlimit(FuncState* fs, int limit, const char* what) +{ + lua_State* L = fs->ls->L; + const char* msg; + int line = fs->f->linedefined; + const char* where = (line == 0) + ? "main function" + : luaO_pushfstring(L, "function at line %d", line); + msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); } -static void checklimit (FuncState *fs, int v, int l, const char *what) { - if (v > l) errorlimit(fs, l, what); +static void checklimit(FuncState* fs, int v, int l, const char* what) +{ + if (v > l) errorlimit(fs, l, what); } -static int testnext (LexState *ls, int c) { - if (ls->t.token == c) { - luaX_next(ls); - return 1; - } - else return 0; +static int testnext(LexState* ls, int c) +{ + if (ls->t.token == c) + { + luaX_next(ls); + return 1; + } + else return 0; } -static void check (LexState *ls, int c) { - if (ls->t.token != c) - error_expected(ls, c); +static void check(LexState* ls, int c) +{ + if (ls->t.token != c) + error_expected(ls, c); } -static void checknext (LexState *ls, int c) { - check(ls, c); - luaX_next(ls); +static void checknext(LexState* ls, int c) +{ + check(ls, c); + luaX_next(ls); } #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } - -static void check_match (LexState *ls, int what, int who, int where) { - if (!testnext(ls, what)) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - "%s expected (to close %s at line %d)", - luaX_token2str(ls, what), luaX_token2str(ls, who), where)); - } - } +static void check_match(LexState* ls, int what, int who, int where) +{ + if (!testnext(ls, what)) + { + if (where == ls->linenumber) + error_expected(ls, what); + else + { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "%s expected (to close %s at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } } -static TString *str_checkname (LexState *ls) { - TString *ts; - check(ls, TK_NAME); - ts = ls->t.seminfo.ts; - luaX_next(ls); - return ts; +static TString* str_checkname(LexState* ls) +{ + TString* ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; } -static void init_exp (expdesc *e, expkind k, int i) { - e->f = e->t = NO_JUMP; - e->k = k; - e->u.info = i; +static void init_exp(expdesc* e, expkind k, int i) +{ + e->f = e->t = NO_JUMP; + e->k = k; + e->u.info = i; } -static void codestring (LexState *ls, expdesc *e, TString *s) { - init_exp(e, VK, luaK_stringK(ls->fs, s)); +static void codestring(LexState* ls, expdesc* e, TString* s) +{ + init_exp(e, VK, luaK_stringK(ls->fs, s)); } -static void checkname (LexState *ls, expdesc *e) { - codestring(ls, e, str_checkname(ls)); +static void checkname(LexState* ls, expdesc* e) +{ + codestring(ls, e, str_checkname(ls)); } -static int registerlocalvar (LexState *ls, TString *varname) { - FuncState *fs = ls->fs; - Proto *f = fs->f; - int oldsize = f->sizelocvars; - luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, SHRT_MAX, "local variables"); - while (oldsize < f->sizelocvars) - f->locvars[oldsize++].varname = NULL; - f->locvars[fs->nlocvars].varname = varname; - luaC_objbarrier(ls->L, f, varname); - return fs->nlocvars++; +static int registerlocalvar(LexState* ls, TString* varname) +{ + FuncState* fs = ls->fs; + Proto* f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, SHRT_MAX, "local variables"); + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; + f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); + return fs->nlocvars++; } -static void new_localvar (LexState *ls, TString *name) { - FuncState *fs = ls->fs; - Dyndata *dyd = ls->dyd; - int reg = registerlocalvar(ls, name); - checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, - MAXVARS, "local variables"); - luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, Vardesc, MAX_INT, "local variables"); - dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); +static void new_localvar(LexState* ls, TString* name) +{ + FuncState* fs = ls->fs; + Dyndata* dyd = ls->dyd; + int reg = registerlocalvar(ls, name); + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, Vardesc, MAX_INT, "local variables"); + dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); } -static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { - new_localvar(ls, luaX_newstring(ls, name, sz)); +static void new_localvarliteral_(LexState* ls, const char* name, size_t sz) +{ + new_localvar(ls, luaX_newstring(ls, name, sz)); } #define new_localvarliteral(ls,v) \ new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) -static LocVar *getlocvar (FuncState *fs, int i) { - int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; - lua_assert(idx < fs->nlocvars); - return &fs->f->locvars[idx]; +static LocVar* getlocvar(FuncState* fs, int i) +{ + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; } -static void adjustlocalvars (LexState *ls, int nvars) { - FuncState *fs = ls->fs; - fs->nactvar = cast_byte(fs->nactvar + nvars); - for (; nvars; nvars--) { - getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; - } +static void adjustlocalvars(LexState* ls, int nvars) +{ + FuncState* fs = ls->fs; + fs->nactvar = cast_byte(fs->nactvar + nvars); + for (; nvars; nvars--) + { + getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; + } } -static void removevars (FuncState *fs, int tolevel) { - fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); - while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar)->endpc = fs->pc; +static void removevars(FuncState* fs, int tolevel) +{ + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } -static int searchupvalue (FuncState *fs, TString *name) { - int i; - Upvaldesc *up = fs->f->upvalues; - for (i = 0; i < fs->nups; i++) { - if (eqstr(up[i].name, name)) return i; - } - return -1; /* not found */ +static int searchupvalue(FuncState* fs, TString* name) +{ + int i; + Upvaldesc* up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) + { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ } -static int newupvalue (FuncState *fs, TString *name, expdesc *v) { - Proto *f = fs->f; - int oldsize = f->sizeupvalues; - checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); - luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, - Upvaldesc, MAXUPVAL, "upvalues"); - while (oldsize < f->sizeupvalues) - f->upvalues[oldsize++].name = NULL; - f->upvalues[fs->nups].instack = (v->k == VLOCAL); - f->upvalues[fs->nups].idx = cast_byte(v->u.info); - f->upvalues[fs->nups].name = name; - luaC_objbarrier(fs->ls->L, f, name); - return fs->nups++; +static int newupvalue(FuncState* fs, TString* name, expdesc* v) +{ + Proto* f = fs->f; + int oldsize = f->sizeupvalues; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, MAXUPVAL, "upvalues"); + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].instack = (v->k == VLOCAL); + f->upvalues[fs->nups].idx = cast_byte(v->u.info); + f->upvalues[fs->nups].name = name; + luaC_objbarrier(fs->ls->L, f, name); + return fs->nups++; } -static int searchvar (FuncState *fs, TString *n) { - int i; - for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { - if (eqstr(n, getlocvar(fs, i)->varname)) - return i; - } - return -1; /* not found */ +static int searchvar(FuncState* fs, TString* n) +{ + int i; + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) + { + if (eqstr(n, getlocvar(fs, i)->varname)) + return i; + } + return -1; /* not found */ } @@ -255,11 +280,12 @@ static int searchvar (FuncState *fs, TString *n) { Mark block where variable at given level was defined (to emit close instructions later). */ -static void markupval (FuncState *fs, int level) { - BlockCnt *bl = fs->bl; - while (bl->nactvar > level) - bl = bl->previous; - bl->upval = 1; +static void markupval(FuncState* fs, int level) +{ + BlockCnt* bl = fs->bl; + while (bl->nactvar > level) + bl = bl->previous; + bl->upval = 1; } @@ -267,132 +293,155 @@ static void markupval (FuncState *fs, int level) { Find variable with given name 'n'. If it is an upvalue, add this upvalue into all intermediate functions. */ -static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) /* no more levels? */ - init_exp(var, VVOID, 0); /* default is global */ - else { - int v = searchvar(fs, n); /* look up locals at current level */ - if (v >= 0) { /* found? */ - init_exp(var, VLOCAL, v); /* variable is local */ - if (!base) - markupval(fs, v); /* local will be used as an upval */ - } - else { /* not found as local at current level; try upvalues */ - int idx = searchupvalue(fs, n); /* try existing upvalues */ - if (idx < 0) { /* not found? */ - singlevaraux(fs->prev, n, var, 0); /* try upper levels */ - if (var->k == VVOID) /* not found? */ - return; /* it is a global */ - /* else was LOCAL or UPVAL */ - idx = newupvalue(fs, n, var); /* will be a new upvalue */ - } - init_exp(var, VUPVAL, idx); /* new or old upvalue */ - } - } +static void singlevaraux(FuncState* fs, TString* n, expdesc* var, int base) +{ + if (fs == NULL) /* no more levels? */ + init_exp(var, VVOID, 0); /* default is global */ + else + { + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) + { + /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ + if (!base) + markupval(fs, v); /* local will be used as an upval */ + } + else + { + /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) + { + /* not found? */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VVOID) /* not found? */ + return; /* it is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); /* new or old upvalue */ + } + } } -static void singlevar (LexState *ls, expdesc *var) { - TString *varname = str_checkname(ls); - FuncState *fs = ls->fs; - singlevaraux(fs, varname, var, 1); - if (var->k == VVOID) { /* global name? */ - expdesc key; - singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ - lua_assert(var->k != VVOID); /* this one must exist */ - codestring(ls, &key, varname); /* key is variable name */ - luaK_indexed(fs, var, &key); /* env[varname] */ - } +static void singlevar(LexState* ls, expdesc* var) +{ + TString* varname = str_checkname(ls); + FuncState* fs = ls->fs; + singlevaraux(fs, varname, var, 1); + if (var->k == VVOID) + { + /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + lua_assert(var->k != VVOID); /* this one must exist */ + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } } -static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { - FuncState *fs = ls->fs; - int extra = nvars - nexps; - if (hasmultret(e->k)) { - extra++; /* includes call itself */ - if (extra < 0) extra = 0; - luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ - if (extra > 1) luaK_reserveregs(fs, extra-1); - } - else { - if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ - if (extra > 0) { - int reg = fs->freereg; - luaK_reserveregs(fs, extra); - luaK_nil(fs, reg, extra); - } - } - if (nexps > nvars) - ls->fs->freereg -= nexps - nvars; /* remove extra values */ +static void adjust_assign(LexState* ls, int nvars, int nexps, expdesc* e) +{ + FuncState* fs = ls->fs; + int extra = nvars - nexps; + if (hasmultret(e->k)) + { + extra++; /* includes call itself */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra - 1); + } + else + { + if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) + { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ } -static void enterlevel (LexState *ls) { - lua_State *L = ls->L; - ++L->nCcalls; - checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); +static void enterlevel(LexState* ls) +{ + lua_State* L = ls->L; + ++L->nCcalls; + checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); } #define leavelevel(ls) ((ls)->L->nCcalls--) -static void closegoto (LexState *ls, int g, Labeldesc *label) { - int i; - FuncState *fs = ls->fs; - Labellist *gl = &ls->dyd->gt; - Labeldesc *gt = &gl->arr[g]; - lua_assert(eqstr(gt->name, label->name)); - if (gt->nactvar < label->nactvar) { - TString *vname = getlocvar(fs, gt->nactvar)->varname; - const char *msg = luaO_pushfstring(ls->L, - " at line %d jumps into the scope of local '%s'", - getstr(gt->name), gt->line, getstr(vname)); - semerror(ls, msg); - } - luaK_patchlist(fs, gt->pc, label->pc); - /* remove goto from pending list */ - for (i = g; i < gl->n - 1; i++) - gl->arr[i] = gl->arr[i + 1]; - gl->n--; +static void closegoto(LexState* ls, int g, Labeldesc* label) +{ + int i; + FuncState* fs = ls->fs; + Labellist* gl = &ls->dyd->gt; + Labeldesc* gt = &gl->arr[g]; + lua_assert(eqstr(gt->name, label->name)); + if (gt->nactvar < label->nactvar) + { + TString* vname = getlocvar(fs, gt->nactvar)->varname; + const char* msg = luaO_pushfstring(ls->L, + " at line %d jumps into the scope of local '%s'", + getstr(gt->name), gt->line, getstr(vname)); + semerror(ls, msg); + } + luaK_patchlist(fs, gt->pc, label->pc); + /* remove goto from pending list */ + for (i = g; i < gl->n - 1; i++) + gl->arr[i] = gl->arr[i + 1]; + gl->n--; } /* ** try to close a goto with existing labels; this solves backward jumps */ -static int findlabel (LexState *ls, int g) { - int i; - BlockCnt *bl = ls->fs->bl; - Dyndata *dyd = ls->dyd; - Labeldesc *gt = &dyd->gt.arr[g]; - /* check labels in current block for a match */ - for (i = bl->firstlabel; i < dyd->label.n; i++) { - Labeldesc *lb = &dyd->label.arr[i]; - if (eqstr(lb->name, gt->name)) { /* correct label? */ - if (gt->nactvar > lb->nactvar && - (bl->upval || dyd->label.n > bl->firstlabel)) - luaK_patchclose(ls->fs, gt->pc, lb->nactvar); - closegoto(ls, g, lb); /* close it */ - return 1; - } - } - return 0; /* label not found; cannot close goto */ +static int findlabel(LexState* ls, int g) +{ + int i; + BlockCnt* bl = ls->fs->bl; + Dyndata* dyd = ls->dyd; + Labeldesc* gt = &dyd->gt.arr[g]; + /* check labels in current block for a match */ + for (i = bl->firstlabel; i < dyd->label.n; i++) + { + Labeldesc* lb = &dyd->label.arr[i]; + if (eqstr(lb->name, gt->name)) + { + /* correct label? */ + if (gt->nactvar > lb->nactvar && + (bl->upval || dyd->label.n > bl->firstlabel)) + luaK_patchclose(ls->fs, gt->pc, lb->nactvar); + closegoto(ls, g, lb); /* close it */ + return 1; + } + } + return 0; /* label not found; cannot close goto */ } -static int newlabelentry (LexState *ls, Labellist *l, TString *name, - int line, int pc) { - int n = l->n; - luaM_growvector(ls->L, l->arr, n, l->size, - Labeldesc, SHRT_MAX, "labels/gotos"); - l->arr[n].name = name; - l->arr[n].line = line; - l->arr[n].nactvar = ls->fs->nactvar; - l->arr[n].pc = pc; - l->n = n + 1; - return n; +static int newlabelentry(LexState* ls, Labellist* l, TString* name, + int line, int pc) +{ + int n = l->n; + luaM_growvector(ls->L, l->arr, n, l->size, + Labeldesc, SHRT_MAX, "labels/gotos"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].pc = pc; + l->n = n + 1; + return n; } @@ -400,15 +449,17 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name, ** check whether new label 'lb' matches any pending gotos in current ** block; solves forward jumps */ -static void findgotos (LexState *ls, Labeldesc *lb) { - Labellist *gl = &ls->dyd->gt; - int i = ls->fs->bl->firstgoto; - while (i < gl->n) { - if (eqstr(gl->arr[i].name, lb->name)) - closegoto(ls, i, lb); - else - i++; - } +static void findgotos(LexState* ls, Labeldesc* lb) +{ + Labellist* gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + while (i < gl->n) + { + if (eqstr(gl->arr[i].name, lb->name)) + closegoto(ls, i, lb); + else + i++; + } } @@ -418,98 +469,108 @@ static void findgotos (LexState *ls, Labeldesc *lb) { ** the goto exits the scope of any variable (which can be the ** upvalue), close those variables being exited. */ -static void movegotosout (FuncState *fs, BlockCnt *bl) { - int i = bl->firstgoto; - Labellist *gl = &fs->ls->dyd->gt; - /* correct pending gotos to current block and try to close it - with visible labels */ - while (i < gl->n) { - Labeldesc *gt = &gl->arr[i]; - if (gt->nactvar > bl->nactvar) { - if (bl->upval) - luaK_patchclose(fs, gt->pc, bl->nactvar); - gt->nactvar = bl->nactvar; - } - if (!findlabel(fs->ls, i)) - i++; /* move to next one */ - } +static void movegotosout(FuncState* fs, BlockCnt* bl) +{ + int i = bl->firstgoto; + Labellist* gl = &fs->ls->dyd->gt; + /* correct pending gotos to current block and try to close it + with visible labels */ + while (i < gl->n) + { + Labeldesc* gt = &gl->arr[i]; + if (gt->nactvar > bl->nactvar) + { + if (bl->upval) + luaK_patchclose(fs, gt->pc, bl->nactvar); + gt->nactvar = bl->nactvar; + } + if (!findlabel(fs->ls, i)) + i++; /* move to next one */ + } } -static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { - bl->isloop = isloop; - bl->nactvar = fs->nactvar; - bl->firstlabel = fs->ls->dyd->label.n; - bl->firstgoto = fs->ls->dyd->gt.n; - bl->upval = 0; - bl->previous = fs->bl; - fs->bl = bl; - lua_assert(fs->freereg == fs->nactvar); +static void enterblock(FuncState* fs, BlockCnt* bl, lu_byte isloop) +{ + bl->isloop = isloop; + bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; + bl->upval = 0; + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == fs->nactvar); } /* ** create a label named 'break' to resolve break statements */ -static void breaklabel (LexState *ls) { - TString *n = luaS_new(ls->L, "break"); - int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); - findgotos(ls, &ls->dyd->label.arr[l]); +static void breaklabel(LexState* ls) +{ + TString* n = luaS_new(ls->L, "break"); + int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); + findgotos(ls, &ls->dyd->label.arr[l]); } /* ** generates an error for an undefined 'goto'; choose appropriate ** message when label name is a reserved word (which can only be 'break') */ -static l_noret undefgoto (LexState *ls, Labeldesc *gt) { - const char *msg = isreserved(gt->name) - ? "<%s> at line %d not inside a loop" - : "no visible label '%s' for at line %d"; - msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); - semerror(ls, msg); +static l_noret undefgoto(LexState* ls, Labeldesc* gt) +{ + const char* msg = isreserved(gt->name) + ? "<%s> at line %d not inside a loop" + : "no visible label '%s' for at line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); + semerror(ls, msg); } -static void leaveblock (FuncState *fs) { - BlockCnt *bl = fs->bl; - LexState *ls = fs->ls; - if (bl->previous && bl->upval) { - /* create a 'jump to here' to close upvalues */ - int j = luaK_jump(fs); - luaK_patchclose(fs, j, bl->nactvar); - luaK_patchtohere(fs, j); - } - if (bl->isloop) - breaklabel(ls); /* close pending breaks */ - fs->bl = bl->previous; - removevars(fs, bl->nactvar); - lua_assert(bl->nactvar == fs->nactvar); - fs->freereg = fs->nactvar; /* free registers */ - ls->dyd->label.n = bl->firstlabel; /* remove local labels */ - if (bl->previous) /* inner block? */ - movegotosout(fs, bl); /* update pending gotos to outer block */ - else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ - undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ +static void leaveblock(FuncState* fs) +{ + BlockCnt* bl = fs->bl; + LexState* ls = fs->ls; + if (bl->previous && bl->upval) + { + /* create a 'jump to here' to close upvalues */ + int j = luaK_jump(fs); + luaK_patchclose(fs, j, bl->nactvar); + luaK_patchtohere(fs, j); + } + if (bl->isloop) + breaklabel(ls); /* close pending breaks */ + fs->bl = bl->previous; + removevars(fs, bl->nactvar); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + if (bl->previous) /* inner block? */ + movegotosout(fs, bl); /* update pending gotos to outer block */ + else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ } /* ** adds a new prototype into list of prototypes */ -static Proto *addprototype (LexState *ls) { - Proto *clp; - lua_State *L = ls->L; - FuncState *fs = ls->fs; - Proto *f = fs->f; /* prototype of current function */ - if (fs->np >= f->sizep) { - int oldsize = f->sizep; - luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); - while (oldsize < f->sizep) - f->p[oldsize++] = NULL; - } - f->p[fs->np++] = clp = luaF_newproto(L); - luaC_objbarrier(L, f, clp); - return clp; +static Proto* addprototype(LexState* ls) +{ + Proto* clp; + lua_State* L = ls->L; + FuncState* fs = ls->fs; + Proto* f = fs->f; /* prototype of current function */ + if (fs->np >= f->sizep) + { + int oldsize = f->sizep; + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; + } + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; } @@ -519,61 +580,63 @@ static Proto *addprototype (LexState *ls) { ** so that, if it invokes the GC, the GC knows which registers ** are in use at that time. */ -static void codeclosure (LexState *ls, expdesc *v) { - FuncState *fs = ls->fs->prev; - init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); - luaK_exp2nextreg(fs, v); /* fix it at the last register */ +static void codeclosure(LexState* ls, expdesc* v) +{ + FuncState* fs = ls->fs->prev; + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ } -static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { - Proto *f; - fs->prev = ls->fs; /* linked list of funcstates */ - fs->ls = ls; - ls->fs = fs; - fs->pc = 0; - fs->lasttarget = 0; - fs->jpc = NO_JUMP; - fs->freereg = 0; - fs->nk = 0; - fs->np = 0; - fs->nups = 0; - fs->nlocvars = 0; - fs->nactvar = 0; - fs->firstlocal = ls->dyd->actvar.n; - fs->bl = NULL; - f = fs->f; - f->source = ls->source; - f->maxstacksize = 2; /* registers 0/1 are always valid */ - enterblock(fs, bl, 0); +static void open_func(LexState* ls, FuncState* fs, BlockCnt* bl) +{ + Proto* f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + fs->lasttarget = 0; + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->np = 0; + fs->nups = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->firstlocal = ls->dyd->actvar.n; + fs->bl = NULL; + f = fs->f; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ + enterblock(fs, bl, 0); } -static void close_func (LexState *ls) { - lua_State *L = ls->L; - FuncState *fs = ls->fs; - Proto *f = fs->f; - luaK_ret(fs, 0, 0); /* final return */ - leaveblock(fs); - luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); - f->sizecode = fs->pc; - luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); - f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); - f->sizek = fs->nk; - luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); - f->sizep = fs->np; - luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); - f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); - f->sizeupvalues = fs->nups; - lua_assert(fs->bl == NULL); - ls->fs = fs->prev; - luaC_checkGC(L); +static void close_func(LexState* ls) +{ + lua_State* L = ls->L; + FuncState* fs = ls->fs; + Proto* f = fs->f; + luaK_ret(fs, 0, 0); /* final return */ + leaveblock(fs); + luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); + f->sizecode = fs->pc; + luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); + f->sizek = fs->nk; + luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); + f->sizep = fs->np; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + f->sizeupvalues = fs->nups; + lua_assert(fs->bl == NULL); + ls->fs = fs->prev; + luaC_checkGC(L); } - /*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ @@ -584,46 +647,55 @@ static void close_func (LexState *ls) { ** 'until' closes syntactical blocks, but do not close scope, ** so it is handled in separate. */ -static int block_follow (LexState *ls, int withuntil) { - switch (ls->t.token) { - case TK_ELSE: case TK_ELSEIF: - case TK_END: case TK_EOS: - return 1; - case TK_UNTIL: return withuntil; - default: return 0; - } +static int block_follow(LexState* ls, int withuntil) +{ + switch (ls->t.token) + { + case TK_ELSE: + case TK_ELSEIF: + case TK_END: + case TK_EOS: + return 1; + case TK_UNTIL: return withuntil; + default: return 0; + } } -static void statlist (LexState *ls) { - /* statlist -> { stat [';'] } */ - while (!block_follow(ls, 1)) { - if (ls->t.token == TK_RETURN) { - statement(ls); - return; /* 'return' must be last statement */ - } - statement(ls); - } +static void statlist(LexState* ls) +{ + /* statlist -> { stat [';'] } */ + while (!block_follow(ls, 1)) + { + if (ls->t.token == TK_RETURN) + { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } } -static void fieldsel (LexState *ls, expdesc *v) { - /* fieldsel -> ['.' | ':'] NAME */ - FuncState *fs = ls->fs; - expdesc key; - luaK_exp2anyregup(fs, v); - luaX_next(ls); /* skip the dot or colon */ - checkname(ls, &key); - luaK_indexed(fs, v, &key); +static void fieldsel(LexState* ls, expdesc* v) +{ + /* fieldsel -> ['.' | ':'] NAME */ + FuncState* fs = ls->fs; + expdesc key; + luaK_exp2anyregup(fs, v); + luaX_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); } -static void yindex (LexState *ls, expdesc *v) { - /* index -> '[' expr ']' */ - luaX_next(ls); /* skip the '[' */ - expr(ls, v); - luaK_exp2val(ls->fs, v); - checknext(ls, ']'); +static void yindex(LexState* ls, expdesc* v) +{ + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); } @@ -634,233 +706,273 @@ static void yindex (LexState *ls, expdesc *v) { */ -struct ConsControl { - expdesc v; /* last list item read */ - expdesc *t; /* table descriptor */ - int nh; /* total number of 'record' elements */ - int na; /* total number of array elements */ - int tostore; /* number of array elements pending to be stored */ +struct ConsControl +{ + expdesc v; /* last list item read */ + expdesc* t; /* table descriptor */ + int nh; /* total number of 'record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ }; -static void recfield (LexState *ls, struct ConsControl *cc) { - /* recfield -> (NAME | '['exp1']') = exp1 */ - FuncState *fs = ls->fs; - int reg = ls->fs->freereg; - expdesc key, val; - int rkkey; - if (ls->t.token == TK_NAME) { - checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); - checkname(ls, &key); - } - else /* ls->t.token == '[' */ - yindex(ls, &key); - cc->nh++; - checknext(ls, '='); - rkkey = luaK_exp2RK(fs, &key); - expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); - fs->freereg = reg; /* free registers */ +static void recfield(LexState* ls, struct ConsControl* cc) +{ + /* recfield -> (NAME | '['exp1']') = exp1 */ + FuncState* fs = ls->fs; + int reg = ls->fs->freereg; + expdesc key, val; + int rkkey; + if (ls->t.token == TK_NAME) + { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ } -static void closelistfield (FuncState *fs, struct ConsControl *cc) { - if (cc->v.k == VVOID) return; /* there is no list item */ - luaK_exp2nextreg(fs, &cc->v); - cc->v.k = VVOID; - if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ - cc->tostore = 0; /* no more items pending */ - } +static void closelistfield(FuncState* fs, struct ConsControl* cc) +{ + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) + { + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } } -static void lastlistfield (FuncState *fs, struct ConsControl *cc) { - if (cc->tostore == 0) return; - if (hasmultret(cc->v.k)) { - luaK_setmultret(fs, &cc->v); - luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); - cc->na--; /* do not count last expression (unknown number of elements) */ - } - else { - if (cc->v.k != VVOID) - luaK_exp2nextreg(fs, &cc->v); - luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); - } +static void lastlistfield(FuncState* fs, struct ConsControl* cc) +{ + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) + { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else + { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); + } } -static void listfield (LexState *ls, struct ConsControl *cc) { - /* listfield -> exp */ - expr(ls, &cc->v); - checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); - cc->na++; - cc->tostore++; +static void listfield(LexState* ls, struct ConsControl* cc) +{ + /* listfield -> exp */ + expr(ls, &cc->v); + checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + cc->na++; + cc->tostore++; } -static void field (LexState *ls, struct ConsControl *cc) { - /* field -> listfield | recfield */ - switch(ls->t.token) { - case TK_NAME: { /* may be 'listfield' or 'recfield' */ - if (luaX_lookahead(ls) != '=') /* expression? */ - listfield(ls, cc); - else - recfield(ls, cc); - break; - } - case '[': { - recfield(ls, cc); - break; - } - default: { - listfield(ls, cc); - break; - } - } +static void field(LexState* ls, struct ConsControl* cc) +{ + /* field -> listfield | recfield */ + switch (ls->t.token) + { + case TK_NAME: + { + /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': + { + recfield(ls, cc); + break; + } + default: + { + listfield(ls, cc); + break; + } + } } -static void constructor (LexState *ls, expdesc *t) { - /* constructor -> '{' [ field { sep field } [sep] ] '}' - sep -> ',' | ';' */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); - struct ConsControl cc; - cc.na = cc.nh = cc.tostore = 0; - cc.t = t; - init_exp(t, VRELOCABLE, pc); - init_exp(&cc.v, VVOID, 0); /* no value (yet) */ - luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ - checknext(ls, '{'); - do { - lua_assert(cc.v.k == VVOID || cc.tostore > 0); - if (ls->t.token == '}') break; - closelistfield(fs, &cc); - field(ls, &cc); - } while (testnext(ls, ',') || testnext(ls, ';')); - check_match(ls, '}', '{', line); - lastlistfield(fs, &cc); - SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ - SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ +static void constructor(LexState* ls, expdesc* t) +{ + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + FuncState* fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ + checknext(ls, '{'); + do + { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + field(ls, &cc); + } + while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ - -static void parlist (LexState *ls) { - /* parlist -> [ param { ',' param } ] */ - FuncState *fs = ls->fs; - Proto *f = fs->f; - int nparams = 0; - f->is_vararg = 0; - if (ls->t.token != ')') { /* is 'parlist' not empty? */ - do { - switch (ls->t.token) { - case TK_NAME: { /* param -> NAME */ - new_localvar(ls, str_checkname(ls)); - nparams++; - break; - } - case TK_DOTS: { /* param -> '...' */ - luaX_next(ls); - f->is_vararg = 1; /* declared vararg */ - break; - } - default: luaX_syntaxerror(ls, " or '...' expected"); - } - } while (!f->is_vararg && testnext(ls, ',')); - } - adjustlocalvars(ls, nparams); - f->numparams = cast_byte(fs->nactvar); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +static void parlist(LexState* ls) +{ + /* parlist -> [ param { ',' param } ] */ + FuncState* fs = ls->fs; + Proto* f = fs->f; + int nparams = 0; + f->is_vararg = 0; + if (ls->t.token != ')') + { + /* is 'parlist' not empty? */ + do + { + switch (ls->t.token) + { + case TK_NAME: + { + /* param -> NAME */ + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: + { + /* param -> '...' */ + luaX_next(ls); + f->is_vararg = 1; /* declared vararg */ + break; + } + default: luaX_syntaxerror(ls, " or '...' expected"); + } + } + while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } -static void body (LexState *ls, expdesc *e, int ismethod, int line) { - /* body -> '(' parlist ')' block END */ - FuncState new_fs; - BlockCnt bl; - new_fs.f = addprototype(ls); - new_fs.f->linedefined = line; - open_func(ls, &new_fs, &bl); - checknext(ls, '('); - if (ismethod) { - new_localvarliteral(ls, "self"); /* create 'self' parameter */ - adjustlocalvars(ls, 1); - } - parlist(ls); - checknext(ls, ')'); - statlist(ls); - new_fs.f->lastlinedefined = ls->linenumber; - check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, e); - close_func(ls); +static void body(LexState* ls, expdesc* e, int ismethod, int line) +{ + /* body -> '(' parlist ')' block END */ + FuncState new_fs; + BlockCnt bl; + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '('); + if (ismethod) + { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); } -static int explist (LexState *ls, expdesc *v) { - /* explist -> expr { ',' expr } */ - int n = 1; /* at least one expression */ - expr(ls, v); - while (testnext(ls, ',')) { - luaK_exp2nextreg(ls->fs, v); - expr(ls, v); - n++; - } - return n; +static int explist(LexState* ls, expdesc* v) +{ + /* explist -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) + { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; } -static void funcargs (LexState *ls, expdesc *f, int line) { - FuncState *fs = ls->fs; - expdesc args; - int base, nparams; - switch (ls->t.token) { - case '(': { /* funcargs -> '(' [ explist ] ')' */ - luaX_next(ls); - if (ls->t.token == ')') /* arg list is empty? */ - args.k = VVOID; - else { - explist(ls, &args); - luaK_setmultret(fs, &args); - } - check_match(ls, ')', '(', line); - break; - } - case '{': { /* funcargs -> constructor */ - constructor(ls, &args); - break; - } - case TK_STRING: { /* funcargs -> STRING */ - codestring(ls, &args, ls->t.seminfo.ts); - luaX_next(ls); /* must use 'seminfo' before 'next' */ - break; - } - default: { - luaX_syntaxerror(ls, "function arguments expected"); - } - } - lua_assert(f->k == VNONRELOC); - base = f->u.info; /* base register for call */ - if (hasmultret(args.k)) - nparams = LUA_MULTRET; /* open call */ - else { - if (args.k != VVOID) - luaK_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); - luaK_fixline(fs, line); - fs->freereg = base+1; /* call remove function and arguments and leaves +static void funcargs(LexState* ls, expdesc* f, int line) +{ + FuncState* fs = ls->fs; + expdesc args; + int base, nparams; + switch (ls->t.token) + { + case '(': + { + /* funcargs -> '(' [ explist ] ')' */ + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else + { + explist(ls, &args); + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': + { + /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: + { + /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + luaX_next(ls); /* must use 'seminfo' before 'next' */ + break; + } + default: + { + luaX_syntaxerror(ls, "function arguments expected"); + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else + { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base + 1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams + 1, 2)); + luaK_fixline(fs, line); + fs->freereg = base + 1; /* call remove function and arguments and leaves (unless changed) one result */ } - - /* ** {====================================================================== ** Expression parsing @@ -868,174 +980,212 @@ static void funcargs (LexState *ls, expdesc *f, int line) { */ -static void primaryexp (LexState *ls, expdesc *v) { - /* primaryexp -> NAME | '(' expr ')' */ - switch (ls->t.token) { - case '(': { - int line = ls->linenumber; - luaX_next(ls); - expr(ls, v); - check_match(ls, ')', '(', line); - luaK_dischargevars(ls->fs, v); - return; - } - case TK_NAME: { - singlevar(ls, v); - return; - } - default: { - luaX_syntaxerror(ls, "unexpected symbol"); - } - } +static void primaryexp(LexState* ls, expdesc* v) +{ + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) + { + case '(': + { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: + { + singlevar(ls, v); + return; + } + default: + { + luaX_syntaxerror(ls, "unexpected symbol"); + } + } } -static void suffixedexp (LexState *ls, expdesc *v) { - /* suffixedexp -> - primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - primaryexp(ls, v); - for (;;) { - switch (ls->t.token) { - case '.': { /* fieldsel */ - fieldsel(ls, v); - break; - } - case '[': { /* '[' exp1 ']' */ - expdesc key; - luaK_exp2anyregup(fs, v); - yindex(ls, &key); - luaK_indexed(fs, v, &key); - break; - } - case ':': { /* ':' NAME funcargs */ - expdesc key; - luaX_next(ls); - checkname(ls, &key); - luaK_self(fs, v, &key); - funcargs(ls, v, line); - break; - } - case '(': case TK_STRING: case '{': { /* funcargs */ - luaK_exp2nextreg(fs, v); - funcargs(ls, v, line); - break; - } - default: return; - } - } +static void suffixedexp(LexState* ls, expdesc* v) +{ + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + FuncState* fs = ls->fs; + int line = ls->linenumber; + primaryexp(ls, v); + for (;;) + { + switch (ls->t.token) + { + case '.': + { + /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': + { + /* '[' exp1 ']' */ + expdesc key; + luaK_exp2anyregup(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': + { + /* ':' NAME funcargs */ + expdesc key; + luaX_next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': + case TK_STRING: + case '{': + { + /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: return; + } + } } -static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | - constructor | FUNCTION body | suffixedexp */ - switch (ls->t.token) { - case TK_FLT: { - init_exp(v, VKFLT, 0); - v->u.nval = ls->t.seminfo.r; - break; - } - case TK_INT: { - init_exp(v, VKINT, 0); - v->u.ival = ls->t.seminfo.i; - break; - } - case TK_STRING: { - codestring(ls, v, ls->t.seminfo.ts); - break; - } - case TK_NIL: { - init_exp(v, VNIL, 0); - break; - } - case TK_TRUE: { - init_exp(v, VTRUE, 0); - break; - } - case TK_FALSE: { - init_exp(v, VFALSE, 0); - break; - } - case TK_DOTS: { /* vararg */ - FuncState *fs = ls->fs; - check_condition(ls, fs->f->is_vararg, - "cannot use '...' outside a vararg function"); - init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); - break; - } - case '{': { /* constructor */ - constructor(ls, v); - return; - } - case TK_FUNCTION: { - luaX_next(ls); - body(ls, v, 0, ls->linenumber); - return; - } - default: { - suffixedexp(ls, v); - return; - } - } - luaX_next(ls); +static void simpleexp(LexState* ls, expdesc* v) +{ + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) + { + case TK_FLT: + { + init_exp(v, VKFLT, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_INT: + { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } + case TK_STRING: + { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: + { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: + { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: + { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: + { + /* vararg */ + FuncState* fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use '...' outside a vararg function"); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': + { + /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: + { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: + { + suffixedexp(ls, v); + return; + } + } + luaX_next(ls); } -static UnOpr getunopr (int op) { - switch (op) { - case TK_NOT: return OPR_NOT; - case '-': return OPR_MINUS; - case '~': return OPR_BNOT; - case '#': return OPR_LEN; - default: return OPR_NOUNOPR; - } +static UnOpr getunopr(int op) +{ + switch (op) + { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '~': return OPR_BNOT; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } } -static BinOpr getbinopr (int op) { - switch (op) { - case '+': return OPR_ADD; - case '-': return OPR_SUB; - case '*': return OPR_MUL; - case '%': return OPR_MOD; - case '^': return OPR_POW; - case '/': return OPR_DIV; - case TK_IDIV: return OPR_IDIV; - case '&': return OPR_BAND; - case '|': return OPR_BOR; - case '~': return OPR_BXOR; - case TK_SHL: return OPR_SHL; - case TK_SHR: return OPR_SHR; - case TK_CONCAT: return OPR_CONCAT; - case TK_NE: return OPR_NE; - case TK_EQ: return OPR_EQ; - case '<': return OPR_LT; - case TK_LE: return OPR_LE; - case '>': return OPR_GT; - case TK_GE: return OPR_GE; - case TK_AND: return OPR_AND; - case TK_OR: return OPR_OR; - default: return OPR_NOBINOPR; - } +static BinOpr getbinopr(int op) +{ + switch (op) + { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } } -static const struct { - lu_byte left; /* left priority for each binary operator */ - lu_byte right; /* right priority */ -} priority[] = { /* ORDER OPR */ - {10, 10}, {10, 10}, /* '+' '-' */ - {11, 11}, {11, 11}, /* '*' '%' */ - {14, 13}, /* '^' (right associative) */ - {11, 11}, {11, 11}, /* '/' '//' */ - {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ - {7, 7}, {7, 7}, /* '<<' '>>' */ - {9, 8}, /* '..' (right associative) */ - {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ - {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ - {2, 2}, {1, 1} /* and, or */ +static const struct +{ + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { + /* ORDER OPR */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ }; #define UNARY_PRIORITY 12 /* priority for unary operators */ @@ -1045,44 +1195,47 @@ static const struct { ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where 'binop' is any binary operator with a priority higher than 'limit' */ -static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { - BinOpr op; - UnOpr uop; - enterlevel(ls); - uop = getunopr(ls->t.token); - if (uop != OPR_NOUNOPR) { - int line = ls->linenumber; - luaX_next(ls); - subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls->fs, uop, v, line); - } - else simpleexp(ls, v); - /* expand while operators have priorities higher than 'limit' */ - op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && priority[op].left > limit) { - expdesc v2; - BinOpr nextop; - int line = ls->linenumber; - luaX_next(ls); - luaK_infix(ls->fs, op, v); - /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, priority[op].right); - luaK_posfix(ls->fs, op, v, &v2, line); - op = nextop; - } - leavelevel(ls); - return op; /* return first untreated operator */ +static BinOpr subexpr(LexState* ls, expdesc* v, int limit) +{ + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) + { + int line = ls->linenumber; + luaX_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v, line); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than 'limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) + { + expdesc v2; + BinOpr nextop; + int line = ls->linenumber; + luaX_next(ls); + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ } -static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, 0); +static void expr(LexState* ls, expdesc* v) +{ + subexpr(ls, v, 0); } /* }==================================================================== */ - /* ** {====================================================================== ** Rules for Statements @@ -1090,13 +1243,14 @@ static void expr (LexState *ls, expdesc *v) { */ -static void block (LexState *ls) { - /* block -> statlist */ - FuncState *fs = ls->fs; - BlockCnt bl; - enterblock(fs, &bl, 0); - statlist(ls); - leaveblock(fs); +static void block(LexState* ls) +{ + /* block -> statlist */ + FuncState* fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); } @@ -1104,9 +1258,10 @@ static void block (LexState *ls) { ** structure to chain all variables in the left-hand side of an ** assignment */ -struct LHS_assign { - struct LHS_assign *prev; - expdesc v; /* variable (global, local, upvalue, or indexed) */ +struct LHS_assign +{ + struct LHS_assign* prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ }; @@ -1116,490 +1271,583 @@ struct LHS_assign { ** table. If so, save original upvalue/local value in a safe place and ** use this safe copy in the previous assignment. */ -static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { - FuncState *fs = ls->fs; - int extra = fs->freereg; /* eventual position to save local variable */ - int conflict = 0; - for (; lh; lh = lh->prev) { /* check all previous assignments */ - if (lh->v.k == VINDEXED) { /* assigning to a table? */ - /* table is the upvalue/local being assigned now? */ - if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { - conflict = 1; - lh->v.u.ind.vt = VLOCAL; - lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ - } - /* index is the local being assigned? (index cannot be upvalue) */ - if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { - conflict = 1; - lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ - } - } - } - if (conflict) { - /* copy upvalue/local value to a temporary (in position 'extra') */ - OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - luaK_codeABC(fs, op, extra, v->u.info, 0); - luaK_reserveregs(fs, 1); - } +static void check_conflict(LexState* ls, struct LHS_assign* lh, expdesc* v) +{ + FuncState* fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) + { + /* check all previous assignments */ + if (lh->v.k == VINDEXED) + { + /* assigning to a table? */ + /* table is the upvalue/local being assigned now? */ + if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) + { + conflict = 1; + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ + } + /* index is the local being assigned? (index cannot be upvalue) */ + if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) + { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) + { + /* copy upvalue/local value to a temporary (in position 'extra') */ + OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, op, extra, v->u.info, 0); + luaK_reserveregs(fs, 1); + } } -static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { - expdesc e; - check_condition(ls, vkisvar(lh->v.k), "syntax error"); - if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ - struct LHS_assign nv; - nv.prev = lh; - suffixedexp(ls, &nv.v); - if (nv.v.k != VINDEXED) - check_conflict(ls, lh, &nv.v); - checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, - "C levels"); - assignment(ls, &nv, nvars+1); - } - else { /* assignment -> '=' explist */ - int nexps; - checknext(ls, '='); - nexps = explist(ls, &e); - if (nexps != nvars) - adjust_assign(ls, nvars, nexps, &e); - else { - luaK_setoneret(ls->fs, &e); /* close last expression */ - luaK_storevar(ls->fs, &lh->v, &e); - return; /* avoid default */ - } - } - init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ - luaK_storevar(ls->fs, &lh->v, &e); +static void assignment(LexState* ls, struct LHS_assign* lh, int nvars) +{ + expdesc e; + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + if (testnext(ls, ',')) + { + /* assignment -> ',' suffixedexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (nv.v.k != VINDEXED) + check_conflict(ls, lh, &nv.v); + checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, + "C levels"); + assignment(ls, &nv, nvars + 1); + } + else + { + /* assignment -> '=' explist */ + int nexps; + checknext(ls, '='); + nexps = explist(ls, &e); + if (nexps != nvars) + adjust_assign(ls, nvars, nexps, &e); + else + { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg - 1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); } -static int cond (LexState *ls) { - /* cond -> exp */ - expdesc v; - expr(ls, &v); /* read condition */ - if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ - luaK_goiftrue(ls->fs, &v); - return v.f; +static int cond(LexState* ls) +{ + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; } -static void gotostat (LexState *ls, int pc) { - int line = ls->linenumber; - TString *label; - int g; - if (testnext(ls, TK_GOTO)) - label = str_checkname(ls); - else { - luaX_next(ls); /* skip break */ - label = luaS_new(ls->L, "break"); - } - g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); - findlabel(ls, g); /* close it if label already defined */ +static void gotostat(LexState* ls, int pc) +{ + int line = ls->linenumber; + TString* label; + int g; + if (testnext(ls, TK_GOTO)) + label = str_checkname(ls); + else + { + luaX_next(ls); /* skip break */ + label = luaS_new(ls->L, "break"); + } + g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); + findlabel(ls, g); /* close it if label already defined */ } /* check for repeated labels on the same block */ -static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { - int i; - for (i = fs->bl->firstlabel; i < ll->n; i++) { - if (eqstr(label, ll->arr[i].name)) { - const char *msg = luaO_pushfstring(fs->ls->L, - "label '%s' already defined on line %d", - getstr(label), ll->arr[i].line); - semerror(fs->ls, msg); - } - } +static void checkrepeated(FuncState* fs, Labellist* ll, TString* label) +{ + int i; + for (i = fs->bl->firstlabel; i < ll->n; i++) + { + if (eqstr(label, ll->arr[i].name)) + { + const char* msg = luaO_pushfstring(fs->ls->L, + "label '%s' already defined on line %d", + getstr(label), ll->arr[i].line); + semerror(fs->ls, msg); + } + } } /* skip no-op statements */ -static void skipnoopstat (LexState *ls) { - while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) - statement(ls); +static void skipnoopstat(LexState* ls) +{ + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); } -static void labelstat (LexState *ls, TString *label, int line) { - /* label -> '::' NAME '::' */ - FuncState *fs = ls->fs; - Labellist *ll = &ls->dyd->label; - int l; /* index of new label being created */ - checkrepeated(fs, ll, label); /* check for repeated labels */ - checknext(ls, TK_DBCOLON); /* skip double colon */ - /* create new entry for this label */ - l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); - skipnoopstat(ls); /* skip other no-op statements */ - if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ - /* assume that locals are already out of scope */ - ll->arr[l].nactvar = fs->bl->nactvar; - } - findgotos(ls, &ll->arr[l]); +static void labelstat(LexState* ls, TString* label, int line) +{ + /* label -> '::' NAME '::' */ + FuncState* fs = ls->fs; + Labellist* ll = &ls->dyd->label; + int l; /* index of new label being created */ + checkrepeated(fs, ll, label); /* check for repeated labels */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); + skipnoopstat(ls); /* skip other no-op statements */ + if (block_follow(ls, 0)) + { + /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + findgotos(ls, &ll->arr[l]); } -static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ - FuncState *fs = ls->fs; - int whileinit; - int condexit; - BlockCnt bl; - luaX_next(ls); /* skip WHILE */ - whileinit = luaK_getlabel(fs); - condexit = cond(ls); - enterblock(fs, &bl, 1); - checknext(ls, TK_DO); - block(ls); - luaK_jumpto(fs, whileinit); - check_match(ls, TK_END, TK_WHILE, line); - leaveblock(fs); - luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +static void whilestat(LexState* ls, int line) +{ + /* whilestat -> WHILE cond DO block END */ + FuncState* fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_jumpto(fs, whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ } -static void repeatstat (LexState *ls, int line) { - /* repeatstat -> REPEAT block UNTIL cond */ - int condexit; - FuncState *fs = ls->fs; - int repeat_init = luaK_getlabel(fs); - BlockCnt bl1, bl2; - enterblock(fs, &bl1, 1); /* loop block */ - enterblock(fs, &bl2, 0); /* scope block */ - luaX_next(ls); /* skip REPEAT */ - statlist(ls); - check_match(ls, TK_UNTIL, TK_REPEAT, line); - condexit = cond(ls); /* read condition (inside scope block) */ - if (bl2.upval) /* upvalues? */ - luaK_patchclose(fs, condexit, bl2.nactvar); - leaveblock(fs); /* finish scope */ - luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ - leaveblock(fs); /* finish loop */ +static void repeatstat(LexState* ls, int line) +{ + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState* fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (bl2.upval) /* upvalues? */ + luaK_patchclose(fs, condexit, bl2.nactvar); + leaveblock(fs); /* finish scope */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ + leaveblock(fs); /* finish loop */ } -static int exp1 (LexState *ls) { - expdesc e; - int reg; - expr(ls, &e); - luaK_exp2nextreg(ls->fs, &e); - lua_assert(e.k == VNONRELOC); - reg = e.u.info; - return reg; +static int exp1(LexState* ls) +{ + expdesc e; + int reg; + expr(ls, &e); + luaK_exp2nextreg(ls->fs, &e); + lua_assert(e.k == VNONRELOC); + reg = e.u.info; + return reg; } -static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { - /* forbody -> DO block */ - BlockCnt bl; - FuncState *fs = ls->fs; - int prep, endfor; - adjustlocalvars(ls, 3); /* control variables */ - checknext(ls, TK_DO); - prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); - enterblock(fs, &bl, 0); /* scope for declared variables */ - adjustlocalvars(ls, nvars); - luaK_reserveregs(fs, nvars); - block(ls); - leaveblock(fs); /* end of scope for declared variables */ - luaK_patchtohere(fs, prep); - if (isnum) /* numeric for? */ - endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); - else { /* generic for */ - luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); - luaK_fixline(fs, line); - endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); - } - luaK_patchlist(fs, endfor, prep + 1); - luaK_fixline(fs, line); +static void forbody(LexState* ls, int base, int line, int nvars, int isnum) +{ + /* forbody -> DO block */ + BlockCnt bl; + FuncState* fs = ls->fs; + int prep, endfor; + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + if (isnum) /* numeric for? */ + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + else + { + /* generic for */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); + } + luaK_patchlist(fs, endfor, prep + 1); + luaK_fixline(fs, line); } -static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] forbody */ - FuncState *fs = ls->fs; - int base = fs->freereg; - new_localvarliteral(ls, "(for index)"); - new_localvarliteral(ls, "(for limit)"); - new_localvarliteral(ls, "(for step)"); - new_localvar(ls, varname); - checknext(ls, '='); - exp1(ls); /* initial value */ - checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ - else { /* default step = 1 */ - luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); - luaK_reserveregs(fs, 1); - } - forbody(ls, base, line, 1, 1); +static void fornum(LexState* ls, TString* varname, int line) +{ + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState* fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for index)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else + { + /* default step = 1 */ + luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); } -static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist forbody */ - FuncState *fs = ls->fs; - expdesc e; - int nvars = 4; /* gen, state, control, plus at least one declared var */ - int line; - int base = fs->freereg; - /* create control variables */ - new_localvarliteral(ls, "(for generator)"); - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for control)"); - /* create declared variables */ - new_localvar(ls, indexname); - while (testnext(ls, ',')) { - new_localvar(ls, str_checkname(ls)); - nvars++; - } - checknext(ls, TK_IN); - line = ls->linenumber; - adjust_assign(ls, 3, explist(ls, &e), &e); - luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 3, 0); +static void forlist(LexState* ls, TString* indexname) +{ + /* forlist -> NAME {,NAME} IN explist forbody */ + FuncState* fs = ls->fs; + expdesc e; + int nvars = 4; /* gen, state, control, plus at least one declared var */ + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for generator)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); + /* create declared variables */ + new_localvar(ls, indexname); + while (testnext(ls, ',')) + { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 3, explist(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); } -static void forstat (LexState *ls, int line) { - /* forstat -> FOR (fornum | forlist) END */ - FuncState *fs = ls->fs; - TString *varname; - BlockCnt bl; - enterblock(fs, &bl, 1); /* scope for loop and control variables */ - luaX_next(ls); /* skip 'for' */ - varname = str_checkname(ls); /* first variable name */ - switch (ls->t.token) { - case '=': fornum(ls, varname, line); break; - case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, "'=' or 'in' expected"); - } - check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); /* loop scope ('break' jumps to this point) */ +static void forstat(LexState* ls, int line) +{ + /* forstat -> FOR (fornum | forlist) END */ + FuncState* fs = ls->fs; + TString* varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip 'for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) + { + case '=': fornum(ls, varname, line); + break; + case ',': + case TK_IN: forlist(ls, varname); + break; + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope ('break' jumps to this point) */ } -static void test_then_block (LexState *ls, int *escapelist) { - /* test_then_block -> [IF | ELSEIF] cond THEN block */ - BlockCnt bl; - FuncState *fs = ls->fs; - expdesc v; - int jf; /* instruction to skip 'then' code (if condition is false) */ - luaX_next(ls); /* skip IF or ELSEIF */ - expr(ls, &v); /* read condition */ - checknext(ls, TK_THEN); - if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { - luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ - enterblock(fs, &bl, 0); /* must enter block before 'goto' */ - gotostat(ls, v.t); /* handle goto/break */ - skipnoopstat(ls); /* skip other no-op statements */ - if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ - leaveblock(fs); - return; /* and that is it */ - } - else /* must skip over 'then' part if condition is false */ - jf = luaK_jump(fs); - } - else { /* regular case (not goto/break) */ - luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ - enterblock(fs, &bl, 0); - jf = v.f; - } - statlist(ls); /* 'then' part */ - leaveblock(fs); - if (ls->t.token == TK_ELSE || - ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ - luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ - luaK_patchtohere(fs, jf); +static void test_then_block(LexState* ls, int* escapelist) +{ + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + BlockCnt bl; + FuncState* fs = ls->fs; + expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ + luaX_next(ls); /* skip IF or ELSEIF */ + expr(ls, &v); /* read condition */ + checknext(ls, TK_THEN); + if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) + { + luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + gotostat(ls, v.t); /* handle goto/break */ + skipnoopstat(ls); /* skip other no-op statements */ + if (block_follow(ls, 0)) + { + /* 'goto' is the entire block? */ + leaveblock(fs); + return; /* and that is it */ + } + else /* must skip over 'then' part if condition is false */ + jf = luaK_jump(fs); + } + else + { + /* regular case (not goto/break) */ + luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* 'then' part */ + leaveblock(fs); + if (ls->t.token == TK_ELSE || + ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); } -static void ifstat (LexState *ls, int line) { - /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ - FuncState *fs = ls->fs; - int escapelist = NO_JUMP; /* exit list for finished parts */ - test_then_block(ls, &escapelist); /* IF cond THEN block */ - while (ls->t.token == TK_ELSEIF) - test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ - if (testnext(ls, TK_ELSE)) - block(ls); /* 'else' part */ - check_match(ls, TK_END, TK_IF, line); - luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +static void ifstat(LexState* ls, int line) +{ + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState* fs = ls->fs; + int escapelist = NO_JUMP; /* exit list for finished parts */ + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) + block(ls); /* 'else' part */ + check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ } -static void localfunc (LexState *ls) { - expdesc b; - FuncState *fs = ls->fs; - new_localvar(ls, str_checkname(ls)); /* new local variable */ - adjustlocalvars(ls, 1); /* enter its scope */ - body(ls, &b, 0, ls->linenumber); /* function created in next register */ - /* debug information will only see the variable after this point! */ - getlocvar(fs, b.u.info)->startpc = fs->pc; +static void localfunc(LexState* ls) +{ + expdesc b; + FuncState* fs = ls->fs; + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + /* debug information will only see the variable after this point! */ + getlocvar(fs, b.u.info)->startpc = fs->pc; } -static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ - int nvars = 0; - int nexps; - expdesc e; - do { - new_localvar(ls, str_checkname(ls)); - nvars++; - } while (testnext(ls, ',')); - if (testnext(ls, '=')) - nexps = explist(ls, &e); - else { - e.k = VVOID; - nexps = 0; - } - adjust_assign(ls, nvars, nexps, &e); - adjustlocalvars(ls, nvars); +static void localstat(LexState* ls) +{ + /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ + int nvars = 0; + int nexps; + expdesc e; + do + { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else + { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); } -static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {fieldsel} [':' NAME] */ - int ismethod = 0; - singlevar(ls, v); - while (ls->t.token == '.') - fieldsel(ls, v); - if (ls->t.token == ':') { - ismethod = 1; - fieldsel(ls, v); - } - return ismethod; +static int funcname(LexState* ls, expdesc* v) +{ + /* funcname -> NAME {fieldsel} [':' NAME] */ + int ismethod = 0; + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') + { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; } -static void funcstat (LexState *ls, int line) { - /* funcstat -> FUNCTION funcname body */ - int ismethod; - expdesc v, b; - luaX_next(ls); /* skip FUNCTION */ - ismethod = funcname(ls, &v); - body(ls, &b, ismethod, line); - luaK_storevar(ls->fs, &v, &b); - luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ +static void funcstat(LexState* ls, int line) +{ + /* funcstat -> FUNCTION funcname body */ + int ismethod; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ } -static void exprstat (LexState *ls) { - /* stat -> func | assignment */ - FuncState *fs = ls->fs; - struct LHS_assign v; - suffixedexp(ls, &v.v); - if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ - v.prev = NULL; - assignment(ls, &v, 1); - } - else { /* stat -> func */ - check_condition(ls, v.v.k == VCALL, "syntax error"); - SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */ - } +static void exprstat(LexState* ls) +{ + /* stat -> func | assignment */ + FuncState* fs = ls->fs; + struct LHS_assign v; + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') + { + /* stat -> assignment ? */ + v.prev = NULL; + assignment(ls, &v, 1); + } + else + { + /* stat -> func */ + check_condition(ls, v.v.k == VCALL, "syntax error"); + SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */ + } } -static void retstat (LexState *ls) { - /* stat -> RETURN [explist] [';'] */ - FuncState *fs = ls->fs; - expdesc e; - int first, nret; /* registers with returned values */ - if (block_follow(ls, 1) || ls->t.token == ';') - first = nret = 0; /* return no values */ - else { - nret = explist(ls, &e); /* optional return values */ - if (hasmultret(e.k)) { - luaK_setmultret(fs, &e); - if (e.k == VCALL && nret == 1) { /* tail call? */ - SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); - lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); - } - first = fs->nactvar; - nret = LUA_MULTRET; /* return all values */ - } - else { - if (nret == 1) /* only one single value? */ - first = luaK_exp2anyreg(fs, &e); - else { - luaK_exp2nextreg(fs, &e); /* values must go to the stack */ - first = fs->nactvar; /* return all active values */ - lua_assert(nret == fs->freereg - first); - } - } - } - luaK_ret(fs, first, nret); - testnext(ls, ';'); /* skip optional semicolon */ +static void retstat(LexState* ls) +{ + /* stat -> RETURN [explist] [';'] */ + FuncState* fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ + if (block_follow(ls, 1) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else + { + nret = explist(ls, &e); /* optional return values */ + if (hasmultret(e.k)) + { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) + { + /* tail call? */ + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else + { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); + else + { + luaK_exp2nextreg(fs, &e); /* values must go to the stack */ + first = fs->nactvar; /* return all active values */ + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ } -static void statement (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ - enterlevel(ls); - switch (ls->t.token) { - case ';': { /* stat -> ';' (empty statement) */ - luaX_next(ls); /* skip ';' */ - break; - } - case TK_IF: { /* stat -> ifstat */ - ifstat(ls, line); - break; - } - case TK_WHILE: { /* stat -> whilestat */ - whilestat(ls, line); - break; - } - case TK_DO: { /* stat -> DO block END */ - luaX_next(ls); /* skip DO */ - block(ls); - check_match(ls, TK_END, TK_DO, line); - break; - } - case TK_FOR: { /* stat -> forstat */ - forstat(ls, line); - break; - } - case TK_REPEAT: { /* stat -> repeatstat */ - repeatstat(ls, line); - break; - } - case TK_FUNCTION: { /* stat -> funcstat */ - funcstat(ls, line); - break; - } - case TK_LOCAL: { /* stat -> localstat */ - luaX_next(ls); /* skip LOCAL */ - if (testnext(ls, TK_FUNCTION)) /* local function? */ - localfunc(ls); - else - localstat(ls); - break; - } - case TK_DBCOLON: { /* stat -> label */ - luaX_next(ls); /* skip double colon */ - labelstat(ls, str_checkname(ls), line); - break; - } - case TK_RETURN: { /* stat -> retstat */ - luaX_next(ls); /* skip RETURN */ - retstat(ls); - break; - } - case TK_BREAK: /* stat -> breakstat */ - case TK_GOTO: { /* stat -> 'goto' NAME */ - gotostat(ls, luaK_jump(ls->fs)); - break; - } - default: { /* stat -> func | assignment */ - exprstat(ls); - break; - } - } - lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && - ls->fs->freereg >= ls->fs->nactvar); - ls->fs->freereg = ls->fs->nactvar; /* free registers */ - leavelevel(ls); +static void statement(LexState* ls) +{ + int line = ls->linenumber; /* may be needed for error messages */ + enterlevel(ls); + switch (ls->t.token) + { + case ';': + { + /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + break; + } + case TK_IF: + { + /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: + { + /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: + { + /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: + { + /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: + { + /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: + { + /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: + { + /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: + { + /* stat -> label */ + luaX_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: + { + /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: /* stat -> breakstat */ + case TK_GOTO: + { + /* stat -> 'goto' NAME */ + gotostat(ls, luaK_jump(ls->fs)); + break; + } + default: + { + /* stat -> func | assignment */ + exprstat(ls); + break; + } + } + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + leavelevel(ls); } /* }====================================================================== */ @@ -1609,42 +1857,43 @@ static void statement (LexState *ls) { ** compiles the main function, which is a regular vararg function with an ** upvalue named LUA_ENV */ -static void mainfunc (LexState *ls, FuncState *fs) { - BlockCnt bl; - expdesc v; - open_func(ls, fs, &bl); - fs->f->is_vararg = 1; /* main function is always declared vararg */ - init_exp(&v, VLOCAL, 0); /* create and... */ - newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ - luaX_next(ls); /* read first token */ - statlist(ls); /* parse main body */ - check(ls, TK_EOS); - close_func(ls); +static void mainfunc(LexState* ls, FuncState* fs) +{ + BlockCnt bl; + expdesc v; + open_func(ls, fs, &bl); + fs->f->is_vararg = 1; /* main function is always declared vararg */ + init_exp(&v, VLOCAL, 0); /* create and... */ + newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); } -LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { - LexState lexstate; - FuncState funcstate; - LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ - setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ - luaD_inctop(L); - lexstate.h = luaH_new(L); /* create table for scanner */ - sethvalue(L, L->top, lexstate.h); /* anchor it */ - luaD_inctop(L); - funcstate.f = cl->p = luaF_newproto(L); - funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ - lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ - lexstate.buff = buff; - lexstate.dyd = dyd; - dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; - luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); - mainfunc(&lexstate, &funcstate); - lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); - /* all scopes should be correctly finished */ - lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - L->top--; /* remove scanner's table */ - return cl; /* closure is on the stack, too */ +LClosure* luaY_parser(lua_State* L, ZIO* z, Mbuffer* buff, + Dyndata* dyd, const char* name, int firstchar) +{ + LexState lexstate; + FuncState funcstate; + LClosure* cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue(L, L->top, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ + lexstate.buff = buff; + lexstate.dyd = dyd; + dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + /* all scopes should be correctly finished */ + lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); + L->top--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ } - diff --git a/Lua/lparser.h b/Lua/lparser.h index 02e9b03..d2a3b1a 100644 --- a/Lua/lparser.h +++ b/Lua/lparser.h @@ -22,112 +22,141 @@ */ /* kinds of variables/expressions */ -typedef enum { - VVOID, /* when 'expdesc' describes the last expression a list, - this kind means an empty list (so, no expression) */ - VNIL, /* constant nil */ - VTRUE, /* constant true */ - VFALSE, /* constant false */ - VK, /* constant in 'k'; info = index of constant in 'k' */ - VKFLT, /* floating constant; nval = numerical float value */ - VKINT, /* integer constant; nval = numerical integer value */ - VNONRELOC, /* expression has its value in a fixed register; - info = result register */ - VLOCAL, /* local variable; info = local register */ - VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ - VINDEXED, /* indexed variable; - ind.vt = whether 't' is register or upvalue; - ind.t = table register or upvalue; - ind.idx = key's R/K index */ - VJMP, /* expression is a test/comparison; - info = pc of corresponding jump instruction */ - VRELOCABLE, /* expression can put result in any register; - info = instruction pc */ - VCALL, /* expression is a function call; info = instruction pc */ - VVARARG /* vararg expression; info = instruction pc */ +typedef enum +{ + VVOID, + /* when 'expdesc' describes the last expression a list, + this kind means an empty list (so, no expression) */ + VNIL, + /* constant nil */ + VTRUE, + /* constant true */ + VFALSE, + /* constant false */ + VK, + /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, + /* floating constant; nval = numerical float value */ + VKINT, + /* integer constant; nval = numerical integer value */ + VNONRELOC, + /* expression has its value in a fixed register; + info = result register */ + VLOCAL, + /* local variable; info = local register */ + VUPVAL, + /* upvalue variable; info = index of upvalue in 'upvalues' */ + VINDEXED, + /* indexed variable; + ind.vt = whether 't' is register or upvalue; + ind.t = table register or upvalue; + ind.idx = key's R/K index */ + VJMP, + /* expression is a test/comparison; + info = pc of corresponding jump instruction */ + VRELOCABLE, + /* expression can put result in any register; + info = instruction pc */ + VCALL, + /* expression is a function call; info = instruction pc */ + VVARARG /* vararg expression; info = instruction pc */ } expkind; #define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) #define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) -typedef struct expdesc { - expkind k; - union { - lua_Integer ival; /* for VKINT */ - lua_Number nval; /* for VKFLT */ - int info; /* for generic use */ - struct { /* for indexed variables (VINDEXED) */ - short idx; /* index (R/K) */ - lu_byte t; /* table (register or upvalue) */ - lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ - } ind; - } u; - int t; /* patch list of 'exit when true' */ - int f; /* patch list of 'exit when false' */ +typedef struct expdesc +{ + expkind k; + + union + { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + int info; /* for generic use */ + struct + { + /* for indexed variables (VINDEXED) */ + short idx; /* index (R/K) */ + lu_byte t; /* table (register or upvalue) */ + lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ + } ind; + } u; + + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ } expdesc; /* description of active local variable */ -typedef struct Vardesc { - short idx; /* variable index in stack */ +typedef struct Vardesc +{ + short idx; /* variable index in stack */ } Vardesc; /* description of pending goto statements and label statements */ -typedef struct Labeldesc { - TString *name; /* label identifier */ - int pc; /* position in code */ - int line; /* line where it appeared */ - lu_byte nactvar; /* local level where it appears in current block */ +typedef struct Labeldesc +{ + TString* name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + lu_byte nactvar; /* local level where it appears in current block */ } Labeldesc; /* list of labels or gotos */ -typedef struct Labellist { - Labeldesc *arr; /* array */ - int n; /* number of entries in use */ - int size; /* array size */ +typedef struct Labellist +{ + Labeldesc* arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ } Labellist; /* dynamic structures used by the parser */ -typedef struct Dyndata { - struct { /* list of active local variables */ - Vardesc *arr; - int n; - int size; - } actvar; - Labellist gt; /* list of pending gotos */ - Labellist label; /* list of active labels */ +typedef struct Dyndata +{ + struct + { + /* list of active local variables */ + Vardesc* arr; + int n; + int size; + } actvar; + + Labellist gt; /* list of pending gotos */ + Labellist label; /* list of active labels */ } Dyndata; /* control of blocks */ -struct BlockCnt; /* defined in lparser.c */ +struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ -typedef struct FuncState { - Proto *f; /* current function header */ - struct FuncState *prev; /* enclosing function */ - struct LexState *ls; /* lexical state */ - struct BlockCnt *bl; /* chain of current blocks */ - int pc; /* next position to code (equivalent to 'ncode') */ - int lasttarget; /* 'label' of last 'jump label' */ - int jpc; /* list of pending jumps to 'pc' */ - int nk; /* number of elements in 'k' */ - int np; /* number of elements in 'p' */ - int firstlocal; /* index of first local var (in Dyndata array) */ - short nlocvars; /* number of elements in 'f->locvars' */ - lu_byte nactvar; /* number of active local variables */ - lu_byte nups; /* number of upvalues */ - lu_byte freereg; /* first free register */ +typedef struct FuncState +{ + Proto* f; /* current function header */ + struct FuncState* prev; /* enclosing function */ + struct LexState* ls; /* lexical state */ + struct BlockCnt* bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to 'ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int jpc; /* list of pending jumps to 'pc' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ + int firstlocal; /* index of first local var (in Dyndata array) */ + short nlocvars; /* number of elements in 'f->locvars' */ + lu_byte nactvar; /* number of active local variables */ + lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ } FuncState; -LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); +LUAI_FUNC LClosure* luaY_parser(lua_State* L, ZIO* z, Mbuffer* buff, + Dyndata* dyd, const char* name, int firstchar); #endif diff --git a/Lua/lprefix.h b/Lua/lprefix.h index 02daa83..053f05f 100644 --- a/Lua/lprefix.h +++ b/Lua/lprefix.h @@ -42,4 +42,3 @@ #endif /* } */ #endif - diff --git a/Lua/lstate.c b/Lua/lstate.c index 9194ac3..e592976 100644 --- a/Lua/lstate.c +++ b/Lua/lstate.c @@ -47,26 +47,26 @@ #endif - /* ** thread state + extra space */ -typedef struct LX { - lu_byte extra_[LUA_EXTRASPACE]; - lua_State l; +typedef struct LX +{ + lu_byte extra_[LUA_EXTRASPACE]; + lua_State l; } LX; /* ** Main thread combines a thread state and the global state */ -typedef struct LG { - LX l; - global_State g; +typedef struct LG +{ + LX l; + global_State g; } LG; - #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) @@ -78,16 +78,17 @@ typedef struct LG { { size_t t = cast(size_t, e); \ memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } -static unsigned int makeseed (lua_State *L) { - char buff[4 * sizeof(size_t)]; - unsigned int h = luai_makeseed(); - int p = 0; - addbuff(buff, p, L); /* heap variable */ - addbuff(buff, p, &h); /* local variable */ - addbuff(buff, p, luaO_nilobject); /* global variable */ - addbuff(buff, p, &lua_newstate); /* public function */ - lua_assert(p == sizeof(buff)); - return luaS_hash(buff, p, h); +static unsigned int makeseed(lua_State* L) +{ + char buff[4 * sizeof(size_t)]; + unsigned int h = luai_makeseed(); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, luaO_nilobject); /* global variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); } @@ -95,104 +96,114 @@ static unsigned int makeseed (lua_State *L) { ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) ** invariant (and avoiding underflows in 'totalbytes') */ -void luaE_setdebt (global_State *g, l_mem debt) { - l_mem tb = gettotalbytes(g); - lua_assert(tb > 0); - if (debt < tb - MAX_LMEM) - debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ - g->totalbytes = tb - debt; - g->GCdebt = debt; +void luaE_setdebt(global_State* g, l_mem debt) +{ + l_mem tb = gettotalbytes(g); + lua_assert(tb > 0); + if (debt < tb - MAX_LMEM) + debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ + g->totalbytes = tb - debt; + g->GCdebt = debt; } -CallInfo *luaE_extendCI (lua_State *L) { - CallInfo *ci = luaM_new(L, CallInfo); - lua_assert(L->ci->next == NULL); - L->ci->next = ci; - ci->previous = L->ci; - ci->next = NULL; - L->nci++; - return ci; +CallInfo* luaE_extendCI(lua_State* L) +{ + CallInfo* ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + L->nci++; + return ci; } /* ** free all CallInfo structures not in use by a thread */ -void luaE_freeCI (lua_State *L) { - CallInfo *ci = L->ci; - CallInfo *next = ci->next; - ci->next = NULL; - while ((ci = next) != NULL) { - next = ci->next; - luaM_free(L, ci); - L->nci--; - } +void luaE_freeCI(lua_State* L) +{ + CallInfo* ci = L->ci; + CallInfo* next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) + { + next = ci->next; + luaM_free(L, ci); + L->nci--; + } } /* ** free half of the CallInfo structures not in use by a thread */ -void luaE_shrinkCI (lua_State *L) { - CallInfo *ci = L->ci; - CallInfo *next2; /* next's next */ - /* while there are two nexts */ - while (ci->next != NULL && (next2 = ci->next->next) != NULL) { - luaM_free(L, ci->next); /* free next */ - L->nci--; - ci->next = next2; /* remove 'next' from the list */ - next2->previous = ci; - ci = next2; /* keep next's next */ - } +void luaE_shrinkCI(lua_State* L) +{ + CallInfo* ci = L->ci; + CallInfo* next2; /* next's next */ + /* while there are two nexts */ + while (ci->next != NULL && (next2 = ci->next->next) != NULL) + { + luaM_free(L, ci->next); /* free next */ + L->nci--; + ci->next = next2; /* remove 'next' from the list */ + next2->previous = ci; + ci = next2; /* keep next's next */ + } } -static void stack_init (lua_State *L1, lua_State *L) { - int i; CallInfo *ci; - /* initialize stack array */ - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); - L1->stacksize = BASIC_STACK_SIZE; - for (i = 0; i < BASIC_STACK_SIZE; i++) - setnilvalue(L1->stack + i); /* erase new stack */ - L1->top = L1->stack; - L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; - /* initialize first ci */ - ci = &L1->base_ci; - ci->next = ci->previous = NULL; - ci->callstatus = 0; - ci->func = L1->top; - setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ - ci->top = L1->top + LUA_MINSTACK; - L1->ci = ci; +static void stack_init(lua_State* L1, lua_State* L) +{ + int i; + CallInfo* ci; + /* initialize stack array */ + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); + L1->stacksize = BASIC_STACK_SIZE; + for (i = 0; i < BASIC_STACK_SIZE; i++) + setnilvalue(L1->stack + i); /* erase new stack */ + L1->top = L1->stack; + L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; } -static void freestack (lua_State *L) { - if (L->stack == NULL) - return; /* stack not completely built yet */ - L->ci = &L->base_ci; /* free the entire 'ci' list */ - luaE_freeCI(L); - lua_assert(L->nci == 0); - luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ +static void freestack(lua_State* L) +{ + if (L->stack == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ + luaE_freeCI(L); + lua_assert(L->nci == 0); + luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } /* ** Create registry table and its predefined values */ -static void init_registry (lua_State *L, global_State *g) { - TValue temp; - /* create registry */ - Table *registry = luaH_new(L); - sethvalue(L, &g->l_registry, registry); - luaH_resize(L, registry, LUA_RIDX_LAST, 0); - /* registry[LUA_RIDX_MAINTHREAD] = L */ - setthvalue(L, &temp, L); /* temp = L */ - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); - /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); +static void init_registry(lua_State* L, global_State* g) +{ + TValue temp; + /* create registry */ + Table* registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, &temp, L); /* temp = L */ + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); } @@ -200,17 +211,18 @@ static void init_registry (lua_State *L, global_State *g) { ** open parts of the state that may cause memory-allocation errors. ** ('g->version' != NULL flags that the state was completely build) */ -static void f_luaopen (lua_State *L, void *ud) { - global_State *g = G(L); - UNUSED(ud); - stack_init(L, L); /* init stack */ - init_registry(L, g); - luaS_init(L); - luaT_init(L); - luaX_init(L); - g->gcrunning = 1; /* allow gc */ - g->version = lua_version(NULL); - luai_userstateopen(L); +static void f_luaopen(lua_State* L, void* ud) +{ + global_State* g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + init_registry(L, g); + luaS_init(L); + luaT_init(L); + luaX_init(L); + g->gcrunning = 1; /* allow gc */ + g->version = lua_version(NULL); + luai_userstateopen(L); } @@ -218,130 +230,135 @@ static void f_luaopen (lua_State *L, void *ud) { ** preinitialize a thread with consistent values without allocating ** any memory (to avoid errors) */ -static void preinit_thread (lua_State *L, global_State *g) { - G(L) = g; - L->stack = NULL; - L->ci = NULL; - L->nci = 0; - L->stacksize = 0; - L->twups = L; /* thread has no upvalues */ - L->errorJmp = NULL; - L->nCcalls = 0; - L->hook = NULL; - L->hookmask = 0; - L->basehookcount = 0; - L->allowhook = 1; - resethookcount(L); - L->openupval = NULL; - L->nny = 1; - L->status = LUA_OK; - L->errfunc = 0; +static void preinit_thread(lua_State* L, global_State* g) +{ + G(L) = g; + L->stack = NULL; + L->ci = NULL; + L->nci = 0; + L->stacksize = 0; + L->twups = L; /* thread has no upvalues */ + L->errorJmp = NULL; + L->nCcalls = 0; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->nny = 1; + L->status = LUA_OK; + L->errfunc = 0; } -static void close_state (lua_State *L) { - global_State *g = G(L); - luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_freeallobjects(L); /* collect all objects */ - if (g->version) /* closing a fully built state? */ - luai_userstateclose(L); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); - freestack(L); - lua_assert(gettotalbytes(g) == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ +static void close_state(lua_State* L) +{ + global_State* g = G(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_freeallobjects(L); /* collect all objects */ + if (g->version) /* closing a fully built state? */ + luai_userstateclose(L); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ } -LUA_API lua_State *lua_newthread (lua_State *L) { - global_State *g = G(L); - lua_State *L1; - lua_lock(L); - luaC_checkGC(L); - /* create new thread */ - L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; - L1->marked = luaC_white(g); - L1->tt = LUA_TTHREAD; - /* link it on list 'allgc' */ - L1->next = g->allgc; - g->allgc = obj2gco(L1); - /* anchor it on L stack */ - setthvalue(L, L->top, L1); - api_incr_top(L); - preinit_thread(L1, g); - L1->hookmask = L->hookmask; - L1->basehookcount = L->basehookcount; - L1->hook = L->hook; - resethookcount(L1); - /* initialize L1 extra space */ - memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), - LUA_EXTRASPACE); - luai_userstatethread(L, L1); - stack_init(L1, L); /* init stack */ - lua_unlock(L); - return L1; +LUA_API lua_State* lua_newthread(lua_State* L) +{ + global_State* g = G(L); + lua_State* L1; + lua_lock(L); + luaC_checkGC(L); + /* create new thread */ + L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; + L1->marked = luaC_white(g); + L1->tt = LUA_TTHREAD; + /* link it on list 'allgc' */ + L1->next = g->allgc; + g->allgc = obj2gco(L1); + /* anchor it on L stack */ + setthvalue(L, L->top, L1); + api_incr_top(L); + preinit_thread(L1, g); + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); + return L1; } -void luaE_freethread (lua_State *L, lua_State *L1) { - LX *l = fromstate(L1); - luaF_close(L1, L1->stack); /* close all upvalues for this thread */ - lua_assert(L1->openupval == NULL); - luai_userstatefree(L, L1); - freestack(L1); - luaM_free(L, l); +void luaE_freethread(lua_State* L, lua_State* L1) +{ + LX* l = fromstate(L1); + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L, L1); + freestack(L1); + luaM_free(L, l); } -LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { - int i; - lua_State *L; - global_State *g; - LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); - if (l == NULL) return NULL; - L = &l->l.l; - g = &l->g; - L->next = NULL; - L->tt = LUA_TTHREAD; - g->currentwhite = bitmask(WHITE0BIT); - L->marked = luaC_white(g); - preinit_thread(L, g); - g->frealloc = f; - g->ud = ud; - g->mainthread = L; - g->seed = makeseed(L); - g->gcrunning = 0; /* no GC while building state */ - g->GCestimate = 0; - g->strt.size = g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(&g->l_registry); - g->panic = NULL; - g->version = NULL; - g->gcstate = GCSpause; - g->gckind = KGC_NORMAL; - g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; - g->sweepgc = NULL; - g->gray = g->grayagain = NULL; - g->weak = g->ephemeron = g->allweak = NULL; - g->twups = NULL; - g->totalbytes = sizeof(LG); - g->GCdebt = 0; - g->gcfinnum = 0; - g->gcpause = LUAI_GCPAUSE; - g->gcstepmul = LUAI_GCMUL; - for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { - /* memory allocation error: free partial state */ - close_state(L); - L = NULL; - } - return L; +LUA_API lua_State* lua_newstate(lua_Alloc f, void* ud) +{ + int i; + lua_State* L; + global_State* g; + LG* l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); + if (l == NULL) return NULL; + L = &l->l.l; + g = &l->g; + L->next = NULL; + L->tt = LUA_TTHREAD; + g->currentwhite = bitmask(WHITE0BIT); + L->marked = luaC_white(g); + preinit_thread(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->seed = makeseed(L); + g->gcrunning = 0; /* no GC while building state */ + g->GCestimate = 0; + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); + g->panic = NULL; + g->version = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_NORMAL; + g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; + g->sweepgc = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; + g->totalbytes = sizeof(LG); + g->GCdebt = 0; + g->gcfinnum = 0; + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; + for (i = 0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) + { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + return L; } -LUA_API void lua_close (lua_State *L) { - L = G(L)->mainthread; /* only the main thread can be closed */ - lua_lock(L); - close_state(L); +LUA_API void lua_close(lua_State* L) +{ + L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); + close_state(L); } - - diff --git a/Lua/lstate.h b/Lua/lstate.h index a469466..7d86509 100644 --- a/Lua/lstate.h +++ b/Lua/lstate.h @@ -30,7 +30,7 @@ */ -struct lua_longjmp; /* defined in ldo.c */ +struct lua_longjmp; /* defined in ldo.c */ /* @@ -55,10 +55,11 @@ struct lua_longjmp; /* defined in ldo.c */ #define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ -typedef struct stringtable { - TString **hash; - int nuse; /* number of elements */ - int size; +typedef struct stringtable +{ + TString** hash; + int nuse; /* number of elements */ + int size; } stringtable; @@ -71,24 +72,32 @@ typedef struct stringtable { ** the function index so that, in case of errors, the continuation ** function can be called with the correct top. */ -typedef struct CallInfo { - StkId func; /* function index in the stack */ - StkId top; /* top for this function */ - struct CallInfo *previous, *next; /* dynamic call link */ - union { - struct { /* only for Lua functions */ - StkId base; /* base for this function */ - const Instruction *savedpc; - } l; - struct { /* only for C functions */ - lua_KFunction k; /* continuation in case of yields */ - ptrdiff_t old_errfunc; - lua_KContext ctx; /* context info. in case of yields */ - } c; - } u; - ptrdiff_t extra; - short nresults; /* expected number of results from this function */ - unsigned short callstatus; +typedef struct CallInfo +{ + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + struct CallInfo *previous, *next; /* dynamic call link */ + union + { + struct + { + /* only for Lua functions */ + StkId base; /* base for this function */ + const Instruction* savedpc; + } l; + + struct + { + /* only for C functions */ + lua_KFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + lua_KContext ctx; /* context info. in case of yields */ + } c; + } u; + + ptrdiff_t extra; + short nresults; /* expected number of results from this function */ + unsigned short callstatus; } CallInfo; @@ -116,71 +125,73 @@ typedef struct CallInfo { /* ** 'global state', shared by all threads of this state */ -typedef struct global_State { - lua_Alloc frealloc; /* function to reallocate memory */ - void *ud; /* auxiliary data to 'frealloc' */ - l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ - l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - lu_mem GCmemtrav; /* memory traversed by the GC */ - lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ - stringtable strt; /* hash table for strings */ - TValue l_registry; - unsigned int seed; /* randomized seed for hashes */ - lu_byte currentwhite; - lu_byte gcstate; /* state of garbage collector */ - lu_byte gckind; /* kind of GC running */ - lu_byte gcrunning; /* true if GC is running */ - GCObject *allgc; /* list of all collectable objects */ - GCObject **sweepgc; /* current position of sweep in list */ - GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject *gray; /* list of gray objects */ - GCObject *grayagain; /* list of objects to be traversed atomically */ - GCObject *weak; /* list of tables with weak values */ - GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ - GCObject *allweak; /* list of all-weak tables */ - GCObject *tobefnz; /* list of userdata to be GC */ - GCObject *fixedgc; /* list of objects not to be collected */ - struct lua_State *twups; /* list of threads with open upvalues */ - unsigned int gcfinnum; /* number of finalizers to call in each GC step */ - int gcpause; /* size of pause between successive GCs */ - int gcstepmul; /* GC 'granularity' */ - lua_CFunction panic; /* to be called in unprotected errors */ - struct lua_State *mainthread; - const lua_Number *version; /* pointer to version number */ - TString *memerrmsg; /* memory-error message */ - TString *tmname[TM_N]; /* array with tag-method names */ - struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ - TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ +typedef struct global_State +{ + lua_Alloc frealloc; /* function to reallocate memory */ + void* ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + lu_mem GCmemtrav; /* memory traversed by the GC */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ + stringtable strt; /* hash table for strings */ + TValue l_registry; + unsigned int seed; /* randomized seed for hashes */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ + lu_byte gcrunning; /* true if GC is running */ + GCObject* allgc; /* list of all collectable objects */ + GCObject** sweepgc; /* current position of sweep in list */ + GCObject* finobj; /* list of collectable objects with finalizers */ + GCObject* gray; /* list of gray objects */ + GCObject* grayagain; /* list of objects to be traversed atomically */ + GCObject* weak; /* list of tables with weak values */ + GCObject* ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject* allweak; /* list of all-weak tables */ + GCObject* tobefnz; /* list of userdata to be GC */ + GCObject* fixedgc; /* list of objects not to be collected */ + struct lua_State* twups; /* list of threads with open upvalues */ + unsigned int gcfinnum; /* number of finalizers to call in each GC step */ + int gcpause; /* size of pause between successive GCs */ + int gcstepmul; /* GC 'granularity' */ + lua_CFunction panic; /* to be called in unprotected errors */ + struct lua_State* mainthread; + const lua_Number* version; /* pointer to version number */ + TString* memerrmsg; /* memory-error message */ + TString* tmname[TM_N]; /* array with tag-method names */ + struct Table* mt[LUA_NUMTAGS]; /* metatables for basic types */ + TString* strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ } global_State; /* ** 'per thread' state */ -struct lua_State { - CommonHeader; - unsigned short nci; /* number of items in 'ci' list */ - lu_byte status; - StkId top; /* first free slot in the stack */ - global_State *l_G; - CallInfo *ci; /* call info for current function */ - const Instruction *oldpc; /* last pc traced */ - StkId stack_last; /* last free slot in the stack */ - StkId stack; /* stack base */ - UpVal *openupval; /* list of open upvalues in this stack */ - GCObject *gclist; - struct lua_State *twups; /* list of threads with open upvalues */ - struct lua_longjmp *errorJmp; /* current error recover point */ - CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ - volatile lua_Hook hook; - ptrdiff_t errfunc; /* current error handling function (stack index) */ - int stacksize; - int basehookcount; - int hookcount; - unsigned short nny; /* number of non-yieldable calls in stack */ - unsigned short nCcalls; /* number of nested C calls */ - l_signalT hookmask; - lu_byte allowhook; +struct lua_State +{ + CommonHeader; + unsigned short nci; /* number of items in 'ci' list */ + lu_byte status; + StkId top; /* first free slot in the stack */ + global_State* l_G; + CallInfo* ci; /* call info for current function */ + const Instruction* oldpc; /* last pc traced */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + UpVal* openupval; /* list of open upvalues in this stack */ + GCObject* gclist; + struct lua_State* twups; /* list of threads with open upvalues */ + struct lua_longjmp* errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ + int stacksize; + int basehookcount; + int hookcount; + unsigned short nny; /* number of non-yieldable calls in stack */ + unsigned short nCcalls; /* number of nested C calls */ + l_signalT hookmask; + lu_byte allowhook; }; @@ -190,14 +201,15 @@ struct lua_State { /* ** Union of all collectable objects (only for conversions) */ -union GCUnion { - GCObject gc; /* common header */ - struct TString ts; - struct Udata u; - union Closure cl; - struct Table h; - struct Proto p; - struct lua_State th; /* thread */ +union GCUnion +{ + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct lua_State th; /* thread */ }; @@ -224,12 +236,11 @@ union GCUnion { /* actual number of total bytes allocated */ #define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) -LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); -LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); -LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); -LUAI_FUNC void luaE_freeCI (lua_State *L); -LUAI_FUNC void luaE_shrinkCI (lua_State *L); +LUAI_FUNC void luaE_setdebt(global_State* g, l_mem debt); +LUAI_FUNC void luaE_freethread(lua_State* L, lua_State* L1); +LUAI_FUNC CallInfo* luaE_extendCI(lua_State* L); +LUAI_FUNC void luaE_freeCI(lua_State* L); +LUAI_FUNC void luaE_shrinkCI(lua_State* L); #endif - diff --git a/Lua/lstring.c b/Lua/lstring.c index 9351766..c29c49f 100644 --- a/Lua/lstring.c +++ b/Lua/lstring.c @@ -37,62 +37,76 @@ /* ** equality for long strings */ -int luaS_eqlngstr (TString *a, TString *b) { - size_t len = a->u.lnglen; - lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); - return (a == b) || /* same instance or... */ - ((len == b->u.lnglen) && /* equal length and ... */ - (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +int luaS_eqlngstr(TString* a, TString* b) +{ + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->u.lnglen) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ } -unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { - unsigned int h = seed ^ cast(unsigned int, l); - size_t step = (l >> LUAI_HASHLIMIT) + 1; - for (; l >= step; l -= step) - h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); - return h; +unsigned int luaS_hash(const char* str, size_t l, unsigned int seed) +{ + unsigned int h = seed ^ cast(unsigned int, l); + size_t step = (l >> LUAI_HASHLIMIT) + 1; + for (; l >= step; l -= step) + h ^= ((h << 5) + (h >> 2) + cast_byte(str[l - 1])); + return h; } -unsigned int luaS_hashlongstr (TString *ts) { - lua_assert(ts->tt == LUA_TLNGSTR); - if (ts->extra == 0) { /* no hash? */ - ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); - ts->extra = 1; /* now it has its hash */ - } - return ts->hash; +unsigned int luaS_hashlongstr(TString* ts) +{ + lua_assert(ts->tt == LUA_TLNGSTR); + if (ts->extra == 0) + { + /* no hash? */ + ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; } /* ** resizes the string table */ -void luaS_resize (lua_State *L, int newsize) { - int i; - stringtable *tb = &G(L)->strt; - if (newsize > tb->size) { /* grow table if needed */ - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - for (i = tb->size; i < newsize; i++) - tb->hash[i] = NULL; - } - for (i = 0; i < tb->size; i++) { /* rehash */ - TString *p = tb->hash[i]; - tb->hash[i] = NULL; - while (p) { /* for each node in the list */ - TString *hnext = p->u.hnext; /* save next */ - unsigned int h = lmod(p->hash, newsize); /* new position */ - p->u.hnext = tb->hash[h]; /* chain it */ - tb->hash[h] = p; - p = hnext; - } - } - if (newsize < tb->size) { /* shrink table if needed */ - /* vanishing slice should be empty */ - lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - } - tb->size = newsize; +void luaS_resize(lua_State* L, int newsize) +{ + int i; + stringtable* tb = &G(L)->strt; + if (newsize > tb->size) + { + /* grow table if needed */ + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + for (i = tb->size; i < newsize; i++) + tb->hash[i] = NULL; + } + for (i = 0; i < tb->size; i++) + { + /* rehash */ + TString* p = tb->hash[i]; + tb->hash[i] = NULL; + while (p) + { + /* for each node in the list */ + TString* hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, newsize); /* new position */ + p->u.hnext = tb->hash[h]; /* chain it */ + tb->hash[h] = p; + p = hnext; + } + } + if (newsize < tb->size) + { + /* shrink table if needed */ + /* vanishing slice should be empty */ + lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + } + tb->size = newsize; } @@ -100,113 +114,124 @@ void luaS_resize (lua_State *L, int newsize) { ** Clear API string cache. (Entries cannot be empty, so fill them with ** a non-collectable string.) */ -void luaS_clearcache (global_State *g) { - int i, j; - for (i = 0; i < STRCACHE_N; i++) - for (j = 0; j < STRCACHE_M; j++) { - if (iswhite(g->strcache[i][j])) /* will entry be collected? */ - g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ - } +void luaS_clearcache(global_State* g) +{ + int i, j; + for (i = 0; i < STRCACHE_N; i++) + for (j = 0; j < STRCACHE_M; j++) + { + if (iswhite(g->strcache[i][j])) /* will entry be collected? */ + g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ + } } /* ** Initialize the string table and the string cache */ -void luaS_init (lua_State *L) { - global_State *g = G(L); - int i, j; - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ - /* pre-create memory-error message */ - g->memerrmsg = luaS_newliteral(L, MEMERRMSG); - luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ - for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ - for (j = 0; j < STRCACHE_M; j++) - g->strcache[i][j] = g->memerrmsg; +void luaS_init(lua_State* L) +{ + global_State* g = G(L); + int i, j; + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; } - /* ** creates a new string object */ -static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { - TString *ts; - GCObject *o; - size_t totalsize; /* total size of TString object */ - totalsize = sizelstring(l); - o = luaC_newobj(L, tag, totalsize); - ts = gco2ts(o); - ts->hash = h; - ts->extra = 0; - getstr(ts)[l] = '\0'; /* ending 0 */ - return ts; +static TString* createstrobj(lua_State* L, size_t l, int tag, unsigned int h) +{ + TString* ts; + GCObject* o; + size_t totalsize; /* total size of TString object */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ + return ts; } -TString *luaS_createlngstrobj (lua_State *L, size_t l) { - TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); - ts->u.lnglen = l; - return ts; +TString* luaS_createlngstrobj(lua_State* L, size_t l) +{ + TString* ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; } -void luaS_remove (lua_State *L, TString *ts) { - stringtable *tb = &G(L)->strt; - TString **p = &tb->hash[lmod(ts->hash, tb->size)]; - while (*p != ts) /* find previous element */ - p = &(*p)->u.hnext; - *p = (*p)->u.hnext; /* remove element from its list */ - tb->nuse--; +void luaS_remove(lua_State* L, TString* ts) +{ + stringtable* tb = &G(L)->strt; + TString** p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; } /* ** checks whether short string exists and reuses it or creates a new one */ -static TString *internshrstr (lua_State *L, const char *str, size_t l) { - TString *ts; - global_State *g = G(L); - unsigned int h = luaS_hash(str, l, g->seed); - TString **list = &g->strt.hash[lmod(h, g->strt.size)]; - lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ - for (ts = *list; ts != NULL; ts = ts->u.hnext) { - if (l == ts->shrlen && - (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { - /* found! */ - if (isdead(g, ts)) /* dead (but not collected yet)? */ - changewhite(ts); /* resurrect it */ - return ts; - } - } - if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { - luaS_resize(L, g->strt.size * 2); - list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ - } - ts = createstrobj(L, l, LUA_TSHRSTR, h); - memcpy(getstr(ts), str, l * sizeof(char)); - ts->shrlen = cast_byte(l); - ts->u.hnext = *list; - *list = ts; - g->strt.nuse++; - return ts; +static TString* internshrstr(lua_State* L, const char* str, size_t l) +{ + TString* ts; + global_State* g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + TString** list = &g->strt.hash[lmod(h, g->strt.size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) + { + if (l == ts->shrlen && + (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) + { + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ + return ts; + } + } + if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT / 2) + { + luaS_resize(L, g->strt.size * 2); + list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ + } + ts = createstrobj(L, l, LUA_TSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + g->strt.nuse++; + return ts; } /* ** new string (with explicit length) */ -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - if (l <= LUAI_MAXSHORTLEN) /* short string? */ - return internshrstr(L, str, l); - else { - TString *ts; - if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) - luaM_toobig(L); - ts = luaS_createlngstrobj(L, l); - memcpy(getstr(ts), str, l * sizeof(char)); - return ts; - } +TString* luaS_newlstr(lua_State* L, const char* str, size_t l) +{ + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else + { + TString* ts; + if (l >= (MAX_SIZE - sizeof(TString)) / sizeof(char)) + luaM_toobig(L); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; + } } @@ -216,33 +241,35 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { ** only zero-terminated strings, so it is safe to use 'strcmp' to ** check hits. */ -TString *luaS_new (lua_State *L, const char *str) { - unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ - int j; - TString **p = G(L)->strcache[i]; - for (j = 0; j < STRCACHE_M; j++) { - if (strcmp(str, getstr(p[j])) == 0) /* hit? */ - return p[j]; /* that is it */ - } - /* normal route */ - for (j = STRCACHE_M - 1; j > 0; j--) - p[j] = p[j - 1]; /* move out last element */ - /* new element is first in the list */ - p[0] = luaS_newlstr(L, str, strlen(str)); - return p[0]; +TString* luaS_new(lua_State* L, const char* str) +{ + unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ + int j; + TString** p = G(L)->strcache[i]; + for (j = 0; j < STRCACHE_M; j++) + { + if (strcmp(str, getstr(p[j])) == 0) /* hit? */ + return p[j]; /* that is it */ + } + /* normal route */ + for (j = STRCACHE_M - 1; j > 0; j--) + p[j] = p[j - 1]; /* move out last element */ + /* new element is first in the list */ + p[0] = luaS_newlstr(L, str, strlen(str)); + return p[0]; } -Udata *luaS_newudata (lua_State *L, size_t s) { - Udata *u; - GCObject *o; - if (s > MAX_SIZE - sizeof(Udata)) - luaM_toobig(L); - o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); - u = gco2u(o); - u->len = s; - u->metatable = NULL; - setuservalue(L, u, luaO_nilobject); - return u; +Udata* luaS_newudata(lua_State* L, size_t s) +{ + Udata* u; + GCObject* o; + if (s > MAX_SIZE - sizeof(Udata)) + luaM_toobig(L); + o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); + u = gco2u(o); + u->len = s; + u->metatable = NULL; + setuservalue(L, u, luaO_nilobject); + return u; } - diff --git a/Lua/lstring.h b/Lua/lstring.h index 27efd20..a40204e 100644 --- a/Lua/lstring.h +++ b/Lua/lstring.h @@ -33,17 +33,17 @@ #define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) -LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); -LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); -LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); -LUAI_FUNC void luaS_resize (lua_State *L, int newsize); -LUAI_FUNC void luaS_clearcache (global_State *g); -LUAI_FUNC void luaS_init (lua_State *L); -LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); -LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); -LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); -LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); -LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); +LUAI_FUNC unsigned int luaS_hash(const char* str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr(TString* ts); +LUAI_FUNC int luaS_eqlngstr(TString* a, TString* b); +LUAI_FUNC void luaS_resize(lua_State* L, int newsize); +LUAI_FUNC void luaS_clearcache(global_State* g); +LUAI_FUNC void luaS_init(lua_State* L); +LUAI_FUNC void luaS_remove(lua_State* L, TString* ts); +LUAI_FUNC Udata* luaS_newudata(lua_State* L, size_t s); +LUAI_FUNC TString* luaS_newlstr(lua_State* L, const char* str, size_t l); +LUAI_FUNC TString* luaS_new(lua_State* L, const char* str); +LUAI_FUNC TString* luaS_createlngstrobj(lua_State* L, size_t l); #endif diff --git a/Lua/lstrlib.c b/Lua/lstrlib.c index c7aa755..a0c25fa 100644 --- a/Lua/lstrlib.c +++ b/Lua/lstrlib.c @@ -49,157 +49,174 @@ (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) - - -static int str_len (lua_State *L) { - size_t l; - luaL_checklstring(L, 1, &l); - lua_pushinteger(L, (lua_Integer)l); - return 1; +static int str_len(lua_State* L) +{ + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; } /* translate a relative string position: negative means back from end */ -static lua_Integer posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; +static lua_Integer posrelat(lua_Integer pos, size_t len) +{ + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; } -static int str_sub (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); - lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (lua_Integer)l) end = l; - if (start <= end) - lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); - else lua_pushliteral(L, ""); - return 1; +static int str_sub(lua_State* L) +{ + size_t l; + const char* s = luaL_checklstring(L, 1, &l); + lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); + lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (lua_Integer)l) end = l; + if (start <= end) + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); + else + lua_pushliteral(L, ""); + return 1; } -static int str_reverse (lua_State *L) { - size_t l, i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i = 0; i < l; i++) - p[i] = s[l - i - 1]; - luaL_pushresultsize(&b, l); - return 1; +static int str_reverse(lua_State* L) +{ + size_t l, i; + luaL_Buffer b; + const char* s = luaL_checklstring(L, 1, &l); + char* p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; } -static int str_lower (lua_State *L) { - size_t l; - size_t i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i=0; i MAXSIZE / n) /* may overflow? */ - return luaL_error(L, "resulting string too large"); - else { - size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; - luaL_Buffer b; - char *p = luaL_buffinitsize(L, &b, totallen); - while (n-- > 1) { /* first n-1 copies (followed by separator) */ - memcpy(p, s, l * sizeof(char)); p += l; - if (lsep > 0) { /* empty 'memcpy' is not that cheap */ - memcpy(p, sep, lsep * sizeof(char)); - p += lsep; - } - } - memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ - luaL_pushresultsize(&b, totallen); - } - return 1; +static int str_rep(lua_State* L) +{ + size_t l, lsep; + const char* s = luaL_checklstring(L, 1, &l); + lua_Integer n = luaL_checkinteger(L, 2); + const char* sep = luaL_optlstring(L, 3, "", &lsep); + if (n <= 0) + lua_pushliteral(L, ""); + else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else + { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char* p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) + { + /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); + p += l; + if (lsep > 0) + { + /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; } -static int str_byte (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); - lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); - int n, i; - if (posi < 1) posi = 1; - if (pose > (lua_Integer)l) pose = l; - if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* arithmetic overflow? */ - return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; - luaL_checkstack(L, n, "string slice too long"); - for (i=0; i (lua_Integer)l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i = 0; i < n; i++) + lua_pushinteger(L, uchar(s[posi+i-1])); + return n; } -static int str_char (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int i; - luaL_Buffer b; - char *p = luaL_buffinitsize(L, &b, n); - for (i=1; i<=n; i++) { - lua_Integer c = luaL_checkinteger(L, i); - luaL_argcheck(L, uchar(c) == c, i, "value out of range"); - p[i - 1] = uchar(c); - } - luaL_pushresultsize(&b, n); - return 1; +static int str_char(lua_State* L) +{ + int n = lua_gettop(L); /* number of arguments */ + int i; + luaL_Buffer b; + char* p = luaL_buffinitsize(L, &b, n); + for (i = 1; i <= n; i++) + { + lua_Integer c = luaL_checkinteger(L, i); + luaL_argcheck(L, uchar(c) == c, i, "value out of range"); + p[i - 1] = uchar(c); + } + luaL_pushresultsize(&b, n); + return 1; } -static int writer (lua_State *L, const void *b, size_t size, void *B) { - (void)L; - luaL_addlstring((luaL_Buffer *) B, (const char *)b, size); - return 0; +static int writer(lua_State* L, const void* b, size_t size, void* B) +{ + (void)L; + luaL_addlstring((luaL_Buffer*)B, (const char*)b, size); + return 0; } -static int str_dump (lua_State *L) { - luaL_Buffer b; - int strip = lua_toboolean(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 1); - luaL_buffinit(L,&b); - if (lua_dump(L, writer, &b, strip) != 0) - return luaL_error(L, "unable to dump given function"); - luaL_pushresult(&b); - return 1; +static int str_dump(lua_State* L) +{ + luaL_Buffer b; + int strip = lua_toboolean(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + luaL_buffinit(L, &b); + if (lua_dump(L, writer, &b, strip) != 0) + return luaL_error(L, "unable to dump given function"); + luaL_pushresult(&b); + return 1; } - /* ** {====================================================== ** PATTERN MATCHING @@ -211,22 +228,24 @@ static int str_dump (lua_State *L) { #define CAP_POSITION (-2) -typedef struct MatchState { - const char *src_init; /* init of source string */ - const char *src_end; /* end ('\0') of source string */ - const char *p_end; /* end ('\0') of pattern */ - lua_State *L; - int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ - unsigned char level; /* total number of captures (finished or unfinished) */ - struct { - const char *init; - ptrdiff_t len; - } capture[LUA_MAXCAPTURES]; +typedef struct MatchState +{ + const char* src_init; /* init of source string */ + const char* src_end; /* end ('\0') of source string */ + const char* p_end; /* end ('\0') of pattern */ + lua_State* L; + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ + unsigned char level; /* total number of captures (finished or unfinished) */ + struct + { + const char* init; + ptrdiff_t len; + } capture[LUA_MAXCAPTURES]; } MatchState; /* recursive function */ -static const char *match (MatchState *ms, const char *s, const char *p); +static const char* match(MatchState* ms, const char* s, const char* p); /* maximum recursion depth for 'match' */ @@ -239,568 +258,710 @@ static const char *match (MatchState *ms, const char *s, const char *p); #define SPECIALS "^$*+?.([%-" -static int check_capture (MatchState *ms, int l) { - l -= '1'; - if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index %%%d", l + 1); - return l; +static int check_capture(MatchState* ms, int l) +{ + l -= '1'; + if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; } -static int capture_to_close (MatchState *ms) { - int level = ms->level; - for (level--; level>=0; level--) - if (ms->capture[level].len == CAP_UNFINISHED) return level; - return luaL_error(ms->L, "invalid pattern capture"); +static int capture_to_close(MatchState* ms) +{ + int level = ms->level; + for (level--; level >= 0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); } -static const char *classend (MatchState *ms, const char *p) { - switch (*p++) { - case L_ESC: { - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (ends with '%%')"); - return p+1; - } - case '[': { - if (*p == '^') p++; - do { /* look for a ']' */ - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (missing ']')"); - if (*(p++) == L_ESC && p < ms->p_end) - p++; /* skip escapes (e.g. '%]') */ - } while (*p != ']'); - return p+1; - } - default: { - return p; - } - } +static const char* classend(MatchState* ms, const char* p) +{ + switch (*p++) + { + case L_ESC: + { + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p + 1; + } + case '[': + { + if (*p == '^') p++; + do + { + /* look for a ']' */ + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } + while (*p != ']'); + return p + 1; + } + default: + { + return p; + } + } } -static int match_class (int c, int cl) { - int res; - switch (tolower(cl)) { - case 'a' : res = isalpha(c); break; - case 'c' : res = iscntrl(c); break; - case 'd' : res = isdigit(c); break; - case 'g' : res = isgraph(c); break; - case 'l' : res = islower(c); break; - case 'p' : res = ispunct(c); break; - case 's' : res = isspace(c); break; - case 'u' : res = isupper(c); break; - case 'w' : res = isalnum(c); break; - case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; /* deprecated option */ - default: return (cl == c); - } - return (islower(cl) ? res : !res); +static int match_class(int c, int cl) +{ + int res; + switch (tolower(cl)) + { + case 'a': res = isalpha(c); + break; + case 'c': res = iscntrl(c); + break; + case 'd': res = isdigit(c); + break; + case 'g': res = isgraph(c); + break; + case 'l': res = islower(c); + break; + case 'p': res = ispunct(c); + break; + case 's': res = isspace(c); + break; + case 'u': res = isupper(c); + break; + case 'w': res = isalnum(c); + break; + case 'x': res = isxdigit(c); + break; + case 'z': res = (c == 0); + break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); } -static int matchbracketclass (int c, const char *p, const char *ec) { - int sig = 1; - if (*(p+1) == '^') { - sig = 0; - p++; /* skip the '^' */ - } - while (++p < ec) { - if (*p == L_ESC) { - p++; - if (match_class(c, uchar(*p))) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < ec)) { - p+=2; - if (uchar(*(p-2)) <= c && c <= uchar(*p)) - return sig; - } - else if (uchar(*p) == c) return sig; - } - return !sig; +static int matchbracketclass(int c, const char* p, const char* ec) +{ + int sig = 1; + if (*(p + 1) == '^') + { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) + { + if (*p == L_ESC) + { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p + 1) == '-') && (p + 2 < ec)) + { + p += 2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; } -static int singlematch (MatchState *ms, const char *s, const char *p, - const char *ep) { - if (s >= ms->src_end) - return 0; - else { - int c = uchar(*s); - switch (*p) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, uchar(*(p+1))); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); - } - } +static int singlematch(MatchState* ms, const char* s, const char* p, + const char* ep) +{ + if (s >= ms->src_end) + return 0; + else + { + int c = uchar(*s); + switch (*p) + { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep - 1); + default: return (uchar(*p) == c); + } + } } -static const char *matchbalance (MatchState *ms, const char *s, - const char *p) { - if (p >= ms->p_end - 1) - luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); - if (*s != *p) return NULL; - else { - int b = *p; - int e = *(p+1); - int cont = 1; - while (++s < ms->src_end) { - if (*s == e) { - if (--cont == 0) return s+1; - } - else if (*s == b) cont++; - } - } - return NULL; /* string ends out of balance */ +static const char* matchbalance(MatchState* ms, const char* s, + const char* p) +{ + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else + { + int b = *p; + int e = *(p + 1); + int cont = 1; + while (++s < ms->src_end) + { + if (*s == e) + { + if (--cont == 0) return s + 1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ } -static const char *max_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - ptrdiff_t i = 0; /* counts maximum expand for item */ - while (singlematch(ms, s + i, p, ep)) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - const char *res = match(ms, (s+i), ep+1); - if (res) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return NULL; +static const char* max_expand(MatchState* ms, const char* s, + const char* p, const char* ep) +{ + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i >= 0) + { + const char* res = match(ms, (s + i), ep + 1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; } -static const char *min_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - for (;;) { - const char *res = match(ms, s, ep+1); - if (res != NULL) - return res; - else if (singlematch(ms, s, p, ep)) - s++; /* try with one more repetition */ - else return NULL; - } +static const char* min_expand(MatchState* ms, const char* s, + const char* p, const char* ep) +{ + for (;;) + { + const char* res = match(ms, s, ep + 1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } } -static const char *start_capture (MatchState *ms, const char *s, - const char *p, int what) { - const char *res; - int level = ms->level; - if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); - ms->capture[level].init = s; - ms->capture[level].len = what; - ms->level = level+1; - if ((res=match(ms, s, p)) == NULL) /* match failed? */ - ms->level--; /* undo capture */ - return res; +static const char* start_capture(MatchState* ms, const char* s, + const char* p, int what) +{ + const char* res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level + 1; + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; } -static const char *end_capture (MatchState *ms, const char *s, - const char *p) { - int l = capture_to_close(ms); - const char *res; - ms->capture[l].len = s - ms->capture[l].init; /* close capture */ - if ((res = match(ms, s, p)) == NULL) /* match failed? */ - ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ - return res; +static const char* end_capture(MatchState* ms, const char* s, + const char* p) +{ + int l = capture_to_close(ms); + const char* res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; } -static const char *match_capture (MatchState *ms, const char *s, int l) { - size_t len; - l = check_capture(ms, l); - len = ms->capture[l].len; - if ((size_t)(ms->src_end-s) >= len && - memcmp(ms->capture[l].init, s, len) == 0) - return s+len; - else return NULL; +static const char* match_capture(MatchState* ms, const char* s, int l) +{ + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end - s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s + len; + else return NULL; } -static const char *match (MatchState *ms, const char *s, const char *p) { - if (ms->matchdepth-- == 0) - luaL_error(ms->L, "pattern too complex"); - init: /* using goto's to optimize tail recursion */ - if (p != ms->p_end) { /* end of pattern? */ - switch (*p) { - case '(': { /* start capture */ - if (*(p + 1) == ')') /* position capture? */ - s = start_capture(ms, s, p + 2, CAP_POSITION); - else - s = start_capture(ms, s, p + 1, CAP_UNFINISHED); - break; - } - case ')': { /* end capture */ - s = end_capture(ms, s, p + 1); - break; - } - case '$': { - if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ - goto dflt; /* no; go to default */ - s = (s == ms->src_end) ? s : NULL; /* check end of string */ - break; - } - case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ - switch (*(p + 1)) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p + 2); - if (s != NULL) { - p += 4; goto init; /* return match(ms, s, p + 4); */ - } /* else fail (s == NULL) */ - break; - } - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - luaL_error(ms->L, "missing '[' after '%%f' in pattern"); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s - 1); - if (!matchbracketclass(uchar(previous), p, ep - 1) && - matchbracketclass(uchar(*s), p, ep - 1)) { - p = ep; goto init; /* return match(ms, s, ep); */ - } - s = NULL; /* match failed */ - break; - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p + 1))); - if (s != NULL) { - p += 2; goto init; /* return match(ms, s, p + 2) */ - } - break; - } - default: goto dflt; - } - break; - } - default: dflt: { /* pattern class plus optional suffix */ - const char *ep = classend(ms, p); /* points to optional suffix */ - /* does not match at least once? */ - if (!singlematch(ms, s, p, ep)) { - if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ - p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ - } - else /* '+' or no suffix */ - s = NULL; /* fail */ - } - else { /* matched once */ - switch (*ep) { /* handle optional suffix */ - case '?': { /* optional */ - const char *res; - if ((res = match(ms, s + 1, ep + 1)) != NULL) - s = res; - else { - p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ - } - break; - } - case '+': /* 1 or more repetitions */ - s++; /* 1 match already done */ - /* FALLTHROUGH */ - case '*': /* 0 or more repetitions */ - s = max_expand(ms, s, p, ep); - break; - case '-': /* 0 or more repetitions (minimum) */ - s = min_expand(ms, s, p, ep); - break; - default: /* no suffix */ - s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ - } - } - break; - } - } - } - ms->matchdepth++; - return s; +static const char* match(MatchState* ms, const char* s, const char* p) +{ + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); +init: /* using goto's to optimize tail recursion */ + if (p != ms->p_end) + { + /* end of pattern? */ + switch (*p) + { + case '(': + { + /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': + { + /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': + { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: + { + /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) + { + case 'b': + { + /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) + { + p += 4; + goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': + { + /* frontier? */ + const char* ep; + char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) + { + p = ep; + goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) + { + p += 2; + goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: + { + /* pattern class plus optional suffix */ + const char* ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) + { + if (*ep == '*' || *ep == '?' || *ep == '-') + { + /* accept empty? */ + p = ep + 1; + goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else + { + /* matched once */ + switch (*ep) + { + /* handle optional suffix */ + case '?': + { + /* optional */ + const char* res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else + { + p = ep + 1; + goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; + p = ep; + goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; } - -static const char *lmemfind (const char *s1, size_t l1, - const char *s2, size_t l2) { - if (l2 == 0) return s1; /* empty strings are everywhere */ - else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ - else { - const char *init; /* to search for a '*s2' inside 's1' */ - l2--; /* 1st char will be checked by 'memchr' */ - l1 = l1-l2; /* 's2' cannot be found after that */ - while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { - init++; /* 1st char is already checked */ - if (memcmp(init, s2+1, l2) == 0) - return init-1; - else { /* correct 'l1' and 's1' to try again */ - l1 -= init-s1; - s1 = init; - } - } - return NULL; /* not found */ - } +static const char* lmemfind(const char* s1, size_t l1, + const char* s2, size_t l2) +{ + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else + { + const char* init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1 - l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char*)memchr(s1, *s2, l1)) != NULL) + { + init++; /* 1st char is already checked */ + if (memcmp(init, s2 + 1, l2) == 0) + return init - 1; + else + { + /* correct 'l1' and 's1' to try again */ + l1 -= init - s1; + s1 = init; + } + } + return NULL; /* not found */ + } } -static void push_onecapture (MatchState *ms, int i, const char *s, - const char *e) { - if (i >= ms->level) { - if (i == 0) /* ms->level == 0, too */ - lua_pushlstring(ms->L, s, e - s); /* add whole match */ - else - luaL_error(ms->L, "invalid capture index %%%d", i + 1); - } - else { - ptrdiff_t l = ms->capture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); - else - lua_pushlstring(ms->L, ms->capture[i].init, l); - } +static void push_onecapture(MatchState* ms, int i, const char* s, + const char* e) +{ + if (i >= ms->level) + { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index %%%d", i + 1); + } + else + { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } } -static int push_captures (MatchState *ms, const char *s, const char *e) { - int i; - int nlevels = (ms->level == 0 && s) ? 1 : ms->level; - luaL_checkstack(ms->L, nlevels, "too many captures"); - for (i = 0; i < nlevels; i++) - push_onecapture(ms, i, s, e); - return nlevels; /* number of strings pushed */ +static int push_captures(MatchState* ms, const char* s, const char* e) +{ + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ } /* check whether pattern has no special characters */ -static int nospecials (const char *p, size_t l) { - size_t upto = 0; - do { - if (strpbrk(p + upto, SPECIALS)) - return 0; /* pattern has a special character */ - upto += strlen(p + upto) + 1; /* may have more after \0 */ - } while (upto <= l); - return 1; /* no special chars found */ +static int nospecials(const char* p, size_t l) +{ + size_t upto = 0; + do + { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } + while (upto <= l); + return 1; /* no special chars found */ } -static void prepstate (MatchState *ms, lua_State *L, - const char *s, size_t ls, const char *p, size_t lp) { - ms->L = L; - ms->matchdepth = MAXCCALLS; - ms->src_init = s; - ms->src_end = s + ls; - ms->p_end = p + lp; +static void prepstate(MatchState* ms, lua_State* L, + const char* s, size_t ls, const char* p, size_t lp) +{ + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; } -static void reprepstate (MatchState *ms) { - ms->level = 0; - lua_assert(ms->matchdepth == MAXCCALLS); +static void reprepstate(MatchState* ms) +{ + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); } -static int str_find_aux (lua_State *L, int find) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); - if (init < 1) init = 1; - else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ - lua_pushnil(L); /* cannot find anything */ - return 1; - } - /* explicit request or no special characters? */ - if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { - /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); - if (s2) { - lua_pushinteger(L, (s2 - s) + 1); - lua_pushinteger(L, (s2 - s) + lp); - return 2; - } - } - else { - MatchState ms; - const char *s1 = s + init - 1; - int anchor = (*p == '^'); - if (anchor) { - p++; lp--; /* skip anchor character */ - } - prepstate(&ms, L, s, ls, p, lp); - do { - const char *res; - reprepstate(&ms); - if ((res=match(&ms, s1, p)) != NULL) { - if (find) { - lua_pushinteger(L, (s1 - s) + 1); /* start */ - lua_pushinteger(L, res - s); /* end */ - return push_captures(&ms, NULL, 0) + 2; - } - else - return push_captures(&ms, s1, res); - } - } while (s1++ < ms.src_end && !anchor); - } - lua_pushnil(L); /* not found */ - return 1; +static int str_find_aux(lua_State* L, int find) +{ + size_t ls, lp; + const char* s = luaL_checklstring(L, 1, &ls); + const char* p = luaL_checklstring(L, 2, &lp); + lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); + if (init < 1) init = 1; + else if (init > (lua_Integer)ls + 1) + { + /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) + { + /* do a plain search */ + const char* s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); + if (s2) + { + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); + return 2; + } + } + else + { + MatchState ms; + const char* s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) + { + p++; + lp--; /* skip anchor character */ + } + prepstate(&ms, L, s, ls, p, lp); + do + { + const char* res; + reprepstate(&ms); + if ((res = match(&ms, s1, p)) != NULL) + { + if (find) + { + lua_pushinteger(L, (s1 - s) + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } + while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; } -static int str_find (lua_State *L) { - return str_find_aux(L, 1); +static int str_find(lua_State* L) +{ + return str_find_aux(L, 1); } -static int str_match (lua_State *L) { - return str_find_aux(L, 0); +static int str_match(lua_State* L) +{ + return str_find_aux(L, 0); } /* state for 'gmatch' */ -typedef struct GMatchState { - const char *src; /* current position */ - const char *p; /* pattern */ - const char *lastmatch; /* end of last match */ - MatchState ms; /* match state */ +typedef struct GMatchState +{ + const char* src; /* current position */ + const char* p; /* pattern */ + const char* lastmatch; /* end of last match */ + MatchState ms; /* match state */ } GMatchState; -static int gmatch_aux (lua_State *L) { - GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); - const char *src; - gm->ms.L = L; - for (src = gm->src; src <= gm->ms.src_end; src++) { - const char *e; - reprepstate(&gm->ms); - if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { - gm->src = gm->lastmatch = e; - return push_captures(&gm->ms, src, e); - } - } - return 0; /* not found */ +static int gmatch_aux(lua_State* L) +{ + GMatchState* gm = (GMatchState*)lua_touserdata(L, lua_upvalueindex(3)); + const char* src; + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) + { + const char* e; + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) + { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); + } + } + return 0; /* not found */ } -static int gmatch (lua_State *L) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - GMatchState *gm; - lua_settop(L, 2); /* keep them on closure to avoid being collected */ - gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); - prepstate(&gm->ms, L, s, ls, p, lp); - gm->src = s; gm->p = p; gm->lastmatch = NULL; - lua_pushcclosure(L, gmatch_aux, 3); - return 1; +static int gmatch(lua_State* L) +{ + size_t ls, lp; + const char* s = luaL_checklstring(L, 1, &ls); + const char* p = luaL_checklstring(L, 2, &lp); + GMatchState* gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState*)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; + gm->p = p; + gm->lastmatch = NULL; + lua_pushcclosure(L, gmatch_aux, 3); + return 1; } -static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { - size_t l, i; - lua_State *L = ms->L; - const char *news = lua_tolstring(L, 3, &l); - for (i = 0; i < l; i++) { - if (news[i] != L_ESC) - luaL_addchar(b, news[i]); - else { - i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) { - if (news[i] != L_ESC) - luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); - luaL_addchar(b, news[i]); - } - else if (news[i] == '0') - luaL_addlstring(b, s, e - s); - else { - push_onecapture(ms, news[i] - '1', s, e); - luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ - lua_remove(L, -2); /* remove original value */ - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } +static void add_s(MatchState* ms, luaL_Buffer* b, const char* s, + const char* e) +{ + size_t l, i; + lua_State* L = ms->L; + const char* news = lua_tolstring(L, 3, &l); + for (i = 0; i < l; i++) + { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else + { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) + { + if (news[i] != L_ESC) + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); + luaL_addchar(b, news[i]); + } + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); + else + { + push_onecapture(ms, news[i] - '1', s, e); + luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ + lua_remove(L, -2); /* remove original value */ + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } } -static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e, int tr) { - lua_State *L = ms->L; - switch (tr) { - case LUA_TFUNCTION: { - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - break; - } - case LUA_TTABLE: { - push_onecapture(ms, 0, s, e); - lua_gettable(L, 3); - break; - } - default: { /* LUA_TNUMBER or LUA_TSTRING */ - add_s(ms, b, s, e); - return; - } - } - if (!lua_toboolean(L, -1)) { /* nil or false? */ - lua_pop(L, 1); - lua_pushlstring(L, s, e - s); /* keep original text */ - } - else if (!lua_isstring(L, -1)) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); - luaL_addvalue(b); /* add result to accumulator */ +static void add_value(MatchState* ms, luaL_Buffer* b, const char* s, + const char* e, int tr) +{ + lua_State* L = ms->L; + switch (tr) + { + case LUA_TFUNCTION: + { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: + { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + default: + { + /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } + } + if (!lua_toboolean(L, -1)) + { + /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ } -static int str_gsub (lua_State *L) { - size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ - const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ - const char *lastmatch = NULL; /* end of last match */ - int tr = lua_type(L, 3); /* replacement type */ - lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ - int anchor = (*p == '^'); - lua_Integer n = 0; /* replacement count */ - MatchState ms; - luaL_Buffer b; - luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || - tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, - "string/function/table expected"); - luaL_buffinit(L, &b); - if (anchor) { - p++; lp--; /* skip anchor character */ - } - prepstate(&ms, L, src, srcl, p, lp); - while (n < max_s) { - const char *e; - reprepstate(&ms); /* (re)prepare state for new match */ - if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ - n++; - add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ - src = lastmatch = e; - } - else if (src < ms.src_end) /* otherwise, skip one character */ - luaL_addchar(&b, *src++); - else break; /* end of subject */ - if (anchor) break; - } - luaL_addlstring(&b, src, ms.src_end-src); - luaL_pushresult(&b); - lua_pushinteger(L, n); /* number of substitutions */ - return 2; +static int str_gsub(lua_State* L) +{ + size_t srcl, lp; + const char* src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char* p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char* lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + int anchor = (*p == '^'); + lua_Integer n = 0; /* replacement count */ + MatchState ms; + luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); + luaL_buffinit(L, &b); + if (anchor) + { + p++; + lp--; /* skip anchor character */ + } + prepstate(&ms, L, src, srcl, p, lp); + while (n < max_s) + { + const char* e; + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) + { + /* match? */ + n++; + add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ + src = lastmatch = e; + } + else if (src < ms.src_end) /* otherwise, skip one character */ + luaL_addchar(&b, *src++); + else break; /* end of subject */ + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end - src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; } /* }====================================================== */ - /* ** {====================================================== ** STRING FORMAT @@ -830,57 +991,72 @@ static int str_gsub (lua_State *L) { /* ** Add integer part of 'x' to buffer and return new 'x' */ -static lua_Number adddigit (char *buff, int n, lua_Number x) { - lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ - int d = (int)dd; - buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ - return x - dd; /* return what is left */ +static lua_Number adddigit(char* buff, int n, lua_Number x) +{ + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ } -static int num2straux (char *buff, int sz, lua_Number x) { - /* if 'inf' or 'NaN', format it like '%g' */ - if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) - return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); - else if (x == 0) { /* can be -0... */ - /* create "0" or "-0" followed by exponent */ - return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); - } - else { - int e; - lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ - int n = 0; /* character count */ - if (m < 0) { /* is number negative? */ - buff[n++] = '-'; /* add signal */ - m = -m; /* make it positive */ - } - buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ - m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ - e -= L_NBFD; /* this digit goes before the radix point */ - if (m > 0) { /* more digits? */ - buff[n++] = lua_getlocaledecpoint(); /* add radix point */ - do { /* add as many digits as needed */ - m = adddigit(buff, n++, m * 16); - } while (m > 0); - } - n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ - lua_assert(n < sz); - return n; - } +static int num2straux(char* buff, int sz, lua_Number x) +{ + /* if 'inf' or 'NaN', format it like '%g' */ + if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) + return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); + else if (x == 0) + { + /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); + } + else + { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) + { + /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; + buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) + { + /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do + { + /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } + while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } } -static int lua_number2strx (lua_State *L, char *buff, int sz, - const char *fmt, lua_Number x) { - int n = num2straux(buff, sz, x); - if (fmt[SIZELENMOD] == 'A') { - int i; - for (i = 0; i < n; i++) - buff[i] = toupper(uchar(buff[i])); - } - else if (fmt[SIZELENMOD] != 'a') - luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); - return n; +static int lua_number2strx(lua_State* L, char* buff, int sz, + const char* fmt, lua_Number x) +{ + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') + { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; } #endif /* } */ @@ -905,191 +1081,236 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, #define MAX_FORMAT 32 -static void addquoted (luaL_Buffer *b, const char *s, size_t len) { - luaL_addchar(b, '"'); - while (len--) { - if (*s == '"' || *s == '\\' || *s == '\n') { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - } - else if (iscntrl(uchar(*s))) { - char buff[10]; - if (!isdigit(uchar(*(s+1)))) - l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); - else - l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); - luaL_addstring(b, buff); - } - else - luaL_addchar(b, *s); - s++; - } - luaL_addchar(b, '"'); +static void addquoted(luaL_Buffer* b, const char* s, size_t len) +{ + luaL_addchar(b, '"'); + while (len--) + { + if (*s == '"' || *s == '\\' || *s == '\n') + { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (iscntrl(uchar(*s))) + { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); + else + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); } /* ** Ensures the 'buff' string uses a dot as the radix character. */ -static void checkdp (char *buff, int nb) { - if (memchr(buff, '.', nb) == NULL) { /* no dot? */ - char point = lua_getlocaledecpoint(); /* try locale point */ - char *ppoint = (char *)memchr(buff, point, nb); - if (ppoint) *ppoint = '.'; /* change it to a dot */ - } +static void checkdp(char* buff, int nb) +{ + if (memchr(buff, '.', nb) == NULL) + { + /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char* ppoint = (char*)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } } -static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { - switch (lua_type(L, arg)) { - case LUA_TSTRING: { - size_t len; - const char *s = lua_tolstring(L, arg, &len); - addquoted(b, s, len); - break; - } - case LUA_TNUMBER: { - char *buff = luaL_prepbuffsize(b, MAX_ITEM); - int nb; - if (!lua_isinteger(L, arg)) { /* float? */ - lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ - nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); - checkdp(buff, nb); /* ensure it uses a dot */ - } - else { /* integers */ - lua_Integer n = lua_tointeger(L, arg); - const char *format = (n == LUA_MININTEGER) /* corner case? */ - ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ - : LUA_INTEGER_FMT; /* else use default format */ - nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); - } - luaL_addsize(b, nb); - break; - } - case LUA_TNIL: case LUA_TBOOLEAN: { - luaL_tolstring(L, arg, NULL); - luaL_addvalue(b); - break; - } - default: { - luaL_argerror(L, arg, "value has no literal form"); - } - } +static void addliteral(lua_State* L, luaL_Buffer* b, int arg) +{ + switch (lua_type(L, arg)) + { + case LUA_TSTRING: + { + size_t len; + const char* s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: + { + char* buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) + { + /* float? */ + lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); + checkdp(buff, nb); /* ensure it uses a dot */ + } + else + { + /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char* format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: + case LUA_TBOOLEAN: + { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: + { + luaL_argerror(L, arg, "value has no literal form"); + } + } } -static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { - const char *p = strfrmt; - while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit(uchar(*p))) p++; /* skip width */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - if (*p == '.') { - p++; - if (isdigit(uchar(*p))) p++; /* skip precision */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - } - if (isdigit(uchar(*p))) - luaL_error(L, "invalid format (width or precision too long)"); - *(form++) = '%'; - memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); - form += (p - strfrmt) + 1; - *form = '\0'; - return p; +static const char* scanformat(lua_State* L, const char* strfrmt, char* form) +{ + const char* p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS) / sizeof(char)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') + { + p++; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + *(form++) = '%'; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; + *form = '\0'; + return p; } /* ** add length modifier into formats */ -static void addlenmod (char *form, const char *lenmod) { - size_t l = strlen(form); - size_t lm = strlen(lenmod); - char spec = form[l - 1]; - strcpy(form + l - 1, lenmod); - form[l + lm - 1] = spec; - form[l + lm] = '\0'; +static void addlenmod(char* form, const char* lenmod) +{ + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; } -static int str_format (lua_State *L) { - int top = lua_gettop(L); - int arg = 1; - size_t sfl; - const char *strfrmt = luaL_checklstring(L, arg, &sfl); - const char *strfrmt_end = strfrmt+sfl; - luaL_Buffer b; - luaL_buffinit(L, &b); - while (strfrmt < strfrmt_end) { - if (*strfrmt != L_ESC) - luaL_addchar(&b, *strfrmt++); - else if (*++strfrmt == L_ESC) - luaL_addchar(&b, *strfrmt++); /* %% */ - else { /* format item */ - char form[MAX_FORMAT]; /* to store the format ('%...') */ - char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ - int nb = 0; /* number of bytes in added item */ - if (++arg > top) - luaL_argerror(L, arg, "no value"); - strfrmt = scanformat(L, strfrmt, form); - switch (*strfrmt++) { - case 'c': { - nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); - break; - } - case 'd': case 'i': - case 'o': case 'u': case 'x': case 'X': { - lua_Integer n = luaL_checkinteger(L, arg); - addlenmod(form, LUA_INTEGER_FRMLEN); - nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); - break; - } - case 'a': case 'A': - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = lua_number2strx(L, buff, MAX_ITEM, form, - luaL_checknumber(L, arg)); - break; - case 'e': case 'E': case 'f': - case 'g': case 'G': { - lua_Number n = luaL_checknumber(L, arg); - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); - break; - } - case 'q': { - addliteral(L, &b, arg); - break; - } - case 's': { - size_t l; - const char *s = luaL_tolstring(L, arg, &l); - if (form[2] == '\0') /* no modifiers? */ - luaL_addvalue(&b); /* keep entire string */ - else { - luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); - if (!strchr(form, '.') && l >= 100) { - /* no precision and string is too long to be formatted */ - luaL_addvalue(&b); /* keep entire string */ - } - else { /* format the string into 'buff' */ - nb = l_sprintf(buff, MAX_ITEM, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - } - } - break; - } - default: { /* also treat cases 'pnLlh' */ - return luaL_error(L, "invalid option '%%%c' to 'format'", - *(strfrmt - 1)); - } - } - lua_assert(nb < MAX_ITEM); - luaL_addsize(&b, nb); - } - } - luaL_pushresult(&b); - return 1; +static int str_format(lua_State* L) +{ + int top = lua_gettop(L); + int arg = 1; + size_t sfl; + const char* strfrmt = luaL_checklstring(L, arg, &sfl); + const char* strfrmt_end = strfrmt + sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) + { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else + { + /* format item */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ + char* buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); + strfrmt = scanformat(L, strfrmt, form); + switch (*strfrmt++) + { + case 'c': + { + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); + break; + } + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + { + lua_Integer n = luaL_checkinteger(L, arg); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); + break; + } + case 'a': + case 'A': + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + { + lua_Number n = luaL_checknumber(L, arg); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); + break; + } + case 'q': + { + addliteral(L, &b, arg); + break; + } + case 's': + { + size_t l; + const char* s = luaL_tolstring(L, arg, &l); + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ + else + { + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) + { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else + { + /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } + } + break; + } + default: + { + /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid option '%%%c' to 'format'", + *(strfrmt - 1)); + } + } + lua_assert(nb < MAX_ITEM); + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; } /* }====================================================== */ @@ -1121,16 +1342,25 @@ static int str_format (lua_State *L) { /* dummy union to get native endianness */ -static const union { - int dummy; - char little; /* true iff machine is little endian */ +static const union +{ + int dummy; + char little; /* true iff machine is little endian */ } nativeendian = {1}; /* dummy structure to get native alignment requirements */ -struct cD { - char c; - union { double d; void *p; lua_Integer i; lua_Number n; } u; +struct cD +{ + char c; + + union + { + double d; + void* p; + lua_Integer i; + lua_Number n; + } u; }; #define MAXALIGN (offsetof(struct cD, u)) @@ -1139,37 +1369,48 @@ struct cD { /* ** Union for serializing floats */ -typedef union Ftypes { - float f; - double d; - lua_Number n; - char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +typedef union Ftypes +{ + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ } Ftypes; /* ** information to pack/unpack stuff */ -typedef struct Header { - lua_State *L; - int islittle; - int maxalign; +typedef struct Header +{ + lua_State* L; + int islittle; + int maxalign; } Header; /* ** options for pack/unpack */ -typedef enum KOption { - Kint, /* signed integers */ - Kuint, /* unsigned integers */ - Kfloat, /* floating-point numbers */ - Kchar, /* fixed-length strings */ - Kstring, /* strings with prefixed length */ - Kzstr, /* zero-terminated strings */ - Kpadding, /* padding */ - Kpaddalign, /* padding for alignment */ - Knop /* no-op (configuration or spaces) */ +typedef enum KOption +{ + Kint, + /* signed integers */ + Kuint, + /* unsigned integers */ + Kfloat, + /* floating-point numbers */ + Kchar, + /* fixed-length strings */ + Kstring, + /* strings with prefixed length */ + Kzstr, + /* zero-terminated strings */ + Kpadding, + /* padding */ + Kpaddalign, + /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ } KOption; @@ -1177,18 +1418,22 @@ typedef enum KOption { ** Read an integer numeral from string 'fmt' or return 'df' if ** there is no numeral */ -static int digit (int c) { return '0' <= c && c <= '9'; } +static int digit(int c) { return '0' <= c && c <= '9'; } -static int getnum (const char **fmt, int df) { - if (!digit(**fmt)) /* no number? */ - return df; /* return default value */ - else { - int a = 0; - do { - a = a*10 + (*((*fmt)++) - '0'); - } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); - return a; - } +static int getnum(const char** fmt, int df) +{ + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else + { + int a = 0; + do + { + a = a * 10 + (*((*fmt)++) - '0'); + } + while (digit(**fmt) && a <= ((int)MAXSIZE - 9) / 10); + return a; + } } @@ -1196,63 +1441,87 @@ static int getnum (const char **fmt, int df) { ** Read an integer numeral and raises an error if it is larger ** than the maximum size for integers. */ -static int getnumlimit (Header *h, const char **fmt, int df) { - int sz = getnum(fmt, df); - if (sz > MAXINTSIZE || sz <= 0) - luaL_error(h->L, "integral size (%d) out of limits [1,%d]", - sz, MAXINTSIZE); - return sz; +static int getnumlimit(Header* h, const char** fmt, int df) +{ + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; } /* ** Initialize Header */ -static void initheader (lua_State *L, Header *h) { - h->L = L; - h->islittle = nativeendian.little; - h->maxalign = 1; +static void initheader(lua_State* L, Header* h) +{ + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; } /* ** Read and classify next option. 'size' is filled with option's size. */ -static KOption getoption (Header *h, const char **fmt, int *size) { - int opt = *((*fmt)++); - *size = 0; /* default */ - switch (opt) { - case 'b': *size = sizeof(char); return Kint; - case 'B': *size = sizeof(char); return Kuint; - case 'h': *size = sizeof(short); return Kint; - case 'H': *size = sizeof(short); return Kuint; - case 'l': *size = sizeof(long); return Kint; - case 'L': *size = sizeof(long); return Kuint; - case 'j': *size = sizeof(lua_Integer); return Kint; - case 'J': *size = sizeof(lua_Integer); return Kuint; - case 'T': *size = sizeof(size_t); return Kuint; - case 'f': *size = sizeof(float); return Kfloat; - case 'd': *size = sizeof(double); return Kfloat; - case 'n': *size = sizeof(lua_Number); return Kfloat; - case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; - case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; - case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; - case 'c': - *size = getnum(fmt, -1); - if (*size == -1) - luaL_error(h->L, "missing size for format option 'c'"); - return Kchar; - case 'z': return Kzstr; - case 'x': *size = 1; return Kpadding; - case 'X': return Kpaddalign; - case ' ': break; - case '<': h->islittle = 1; break; - case '>': h->islittle = 0; break; - case '=': h->islittle = nativeendian.little; break; - case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; - default: luaL_error(h->L, "invalid format option '%c'", opt); - } - return Knop; +static KOption getoption(Header* h, const char** fmt, int* size) +{ + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) + { + case 'b': *size = sizeof(char); + return Kint; + case 'B': *size = sizeof(char); + return Kuint; + case 'h': *size = sizeof(short); + return Kint; + case 'H': *size = sizeof(short); + return Kuint; + case 'l': *size = sizeof(long); + return Kint; + case 'L': *size = sizeof(long); + return Kuint; + case 'j': *size = sizeof(lua_Integer); + return Kint; + case 'J': *size = sizeof(lua_Integer); + return Kuint; + case 'T': *size = sizeof(size_t); + return Kuint; + case 'f': *size = sizeof(float); + return Kfloat; + case 'd': *size = sizeof(double); + return Kfloat; + case 'n': *size = sizeof(lua_Number); + return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); + return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); + return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); + return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; + return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; + break; + case '>': h->islittle = 0; + break; + case '=': h->islittle = nativeendian.little; + break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); + break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; } @@ -1265,24 +1534,28 @@ static KOption getoption (Header *h, const char **fmt, int *size) { ** the maximum alignment ('maxalign'). Kchar option needs no alignment ** despite its size. */ -static KOption getdetails (Header *h, size_t totalsize, - const char **fmt, int *psize, int *ntoalign) { - KOption opt = getoption(h, fmt, psize); - int align = *psize; /* usually, alignment follows size */ - if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ - if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) - luaL_argerror(h->L, 1, "invalid next option for option 'X'"); - } - if (align <= 1 || opt == Kchar) /* need no alignment? */ - *ntoalign = 0; - else { - if (align > h->maxalign) /* enforce maximum alignment */ - align = h->maxalign; - if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ - luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); - *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); - } - return opt; +static KOption getdetails(Header* h, size_t totalsize, + const char** fmt, int* psize, int* ntoalign) +{ + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) + { + /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else + { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; } @@ -1292,20 +1565,24 @@ static KOption getdetails (Header *h, size_t totalsize, ** the size of a Lua integer, correcting the extra sign-extension ** bytes if necessary (by default they would be zeros). */ -static void packint (luaL_Buffer *b, lua_Unsigned n, - int islittle, int size, int neg) { - char *buff = luaL_prepbuffsize(b, size); - int i; - buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ - for (i = 1; i < size; i++) { - n >>= NB; - buff[islittle ? i : size - 1 - i] = (char)(n & MC); - } - if (neg && size > SZINT) { /* negative number need sign extension? */ - for (i = SZINT; i < size; i++) /* correct extra bytes */ - buff[islittle ? i : size - 1 - i] = (char)MC; - } - luaL_addsize(b, size); /* add result to buffer */ +static void packint(luaL_Buffer* b, lua_Unsigned n, + int islittle, int size, int neg) +{ + char* buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) + { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) + { + /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ } @@ -1313,129 +1590,153 @@ static void packint (luaL_Buffer *b, lua_Unsigned n, ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if ** given 'islittle' is different from native endianness. */ -static void copywithendian (volatile char *dest, volatile const char *src, - int size, int islittle) { - if (islittle == nativeendian.little) { - while (size-- != 0) - *(dest++) = *(src++); - } - else { - dest += size - 1; - while (size-- != 0) - *(dest--) = *(src++); - } +static void copywithendian(volatile char* dest, volatile const char* src, + int size, int islittle) +{ + if (islittle == nativeendian.little) + { + while (size-- != 0) + *(dest++) = *(src++); + } + else + { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } } -static int str_pack (lua_State *L) { - luaL_Buffer b; - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - int arg = 1; /* current argument to pack */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - lua_pushnil(L); /* mark to separate arguments from string buffer */ - luaL_buffinit(L, &b); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - totalsize += ntoalign + size; - while (ntoalign-- > 0) - luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ - arg++; - switch (opt) { - case Kint: { /* signed integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) { /* need overflow check? */ - lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); - luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); - } - packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); - break; - } - case Kuint: { /* unsigned integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) /* need overflow check? */ - luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), - arg, "unsigned overflow"); - packint(&b, (lua_Unsigned)n, h.islittle, size, 0); - break; - } - case Kfloat: { /* floating-point options */ - volatile Ftypes u; - char *buff = luaL_prepbuffsize(&b, size); - lua_Number n = luaL_checknumber(L, arg); /* get argument */ - if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ - else if (size == sizeof(u.d)) u.d = (double)n; - else u.n = n; - /* move 'u' to final result, correcting endianness if needed */ - copywithendian(buff, u.buff, size, h.islittle); - luaL_addsize(&b, size); - break; - } - case Kchar: { /* fixed-size string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, len <= (size_t)size, arg, - "string longer than given size"); - luaL_addlstring(&b, s, len); /* add string */ - while (len++ < (size_t)size) /* pad extra space */ - luaL_addchar(&b, LUAL_PACKPADBYTE); - break; - } - case Kstring: { /* strings with length count */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, size >= (int)sizeof(size_t) || - len < ((size_t)1 << (size * NB)), - arg, "string length does not fit in given size"); - packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ - luaL_addlstring(&b, s, len); - totalsize += len; - break; - } - case Kzstr: { /* zero-terminated string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); - luaL_addlstring(&b, s, len); - luaL_addchar(&b, '\0'); /* add zero at the end */ - totalsize += len + 1; - break; - } - case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ - case Kpaddalign: case Knop: - arg--; /* undo increment */ - break; - } - } - luaL_pushresult(&b); - return 1; +static int str_pack(lua_State* L) +{ + luaL_Buffer b; + Header h; + const char* fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') + { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) + { + case Kint: + { + /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) + { + /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: + { + /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: + { + /* floating-point options */ + volatile Ftypes u; + char* buff = luaL_prepbuffsize(&b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: + { + /* fixed-size string */ + size_t len; + const char* s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: + { + /* strings with length count */ + size_t len; + const char* s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: + { + /* zero-terminated string */ + size_t len; + const char* s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: + case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; } -static int str_packsize (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - size += ntoalign; /* total space used by option */ - luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, - "format result too large"); - totalsize += size; - switch (opt) { - case Kstring: /* strings with length count */ - case Kzstr: /* zero-terminated string */ - luaL_argerror(L, 1, "variable-length format"); - /* call never return, but to avoid warnings: *//* FALLTHROUGH */ - default: break; - } - } - lua_pushinteger(L, (lua_Integer)totalsize); - return 1; +static int str_packsize(lua_State* L) +{ + Header h; + const char* fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') + { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) + { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: */ /* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; } @@ -1447,138 +1748,158 @@ static int str_packsize (lua_State *L) { ** it must check the unread bytes to see whether they do not cause an ** overflow. */ -static lua_Integer unpackint (lua_State *L, const char *str, - int islittle, int size, int issigned) { - lua_Unsigned res = 0; - int i; - int limit = (size <= SZINT) ? size : SZINT; - for (i = limit - 1; i >= 0; i--) { - res <<= NB; - res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; - } - if (size < SZINT) { /* real size smaller than lua_Integer? */ - if (issigned) { /* needs sign extension? */ - lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); - res = ((res ^ mask) - mask); /* do sign extension */ - } - } - else if (size > SZINT) { /* must check unread bytes */ - int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; - for (i = limit; i < size; i++) { - if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) - luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); - } - } - return (lua_Integer)res; +static lua_Integer unpackint(lua_State* L, const char* str, + int islittle, int size, int issigned) +{ + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) + { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) + { + /* real size smaller than lua_Integer? */ + if (issigned) + { + /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size * NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) + { + /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) + { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; } -static int str_unpack (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); - size_t ld; - const char *data = luaL_checklstring(L, 2, &ld); - size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; - int n = 0; /* number of results */ - luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); - if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) - luaL_argerror(L, 2, "data string too short"); - pos += ntoalign; /* skip alignment */ - /* stack space for item + next position */ - luaL_checkstack(L, 2, "too many results"); - n++; - switch (opt) { - case Kint: - case Kuint: { - lua_Integer res = unpackint(L, data + pos, h.islittle, size, - (opt == Kint)); - lua_pushinteger(L, res); - break; - } - case Kfloat: { - volatile Ftypes u; - lua_Number num; - copywithendian(u.buff, data + pos, size, h.islittle); - if (size == sizeof(u.f)) num = (lua_Number)u.f; - else if (size == sizeof(u.d)) num = (lua_Number)u.d; - else num = u.n; - lua_pushnumber(L, num); - break; - } - case Kchar: { - lua_pushlstring(L, data + pos, size); - break; - } - case Kstring: { - size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); - luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); - lua_pushlstring(L, data + pos + size, len); - pos += len; /* skip string */ - break; - } - case Kzstr: { - size_t len = (int)strlen(data + pos); - lua_pushlstring(L, data + pos, len); - pos += len + 1; /* skip string plus final '\0' */ - break; - } - case Kpaddalign: case Kpadding: case Knop: - n--; /* undo increment */ - break; - } - pos += size; - } - lua_pushinteger(L, pos + 1); /* next position */ - return n + 1; +static int str_unpack(lua_State* L) +{ + Header h; + const char* fmt = luaL_checkstring(L, 1); + size_t ld; + const char* data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') + { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) + { + case Kint: + case Kuint: + { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: + { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: + { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: + { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: + { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: + case Kpadding: + case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; } /* }====================================================== */ static const luaL_Reg strlib[] = { - {"byte", str_byte}, - {"char", str_char}, - {"dump", str_dump}, - {"find", str_find}, - {"format", str_format}, - {"gmatch", gmatch}, - {"gsub", str_gsub}, - {"len", str_len}, - {"lower", str_lower}, - {"match", str_match}, - {"rep", str_rep}, - {"reverse", str_reverse}, - {"sub", str_sub}, - {"upper", str_upper}, - {"pack", str_pack}, - {"packsize", str_packsize}, - {"unpack", str_unpack}, - {NULL, NULL} + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, + {NULL, NULL} }; -static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* table to be metatable for strings */ - lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); /* copy table */ - lua_setmetatable(L, -2); /* set table as metatable for strings */ - lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* get string library */ - lua_setfield(L, -2, "__index"); /* metatable.__index = string */ - lua_pop(L, 1); /* pop metatable */ +static void createmetatable(lua_State* L) +{ + lua_createtable(L, 0, 1); /* table to be metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ } /* ** Open string library */ -LUAMOD_API int luaopen_string (lua_State *L) { - luaL_newlib(L, strlib); - createmetatable(L); - return 1; +LUAMOD_API int luaopen_string(lua_State* L) +{ + luaL_newlib(L, strlib); + createmetatable(L); + return 1; } - diff --git a/Lua/ltable.c b/Lua/ltable.c index d080189..1ae8598 100644 --- a/Lua/ltable.c +++ b/Lua/ltable.c @@ -75,8 +75,8 @@ #define dummynode (&dummynode_) static const Node dummynode_ = { - {NILCONSTANT}, /* value */ - {{NILCONSTANT, 0}} /* key */ + {NILCONSTANT}, /* value */ + {{NILCONSTANT, 0}} /* key */ }; @@ -94,18 +94,23 @@ static const Node dummynode_ = { ** INT_MIN. */ #if !defined(l_hashfloat) -static int l_hashfloat (lua_Number n) { - int i; - lua_Integer ni; - n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); - if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ - lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); - return 0; - } - else { /* normal case */ - unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); - return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); - } +static int l_hashfloat(lua_Number n) +{ + int i; + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) + { + /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else + { + /* normal case */ + unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); + return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); + } } #endif @@ -114,26 +119,28 @@ static int l_hashfloat (lua_Number n) { ** returns the 'main' position of an element in a table (that is, the index ** of its hash value) */ -static Node *mainposition (const Table *t, const TValue *key) { - switch (ttype(key)) { - case LUA_TNUMINT: - return hashint(t, ivalue(key)); - case LUA_TNUMFLT: - return hashmod(t, l_hashfloat(fltvalue(key))); - case LUA_TSHRSTR: - return hashstr(t, tsvalue(key)); - case LUA_TLNGSTR: - return hashpow2(t, luaS_hashlongstr(tsvalue(key))); - case LUA_TBOOLEAN: - return hashboolean(t, bvalue(key)); - case LUA_TLIGHTUSERDATA: - return hashpointer(t, pvalue(key)); - case LUA_TLCF: - return hashpointer(t, fvalue(key)); - default: - lua_assert(!ttisdeadkey(key)); - return hashpointer(t, gcvalue(key)); - } +static Node* mainposition(const Table* t, const TValue* key) +{ + switch (ttype(key)) + { + case LUA_TNUMINT: + return hashint(t, ivalue(key)); + case LUA_TNUMFLT: + return hashmod(t, l_hashfloat(fltvalue(key))); + case LUA_TSHRSTR: + return hashstr(t, tsvalue(key)); + case LUA_TLNGSTR: + return hashpow2(t, luaS_hashlongstr(tsvalue(key))); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + case LUA_TLCF: + return hashpointer(t, fvalue(key)); + default: + lua_assert(!ttisdeadkey(key)); + return hashpointer(t, gcvalue(key)); + } } @@ -141,13 +148,15 @@ static Node *mainposition (const Table *t, const TValue *key) { ** returns the index for 'key' if 'key' is an appropriate key to live in ** the array part of the table, 0 otherwise. */ -static unsigned int arrayindex (const TValue *key) { - if (ttisinteger(key)) { - lua_Integer k = ivalue(key); - if (0 < k && (lua_Unsigned)k <= MAXASIZE) - return cast(unsigned int, k); /* 'key' is an appropriate array index */ - } - return 0; /* 'key' did not match some condition */ +static unsigned int arrayindex(const TValue* key) +{ + if (ttisinteger(key)) + { + lua_Integer k = ivalue(key); + if (0 < k && (lua_Unsigned)k <= MAXASIZE) + return cast(unsigned int, k); /* 'key' is an appropriate array index */ + } + return 0; /* 'key' did not match some condition */ } @@ -156,50 +165,64 @@ static unsigned int arrayindex (const TValue *key) { ** elements in the array part, then elements in the hash part. The ** beginning of a traversal is signaled by 0. */ -static unsigned int findindex (lua_State *L, Table *t, StkId key) { - unsigned int i; - if (ttisnil(key)) return 0; /* first iteration */ - i = arrayindex(key); - if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ - return i; /* yes; that's the index */ - else { - int nx; - Node *n = mainposition(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in 'next' */ - if (luaV_rawequalobj(gkey(n), key) || - (ttisdeadkey(gkey(n)) && iscollectable(key) && - deadvalue(gkey(n)) == gcvalue(key))) { - i = cast_int(n - gnode(t, 0)); /* key index in hash table */ - /* hash elements are numbered after array ones */ - return (i + 1) + t->sizearray; - } - nx = gnext(n); - if (nx == 0) - luaG_runerror(L, "invalid key to 'next'"); /* key not found */ - else n += nx; - } - } +static unsigned int findindex(lua_State* L, Table* t, StkId key) +{ + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ + i = arrayindex(key); + if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ + else + { + int nx; + Node* n = mainposition(t, key); + for (;;) + { + /* check whether 'key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in 'next' */ + if (luaV_rawequalobj(gkey(n), key) || + (ttisdeadkey(gkey(n)) && iscollectable(key) && + deadvalue(gkey(n)) == gcvalue(key))) + { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return (i + 1) + t->sizearray; + } + nx = gnext(n); + if (nx == 0) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + else n += nx; + } + } } -int luaH_next (lua_State *L, Table *t, StkId key) { - unsigned int i = findindex(L, t, key); /* find original element */ - for (; i < t->sizearray; i++) { /* try first array part */ - if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setivalue(key, i + 1); - setobj2s(L, key+1, &t->array[i]); - return 1; - } - } - for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(L, key, gkey(gnode(t, i))); - setobj2s(L, key+1, gval(gnode(t, i))); - return 1; - } - } - return 0; /* no more elements */ +int luaH_next(lua_State* L, Table* t, StkId key) +{ + unsigned int i = findindex(L, t, key); /* find original element */ + for (; i < t->sizearray; i++) + { + /* try first array part */ + if (!ttisnil(&t->array[i])) + { + /* a non-nil value? */ + setivalue(key, i + 1); + setobj2s(L, key+1, &t->array[i]); + return 1; + } + } + for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) + { + /* hash part */ + if (!ttisnil(gval(gnode(t, i)))) + { + /* a non-nil value? */ + setobj2s(L, key, gkey(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ } @@ -216,36 +239,44 @@ int luaH_next (lua_State *L, Table *t, StkId key) { ** integer keys in the table and leaves with the number of keys that ** will go to the array part; return the optimal size. */ -static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { - int i; - unsigned int twotoi; /* 2^i (candidate for optimal size) */ - unsigned int a = 0; /* number of elements smaller than 2^i */ - unsigned int na = 0; /* number of elements to go to array part */ - unsigned int optimal = 0; /* optimal size for array part */ - /* loop while keys can fill more than half of total size */ - for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { - if (nums[i] > 0) { - a += nums[i]; - if (a > twotoi/2) { /* more than half elements present? */ - optimal = twotoi; /* optimal size (till now) */ - na = a; /* all elements up to 'optimal' will go to array part */ - } - } - } - lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); - *pna = na; - return optimal; +static unsigned int computesizes(unsigned int nums[], unsigned int* pna) +{ + int i; + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) + { + if (nums[i] > 0) + { + a += nums[i]; + if (a > twotoi / 2) + { + /* more than half elements present? */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ + } + } + } + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; } -static int countint (const TValue *key, unsigned int *nums) { - unsigned int k = arrayindex(key); - if (k != 0) { /* is 'key' an appropriate array index? */ - nums[luaO_ceillog2(k)]++; /* count as such */ - return 1; - } - else - return 0; +static int countint(const TValue* key, unsigned int* nums) +{ + unsigned int k = arrayindex(key); + if (k != 0) + { + /* is 'key' an appropriate array index? */ + nums[luaO_ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; } @@ -254,184 +285,208 @@ static int countint (const TValue *key, unsigned int *nums) { ** number of keys that will go into corresponding slice and return ** total number of non-nil keys. */ -static unsigned int numusearray (const Table *t, unsigned int *nums) { - int lg; - unsigned int ttlg; /* 2^lg */ - unsigned int ause = 0; /* summation of 'nums' */ - unsigned int i = 1; /* count to traverse all array keys */ - /* traverse each slice */ - for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { - unsigned int lc = 0; /* counter */ - unsigned int lim = ttlg; - if (lim > t->sizearray) { - lim = t->sizearray; /* adjust upper limit */ - if (i > lim) - break; /* no more elements to count */ - } - /* count elements in range (2^(lg - 1), 2^lg] */ - for (; i <= lim; i++) { - if (!ttisnil(&t->array[i-1])) - lc++; - } - nums[lg] += lc; - ause += lc; - } - return ause; +static unsigned int numusearray(const Table* t, unsigned int* nums) +{ + int lg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) + { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; + if (lim > t->sizearray) + { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg - 1), 2^lg] */ + for (; i <= lim; i++) + { + if (!ttisnil(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; } -static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { - int totaluse = 0; /* total number of elements */ - int ause = 0; /* elements added to 'nums' (can go to array part) */ - int i = sizenode(t); - while (i--) { - Node *n = &t->node[i]; - if (!ttisnil(gval(n))) { - ause += countint(gkey(n), nums); - totaluse++; - } - } - *pna += ause; - return totaluse; +static int numusehash(const Table* t, unsigned int* nums, unsigned int* pna) +{ + int totaluse = 0; /* total number of elements */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ + int i = sizenode(t); + while (i--) + { + Node* n = &t->node[i]; + if (!ttisnil(gval(n))) + { + ause += countint(gkey(n), nums); + totaluse++; + } + } + *pna += ause; + return totaluse; } -static void setarrayvector (lua_State *L, Table *t, unsigned int size) { - unsigned int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TValue); - for (i=t->sizearray; iarray[i]); - t->sizearray = size; +static void setarrayvector(lua_State* L, Table* t, unsigned int size) +{ + unsigned int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i = t->sizearray; i < size; i++) + setnilvalue(&t->array[i]); + t->sizearray = size; } -static void setnodevector (lua_State *L, Table *t, unsigned int size) { - if (size == 0) { /* no elements to hash part? */ - t->node = cast(Node *, dummynode); /* use common 'dummynode' */ - t->lsizenode = 0; - t->lastfree = NULL; /* signal that it is using dummy node */ - } - else { - int i; - int lsize = luaO_ceillog2(size); - if (lsize > MAXHBITS) - luaG_runerror(L, "table overflow"); - size = twoto(lsize); - t->node = luaM_newvector(L, size, Node); - for (i = 0; i < (int)size; i++) { - Node *n = gnode(t, i); - gnext(n) = 0; - setnilvalue(wgkey(n)); - setnilvalue(gval(n)); - } - t->lsizenode = cast_byte(lsize); - t->lastfree = gnode(t, size); /* all positions are free */ - } +static void setnodevector(lua_State* L, Table* t, unsigned int size) +{ + if (size == 0) + { + /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ + t->lsizenode = 0; + t->lastfree = NULL; /* signal that it is using dummy node */ + } + else + { + int i; + int lsize = luaO_ceillog2(size); + if (lsize > MAXHBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i = 0; i < (int)size; i++) + { + Node* n = gnode(t, i); + gnext(n) = 0; + setnilvalue(wgkey(n)); + setnilvalue(gval(n)); + } + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ + } } -void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize) { - unsigned int i; - int j; - unsigned int oldasize = t->sizearray; - int oldhsize = allocsizenode(t); - Node *nold = t->node; /* save old hash ... */ - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ - setnodevector(L, t, nhsize); - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; iarray[i])) - luaH_setint(L, t, i + 1, &t->array[i]); - } - /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TValue); - } - /* re-insert elements from hash part */ - for (j = oldhsize - 1; j >= 0; j--) { - Node *old = nold + j; - if (!ttisnil(gval(old))) { - /* doesn't need barrier/invalidate cache, as entry was - already present in the table */ - setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); - } - } - if (oldhsize > 0) /* not the dummy node? */ - luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ +void luaH_resize(lua_State* L, Table* t, unsigned int nasize, + unsigned int nhsize) +{ + unsigned int i; + int j; + unsigned int oldasize = t->sizearray; + int oldhsize = allocsizenode(t); + Node* nold = t->node; /* save old hash ... */ + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + setnodevector(L, t, nhsize); + if (nasize < oldasize) + { + /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i = nasize; i < oldasize; i++) + { + if (!ttisnil(&t->array[i])) + luaH_setint(L, t, i + 1, &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + } + /* re-insert elements from hash part */ + for (j = oldhsize - 1; j >= 0; j--) + { + Node* old = nold + j; + if (!ttisnil(gval(old))) + { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ + setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); + } + } + if (oldhsize > 0) /* not the dummy node? */ + luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ } -void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { - int nsize = allocsizenode(t); - luaH_resize(L, t, nasize, nsize); +void luaH_resizearray(lua_State* L, Table* t, unsigned int nasize) +{ + int nsize = allocsizenode(t); + luaH_resize(L, t, nasize, nsize); } /* ** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i */ -static void rehash (lua_State *L, Table *t, const TValue *ek) { - unsigned int asize; /* optimal size for array part */ - unsigned int na; /* number of keys in the array part */ - unsigned int nums[MAXABITS + 1]; - int i; - int totaluse; - for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ - na = numusearray(t, nums); /* count keys in array part */ - totaluse = na; /* all those keys are integer keys */ - totaluse += numusehash(t, nums, &na); /* count keys in hash part */ - /* count extra key */ - na += countint(ek, nums); - totaluse++; - /* compute new size for array part */ - asize = computesizes(nums, &na); - /* resize the table to new computed sizes */ - luaH_resize(L, t, asize, totaluse - na); +static void rehash(lua_State* L, Table* t, const TValue* ek) +{ + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; + int i; + int totaluse; + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ + /* count extra key */ + na += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + asize = computesizes(nums, &na); + /* resize the table to new computed sizes */ + luaH_resize(L, t, asize, totaluse - na); } - /* ** }============================================================= */ -Table *luaH_new (lua_State *L) { - GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); - Table *t = gco2t(o); - t->metatable = NULL; - t->flags = cast_byte(~0); - t->array = NULL; - t->sizearray = 0; - setnodevector(L, t, 0); - return t; +Table* luaH_new(lua_State* L) +{ + GCObject* o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); + Table* t = gco2t(o); + t->metatable = NULL; + t->flags = cast_byte(~0); + t->array = NULL; + t->sizearray = 0; + setnodevector(L, t, 0); + return t; } -void luaH_free (lua_State *L, Table *t) { - if (!isdummy(t)) - luaM_freearray(L, t->node, cast(size_t, sizenode(t))); - luaM_freearray(L, t->array, t->sizearray); - luaM_free(L, t); +void luaH_free(lua_State* L, Table* t) +{ + if (!isdummy(t)) + luaM_freearray(L, t->node, cast(size_t, sizenode(t))); + luaM_freearray(L, t->array, t->sizearray); + luaM_free(L, t); } -static Node *getfreepos (Table *t) { - if (!isdummy(t)) { - while (t->lastfree > t->node) { - t->lastfree--; - if (ttisnil(gkey(t->lastfree))) - return t->lastfree; - } - } - return NULL; /* could not find a free place */ +static Node* getfreepos(Table* t) +{ + if (!isdummy(t)) + { + while (t->lastfree > t->node) + { + t->lastfree--; + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; + } + } + return NULL; /* could not find a free place */ } - /* ** inserts a new key into a hash table; first, check whether key's main ** position is free. If not, check whether colliding node is in its main @@ -439,98 +494,121 @@ static Node *getfreepos (Table *t) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { - Node *mp; - TValue aux; - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisfloat(key)) { - lua_Integer k; - if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */ - setivalue(&aux, k); - key = &aux; /* insert it as an integer */ - } - else if (luai_numisnan(fltvalue(key))) - luaG_runerror(L, "table index is NaN"); - } - mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ - Node *othern; - Node *f = getfreepos(t); /* get a free place */ - if (f == NULL) { /* cannot find a free place? */ - rehash(L, t, key); /* grow table */ - /* whatever called 'newkey' takes care of TM cache */ - return luaH_set(L, t, key); /* insert key into grown table */ - } - lua_assert(!isdummy(t)); - othern = mainposition(t, gkey(mp)); - if (othern != mp) { /* is colliding node out of its main position? */ - /* yes; move colliding node into free position */ - while (othern + gnext(othern) != mp) /* find previous */ - othern += gnext(othern); - gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ - *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - if (gnext(mp) != 0) { - gnext(f) += cast_int(mp - f); /* correct 'next' */ - gnext(mp) = 0; /* now 'mp' is free */ - } - setnilvalue(gval(mp)); - } - else { /* colliding node is in its own main position */ - /* new node will go into free position */ - if (gnext(mp) != 0) - gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ - else lua_assert(gnext(f) == 0); - gnext(mp) = cast_int(f - mp); - mp = f; - } - } - setnodekey(L, &mp->i_key, key); - luaC_barrierback(L, t, key); - lua_assert(ttisnil(gval(mp))); - return gval(mp); +TValue* luaH_newkey(lua_State* L, Table* t, const TValue* key) +{ + Node* mp; + TValue aux; + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisfloat(key)) + { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) + { + /* does index fit in an integer? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (luai_numisnan(fltvalue(key))) + luaG_runerror(L, "table index is NaN"); + } + mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || isdummy(t)) + { + /* main position is taken? */ + Node* othern; + Node* f = getfreepos(t); /* get a free place */ + if (f == NULL) + { + /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + /* whatever called 'newkey' takes care of TM cache */ + return luaH_set(L, t, key); /* insert key into grown table */ + } + lua_assert(!isdummy(t)); + othern = mainposition(t, gkey(mp)); + if (othern != mp) + { + /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) + { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } + setnilvalue(gval(mp)); + } + else + { + /* colliding node is in its own main position */ + /* new node will go into free position */ + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else + lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; + } + } + setnodekey(L, &mp->i_key, key); + luaC_barrierback(L, t, key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); } /* ** search function for integers */ -const TValue *luaH_getint (Table *t, lua_Integer key) { - /* (1 <= key && key <= t->sizearray) */ - if (l_castS2U(key) - 1 < t->sizearray) - return &t->array[key - 1]; - else { - Node *n = hashint(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) break; - n += nx; - } - } - return luaO_nilobject; - } +const TValue* luaH_getint(Table* t, lua_Integer key) +{ + /* (1 <= key && key <= t->sizearray) */ + if (l_castS2U(key) - 1 < t->sizearray) + return &t->array[key - 1]; + else + { + Node* n = hashint(t, key); + for (;;) + { + /* check whether 'key' is somewhere in the chain */ + if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) + return gval(n); /* that's it */ + else + { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } + return luaO_nilobject; + } } /* ** search function for short strings */ -const TValue *luaH_getshortstr (Table *t, TString *key) { - Node *n = hashstr(t, key); - lua_assert(key->tt == LUA_TSHRSTR); - for (;;) { /* check whether 'key' is somewhere in the chain */ - const TValue *k = gkey(n); - if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) - return luaO_nilobject; /* not found */ - n += nx; - } - } +const TValue* luaH_getshortstr(Table* t, TString* key) +{ + Node* n = hashstr(t, key); + lua_assert(key->tt == LUA_TSHRSTR); + for (;;) + { + /* check whether 'key' is somewhere in the chain */ + const TValue* k = gkey(n); + if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) + return gval(n); /* that's it */ + else + { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } } @@ -538,49 +616,59 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { ** "Generic" get version. (Not that generic: not valid for integers, ** which may be in array part, nor for floats with integral values.) */ -static const TValue *getgeneric (Table *t, const TValue *key) { - Node *n = mainposition(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - if (luaV_rawequalobj(gkey(n), key)) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) - return luaO_nilobject; /* not found */ - n += nx; - } - } +static const TValue* getgeneric(Table* t, const TValue* key) +{ + Node* n = mainposition(t, key); + for (;;) + { + /* check whether 'key' is somewhere in the chain */ + if (luaV_rawequalobj(gkey(n), key)) + return gval(n); /* that's it */ + else + { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } } -const TValue *luaH_getstr (Table *t, TString *key) { - if (key->tt == LUA_TSHRSTR) - return luaH_getshortstr(t, key); - else { /* for long strings, use generic case */ - TValue ko; - setsvalue(cast(lua_State *, NULL), &ko, key); - return getgeneric(t, &ko); - } +const TValue* luaH_getstr(Table* t, TString* key) +{ + if (key->tt == LUA_TSHRSTR) + return luaH_getshortstr(t, key); + else + { + /* for long strings, use generic case */ + TValue ko; + setsvalue(cast(lua_State *, NULL), &ko, key); + return getgeneric(t, &ko); + } } /* ** main search function */ -const TValue *luaH_get (Table *t, const TValue *key) { - switch (ttype(key)) { - case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); - case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); - case LUA_TNIL: return luaO_nilobject; - case LUA_TNUMFLT: { - lua_Integer k; - if (luaV_tointeger(key, &k, 0)) /* index is int? */ - return luaH_getint(t, k); /* use specialized version */ - /* else... */ - } /* FALLTHROUGH */ - default: - return getgeneric(t, key); - } +const TValue* luaH_get(Table* t, const TValue* key) +{ + switch (ttype(key)) + { + case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); + case LUA_TNIL: return luaO_nilobject; + case LUA_TNUMFLT: + { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) /* index is int? */ + return luaH_getint(t, k); /* use specialized version */ + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key); + } } @@ -588,49 +676,57 @@ const TValue *luaH_get (Table *t, const TValue *key) { ** beware: when using this function you probably need to check a GC ** barrier and invalidate the TM cache. */ -TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { - const TValue *p = luaH_get(t, key); - if (p != luaO_nilobject) - return cast(TValue *, p); - else return luaH_newkey(L, t, key); +TValue* luaH_set(lua_State* L, Table* t, const TValue* key) +{ + const TValue* p = luaH_get(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else return luaH_newkey(L, t, key); } -void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { - const TValue *p = luaH_getint(t, key); - TValue *cell; - if (p != luaO_nilobject) - cell = cast(TValue *, p); - else { - TValue k; - setivalue(&k, key); - cell = luaH_newkey(L, t, &k); - } - setobj2t(L, cell, value); +void luaH_setint(lua_State* L, Table* t, lua_Integer key, TValue* value) +{ + const TValue* p = luaH_getint(t, key); + TValue* cell; + if (p != luaO_nilobject) + cell = cast(TValue *, p); + else + { + TValue k; + setivalue(&k, key); + cell = luaH_newkey(L, t, &k); + } + setobj2t(L, cell, value); } -static int unbound_search (Table *t, unsigned int j) { - unsigned int i = j; /* i is zero or a present index */ - j++; - /* find 'i' and 'j' such that i is present and j is not */ - while (!ttisnil(luaH_getint(t, j))) { - i = j; - if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ - i = 1; - while (!ttisnil(luaH_getint(t, i))) i++; - return i - 1; - } - j *= 2; - } - /* now do a binary search between them */ - while (j - i > 1) { - unsigned int m = (i+j)/2; - if (ttisnil(luaH_getint(t, m))) j = m; - else i = m; - } - return i; +static int unbound_search(Table* t, unsigned int j) +{ + unsigned int i = j; /* i is zero or a present index */ + j++; + /* find 'i' and 'j' such that i is present and j is not */ + while (!ttisnil(luaH_getint(t, j))) + { + i = j; + if (j > cast(unsigned int, MAX_INT) / 2) + { + /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getint(t, i))) i++; + return i - 1; + } + j *= 2; + } + /* now do a binary search between them */ + while (j - i > 1) + { + unsigned int m = (i + j) / 2; + if (ttisnil(luaH_getint(t, m))) j = m; + else i = m; + } + return i; } @@ -638,26 +734,28 @@ static int unbound_search (Table *t, unsigned int j) { ** Try to find a boundary in table 't'. A 'boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ -int luaH_getn (Table *t) { - unsigned int j = t->sizearray; - if (j > 0 && ttisnil(&t->array[j - 1])) { - /* there is a boundary in the array part: (binary) search for it */ - unsigned int i = 0; - while (j - i > 1) { - unsigned int m = (i+j)/2; - if (ttisnil(&t->array[m - 1])) j = m; - else i = m; - } - return i; - } - /* else must find a boundary in hash part */ - else if (isdummy(t)) /* hash part is empty? */ - return j; /* that is easy... */ - else return unbound_search(t, j); +int luaH_getn(Table* t) +{ + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) + { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) + { + unsigned int m = (i + j) / 2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (isdummy(t)) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); } - #if defined(LUA_DEBUG) Node *luaH_mainposition (const Table *t, const TValue *key) { diff --git a/Lua/ltable.h b/Lua/ltable.h index 6da9024..b879c03 100644 --- a/Lua/ltable.h +++ b/Lua/ltable.h @@ -40,21 +40,21 @@ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) -LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); -LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, - TValue *value); -LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); -LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); -LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); -LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); -LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); -LUAI_FUNC Table *luaH_new (lua_State *L); -LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize); -LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); -LUAI_FUNC void luaH_free (lua_State *L, Table *t); -LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); -LUAI_FUNC int luaH_getn (Table *t); +LUAI_FUNC const TValue* luaH_getint(Table* t, lua_Integer key); +LUAI_FUNC void luaH_setint(lua_State* L, Table* t, lua_Integer key, + TValue* value); +LUAI_FUNC const TValue* luaH_getshortstr(Table* t, TString* key); +LUAI_FUNC const TValue* luaH_getstr(Table* t, TString* key); +LUAI_FUNC const TValue* luaH_get(Table* t, const TValue* key); +LUAI_FUNC TValue* luaH_newkey(lua_State* L, Table* t, const TValue* key); +LUAI_FUNC TValue* luaH_set(lua_State* L, Table* t, const TValue* key); +LUAI_FUNC Table* luaH_new(lua_State* L); +LUAI_FUNC void luaH_resize(lua_State* L, Table* t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray(lua_State* L, Table* t, unsigned int nasize); +LUAI_FUNC void luaH_free(lua_State* L, Table* t); +LUAI_FUNC int luaH_next(lua_State* L, Table* t, StkId key); +LUAI_FUNC int luaH_getn(Table* t); #if defined(LUA_DEBUG) diff --git a/Lua/ltablib.c b/Lua/ltablib.c index 98b2f87..7834a89 100644 --- a/Lua/ltablib.c +++ b/Lua/ltablib.c @@ -33,9 +33,10 @@ #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) -static int checkfield (lua_State *L, const char *key, int n) { - lua_pushstring(L, key); - return (lua_rawget(L, -n) != LUA_TNIL); +static int checkfield(lua_State* L, const char* key, int n) +{ + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); } @@ -43,18 +44,22 @@ static int checkfield (lua_State *L, const char *key, int n) { ** Check that 'arg' either is a table or can behave like one (that is, ** has a metatable with the required metamethods) */ -static void checktab (lua_State *L, int arg, int what) { - if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ - int n = 1; /* number of elements to pop */ - if (lua_getmetatable(L, arg) && /* must have metatable */ - (!(what & TAB_R) || checkfield(L, "__index", ++n)) && - (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && - (!(what & TAB_L) || checkfield(L, "__len", ++n))) { - lua_pop(L, n); /* pop metatable and tested metamethods */ - } - else - luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ - } +static void checktab(lua_State* L, int arg, int what) +{ + if (lua_type(L, arg) != LUA_TTABLE) + { + /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) + { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } } @@ -76,46 +81,56 @@ static int maxn (lua_State *L) { #endif -static int tinsert (lua_State *L) { - lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ - lua_Integer pos; /* where to insert new element */ - switch (lua_gettop(L)) { - case 2: { /* called with only 2 arguments */ - pos = e; /* insert new element at the end */ - break; - } - case 3: { - lua_Integer i; - pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ - luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); - for (i = e; i > pos; i--) { /* move up elements */ - lua_geti(L, 1, i - 1); - lua_seti(L, 1, i); /* t[i] = t[i - 1] */ - } - break; - } - default: { - return luaL_error(L, "wrong number of arguments to 'insert'"); - } - } - lua_seti(L, 1, pos); /* t[pos] = v */ - return 0; +static int tinsert(lua_State* L) +{ + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ + lua_Integer pos; /* where to insert new element */ + switch (lua_gettop(L)) + { + case 2: + { + /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: + { + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); + for (i = e; i > pos; i--) + { + /* move up elements */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + } + break; + } + default: + { + return luaL_error(L, "wrong number of arguments to 'insert'"); + } + } + lua_seti(L, 1, pos); /* t[pos] = v */ + return 0; } -static int tremove (lua_State *L) { - lua_Integer size = aux_getn(L, 1, TAB_RW); - lua_Integer pos = luaL_optinteger(L, 2, size); - if (pos != size) /* validate 'pos' if given */ - luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - lua_geti(L, 1, pos); /* result = t[pos] */ - for ( ; pos < size; pos++) { - lua_geti(L, 1, pos + 1); - lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ - } - lua_pushnil(L); - lua_seti(L, 1, pos); /* t[pos] = nil */ - return 1; +static int tremove(lua_State* L) +{ + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); + lua_geti(L, 1, pos); /* result = t[pos] */ + for (; pos < size; pos++) + { + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + } + lua_pushnil(L); + lua_seti(L, 1, pos); /* t[pos] = nil */ + return 1; } @@ -125,63 +140,73 @@ static int tremove (lua_State *L) { ** "possible" means destination after original range, or smaller ** than origin, or copying to another table. */ -static int tmove (lua_State *L) { - lua_Integer f = luaL_checkinteger(L, 2); - lua_Integer e = luaL_checkinteger(L, 3); - lua_Integer t = luaL_checkinteger(L, 4); - int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ - checktab(L, 1, TAB_R); - checktab(L, tt, TAB_W); - if (e >= f) { /* otherwise, nothing to move */ - lua_Integer n, i; - luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, - "too many elements to move"); - n = e - f + 1; /* number of elements to move */ - luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, - "destination wrap around"); - if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { - for (i = 0; i < n; i++) { - lua_geti(L, 1, f + i); - lua_seti(L, tt, t + i); - } - } - else { - for (i = n - 1; i >= 0; i--) { - lua_geti(L, 1, f + i); - lua_seti(L, tt, t + i); - } - } - } - lua_pushvalue(L, tt); /* return destination table */ - return 1; +static int tmove(lua_State* L) +{ + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) + { + /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) + { + for (i = 0; i < n; i++) + { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else + { + for (i = n - 1; i >= 0; i--) + { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; } -static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { - lua_geti(L, 1, i); - if (!lua_isstring(L, -1)) - luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", - luaL_typename(L, -1), i); - luaL_addvalue(b); +static void addfield(lua_State* L, luaL_Buffer* b, lua_Integer i) +{ + lua_geti(L, 1, i); + if (!lua_isstring(L, -1)) + luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", + luaL_typename(L, -1), i); + luaL_addvalue(b); } -static int tconcat (lua_State *L) { - luaL_Buffer b; - lua_Integer last = aux_getn(L, 1, TAB_R); - size_t lsep; - const char *sep = luaL_optlstring(L, 2, "", &lsep); - lua_Integer i = luaL_optinteger(L, 3, 1); - last = luaL_optinteger(L, 4, last); - luaL_buffinit(L, &b); - for (; i < last; i++) { - addfield(L, &b, i); - luaL_addlstring(&b, sep, lsep); - } - if (i == last) /* add last value (if interval was not empty) */ - addfield(L, &b, i); - luaL_pushresult(&b); - return 1; +static int tconcat(lua_State* L) +{ + luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); + size_t lsep; + const char* sep = luaL_optlstring(L, 2, "", &lsep); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); + luaL_buffinit(L, &b); + for (; i < last; i++) + { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); + } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); + luaL_pushresult(&b); + return 1; } @@ -191,38 +216,41 @@ static int tconcat (lua_State *L) { ** ======================================================= */ -static int pack (lua_State *L) { - int i; - int n = lua_gettop(L); /* number of elements to pack */ - lua_createtable(L, n, 1); /* create result table */ - lua_insert(L, 1); /* put it at index 1 */ - for (i = n; i >= 1; i--) /* assign elements */ - lua_seti(L, 1, i); - lua_pushinteger(L, n); - lua_setfield(L, 1, "n"); /* t.n = number of elements */ - return 1; /* return table */ +static int pack(lua_State* L) +{ + int i; + int n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, "n"); /* t.n = number of elements */ + return 1; /* return table */ } -static int unpack (lua_State *L) { - lua_Unsigned n; - lua_Integer i = luaL_optinteger(L, 2, 1); - lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); - if (i > e) return 0; /* empty range */ - n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ - if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) - return luaL_error(L, "too many results to unpack"); - for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ - lua_geti(L, 1, i); - } - lua_geti(L, 1, e); /* push last element */ - return (int)n; +static int unpack(lua_State* L) +{ + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + if (i > e) return 0; /* empty range */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) + return luaL_error(L, "too many results to unpack"); + for (; i < e; i++) + { + /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; } /* }====================================================== */ - /* ** {====================================================== ** Quicksort @@ -255,16 +283,17 @@ typedef unsigned int IdxT; ** anything without risking overflows. A safe way to use their values ** is to copy them to an array of a known type and use the array values. */ -static unsigned int l_randomizePivot (void) { - clock_t c = clock(); - time_t t = time(NULL); - unsigned int buff[sof(c) + sof(t)]; - unsigned int i, rnd = 0; - memcpy(buff, &c, sof(c) * sizeof(unsigned int)); - memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); - for (i = 0; i < sof(buff); i++) - rnd += buff[i]; - return rnd; +static unsigned int l_randomizePivot(void) +{ + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; } #endif /* } */ @@ -274,9 +303,10 @@ static unsigned int l_randomizePivot (void) { #define RANLIMIT 100u -static void set2 (lua_State *L, IdxT i, IdxT j) { - lua_seti(L, 1, i); - lua_seti(L, 1, j); +static void set2(lua_State* L, IdxT i, IdxT j) +{ + lua_seti(L, 1, i); + lua_seti(L, 1, j); } @@ -284,19 +314,22 @@ static void set2 (lua_State *L, IdxT i, IdxT j) { ** Return true iff value at stack index 'a' is less than the value at ** index 'b' (according to the order of the sort). */ -static int sort_comp (lua_State *L, int a, int b) { - if (lua_isnil(L, 2)) /* no function? */ - return lua_compare(L, a, b, LUA_OPLT); /* a < b */ - else { /* function */ - int res; - lua_pushvalue(L, 2); /* push function */ - lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ - lua_call(L, 2, 1); /* call function */ - res = lua_toboolean(L, -1); /* get result */ - lua_pop(L, 1); /* pop result */ - return res; - } +static int sort_comp(lua_State* L, int a, int b) +{ + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else + { + /* function */ + int res; + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a - 1); /* -1 to compensate function */ + lua_pushvalue(L, b - 2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ + return res; + } } @@ -307,35 +340,41 @@ static int sort_comp (lua_State *L, int a, int b) { ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** returns 'i'. */ -static IdxT partition (lua_State *L, IdxT lo, IdxT up) { - IdxT i = lo; /* will be incremented before first use */ - IdxT j = up - 1; /* will be decremented before first use */ - /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ - for (;;) { - /* next loop: repeat ++i while a[i] < P */ - while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ - luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ - /* next loop: repeat --j while P < a[j] */ - while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j < i) /* j < i but a[j] > P ?? */ - luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ - if (j < i) { /* no elements out of place? */ - /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ - lua_pop(L, 1); /* pop a[j] */ - /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ - set2(L, up - 1, i); - return i; - } - /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ - set2(L, i, j); - } +static IdxT partition(lua_State* L, IdxT lo, IdxT up) +{ + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) + { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) + { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) + { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) + { + /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } } @@ -343,108 +382,119 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) { ** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** "randomized" by 'rnd' */ -static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { - IdxT r4 = (up - lo) / 4; /* range/4 */ - IdxT p = rnd % (r4 * 2) + (lo + r4); - lua_assert(lo + r4 <= p && p <= up - r4); - return p; +static IdxT choosePivot(IdxT lo, IdxT up, unsigned int rnd) +{ + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; } /* ** QuickSort algorithm (recursive function) */ -static void auxsort (lua_State *L, IdxT lo, IdxT up, - unsigned int rnd) { - while (lo < up) { /* loop for tail recursion */ - IdxT p; /* Pivot index */ - IdxT n; /* to be used later */ - /* sort elements 'lo', 'p', and 'up' */ - lua_geti(L, 1, lo); - lua_geti(L, 1, up); - if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ - set2(L, lo, up); /* swap a[lo] - a[up] */ - else - lua_pop(L, 2); /* remove both values */ - if (up - lo == 1) /* only 2 elements? */ - return; /* already sorted */ - if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ - p = (lo + up)/2; /* middle element is a good pivot */ - else /* for larger intervals, it is worth a random pivot */ - p = choosePivot(lo, up, rnd); - lua_geti(L, 1, p); - lua_geti(L, 1, lo); - if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ - set2(L, p, lo); /* swap a[p] - a[lo] */ - else { - lua_pop(L, 1); /* remove a[lo] */ - lua_geti(L, 1, up); - if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ - set2(L, p, up); /* swap a[up] - a[p] */ - else - lua_pop(L, 2); - } - if (up - lo == 2) /* only 3 elements? */ - return; /* already sorted */ - lua_geti(L, 1, p); /* get middle element (Pivot) */ - lua_pushvalue(L, -1); /* push Pivot */ - lua_geti(L, 1, up - 1); /* push a[up - 1] */ - set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ - p = partition(L, lo, up); - /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ - if (p - lo < up - p) { /* lower interval is smaller? */ - auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ - n = p - lo; /* size of smaller interval */ - lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ - } - else { - auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ - n = up - p; /* size of smaller interval */ - up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ - } - if ((up - lo) / 128 > n) /* partition too imbalanced? */ - rnd = l_randomizePivot(); /* try a new randomization */ - } /* tail call auxsort(L, lo, up, rnd) */ +static void auxsort(lua_State* L, IdxT lo, IdxT up, + unsigned int rnd) +{ + while (lo < up) + { + /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ + else + lua_pop(L, 2); /* remove both values */ + if (up - lo == 1) /* only 2 elements? */ + return; /* already sorted */ + if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ + p = (lo + up) / 2; /* middle element is a good pivot */ + else /* for larger intervals, it is worth a random pivot */ + p = choosePivot(lo, up, rnd); + lua_geti(L, 1, p); + lua_geti(L, 1, lo); + if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ + set2(L, p, lo); /* swap a[p] - a[lo] */ + else + { + lua_pop(L, 1); /* remove a[lo] */ + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ + set2(L, p, up); /* swap a[up] - a[p] */ + else + lua_pop(L, 2); + } + if (up - lo == 2) /* only 3 elements? */ + return; /* already sorted */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ + set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ + p = partition(L, lo, up); + /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ + if (p - lo < up - p) + { + /* lower interval is smaller? */ + auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ + n = p - lo; /* size of smaller interval */ + lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ + } + else + { + auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ + n = up - p; /* size of smaller interval */ + up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ + } + if ((up - lo) / 128 > n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ } -static int sort (lua_State *L) { - lua_Integer n = aux_getn(L, 1, TAB_RW); - if (n > 1) { /* non-trivial interval? */ - luaL_argcheck(L, n < INT_MAX, 1, "array too big"); - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ - lua_settop(L, 2); /* make sure there are two arguments */ - auxsort(L, 1, (IdxT)n, 0); - } - return 0; +static int sort(lua_State* L) +{ + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) + { + /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } + return 0; } /* }====================================================== */ static const luaL_Reg tab_funcs[] = { - {"concat", tconcat}, + {"concat", tconcat}, #if defined(LUA_COMPAT_MAXN) {"maxn", maxn}, #endif - {"insert", tinsert}, - {"pack", pack}, - {"unpack", unpack}, - {"remove", tremove}, - {"move", tmove}, - {"sort", sort}, - {NULL, NULL} + {"insert", tinsert}, + {"pack", pack}, + {"unpack", unpack}, + {"remove", tremove}, + {"move", tmove}, + {"sort", sort}, + {NULL, NULL} }; -LUAMOD_API int luaopen_table (lua_State *L) { - luaL_newlib(L, tab_funcs); +LUAMOD_API int luaopen_table(lua_State* L) +{ + luaL_newlib(L, tab_funcs); #if defined(LUA_COMPAT_UNPACK) /* _G.unpack = table.unpack */ lua_getfield(L, -1, "unpack"); lua_setglobal(L, "unpack"); #endif - return 1; + return 1; } - diff --git a/Lua/ltm.c b/Lua/ltm.c index 14e5257..f0e68a7 100644 --- a/Lua/ltm.c +++ b/Lua/ltm.c @@ -26,29 +26,32 @@ static const char udatatypename[] = "userdata"; -LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { - "no value", - "nil", "boolean", udatatypename, "number", - "string", "table", "function", udatatypename, "thread", - "proto" /* this last case is used for tests only */ +LUAI_DDEF const char* const luaT_typenames_[LUA_TOTALTAGS] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", + "proto" /* this last case is used for tests only */ }; -void luaT_init (lua_State *L) { - static const char *const luaT_eventname[] = { /* ORDER TM */ - "__index", "__newindex", - "__gc", "__mode", "__len", "__eq", - "__add", "__sub", "__mul", "__mod", "__pow", - "__div", "__idiv", - "__band", "__bor", "__bxor", "__shl", "__shr", - "__unm", "__bnot", "__lt", "__le", - "__concat", "__call" - }; - int i; - for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); - luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ - } +void luaT_init(lua_State* L) +{ + static const char* const luaT_eventname[] = { + /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__len", "__eq", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", + "__concat", "__call" + }; + int i; + for (i = 0; i < TM_N; i++) + { + G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ + } } @@ -56,30 +59,35 @@ void luaT_init (lua_State *L) { ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ -const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { - const TValue *tm = luaH_getshortstr(events, ename); - lua_assert(event <= TM_EQ); - if (ttisnil(tm)) { /* no tag method? */ - events->flags |= cast_byte(1u<flags |= cast_byte(1u<metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(o)->metatable; - break; - default: - mt = G(L)->mt[ttnov(o)]; - } - return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); +const TValue* luaT_gettmbyobj(lua_State* L, const TValue* o, TMS event) +{ + Table* mt; + switch (ttnov(o)) + { + case LUA_TTABLE: + mt = hvalue(o)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttnov(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); } @@ -87,79 +95,93 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { ** Return the name of the type of an object. For tables and userdata ** with metatable, use their '__name' metafield, if present. */ -const char *luaT_objtypename (lua_State *L, const TValue *o) { - Table *mt; - if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || - (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { - const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); - if (ttisstring(name)) /* is '__name' a string? */ - return getstr(tsvalue(name)); /* use it as type name */ - } - return ttypename(ttnov(o)); /* else use standard type name */ +const char* luaT_objtypename(lua_State* L, const TValue* o) +{ + Table* mt; + if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || + (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) + { + const TValue* name = luaH_getshortstr(mt, luaS_new(L, "__name")); + if (ttisstring(name)) /* is '__name' a string? */ + return getstr(tsvalue(name)); /* use it as type name */ + } + return ttypename(ttnov(o)); /* else use standard type name */ } -void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres) { - ptrdiff_t result = savestack(L, p3); - StkId func = L->top; - setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ - setobj2s(L, func + 1, p1); /* 1st argument */ - setobj2s(L, func + 2, p2); /* 2nd argument */ - L->top += 3; - if (!hasres) /* no result? 'p3' is third argument */ - setobj2s(L, L->top++, p3); /* 3rd argument */ - /* metamethod may yield only when called from Lua code */ - if (isLua(L->ci)) - luaD_call(L, func, hasres); - else - luaD_callnoyield(L, func, hasres); - if (hasres) { /* if has result, move it to its place */ - p3 = restorestack(L, result); - setobjs2s(L, p3, --L->top); - } +void luaT_callTM(lua_State* L, const TValue* f, const TValue* p1, + const TValue* p2, TValue* p3, int hasres) +{ + ptrdiff_t result = savestack(L, p3); + StkId func = L->top; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top += 3; + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3rd argument */ + /* metamethod may yield only when called from Lua code */ + if (isLua(L->ci)) + luaD_call(L, func, hasres); + else + luaD_callnoyield(L, func, hasres); + if (hasres) + { + /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } } -int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (ttisnil(tm)) return 0; - luaT_callTM(L, tm, p1, p2, res, 1); - return 1; +int luaT_callbinTM(lua_State* L, const TValue* p1, const TValue* p2, + StkId res, TMS event) +{ + const TValue* tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + luaT_callTM(L, tm, p1, p2, res, 1); + return 1; } -void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - if (!luaT_callbinTM(L, p1, p2, res, event)) { - switch (event) { - case TM_CONCAT: - luaG_concaterror(L, p1, p2); - /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ - case TM_BAND: case TM_BOR: case TM_BXOR: - case TM_SHL: case TM_SHR: case TM_BNOT: { - lua_Number dummy; - if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) - luaG_tointerror(L, p1, p2); - else - luaG_opinterror(L, p1, p2, "perform bitwise operation on"); - } - /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ - default: - luaG_opinterror(L, p1, p2, "perform arithmetic on"); - } - } +void luaT_trybinTM(lua_State* L, const TValue* p1, const TValue* p2, + StkId res, TMS event) +{ + if (!luaT_callbinTM(L, p1, p2, res, event)) + { + switch (event) + { + case TM_CONCAT: + luaG_concaterror(L, p1, p2); + /* call never returns, but to avoid warnings: */ /* FALLTHROUGH */ + case TM_BAND: + case TM_BOR: + case TM_BXOR: + case TM_SHL: + case TM_SHR: + case TM_BNOT: + { + lua_Number dummy; + if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: */ /* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } } -int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, - TMS event) { - if (!luaT_callbinTM(L, p1, p2, L->top, event)) - return -1; /* no metamethod */ - else - return !l_isfalse(L->top); +int luaT_callorderTM(lua_State* L, const TValue* p1, const TValue* p2, + TMS event) +{ + if (!luaT_callbinTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } - diff --git a/Lua/ltm.h b/Lua/ltm.h index 63db726..09628cc 100644 --- a/Lua/ltm.h +++ b/Lua/ltm.h @@ -15,36 +15,37 @@ * WARNING: if you change the order of this enumeration, * grep "ORDER TM" and "ORDER OP" */ -typedef enum { - TM_INDEX, - TM_NEWINDEX, - TM_GC, - TM_MODE, - TM_LEN, - TM_EQ, /* last tag method with fast access */ - TM_ADD, - TM_SUB, - TM_MUL, - TM_MOD, - TM_POW, - TM_DIV, - TM_IDIV, - TM_BAND, - TM_BOR, - TM_BXOR, - TM_SHL, - TM_SHR, - TM_UNM, - TM_BNOT, - TM_LT, - TM_LE, - TM_CONCAT, - TM_CALL, - TM_N /* number of elements in the enum */ +typedef enum +{ + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_LEN, + TM_EQ, + /* last tag method with fast access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_MOD, + TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, + TM_UNM, + TM_BNOT, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ } TMS; - #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) @@ -52,25 +53,24 @@ typedef enum { #define ttypename(x) luaT_typenames_[(x) + 1] -LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; +LUAI_DDEC const char* const luaT_typenames_[LUA_TOTALTAGS]; -LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); +LUAI_FUNC const char* luaT_objtypename(lua_State* L, const TValue* o); -LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); -LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, - TMS event); -LUAI_FUNC void luaT_init (lua_State *L); - -LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres); -LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event); -LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event); -LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, - const TValue *p2, TMS event); +LUAI_FUNC const TValue* luaT_gettm(Table* events, TMS event, TString* ename); +LUAI_FUNC const TValue* luaT_gettmbyobj(lua_State* L, const TValue* o, + TMS event); +LUAI_FUNC void luaT_init(lua_State* L); +LUAI_FUNC void luaT_callTM(lua_State* L, const TValue* f, const TValue* p1, + const TValue* p2, TValue* p3, int hasres); +LUAI_FUNC int luaT_callbinTM(lua_State* L, const TValue* p1, const TValue* p2, + StkId res, TMS event); +LUAI_FUNC void luaT_trybinTM(lua_State* L, const TValue* p1, const TValue* p2, + StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM(lua_State* L, const TValue* p1, + const TValue* p2, TMS event); #endif diff --git a/Lua/lua.h b/Lua/lua.h index 26c0e2d..4d6196d 100644 --- a/Lua/lua.h +++ b/Lua/lua.h @@ -74,7 +74,6 @@ typedef struct lua_State lua_State; #define LUA_NUMTAGS 9 - /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 @@ -102,27 +101,26 @@ typedef LUA_KCONTEXT lua_KContext; /* ** Type for C functions registered with Lua */ -typedef int (*lua_CFunction) (lua_State *L); +typedef int (*lua_CFunction)(lua_State* L); /* ** Type for continuation functions */ -typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); +typedef int (*lua_KFunction)(lua_State* L, int status, lua_KContext ctx); /* ** Type for functions that read/write blocks when loading/dumping Lua chunks */ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); +typedef const char* (*lua_Reader)(lua_State* L, void* ud, size_t* sz); -typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); +typedef int (*lua_Writer)(lua_State* L, const void* p, size_t sz, void* ud); /* ** Type for memory-allocation functions */ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - +typedef void* (*lua_Alloc)(void* ud, void* ptr, size_t osize, size_t nsize); /* @@ -142,51 +140,51 @@ extern const char lua_ident[]; /* ** state manipulation */ -LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); -LUA_API void (lua_close) (lua_State *L); -LUA_API lua_State *(lua_newthread) (lua_State *L); +LUA_API lua_State*(lua_newstate)(lua_Alloc f, void* ud); +LUA_API void (lua_close)(lua_State* L); +LUA_API lua_State*(lua_newthread)(lua_State* L); -LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); +LUA_API lua_CFunction (lua_atpanic)(lua_State* L, lua_CFunction panicf); -LUA_API const lua_Number *(lua_version) (lua_State *L); +LUA_API const lua_Number*(lua_version)(lua_State* L); /* ** basic stack manipulation */ -LUA_API int (lua_absindex) (lua_State *L, int idx); -LUA_API int (lua_gettop) (lua_State *L); -LUA_API void (lua_settop) (lua_State *L, int idx); -LUA_API void (lua_pushvalue) (lua_State *L, int idx); -LUA_API void (lua_rotate) (lua_State *L, int idx, int n); -LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); -LUA_API int (lua_checkstack) (lua_State *L, int n); +LUA_API int (lua_absindex)(lua_State* L, int idx); +LUA_API int (lua_gettop)(lua_State* L); +LUA_API void (lua_settop)(lua_State* L, int idx); +LUA_API void (lua_pushvalue)(lua_State* L, int idx); +LUA_API void (lua_rotate)(lua_State* L, int idx, int n); +LUA_API void (lua_copy)(lua_State* L, int fromidx, int toidx); +LUA_API int (lua_checkstack)(lua_State* L, int n); -LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); +LUA_API void (lua_xmove)(lua_State* from, lua_State* to, int n); /* ** access functions (stack -> C) */ -LUA_API int (lua_isnumber) (lua_State *L, int idx); -LUA_API int (lua_isstring) (lua_State *L, int idx); -LUA_API int (lua_iscfunction) (lua_State *L, int idx); -LUA_API int (lua_isinteger) (lua_State *L, int idx); -LUA_API int (lua_isuserdata) (lua_State *L, int idx); -LUA_API int (lua_type) (lua_State *L, int idx); -LUA_API const char *(lua_typename) (lua_State *L, int tp); +LUA_API int (lua_isnumber)(lua_State* L, int idx); +LUA_API int (lua_isstring)(lua_State* L, int idx); +LUA_API int (lua_iscfunction)(lua_State* L, int idx); +LUA_API int (lua_isinteger)(lua_State* L, int idx); +LUA_API int (lua_isuserdata)(lua_State* L, int idx); +LUA_API int (lua_type)(lua_State* L, int idx); +LUA_API const char*(lua_typename)(lua_State* L, int tp); -LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); -LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); -LUA_API int (lua_toboolean) (lua_State *L, int idx); -LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_rawlen) (lua_State *L, int idx); -LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); -LUA_API void *(lua_touserdata) (lua_State *L, int idx); -LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); -LUA_API const void *(lua_topointer) (lua_State *L, int idx); +LUA_API lua_Number (lua_tonumberx)(lua_State* L, int idx, int* isnum); +LUA_API lua_Integer (lua_tointegerx)(lua_State* L, int idx, int* isnum); +LUA_API int (lua_toboolean)(lua_State* L, int idx); +LUA_API const char*(lua_tolstring)(lua_State* L, int idx, size_t* len); +LUA_API size_t (lua_rawlen)(lua_State* L, int idx); +LUA_API lua_CFunction (lua_tocfunction)(lua_State* L, int idx); +LUA_API void*(lua_touserdata)(lua_State* L, int idx); +LUA_API lua_State*(lua_tothread)(lua_State* L, int idx); +LUA_API const void*(lua_topointer)(lua_State* L, int idx); /* @@ -208,89 +206,89 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx); #define LUA_OPUNM 12 #define LUA_OPBNOT 13 -LUA_API void (lua_arith) (lua_State *L, int op); +LUA_API void (lua_arith)(lua_State* L, int op); #define LUA_OPEQ 0 #define LUA_OPLT 1 #define LUA_OPLE 2 -LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); +LUA_API int (lua_rawequal)(lua_State* L, int idx1, int idx2); +LUA_API int (lua_compare)(lua_State* L, int idx1, int idx2, int op); /* ** push functions (C -> stack) */ -LUA_API void (lua_pushnil) (lua_State *L); -LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); -LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); -LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, - va_list argp); -LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); -LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); -LUA_API void (lua_pushboolean) (lua_State *L, int b); -LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); -LUA_API int (lua_pushthread) (lua_State *L); +LUA_API void (lua_pushnil)(lua_State* L); +LUA_API void (lua_pushnumber)(lua_State* L, lua_Number n); +LUA_API void (lua_pushinteger)(lua_State* L, lua_Integer n); +LUA_API const char*(lua_pushlstring)(lua_State* L, const char* s, size_t len); +LUA_API const char*(lua_pushstring)(lua_State* L, const char* s); +LUA_API const char*(lua_pushvfstring)(lua_State* L, const char* fmt, + va_list argp); +LUA_API const char*(lua_pushfstring)(lua_State* L, const char* fmt, ...); +LUA_API void (lua_pushcclosure)(lua_State* L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean)(lua_State* L, int b); +LUA_API void (lua_pushlightuserdata)(lua_State* L, void* p); +LUA_API int (lua_pushthread)(lua_State* L); /* ** get functions (Lua -> stack) */ -LUA_API int (lua_getglobal) (lua_State *L, const char *name); -LUA_API int (lua_gettable) (lua_State *L, int idx); -LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawget) (lua_State *L, int idx); -LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_getglobal)(lua_State* L, const char* name); +LUA_API int (lua_gettable)(lua_State* L, int idx); +LUA_API int (lua_getfield)(lua_State* L, int idx, const char* k); +LUA_API int (lua_geti)(lua_State* L, int idx, lua_Integer n); +LUA_API int (lua_rawget)(lua_State* L, int idx); +LUA_API int (lua_rawgeti)(lua_State* L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp)(lua_State* L, int idx, const void* p); -LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); -LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); -LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API int (lua_getuservalue) (lua_State *L, int idx); +LUA_API void (lua_createtable)(lua_State* L, int narr, int nrec); +LUA_API void*(lua_newuserdata)(lua_State* L, size_t sz); +LUA_API int (lua_getmetatable)(lua_State* L, int objindex); +LUA_API int (lua_getuservalue)(lua_State* L, int idx); /* ** set functions (stack -> Lua) */ -LUA_API void (lua_setglobal) (lua_State *L, const char *name); -LUA_API void (lua_settable) (lua_State *L, int idx); -LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); -LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API void (lua_setuservalue) (lua_State *L, int idx); +LUA_API void (lua_setglobal)(lua_State* L, const char* name); +LUA_API void (lua_settable)(lua_State* L, int idx); +LUA_API void (lua_setfield)(lua_State* L, int idx, const char* k); +LUA_API void (lua_seti)(lua_State* L, int idx, lua_Integer n); +LUA_API void (lua_rawset)(lua_State* L, int idx); +LUA_API void (lua_rawseti)(lua_State* L, int idx, lua_Integer n); +LUA_API void (lua_rawsetp)(lua_State* L, int idx, const void* p); +LUA_API int (lua_setmetatable)(lua_State* L, int objindex); +LUA_API void (lua_setuservalue)(lua_State* L, int idx); /* ** 'load' and 'call' functions (load and run Lua code) */ -LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k); +LUA_API void (lua_callk)(lua_State* L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) -LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k); +LUA_API int (lua_pcallk)(lua_State* L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) -LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode); +LUA_API int (lua_load)(lua_State* L, lua_Reader reader, void* dt, + const char* chunkname, const char* mode); -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); +LUA_API int (lua_dump)(lua_State* L, lua_Writer writer, void* data, int strip); /* ** coroutine functions */ -LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k); -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); -LUA_API int (lua_status) (lua_State *L); -LUA_API int (lua_isyieldable) (lua_State *L); +LUA_API int (lua_yieldk)(lua_State* L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume)(lua_State* L, lua_State* from, int narg); +LUA_API int (lua_status)(lua_State* L); +LUA_API int (lua_isyieldable)(lua_State* L); #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) @@ -309,25 +307,24 @@ LUA_API int (lua_isyieldable) (lua_State *L); #define LUA_GCSETSTEPMUL 7 #define LUA_GCISRUNNING 9 -LUA_API int (lua_gc) (lua_State *L, int what, int data); +LUA_API int (lua_gc)(lua_State* L, int what, int data); /* ** miscellaneous functions */ -LUA_API int (lua_error) (lua_State *L); +LUA_API int (lua_error)(lua_State* L); -LUA_API int (lua_next) (lua_State *L, int idx); +LUA_API int (lua_next)(lua_State* L, int idx); -LUA_API void (lua_concat) (lua_State *L, int n); -LUA_API void (lua_len) (lua_State *L, int idx); +LUA_API void (lua_concat)(lua_State* L, int n); +LUA_API void (lua_len)(lua_State* L, int idx); -LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); - -LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); +LUA_API size_t (lua_stringtonumber)(lua_State* L, const char* s); +LUA_API lua_Alloc (lua_getallocf)(lua_State* L, void** ud); +LUA_API void (lua_setallocf)(lua_State* L, lua_Alloc f, void* ud); /* @@ -414,46 +411,47 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) -typedef struct lua_Debug lua_Debug; /* activation record */ +typedef struct lua_Debug lua_Debug; /* activation record */ /* Functions to be called by the debugger in specific events */ -typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); +typedef void (*lua_Hook)(lua_State* L, lua_Debug* ar); -LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); -LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); -LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); +LUA_API int (lua_getstack)(lua_State* L, int level, lua_Debug* ar); +LUA_API int (lua_getinfo)(lua_State* L, const char* what, lua_Debug* ar); +LUA_API const char*(lua_getlocal)(lua_State* L, const lua_Debug* ar, int n); +LUA_API const char*(lua_setlocal)(lua_State* L, const lua_Debug* ar, int n); +LUA_API const char*(lua_getupvalue)(lua_State* L, int funcindex, int n); +LUA_API const char*(lua_setupvalue)(lua_State* L, int funcindex, int n); -LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); -LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, - int fidx2, int n2); +LUA_API void*(lua_upvalueid)(lua_State* L, int fidx, int n); +LUA_API void (lua_upvaluejoin)(lua_State* L, int fidx1, int n1, + int fidx2, int n2); -LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); -LUA_API lua_Hook (lua_gethook) (lua_State *L); -LUA_API int (lua_gethookmask) (lua_State *L); -LUA_API int (lua_gethookcount) (lua_State *L); +LUA_API void (lua_sethook)(lua_State* L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook)(lua_State* L); +LUA_API int (lua_gethookmask)(lua_State* L); +LUA_API int (lua_gethookcount)(lua_State* L); -struct lua_Debug { - int event; - const char *name; /* (n) */ - const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ - const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ - const char *source; /* (S) */ - int currentline; /* (l) */ - int linedefined; /* (S) */ - int lastlinedefined; /* (S) */ - unsigned char nups; /* (u) number of upvalues */ - unsigned char nparams;/* (u) number of parameters */ - char isvararg; /* (u) */ - char istailcall; /* (t) */ - char short_src[LUA_IDSIZE]; /* (S) */ - /* private part */ - struct CallInfo *i_ci; /* active function */ +struct lua_Debug +{ + int event; + const char* name; /* (n) */ + const char* namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char* what; /* (S) 'Lua', 'C', 'main', 'tail' */ + const char* source; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams; /* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct CallInfo* i_ci; /* active function */ }; /* }====================================================================== */ diff --git a/Lua/luaconf.h b/Lua/luaconf.h index f37bea0..20d0173 100644 --- a/Lua/luaconf.h +++ b/Lua/luaconf.h @@ -82,7 +82,6 @@ #endif - /* @@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. */ @@ -150,8 +149,6 @@ /* }================================================================== */ - - /* ** {================================================================== ** Configuration for Paths. @@ -405,7 +402,6 @@ /* }================================================================== */ - /* ** {================================================================== ** Configuration for Numbers. @@ -505,7 +501,6 @@ #endif /* } */ - /* @@ LUA_INTEGER is the integer type used by Lua. ** @@ -766,8 +761,6 @@ #define LUA_QS LUA_QL("%s") - - /* =================================================================== */ /* @@ -776,8 +769,4 @@ */ - - - #endif - diff --git a/Lua/lualib.h b/Lua/lualib.h index 6c0bc4c..5fb5665 100644 --- a/Lua/lualib.h +++ b/Lua/lualib.h @@ -15,42 +15,41 @@ #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR -LUAMOD_API int (luaopen_base) (lua_State *L); +LUAMOD_API int (luaopen_base)(lua_State* L); #define LUA_COLIBNAME "coroutine" -LUAMOD_API int (luaopen_coroutine) (lua_State *L); +LUAMOD_API int (luaopen_coroutine)(lua_State* L); #define LUA_TABLIBNAME "table" -LUAMOD_API int (luaopen_table) (lua_State *L); +LUAMOD_API int (luaopen_table)(lua_State* L); #define LUA_IOLIBNAME "io" -LUAMOD_API int (luaopen_io) (lua_State *L); +LUAMOD_API int (luaopen_io)(lua_State* L); #define LUA_OSLIBNAME "os" -LUAMOD_API int (luaopen_os) (lua_State *L); +LUAMOD_API int (luaopen_os)(lua_State* L); #define LUA_STRLIBNAME "string" -LUAMOD_API int (luaopen_string) (lua_State *L); +LUAMOD_API int (luaopen_string)(lua_State* L); #define LUA_UTF8LIBNAME "utf8" -LUAMOD_API int (luaopen_utf8) (lua_State *L); +LUAMOD_API int (luaopen_utf8)(lua_State* L); #define LUA_BITLIBNAME "bit32" -LUAMOD_API int (luaopen_bit32) (lua_State *L); +LUAMOD_API int (luaopen_bit32)(lua_State* L); #define LUA_MATHLIBNAME "math" -LUAMOD_API int (luaopen_math) (lua_State *L); +LUAMOD_API int (luaopen_math)(lua_State* L); #define LUA_DBLIBNAME "debug" -LUAMOD_API int (luaopen_debug) (lua_State *L); +LUAMOD_API int (luaopen_debug)(lua_State* L); #define LUA_LOADLIBNAME "package" -LUAMOD_API int (luaopen_package) (lua_State *L); +LUAMOD_API int (luaopen_package)(lua_State* L); /* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); - +LUALIB_API void (luaL_openlibs)(lua_State* L); #if !defined(lua_assert) diff --git a/Lua/luasocket.c b/Lua/luasocket.c index d2752a7..0976680 100644 --- a/Lua/luasocket.c +++ b/Lua/luasocket.c @@ -35,80 +35,87 @@ /*-------------------------------------------------------------------------*\ * Internal function prototypes \*-------------------------------------------------------------------------*/ -static int global_skip(lua_State *L); -static int global_unload(lua_State *L); -static int base_open(lua_State *L); +static int global_skip(lua_State* L); +static int global_unload(lua_State* L); +static int base_open(lua_State* L); /*-------------------------------------------------------------------------*\ * Modules and functions \*-------------------------------------------------------------------------*/ static const luaL_Reg mod[] = { - {"auxiliar", auxiliar_open}, - {"except", except_open}, - {"timeout", timeout_open}, - {"buffer", buffer_open}, - {"inet", inet_open}, - {"tcp", tcp_open}, - {"udp", udp_open}, - {"select", select_open}, - {NULL, NULL} + {"auxiliar", auxiliar_open}, + {"except", except_open}, + {"timeout", timeout_open}, + {"buffer", buffer_open}, + {"inet", inet_open}, + {"tcp", tcp_open}, + {"udp", udp_open}, + {"select", select_open}, + {NULL, NULL} }; static luaL_Reg func[] = { - {"skip", global_skip}, - {"__unload", global_unload}, - {NULL, NULL} + {"skip", global_skip}, + {"__unload", global_unload}, + {NULL, NULL} }; /*-------------------------------------------------------------------------*\ * Skip a few arguments \*-------------------------------------------------------------------------*/ -static int global_skip(lua_State *L) { - int amount = (int) luaL_checkinteger(L, 1); - int ret = lua_gettop(L) - amount - 1; - return ret >= 0 ? ret : 0; +static int global_skip(lua_State* L) +{ + int amount = (int)luaL_checkinteger(L, 1); + int ret = lua_gettop(L) - amount - 1; + return ret >= 0 ? ret : 0; } /*-------------------------------------------------------------------------*\ * Unloads the library \*-------------------------------------------------------------------------*/ -static int global_unload(lua_State *L) { - (void) L; - socket_close(); - return 0; +static int global_unload(lua_State* L) +{ + (void)L; + socket_close(); + return 0; } /*-------------------------------------------------------------------------*\ * Setup basic stuff. \*-------------------------------------------------------------------------*/ -static int base_open(lua_State *L) { - if (socket_open()) { - /* export functions (and leave namespace table on top of stack) */ - lua_newtable(L); - luaL_setfuncs(L, func, 0); +static int base_open(lua_State* L) +{ + if (socket_open()) + { + /* export functions (and leave namespace table on top of stack) */ + lua_newtable(L); + luaL_setfuncs(L, func, 0); #ifdef LUASOCKET_DEBUG lua_pushstring(L, "_DEBUG"); lua_pushboolean(L, 1); lua_rawset(L, -3); #endif - /* make version string available to scripts */ - lua_pushstring(L, "_VERSION"); - lua_pushstring(L, LUASOCKET_VERSION); - lua_rawset(L, -3); - return 1; - } else { - lua_pushstring(L, "unable to initialize library"); - lua_error(L); - return 0; - } + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, LUASOCKET_VERSION); + lua_rawset(L, -3); + return 1; + } + else + { + lua_pushstring(L, "unable to initialize library"); + lua_error(L); + return 0; + } } /*-------------------------------------------------------------------------*\ * Initializes all library modules. \*-------------------------------------------------------------------------*/ -LUASOCKET_API int luaopen_socket_core(lua_State *L) { - int i; - base_open(L); - for (i = 0; mod[i].name; i++) mod[i].func(L); - return 1; +LUASOCKET_API int luaopen_socket_core(lua_State* L) +{ + int i; + base_open(L); + for (i = 0; mod[i].name; i++) mod[i].func(L); + return 1; } diff --git a/Lua/luasocket.h b/Lua/luasocket.h index f75d21f..3e4389a 100644 --- a/Lua/luasocket.h +++ b/Lua/luasocket.h @@ -24,6 +24,6 @@ /*-------------------------------------------------------------------------*\ * Initializes the library. \*-------------------------------------------------------------------------*/ -LUASOCKET_API int luaopen_socket_core(lua_State *L); +LUASOCKET_API int luaopen_socket_core(lua_State* L); #endif /* LUASOCKET_H */ diff --git a/Lua/lundump.c b/Lua/lundump.c index 4080af9..ab88077 100644 --- a/Lua/lundump.c +++ b/Lua/lundump.c @@ -29,16 +29,18 @@ #endif -typedef struct { - lua_State *L; - ZIO *Z; - const char *name; +typedef struct +{ + lua_State* L; + ZIO* Z; + const char* name; } LoadState; -static l_noret error(LoadState *S, const char *why) { - luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); - luaD_throw(S->L, LUA_ERRSYNTAX); +static l_noret error(LoadState* S, const char* why) +{ + luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); } @@ -48,232 +50,256 @@ static l_noret error(LoadState *S, const char *why) { */ #define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) -static void LoadBlock (LoadState *S, void *b, size_t size) { - if (luaZ_read(S->Z, b, size) != 0) - error(S, "truncated"); +static void LoadBlock(LoadState* S, void* b, size_t size) +{ + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated"); } #define LoadVar(S,x) LoadVector(S,&x,1) -static lu_byte LoadByte (LoadState *S) { - lu_byte x; - LoadVar(S, x); - return x; +static lu_byte LoadByte(LoadState* S) +{ + lu_byte x; + LoadVar(S, x); + return x; } -static int LoadInt (LoadState *S) { - int x; - LoadVar(S, x); - return x; +static int LoadInt(LoadState* S) +{ + int x; + LoadVar(S, x); + return x; } -static lua_Number LoadNumber (LoadState *S) { - lua_Number x; - LoadVar(S, x); - return x; +static lua_Number LoadNumber(LoadState* S) +{ + lua_Number x; + LoadVar(S, x); + return x; } -static lua_Integer LoadInteger (LoadState *S) { - lua_Integer x; - LoadVar(S, x); - return x; +static lua_Integer LoadInteger(LoadState* S) +{ + lua_Integer x; + LoadVar(S, x); + return x; } -static TString *LoadString (LoadState *S) { - size_t size = LoadByte(S); - if (size == 0xFF) - LoadVar(S, size); - if (size == 0) - return NULL; - else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ - char buff[LUAI_MAXSHORTLEN]; - LoadVector(S, buff, size); - return luaS_newlstr(S->L, buff, size); - } - else { /* long string */ - TString *ts = luaS_createlngstrobj(S->L, size); - LoadVector(S, getstr(ts), size); /* load directly in final place */ - return ts; - } +static TString* LoadString(LoadState* S) +{ + size_t size = LoadByte(S); + if (size == 0xFF) + LoadVar(S, size); + if (size == 0) + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) + { + /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + LoadVector(S, buff, size); + return luaS_newlstr(S->L, buff, size); + } + else + { + /* long string */ + TString* ts = luaS_createlngstrobj(S->L, size); + LoadVector(S, getstr(ts), size); /* load directly in final place */ + return ts; + } } -static void LoadCode (LoadState *S, Proto *f) { - int n = LoadInt(S); - f->code = luaM_newvector(S->L, n, Instruction); - f->sizecode = n; - LoadVector(S, f->code, n); +static void LoadCode(LoadState* S, Proto* f) +{ + int n = LoadInt(S); + f->code = luaM_newvector(S->L, n, Instruction); + f->sizecode = n; + LoadVector(S, f->code, n); } -static void LoadFunction(LoadState *S, Proto *f, TString *psource); +static void LoadFunction(LoadState* S, Proto* f, TString* psource); -static void LoadConstants (LoadState *S, Proto *f) { - int i; - int n = LoadInt(S); - f->k = luaM_newvector(S->L, n, TValue); - f->sizek = n; - for (i = 0; i < n; i++) - setnilvalue(&f->k[i]); - for (i = 0; i < n; i++) { - TValue *o = &f->k[i]; - int t = LoadByte(S); - switch (t) { - case LUA_TNIL: - setnilvalue(o); - break; - case LUA_TBOOLEAN: - setbvalue(o, LoadByte(S)); - break; - case LUA_TNUMFLT: - setfltvalue(o, LoadNumber(S)); - break; - case LUA_TNUMINT: - setivalue(o, LoadInteger(S)); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - setsvalue2n(S->L, o, LoadString(S)); - break; - default: - lua_assert(0); - } - } +static void LoadConstants(LoadState* S, Proto* f) +{ + int i; + int n = LoadInt(S); + f->k = luaM_newvector(S->L, n, TValue); + f->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) + { + TValue* o = &f->k[i]; + int t = LoadByte(S); + switch (t) + { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o, LoadByte(S)); + break; + case LUA_TNUMFLT: + setfltvalue(o, LoadNumber(S)); + break; + case LUA_TNUMINT: + setivalue(o, LoadInteger(S)); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + setsvalue2n(S->L, o, LoadString(S)); + break; + default: + lua_assert(0); + } + } } -static void LoadProtos (LoadState *S, Proto *f) { - int i; - int n = LoadInt(S); - f->p = luaM_newvector(S->L, n, Proto *); - f->sizep = n; - for (i = 0; i < n; i++) - f->p[i] = NULL; - for (i = 0; i < n; i++) { - f->p[i] = luaF_newproto(S->L); - LoadFunction(S, f->p[i], f->source); - } +static void LoadProtos(LoadState* S, Proto* f) +{ + int i; + int n = LoadInt(S); + f->p = luaM_newvector(S->L, n, Proto *); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) + { + f->p[i] = luaF_newproto(S->L); + LoadFunction(S, f->p[i], f->source); + } } -static void LoadUpvalues (LoadState *S, Proto *f) { - int i, n; - n = LoadInt(S); - f->upvalues = luaM_newvector(S->L, n, Upvaldesc); - f->sizeupvalues = n; - for (i = 0; i < n; i++) - f->upvalues[i].name = NULL; - for (i = 0; i < n; i++) { - f->upvalues[i].instack = LoadByte(S); - f->upvalues[i].idx = LoadByte(S); - } +static void LoadUpvalues(LoadState* S, Proto* f) +{ + int i, n; + n = LoadInt(S); + f->upvalues = luaM_newvector(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) + { + f->upvalues[i].instack = LoadByte(S); + f->upvalues[i].idx = LoadByte(S); + } } -static void LoadDebug (LoadState *S, Proto *f) { - int i, n; - n = LoadInt(S); - f->lineinfo = luaM_newvector(S->L, n, int); - f->sizelineinfo = n; - LoadVector(S, f->lineinfo, n); - n = LoadInt(S); - f->locvars = luaM_newvector(S->L, n, LocVar); - f->sizelocvars = n; - for (i = 0; i < n; i++) - f->locvars[i].varname = NULL; - for (i = 0; i < n; i++) { - f->locvars[i].varname = LoadString(S); - f->locvars[i].startpc = LoadInt(S); - f->locvars[i].endpc = LoadInt(S); - } - n = LoadInt(S); - for (i = 0; i < n; i++) - f->upvalues[i].name = LoadString(S); +static void LoadDebug(LoadState* S, Proto* f) +{ + int i, n; + n = LoadInt(S); + f->lineinfo = luaM_newvector(S->L, n, int); + f->sizelineinfo = n; + LoadVector(S, f->lineinfo, n); + n = LoadInt(S); + f->locvars = luaM_newvector(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) + { + f->locvars[i].varname = LoadString(S); + f->locvars[i].startpc = LoadInt(S); + f->locvars[i].endpc = LoadInt(S); + } + n = LoadInt(S); + for (i = 0; i < n; i++) + f->upvalues[i].name = LoadString(S); } -static void LoadFunction (LoadState *S, Proto *f, TString *psource) { - f->source = LoadString(S); - if (f->source == NULL) /* no source in dump? */ - f->source = psource; /* reuse parent's source */ - f->linedefined = LoadInt(S); - f->lastlinedefined = LoadInt(S); - f->numparams = LoadByte(S); - f->is_vararg = LoadByte(S); - f->maxstacksize = LoadByte(S); - LoadCode(S, f); - LoadConstants(S, f); - LoadUpvalues(S, f); - LoadProtos(S, f); - LoadDebug(S, f); +static void LoadFunction(LoadState* S, Proto* f, TString* psource) +{ + f->source = LoadString(S); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = LoadInt(S); + f->lastlinedefined = LoadInt(S); + f->numparams = LoadByte(S); + f->is_vararg = LoadByte(S); + f->maxstacksize = LoadByte(S); + LoadCode(S, f); + LoadConstants(S, f); + LoadUpvalues(S, f); + LoadProtos(S, f); + LoadDebug(S, f); } -static void checkliteral (LoadState *S, const char *s, const char *msg) { - char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ - size_t len = strlen(s); - LoadVector(S, buff, len); - if (memcmp(s, buff, len) != 0) - error(S, msg); +static void checkliteral(LoadState* S, const char* s, const char* msg) +{ + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + LoadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); } -static void fchecksize (LoadState *S, size_t size, const char *tname) { - if (LoadByte(S) != size) - error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); +static void fchecksize(LoadState* S, size_t size, const char* tname) +{ + if (LoadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); } #define checksize(S,t) fchecksize(S,sizeof(t),#t) -static void checkHeader (LoadState *S) { - checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ - if (LoadByte(S) != LUAC_VERSION) - error(S, "version mismatch in"); - if (LoadByte(S) != LUAC_FORMAT) - error(S, "format mismatch in"); - checkliteral(S, LUAC_DATA, "corrupted"); - checksize(S, int); - checksize(S, size_t); - checksize(S, Instruction); - checksize(S, lua_Integer); - checksize(S, lua_Number); - if (LoadInteger(S) != LUAC_INT) - error(S, "endianness mismatch in"); - if (LoadNumber(S) != LUAC_NUM) - error(S, "float format mismatch in"); +static void checkHeader(LoadState* S) +{ + checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ + if (LoadByte(S) != LUAC_VERSION) + error(S, "version mismatch in"); + if (LoadByte(S) != LUAC_FORMAT) + error(S, "format mismatch in"); + checkliteral(S, LUAC_DATA, "corrupted"); + checksize(S, int); + checksize(S, size_t); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (LoadInteger(S) != LUAC_INT) + error(S, "endianness mismatch in"); + if (LoadNumber(S) != LUAC_NUM) + error(S, "float format mismatch in"); } /* ** load precompiled chunk */ -LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { - LoadState S; - LClosure *cl; - if (*name == '@' || *name == '=') - S.name = name + 1; - else if (*name == LUA_SIGNATURE[0]) - S.name = "binary string"; - else - S.name = name; - S.L = L; - S.Z = Z; - checkHeader(&S); - cl = luaF_newLclosure(L, LoadByte(&S)); - setclLvalue(L, L->top, cl); - luaD_inctop(L); - cl->p = luaF_newproto(L); - LoadFunction(&S, cl->p, NULL); - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luai_verifycode(L, buff, cl->p); - return cl; +LClosure* luaU_undump(lua_State* L, ZIO* Z, const char* name) +{ + LoadState S; + LClosure* cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, LoadByte(&S)); + setclLvalue(L, L->top, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L); + LoadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, buff, cl->p); + return cl; } - diff --git a/Lua/lundump.h b/Lua/lundump.h index aa5cc82..778ba6d 100644 --- a/Lua/lundump.h +++ b/Lua/lundump.h @@ -23,10 +23,10 @@ #define LUAC_FORMAT 0 /* this is the official format */ /* load one chunk; from lundump.c */ -LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); +LUAI_FUNC LClosure* luaU_undump(lua_State* L, ZIO* Z, const char* name); /* dump one chunk; from ldump.c */ -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, - void* data, int strip); +LUAI_FUNC int luaU_dump(lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); #endif diff --git a/Lua/lutf8lib.c b/Lua/lutf8lib.c index de9e3dc..d2b4162 100644 --- a/Lua/lutf8lib.c +++ b/Lua/lutf8lib.c @@ -27,39 +27,44 @@ /* from strlib */ /* translate a relative string position: negative means back from end */ -static lua_Integer u_posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; +static lua_Integer u_posrelat(lua_Integer pos, size_t len) +{ + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; } /* ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. */ -static const char *utf8_decode (const char *o, int *val) { - static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; - const unsigned char *s = (const unsigned char *)o; - unsigned int c = s[0]; - unsigned int res = 0; /* final result */ - if (c < 0x80) /* ascii? */ - res = c; - else { - int count = 0; /* to count number of continuation bytes */ - while (c & 0x40) { /* still have continuation bytes? */ - int cc = s[++count]; /* read next byte */ - if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ - return NULL; /* invalid byte sequence */ - res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ - c <<= 1; /* to test next bit */ - } - res |= ((c & 0x7F) << (count * 5)); /* add first byte */ - if (count > 3 || res > MAXUNICODE || res <= limits[count]) - return NULL; /* invalid byte sequence */ - s += count; /* skip continuation bytes read */ - } - if (val) *val = res; - return (const char *)s + 1; /* +1 to include first byte */ +static const char* utf8_decode(const char* o, int* val) +{ + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + const unsigned char* s = (const unsigned char*)o; + unsigned int c = s[0]; + unsigned int res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else + { + int count = 0; /* to count number of continuation bytes */ + while (c & 0x40) + { + /* still have continuation bytes? */ + int cc = s[++count]; /* read next byte */ + if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + c <<= 1; /* to test next bit */ + } + res |= ((c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 3 || res > MAXUNICODE || res <= limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (val) *val = res; + return (const char*)s + 1; /* +1 to include first byte */ } @@ -68,28 +73,32 @@ static const char *utf8_decode (const char *o, int *val) { ** range [i,j], or nil + current position if 's' is not well formed in ** that interval */ -static int utflen (lua_State *L) { - int n = 0; - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, - "initial position out of string"); - luaL_argcheck(L, --posj < (lua_Integer)len, 3, - "final position out of string"); - while (posi <= posj) { - const char *s1 = utf8_decode(s + posi, NULL); - if (s1 == NULL) { /* conversion error? */ - lua_pushnil(L); /* return nil ... */ - lua_pushinteger(L, posi + 1); /* ... and current position */ - return 2; - } - posi = s1 - s; - n++; - } - lua_pushinteger(L, n); - return 1; +static int utflen(lua_State* L) +{ + int n = 0; + size_t len; + const char* s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of string"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of string"); + while (posi <= posj) + { + const char* s1 = utf8_decode(s + posi, NULL); + if (s1 == NULL) + { + /* conversion error? */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; } @@ -97,59 +106,65 @@ static int utflen (lua_State *L) { ** codepoint(s, [i, [j]]) -> returns codepoints for all characters ** that start in the range [i,j] */ -static int codepoint (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); - int n; - const char *se; - luaL_argcheck(L, posi >= 1, 2, "out of range"); - luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); - if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ - return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; - luaL_checkstack(L, n, "string slice too long"); - n = 0; - se = s + pose; - for (s += posi - 1; s < se;) { - int code; - s = utf8_decode(s, &code); - if (s == NULL) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, code); - n++; - } - return n; +static int codepoint(lua_State* L) +{ + size_t len; + const char* s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int n; + const char* se; + luaL_argcheck(L, posi >= 1, 2, "out of range"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + n = 0; + se = s + pose; + for (s += posi - 1; s < se;) + { + int code; + s = utf8_decode(s, &code); + if (s == NULL) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, code); + n++; + } + return n; } -static void pushutfchar (lua_State *L, int arg) { - lua_Integer code = luaL_checkinteger(L, arg); - luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); - lua_pushfstring(L, "%U", (long)code); +static void pushutfchar(lua_State* L, int arg) +{ + lua_Integer code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); } /* ** utfchar(n1, n2, ...) -> char(n1)..char(n2)... */ -static int utfchar (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - if (n == 1) /* optimize common case of single char */ - pushutfchar(L, 1); - else { - int i; - luaL_Buffer b; - luaL_buffinit(L, &b); - for (i = 1; i <= n; i++) { - pushutfchar(L, i); - luaL_addvalue(&b); - } - luaL_pushresult(&b); - } - return 1; +static int utfchar(lua_State* L) +{ + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else + { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) + { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; } @@ -157,77 +172,95 @@ static int utfchar (lua_State *L) { ** offset(s, n, [i]) -> index where n-th character counting from ** position 'i' starts; 0 means character at 'i'. */ -static int byteoffset (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = luaL_checkinteger(L, 2); - lua_Integer posi = (n >= 0) ? 1 : len + 1; - posi = u_posrelat(luaL_optinteger(L, 3, posi), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, - "position out of range"); - if (n == 0) { - /* find beginning of current byte sequence */ - while (posi > 0 && iscont(s + posi)) posi--; - } - else { - if (iscont(s + posi)) - luaL_error(L, "initial position is a continuation byte"); - if (n < 0) { - while (n < 0 && posi > 0) { /* move back */ - do { /* find beginning of previous character */ - posi--; - } while (posi > 0 && iscont(s + posi)); - n++; - } - } - else { - n--; /* do not move for 1st character */ - while (n > 0 && posi < (lua_Integer)len) { - do { /* find beginning of next character */ - posi++; - } while (iscont(s + posi)); /* (cannot pass final '\0') */ - n--; - } - } - } - if (n == 0) /* did it find given character? */ - lua_pushinteger(L, posi + 1); - else /* no such character */ - lua_pushnil(L); - return 1; +static int byteoffset(lua_State* L) +{ + size_t len; + const char* s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of range"); + if (n == 0) + { + /* find beginning of current byte sequence */ + while (posi > 0 && iscont(s + posi)) posi--; + } + else + { + if (iscont(s + posi)) + luaL_error(L, "initial position is a continuation byte"); + if (n < 0) + { + while (n < 0 && posi > 0) + { + /* move back */ + do + { + /* find beginning of previous character */ + posi--; + } + while (posi > 0 && iscont(s + posi)); + n++; + } + } + else + { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) + { + do + { + /* find beginning of next character */ + posi++; + } + while (iscont(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + lua_pushnil(L); + return 1; } -static int iter_aux (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = lua_tointeger(L, 2) - 1; - if (n < 0) /* first iteration? */ - n = 0; /* start from here */ - else if (n < (lua_Integer)len) { - n++; /* skip current byte */ - while (iscont(s + n)) n++; /* and its continuations */ - } - if (n >= (lua_Integer)len) - return 0; /* no more codepoints */ - else { - int code; - const char *next = utf8_decode(s + n, &code); - if (next == NULL || iscont(next)) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, n + 1); - lua_pushinteger(L, code); - return 2; - } +static int iter_aux(lua_State* L) +{ + size_t len; + const char* s = luaL_checklstring(L, 1, &len); + lua_Integer n = lua_tointeger(L, 2) - 1; + if (n < 0) /* first iteration? */ + n = 0; /* start from here */ + else if (n < (lua_Integer)len) + { + n++; /* skip current byte */ + while (iscont(s + n)) n++; /* and its continuations */ + } + if (n >= (lua_Integer)len) + return 0; /* no more codepoints */ + else + { + int code; + const char* next = utf8_decode(s + n, &code); + if (next == NULL || iscont(next)) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } } -static int iter_codes (lua_State *L) { - luaL_checkstring(L, 1); - lua_pushcfunction(L, iter_aux); - lua_pushvalue(L, 1); - lua_pushinteger(L, 0); - return 3; +static int iter_codes(lua_State* L) +{ + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; } @@ -236,21 +269,21 @@ static int iter_codes (lua_State *L) { static const luaL_Reg funcs[] = { - {"offset", byteoffset}, - {"codepoint", codepoint}, - {"char", utfchar}, - {"len", utflen}, - {"codes", iter_codes}, - /* placeholders */ - {"charpattern", NULL}, - {NULL, NULL} + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} }; -LUAMOD_API int luaopen_utf8 (lua_State *L) { - luaL_newlib(L, funcs); - lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); - lua_setfield(L, -2, "charpattern"); - return 1; +LUAMOD_API int luaopen_utf8(lua_State* L) +{ + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT) / sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; } - diff --git a/Lua/lvm.c b/Lua/lvm.c index 84ade6b..7f6d84c 100644 --- a/Lua/lvm.c +++ b/Lua/lvm.c @@ -35,7 +35,6 @@ #define MAXTAGLOOP 2000 - /* ** 'l_intfitsf' checks whether a given integer can be converted to a ** float without rounding. Used in comparisons. Left undefined if @@ -64,24 +63,26 @@ #endif - /* ** Try to convert a value to a float. The float case is already handled ** by the macro 'tonumber'. */ -int luaV_tonumber_ (const TValue *obj, lua_Number *n) { - TValue v; - if (ttisinteger(obj)) { - *n = cast_num(ivalue(obj)); - return 1; - } - else if (cvt2num(obj) && /* string convertible to number? */ - luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { - *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ - return 1; - } - else - return 0; /* conversion failed */ +int luaV_tonumber_(const TValue* obj, lua_Number* n) +{ + TValue v; + if (ttisinteger(obj)) + { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (cvt2num(obj) && /* string convertible to number? */ + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) + { + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ + return 1; + } + else + return 0; /* conversion failed */ } @@ -91,29 +92,35 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { ** mode == 1: takes the floor of the number ** mode == 2: takes the ceil of the number */ -int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { - TValue v; - again: - if (ttisfloat(obj)) { - lua_Number n = fltvalue(obj); - lua_Number f = l_floor(n); - if (n != f) { /* not an integral value? */ - if (mode == 0) return 0; /* fails if mode demands integral value */ - else if (mode > 1) /* needs ceil? */ - f += 1; /* convert floor to ceil (remember: n != f) */ - } - return lua_numbertointeger(f, p); - } - else if (ttisinteger(obj)) { - *p = ivalue(obj); - return 1; - } - else if (cvt2num(obj) && - luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { - obj = &v; - goto again; /* convert result from 'luaO_str2num' to an integer */ - } - return 0; /* conversion failed */ +int luaV_tointeger(const TValue* obj, lua_Integer* p, int mode) +{ + TValue v; +again: + if (ttisfloat(obj)) + { + lua_Number n = fltvalue(obj); + lua_Number f = l_floor(n); + if (n != f) + { + /* not an integral value? */ + if (mode == 0) return 0; /* fails if mode demands integral value */ + else if (mode > 1) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); + } + else if (ttisinteger(obj)) + { + *p = ivalue(obj); + return 1; + } + else if (cvt2num(obj) && + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) + { + obj = &v; + goto again; /* convert result from 'luaO_str2num' to an integer */ + } + return 0; /* conversion failed */ } @@ -132,23 +139,30 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { ** the extreme case when the initial value is LUA_MININTEGER, in which ** case the LUA_MININTEGER limit would still run the loop once. */ -static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, - int *stopnow) { - *stopnow = 0; /* usually, let loops run */ - if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ - lua_Number n; /* try to convert to float */ - if (!tonumber(obj, &n)) /* cannot convert to float? */ - return 0; /* not a number */ - if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ - *p = LUA_MAXINTEGER; - if (step < 0) *stopnow = 1; - } - else { /* float is smaller than min integer */ - *p = LUA_MININTEGER; - if (step >= 0) *stopnow = 1; - } - } - return 1; +static int forlimit(const TValue* obj, lua_Integer* p, lua_Integer step, + int* stopnow) +{ + *stopnow = 0; /* usually, let loops run */ + if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) + { + /* not fit in integer? */ + lua_Number n; /* try to convert to float */ + if (!tonumber(obj, &n)) /* cannot convert to float? */ + return 0; /* not a number */ + if (luai_numlt(0, n)) + { + /* if true, float is larger than max integer */ + *p = LUA_MAXINTEGER; + if (step < 0) *stopnow = 1; + } + else + { + /* float is smaller than min integer */ + *p = LUA_MININTEGER; + if (step >= 0) *stopnow = 1; + } + } + return 1; } @@ -157,39 +171,51 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to ** t[k] entry (which must be nil). */ -void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, - const TValue *slot) { - int loop; /* counter to avoid infinite loops */ - const TValue *tm; /* metamethod */ - for (loop = 0; loop < MAXTAGLOOP; loop++) { - if (slot == NULL) { /* 't' is not a table? */ - lua_assert(!ttistable(t)); - tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) - luaG_typeerror(L, t, "index"); /* no metamethod */ - /* else will try the metamethod */ - } - else { /* 't' is a table */ - lua_assert(ttisnil(slot)); - tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ - if (tm == NULL) { /* no metamethod? */ - setnilvalue(val); /* result is nil */ - return; - } - /* else will try the metamethod */ - } - if (ttisfunction(tm)) { /* is metamethod a function? */ - luaT_callTM(L, tm, t, key, val, 1); /* call it */ - return; - } - t = tm; /* else try to access 'tm[key]' */ - if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ - setobj2s(L, val, slot); /* done */ - return; - } - /* else repeat (tail call 'luaV_finishget') */ - } - luaG_runerror(L, "'__index' chain too long; possible loop"); +void luaV_finishget(lua_State* L, const TValue* t, TValue* key, StkId val, + const TValue* slot) +{ + int loop; /* counter to avoid infinite loops */ + const TValue* tm; /* metamethod */ + for (loop = 0; loop < MAXTAGLOOP; loop++) + { + if (slot == NULL) + { + /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (ttisnil(tm)) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else + { + /* 't' is a table */ + lua_assert(ttisnil(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) + { + /* no metamethod? */ + setnilvalue(val); /* result is nil */ + return; + } + /* else will try the metamethod */ + } + if (ttisfunction(tm)) + { + /* is metamethod a function? */ + luaT_callTM(L, tm, t, key, val, 1); /* call it */ + return; + } + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L, t, key, slot, luaH_get)) + { + /* fast track? */ + setobj2s(L, val, slot); /* done */ + return; + } + /* else repeat (tail call 'luaV_finishget') */ + } + luaG_runerror(L, "'__index' chain too long; possible loop"); } @@ -200,41 +226,50 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' ** would have done the job.) */ -void luaV_finishset (lua_State *L, const TValue *t, TValue *key, - StkId val, const TValue *slot) { - int loop; /* counter to avoid infinite loops */ - for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; /* '__newindex' metamethod */ - if (slot != NULL) { /* is 't' a table? */ - Table *h = hvalue(t); /* save 't' table */ - lua_assert(ttisnil(slot)); /* old value must be nil */ - tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ - if (tm == NULL) { /* no metamethod? */ - if (slot == luaO_nilobject) /* no previous entry? */ - slot = luaH_newkey(L, h, key); /* create one */ - /* no metamethod and (now) there is an entry with given key */ - setobj2t(L, cast(TValue *, slot), val); /* set its new value */ - invalidateTMcache(h); - luaC_barrierback(L, h, val); - return; - } - /* else will try the metamethod */ - } - else { /* not a table; check metamethod */ - if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) - luaG_typeerror(L, t, "index"); - } - /* try the metamethod */ - if (ttisfunction(tm)) { - luaT_callTM(L, tm, t, key, val, 0); - return; - } - t = tm; /* else repeat assignment over 'tm' */ - if (luaV_fastset(L, t, key, slot, luaH_get, val)) - return; /* done */ - /* else loop */ - } - luaG_runerror(L, "'__newindex' chain too long; possible loop"); +void luaV_finishset(lua_State* L, const TValue* t, TValue* key, + StkId val, const TValue* slot) +{ + int loop; /* counter to avoid infinite loops */ + for (loop = 0; loop < MAXTAGLOOP; loop++) + { + const TValue* tm; /* '__newindex' metamethod */ + if (slot != NULL) + { + /* is 't' a table? */ + Table* h = hvalue(t); /* save 't' table */ + lua_assert(ttisnil(slot)); /* old value must be nil */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) + { + /* no metamethod? */ + if (slot == luaO_nilobject) /* no previous entry? */ + slot = luaH_newkey(L, h, key); /* create one */ + /* no metamethod and (now) there is an entry with given key */ + setobj2t(L, cast(TValue *, slot), val); /* set its new value */ + invalidateTMcache(h); + luaC_barrierback(L, h, val); + return; + } + /* else will try the metamethod */ + } + else + { + /* not a table; check metamethod */ + if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + luaG_typeerror(L, t, "index"); + } + /* try the metamethod */ + if (ttisfunction(tm)) + { + luaT_callTM(L, tm, t, key, val, 0); + return; + } + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastset(L, t, key, slot, luaH_get, val)) + return; /* done */ + /* else loop */ + } + luaG_runerror(L, "'__newindex' chain too long; possible loop"); } @@ -245,26 +280,34 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, ** and it uses 'strcoll' (to respect locales) for each segments ** of the strings. */ -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = tsslen(ls); - const char *r = getstr(rs); - size_t lr = tsslen(rs); - for (;;) { /* for each segment */ - int temp = strcoll(l, r); - if (temp != 0) /* not equal? */ - return temp; /* done */ - else { /* strings are equal up to a '\0' */ - size_t len = strlen(l); /* index of first '\0' in both strings */ - if (len == lr) /* 'rs' is finished? */ - return (len == ll) ? 0 : 1; /* check 'ls' */ - else if (len == ll) /* 'ls' is finished? */ - return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ - /* both strings longer than 'len'; go on comparing after the '\0' */ - len++; - l += len; ll -= len; r += len; lr -= len; - } - } +static int l_strcmp(const TString* ls, const TString* rs) +{ + const char* l = getstr(ls); + size_t ll = tsslen(ls); + const char* r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) + { + /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else + { + /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; + ll -= len; + r += len; + lr -= len; + } + } } @@ -278,18 +321,20 @@ static int l_strcmp (const TString *ls, const TString *rs) { ** truncated is irrelevant.) When 'f' is NaN, comparisons must result ** in false. */ -static int LTintfloat (lua_Integer i, lua_Number f) { +static int LTintfloat(lua_Integer i, lua_Number f) +{ #if defined(l_intfitsf) - if (!l_intfitsf(i)) { - if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ - return 1; /* f >= maxint + 1 > i */ - else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ - return (i < cast(lua_Integer, f)); /* compare them as integers */ - else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ - return 0; - } + if (!l_intfitsf(i)) + { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ + return (i < cast(lua_Integer, f)); /* compare them as integers */ + else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ + return 0; + } #endif - return luai_numlt(cast_num(i), f); /* compare them as floats */ + return luai_numlt(cast_num(i), f); /* compare them as floats */ } @@ -297,79 +342,88 @@ static int LTintfloat (lua_Integer i, lua_Number f) { ** Check whether integer 'i' is less than or equal to float 'f'. ** See comments on previous function. */ -static int LEintfloat (lua_Integer i, lua_Number f) { +static int LEintfloat(lua_Integer i, lua_Number f) +{ #if defined(l_intfitsf) - if (!l_intfitsf(i)) { - if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ - return 1; /* f >= maxint + 1 > i */ - else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ - return (i <= cast(lua_Integer, f)); /* compare them as integers */ - else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ - return 0; - } + if (!l_intfitsf(i)) + { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ + return (i <= cast(lua_Integer, f)); /* compare them as integers */ + else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ + return 0; + } #endif - return luai_numle(cast_num(i), f); /* compare them as floats */ + return luai_numle(cast_num(i), f); /* compare them as floats */ } /* ** Return 'l < r', for numbers. */ -static int LTnum (const TValue *l, const TValue *r) { - if (ttisinteger(l)) { - lua_Integer li = ivalue(l); - if (ttisinteger(r)) - return li < ivalue(r); /* both are integers */ - else /* 'l' is int and 'r' is float */ - return LTintfloat(li, fltvalue(r)); /* l < r ? */ - } - else { - lua_Number lf = fltvalue(l); /* 'l' must be float */ - if (ttisfloat(r)) - return luai_numlt(lf, fltvalue(r)); /* both are float */ - else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ - return 0; /* NaN < i is always false */ - else /* without NaN, (l < r) <--> not(r <= l) */ - return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ - } +static int LTnum(const TValue* l, const TValue* r) +{ + if (ttisinteger(l)) + { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li < ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LTintfloat(li, fltvalue(r)); /* l < r ? */ + } + else + { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numlt(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN < i is always false */ + else /* without NaN, (l < r) <--> not(r <= l) */ + return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ + } } /* ** Return 'l <= r', for numbers. */ -static int LEnum (const TValue *l, const TValue *r) { - if (ttisinteger(l)) { - lua_Integer li = ivalue(l); - if (ttisinteger(r)) - return li <= ivalue(r); /* both are integers */ - else /* 'l' is int and 'r' is float */ - return LEintfloat(li, fltvalue(r)); /* l <= r ? */ - } - else { - lua_Number lf = fltvalue(l); /* 'l' must be float */ - if (ttisfloat(r)) - return luai_numle(lf, fltvalue(r)); /* both are float */ - else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ - return 0; /* NaN <= i is always false */ - else /* without NaN, (l <= r) <--> not(r < l) */ - return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ - } +static int LEnum(const TValue* l, const TValue* r) +{ + if (ttisinteger(l)) + { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li <= ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LEintfloat(li, fltvalue(r)); /* l <= r ? */ + } + else + { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numle(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN <= i is always false */ + else /* without NaN, (l <= r) <--> not(r < l) */ + return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ + } } /* ** Main operation less than; return 'l < r'. */ -int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { - int res; - if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ - return LTnum(l, r); - else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ - return l_strcmp(tsvalue(l), tsvalue(r)) < 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ - luaG_ordererror(L, l, r); /* error */ - return res; +int luaV_lessthan(lua_State* L, const TValue* l, const TValue* r) +{ + int res; + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ + luaG_ordererror(L, l, r); /* error */ + return res; } @@ -381,22 +435,25 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { ** about it (to negate the result of r= 0) /* try 'le' */ - return res; - else { /* try 'lt': */ - L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ - res = luaT_callorderTM(L, r, l, TM_LT); - L->ci->callstatus ^= CIST_LEQ; /* clear mark */ - if (res < 0) - luaG_ordererror(L, l, r); - return !res; /* result is negated */ - } +int luaV_lessequal(lua_State* L, const TValue* l, const TValue* r) +{ + int res; + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LEnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ + return res; + else + { + /* try 'lt': */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + res = luaT_callorderTM(L, r, l, TM_LT); + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + if (res < 0) + luaG_ordererror(L, l, r); + return !res; /* result is negated */ + } } @@ -404,49 +461,57 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { ** Main operation for equality of Lua values; return 't1 == t2'. ** L == NULL means raw equality (no metamethods) */ -int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { - const TValue *tm; - if (ttype(t1) != ttype(t2)) { /* not the same variant? */ - if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) - return 0; /* only numbers can be equal with different variants */ - else { /* two numbers with different variants */ - lua_Integer i1, i2; /* compare them as integers */ - return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); - } - } - /* values have same type and same variant */ - switch (ttype(t1)) { - case LUA_TNIL: return 1; - case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); - case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); - case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ - case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); - case LUA_TLCF: return fvalue(t1) == fvalue(t2); - case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); - case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); - case LUA_TUSERDATA: { - if (uvalue(t1) == uvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - case LUA_TTABLE: { - if (hvalue(t1) == hvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - default: - return gcvalue(t1) == gcvalue(t2); - } - if (tm == NULL) /* no TM? */ - return 0; /* objects are different */ - luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ - return !l_isfalse(L->top); +int luaV_equalobj(lua_State* L, const TValue* t1, const TValue* t2) +{ + const TValue* tm; + if (ttype(t1) != ttype(t2)) + { + /* not the same variant? */ + if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else + { + /* two numbers with different variants */ + lua_Integer i1, i2; /* compare them as integers */ + return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); + } + } + /* values have same type and same variant */ + switch (ttype(t1)) + { + case LUA_TNIL: return 1; + case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); + case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); + case LUA_TUSERDATA: + { + if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: + { + if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: + return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ + return !l_isfalse(L->top); } @@ -457,13 +522,16 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { #define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) /* copy strings in stack from top - n up to top - 1 to buffer */ -static void copy2buff (StkId top, int n, char *buff) { - size_t tl = 0; /* size already copied */ - do { - size_t l = vslen(top - n); /* length of string being copied */ - memcpy(buff + tl, svalue(top - n), l * sizeof(char)); - tl += l; - } while (--n > 0); +static void copy2buff(StkId top, int n, char* buff) +{ + size_t tl = 0; /* size already copied */ + do + { + size_t l = vslen(top - n); /* length of string being copied */ + memcpy(buff + tl, svalue(top - n), l * sizeof(char)); + tl += l; + } + while (--n > 0); } @@ -471,75 +539,93 @@ static void copy2buff (StkId top, int n, char *buff) { ** Main operation for concatenation: concat 'total' values in the stack, ** from 'L->top - total' up to 'L->top - 1'. */ -void luaV_concat (lua_State *L, int total) { - lua_assert(total >= 2); - do { - StkId top = L->top; - int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) - luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); - else if (isemptystr(top - 1)) /* second operand is empty? */ - cast_void(tostring(L, top - 2)); /* result is first operand */ - else if (isemptystr(top - 2)) { /* first operand is an empty string? */ - setobjs2s(L, top - 2, top - 1); /* result is second op. */ - } - else { - /* at least two non-empty string values; get as many as possible */ - size_t tl = vslen(top - 1); - TString *ts; - /* collect total length and number of strings */ - for (n = 1; n < total && tostring(L, top - n - 1); n++) { - size_t l = vslen(top - n - 1); - if (l >= (MAX_SIZE/sizeof(char)) - tl) - luaG_runerror(L, "string length overflow"); - tl += l; - } - if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ - char buff[LUAI_MAXSHORTLEN]; - copy2buff(top, n, buff); /* copy strings to buffer */ - ts = luaS_newlstr(L, buff, tl); - } - else { /* long string; copy strings directly to final result */ - ts = luaS_createlngstrobj(L, tl); - copy2buff(top, n, getstr(ts)); - } - setsvalue2s(L, top - n, ts); /* create result */ - } - total -= n-1; /* got 'n' strings to create 1 new */ - L->top -= n-1; /* popped 'n' strings and pushed one */ - } while (total > 1); /* repeat until only 1 result left */ +void luaV_concat(lua_State* L, int total) +{ + lua_assert(total >= 2); + do + { + StkId top = L->top; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) + luaT_trybinTM(L, top - 2, top - 1, top - 2, TM_CONCAT); + else if (isemptystr(top - 1)) /* second operand is empty? */ + cast_void(tostring(L, top - 2)); /* result is first operand */ + else if (isemptystr(top - 2)) + { + /* first operand is an empty string? */ + setobjs2s(L, top - 2, top - 1); /* result is second op. */ + } + else + { + /* at least two non-empty string values; get as many as possible */ + size_t tl = vslen(top - 1); + TString* ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, top - n - 1); n++) + { + size_t l = vslen(top - n - 1); + if (l >= (MAX_SIZE / sizeof(char)) - tl) + luaG_runerror(L, "string length overflow"); + tl += l; + } + if (tl <= LUAI_MAXSHORTLEN) + { + /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else + { + /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ + } + total -= n - 1; /* got 'n' strings to create 1 new */ + L->top -= n - 1; /* popped 'n' strings and pushed one */ + } + while (total > 1); /* repeat until only 1 result left */ } /* ** Main operation 'ra' = #rb'. */ -void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { - const TValue *tm; - switch (ttype(rb)) { - case LUA_TTABLE: { - Table *h = hvalue(rb); - tm = fasttm(L, h->metatable, TM_LEN); - if (tm) break; /* metamethod? break switch to call it */ - setivalue(ra, luaH_getn(h)); /* else primitive len */ - return; - } - case LUA_TSHRSTR: { - setivalue(ra, tsvalue(rb)->shrlen); - return; - } - case LUA_TLNGSTR: { - setivalue(ra, tsvalue(rb)->u.lnglen); - return; - } - default: { /* try metamethod */ - tm = luaT_gettmbyobj(L, rb, TM_LEN); - if (ttisnil(tm)) /* no metamethod? */ - luaG_typeerror(L, rb, "get length of"); - break; - } - } - luaT_callTM(L, tm, rb, rb, ra, 1); +void luaV_objlen(lua_State* L, StkId ra, const TValue* rb) +{ + const TValue* tm; + switch (ttype(rb)) + { + case LUA_TTABLE: + { + Table* h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setivalue(ra, luaH_getn(h)); /* else primitive len */ + return; + } + case LUA_TSHRSTR: + { + setivalue(ra, tsvalue(rb)->shrlen); + return; + } + case LUA_TLNGSTR: + { + setivalue(ra, tsvalue(rb)->u.lnglen); + return; + } + default: + { + /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (ttisnil(tm)) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + luaT_callTM(L, tm, rb, rb, ra, 1); } @@ -549,18 +635,22 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { ** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, ** otherwise 'floor(q) == trunc(q) - 1'. */ -lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { - if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) - luaG_runerror(L, "attempt to divide by zero"); - return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ - } - else { - lua_Integer q = m / n; /* perform C division */ - if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ - q -= 1; /* correct result for different rounding */ - return q; - } +lua_Integer luaV_div(lua_State* L, lua_Integer m, lua_Integer n) +{ + if (l_castS2U(n) + 1u <= 1u) + { + /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else + { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } } @@ -569,18 +659,22 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { ** negative operands follows C99 behavior. See previous comment ** about luaV_div.) */ -lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { - if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) - luaG_runerror(L, "attempt to perform 'n%%0'"); - return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ - } - else { - lua_Integer r = m % n; - if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ - r += n; /* correct result for different rounding */ - return r; - } +lua_Integer luaV_mod(lua_State* L, lua_Integer m, lua_Integer n) +{ + if (l_castS2U(n) + 1u <= 1u) + { + /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else + { + lua_Integer r = m % n; + if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } } @@ -590,15 +684,20 @@ lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { /* ** Shift left operation. (Shift right just negates 'y'.) */ -lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { - if (y < 0) { /* shift right? */ - if (y <= -NBITS) return 0; - else return intop(>>, x, -y); - } - else { /* shift left */ - if (y >= NBITS) return 0; - else return intop(<<, x, y); - } +lua_Integer luaV_shiftl(lua_Integer x, lua_Integer y) +{ + if (y < 0) + { + /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else + { + /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); + } } @@ -607,19 +706,24 @@ lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { ** whether there is a cached closure with the same upvalues needed by ** new closure to be created. */ -static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { - LClosure *c = p->cache; - if (c != NULL) { /* is there a cached closure? */ - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; - int i; - for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ - TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; - if (c->upvals[i]->v != v) - return NULL; /* wrong upvalue; cannot reuse closure */ - } - } - return c; /* return cached closure (or NULL if no cached closure) */ +static LClosure* getcached(Proto* p, UpVal** encup, StkId base) +{ + LClosure* c = p->cache; + if (c != NULL) + { + /* is there a cached closure? */ + int nup = p->sizeupvalues; + Upvaldesc* uv = p->upvalues; + int i; + for (i = 0; i < nup; i++) + { + /* check whether it has right upvalues */ + TValue* v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; + if (c->upvals[i]->v != v) + return NULL; /* wrong upvalue; cannot reuse closure */ + } + } + return c; /* return cached closure (or NULL if no cached closure) */ } @@ -629,90 +733,120 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { ** already black (which means that 'cache' was already cleared by the ** GC). */ -static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, - StkId ra) { - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; - int i; - LClosure *ncl = luaF_newLclosure(L, nup); - ncl->p = p; - setclLvalue(L, ra, ncl); /* anchor new closure in stack */ - for (i = 0; i < nup; i++) { /* fill in its upvalues */ - if (uv[i].instack) /* upvalue refers to local variable? */ - ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); - else /* get upvalue from enclosing function */ - ncl->upvals[i] = encup[uv[i].idx]; - ncl->upvals[i]->refcount++; - /* new closure is white, so we do not need a barrier here */ - } - if (!isblack(p)) /* cache will not break GC invariant? */ - p->cache = ncl; /* save it on cache for reuse */ +static void pushclosure(lua_State* L, Proto* p, UpVal** encup, StkId base, + StkId ra) +{ + int nup = p->sizeupvalues; + Upvaldesc* uv = p->upvalues; + int i; + LClosure* ncl = luaF_newLclosure(L, nup); + ncl->p = p; + setclLvalue(L, ra, ncl); /* anchor new closure in stack */ + for (i = 0; i < nup; i++) + { + /* fill in its upvalues */ + if (uv[i].instack) /* upvalue refers to local variable? */ + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); + else /* get upvalue from enclosing function */ + ncl->upvals[i] = encup[uv[i].idx]; + ncl->upvals[i]->refcount++; + /* new closure is white, so we do not need a barrier here */ + } + if (!isblack(p)) /* cache will not break GC invariant? */ + p->cache = ncl; /* save it on cache for reuse */ } /* ** finish execution of an opcode interrupted by an yield */ -void luaV_finishOp (lua_State *L) { - CallInfo *ci = L->ci; - StkId base = ci->u.l.base; - Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ - OpCode op = GET_OPCODE(inst); - switch (op) { /* finish its execution */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: - case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: - case OP_MOD: case OP_POW: - case OP_UNM: case OP_BNOT: case OP_LEN: - case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { - setobjs2s(L, base + GETARG_A(inst), --L->top); - break; - } - case OP_LE: case OP_LT: case OP_EQ: { - int res = !l_isfalse(L->top - 1); - L->top--; - if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ - lua_assert(op == OP_LE); - ci->callstatus ^= CIST_LEQ; /* clear mark */ - res = !res; /* negate result */ - } - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); - if (res != GETARG_A(inst)) /* condition failed? */ - ci->u.l.savedpc++; /* skip jump instruction */ - break; - } - case OP_CONCAT: { - StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ - int b = GETARG_B(inst); /* first element to concatenate */ - int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ - setobj2s(L, top - 2, top); /* put TM result in proper position */ - if (total > 1) { /* are there elements to concat? */ - L->top = top - 1; /* top is one after last element (at top-2) */ - luaV_concat(L, total); /* concat them (may yield again) */ - } - /* move final result to final position */ - setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); - L->top = ci->top; /* restore top */ - break; - } - case OP_TFORCALL: { - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); - L->top = ci->top; /* correct top */ - break; - } - case OP_CALL: { - if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ - L->top = ci->top; /* adjust results */ - break; - } - case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: - break; - default: lua_assert(0); - } +void luaV_finishOp(lua_State* L) +{ + CallInfo* ci = L->ci; + StkId base = ci->u.l.base; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + switch (op) + { + /* finish its execution */ + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_IDIV: + case OP_BAND: + case OP_BOR: + case OP_BXOR: + case OP_SHL: + case OP_SHR: + case OP_MOD: + case OP_POW: + case OP_UNM: + case OP_BNOT: + case OP_LEN: + case OP_GETTABUP: + case OP_GETTABLE: + case OP_SELF: + { + setobjs2s(L, base + GETARG_A(inst), --L->top); + break; + } + case OP_LE: + case OP_LT: + case OP_EQ: + { + int res = !l_isfalse(L->top - 1); + L->top--; + if (ci->callstatus & CIST_LEQ) + { + /* "<=" using "<" instead? */ + lua_assert(op == OP_LE); + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_A(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: + { + StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ + int b = GETARG_B(inst); /* first element to concatenate */ + int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ + setobj2s(L, top - 2, top); /* put TM result in proper position */ + if (total > 1) + { + /* are there elements to concat? */ + L->top = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + } + /* move final result to final position */ + setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); + L->top = ci->top; /* restore top */ + break; + } + case OP_TFORCALL: + { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); + L->top = ci->top; /* correct top */ + break; + } + case OP_CALL: + { + if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ + L->top = ci->top; /* adjust results */ + break; + } + case OP_TAILCALL: + case OP_SETTABUP: + case OP_SETTABLE: + break; + default: lua_assert(0); + } } - - /* ** {================================================================== ** Function 'luaV_execute': main interpreter loop @@ -782,541 +916,661 @@ void luaV_finishOp (lua_State *L) { Protect(luaV_finishset(L,t,k,v,slot)); } - -void luaV_execute (lua_State *L) { - CallInfo *ci = L->ci; - LClosure *cl; - TValue *k; - StkId base; - ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ - newframe: /* reentry point when frame changes (call/return) */ - lua_assert(ci == L->ci); - cl = clLvalue(ci->func); /* local reference to function's closure */ - k = cl->p->k; /* local reference to function's constant table */ - base = ci->u.l.base; /* local copy of function's base */ - /* main loop of interpreter */ - for (;;) { - Instruction i; - StkId ra; - vmfetch(); - vmdispatch (GET_OPCODE(i)) { - vmcase(OP_MOVE) { - setobjs2s(L, ra, RB(i)); - vmbreak; - } - vmcase(OP_LOADK) { - TValue *rb = k + GETARG_Bx(i); - setobj2s(L, ra, rb); - vmbreak; - } - vmcase(OP_LOADKX) { - TValue *rb; - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); - rb = k + GETARG_Ax(*ci->u.l.savedpc++); - setobj2s(L, ra, rb); - vmbreak; - } - vmcase(OP_LOADBOOL) { - setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - vmbreak; - } - vmcase(OP_LOADNIL) { - int b = GETARG_B(i); - do { - setnilvalue(ra++); - } while (b--); - vmbreak; - } - vmcase(OP_GETUPVAL) { - int b = GETARG_B(i); - setobj2s(L, ra, cl->upvals[b]->v); - vmbreak; - } - vmcase(OP_GETTABUP) { - TValue *upval = cl->upvals[GETARG_B(i)]->v; - TValue *rc = RKC(i); - gettableProtected(L, upval, rc, ra); - vmbreak; - } - vmcase(OP_GETTABLE) { - StkId rb = RB(i); - TValue *rc = RKC(i); - gettableProtected(L, rb, rc, ra); - vmbreak; - } - vmcase(OP_SETTABUP) { - TValue *upval = cl->upvals[GETARG_A(i)]->v; - TValue *rb = RKB(i); - TValue *rc = RKC(i); - settableProtected(L, upval, rb, rc); - vmbreak; - } - vmcase(OP_SETUPVAL) { - UpVal *uv = cl->upvals[GETARG_B(i)]; - setobj(L, uv->v, ra); - luaC_upvalbarrier(L, uv); - vmbreak; - } - vmcase(OP_SETTABLE) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - settableProtected(L, ra, rb, rc); - vmbreak; - } - vmcase(OP_NEWTABLE) { - int b = GETARG_B(i); - int c = GETARG_C(i); - Table *t = luaH_new(L); - sethvalue(L, ra, t); - if (b != 0 || c != 0) - luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - checkGC(L, ra + 1); - vmbreak; - } - vmcase(OP_SELF) { - const TValue *aux; - StkId rb = RB(i); - TValue *rc = RKC(i); - TString *key = tsvalue(rc); /* key must be a string */ - setobjs2s(L, ra + 1, rb); - if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { - setobj2s(L, ra, aux); - } - else Protect(luaV_finishget(L, rb, rc, ra, aux)); - vmbreak; - } - vmcase(OP_ADD) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(+, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numadd(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } - vmbreak; - } - vmcase(OP_SUB) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(-, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numsub(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } - vmbreak; - } - vmcase(OP_MUL) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(*, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_nummul(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } - vmbreak; - } - vmcase(OP_DIV) { /* float division (always with floats) */ - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numdiv(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } - vmbreak; - } - vmcase(OP_BAND) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(&, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } - vmbreak; - } - vmcase(OP_BOR) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(|, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } - vmbreak; - } - vmcase(OP_BXOR) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(^, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } - vmbreak; - } - vmcase(OP_SHL) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, luaV_shiftl(ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } - vmbreak; - } - vmcase(OP_SHR) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, luaV_shiftl(ib, -ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } - vmbreak; - } - vmcase(OP_MOD) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, luaV_mod(L, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - lua_Number m; - luai_nummod(L, nb, nc, m); - setfltvalue(ra, m); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } - vmbreak; - } - vmcase(OP_IDIV) { /* floor division */ - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, luaV_div(L, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numidiv(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } - vmbreak; - } - vmcase(OP_POW) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numpow(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } - vmbreak; - } - vmcase(OP_UNM) { - TValue *rb = RB(i); - lua_Number nb; - if (ttisinteger(rb)) { - lua_Integer ib = ivalue(rb); - setivalue(ra, intop(-, 0, ib)); - } - else if (tonumber(rb, &nb)) { - setfltvalue(ra, luai_numunm(L, nb)); - } - else { - Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); - } - vmbreak; - } - vmcase(OP_BNOT) { - TValue *rb = RB(i); - lua_Integer ib; - if (tointeger(rb, &ib)) { - setivalue(ra, intop(^, ~l_castS2U(0), ib)); - } - else { - Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); - } - vmbreak; - } - vmcase(OP_NOT) { - TValue *rb = RB(i); - int res = l_isfalse(rb); /* next assignment may change this value */ - setbvalue(ra, res); - vmbreak; - } - vmcase(OP_LEN) { - Protect(luaV_objlen(L, ra, RB(i))); - vmbreak; - } - vmcase(OP_CONCAT) { - int b = GETARG_B(i); - int c = GETARG_C(i); - StkId rb; - L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c - b + 1)); - ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ - rb = base + b; - setobjs2s(L, ra, rb); - checkGC(L, (ra >= rb ? ra + 1 : rb)); - L->top = ci->top; /* restore top */ - vmbreak; - } - vmcase(OP_JMP) { - dojump(ci, i, 0); - vmbreak; - } - vmcase(OP_EQ) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - Protect( - if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - vmbreak; - } - vmcase(OP_LT) { - Protect( - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - vmbreak; - } - vmcase(OP_LE) { - Protect( - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - vmbreak; - } - vmcase(OP_TEST) { - if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) - ci->u.l.savedpc++; - else - donextjump(ci); - vmbreak; - } - vmcase(OP_TESTSET) { - TValue *rb = RB(i); - if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) - ci->u.l.savedpc++; - else { - setobjs2s(L, ra, rb); - donextjump(ci); - } - vmbreak; - } - vmcase(OP_CALL) { - int b = GETARG_B(i); - int nresults = GETARG_C(i) - 1; - if (b != 0) L->top = ra+b; /* else previous instruction set top */ - if (luaD_precall(L, ra, nresults)) { /* C function? */ - if (nresults >= 0) - L->top = ci->top; /* adjust results */ - Protect((void)0); /* update 'base' */ - } - else { /* Lua function */ - ci = L->ci; - goto newframe; /* restart luaV_execute over new Lua function */ - } - vmbreak; - } - vmcase(OP_TAILCALL) { - int b = GETARG_B(i); - if (b != 0) L->top = ra+b; /* else previous instruction set top */ - lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ - Protect((void)0); /* update 'base' */ - } - else { - /* tail call: put called frame (n) in place of caller one (o) */ - CallInfo *nci = L->ci; /* called frame */ - CallInfo *oci = nci->previous; /* caller frame */ - StkId nfunc = nci->func; /* called function */ - StkId ofunc = oci->func; /* caller function */ - /* last stack slot filled by 'precall' */ - StkId lim = nci->u.l.base + getproto(nfunc)->numparams; - int aux; - /* close all upvalues from previous call */ - if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); - /* move new frame into old one */ - for (aux = 0; nfunc + aux < lim; aux++) - setobjs2s(L, ofunc + aux, nfunc + aux); - oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ - oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ - oci->u.l.savedpc = nci->u.l.savedpc; - oci->callstatus |= CIST_TAIL; /* function was tail called */ - ci = L->ci = oci; /* remove new frame */ - lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); - goto newframe; /* restart luaV_execute over new Lua function */ - } - vmbreak; - } - vmcase(OP_RETURN) { - int b = GETARG_B(i); - if (cl->p->sizep > 0) luaF_close(L, base); - b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); - if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ - return; /* external invocation: return */ - else { /* invocation via reentry: continue execution */ - ci = L->ci; - if (b) L->top = ci->top; - lua_assert(isLua(ci)); - lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); - goto newframe; /* restart luaV_execute over new Lua function */ - } - } - vmcase(OP_FORLOOP) { - if (ttisinteger(ra)) { /* integer loop? */ - lua_Integer step = ivalue(ra + 2); - lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ - lua_Integer limit = ivalue(ra + 1); - if ((0 < step) ? (idx <= limit) : (limit <= idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - chgivalue(ra, idx); /* update internal index... */ - setivalue(ra + 3, idx); /* ...and external index */ - } - } - else { /* floating loop */ - lua_Number step = fltvalue(ra + 2); - lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - lua_Number limit = fltvalue(ra + 1); - if (luai_numlt(0, step) ? luai_numle(idx, limit) - : luai_numle(limit, idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - chgfltvalue(ra, idx); /* update internal index... */ - setfltvalue(ra + 3, idx); /* ...and external index */ - } - } - vmbreak; - } - vmcase(OP_FORPREP) { - TValue *init = ra; - TValue *plimit = ra + 1; - TValue *pstep = ra + 2; - lua_Integer ilimit; - int stopnow; - if (ttisinteger(init) && ttisinteger(pstep) && - forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - /* all values are integer */ - lua_Integer initv = (stopnow ? 0 : ivalue(init)); - setivalue(plimit, ilimit); - setivalue(init, intop(-, initv, ivalue(pstep))); - } - else { /* try making all values floats */ - lua_Number ninit; lua_Number nlimit; lua_Number nstep; - if (!tonumber(plimit, &nlimit)) - luaG_runerror(L, "'for' limit must be a number"); - setfltvalue(plimit, nlimit); - if (!tonumber(pstep, &nstep)) - luaG_runerror(L, "'for' step must be a number"); - setfltvalue(pstep, nstep); - if (!tonumber(init, &ninit)) - luaG_runerror(L, "'for' initial value must be a number"); - setfltvalue(init, luai_numsub(L, ninit, nstep)); - } - ci->u.l.savedpc += GETARG_sBx(i); - vmbreak; - } - vmcase(OP_TFORCALL) { - StkId cb = ra + 3; /* call base */ - setobjs2s(L, cb+2, ra+2); - setobjs2s(L, cb+1, ra+1); - setobjs2s(L, cb, ra); - L->top = cb + 3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i))); - L->top = ci->top; - i = *(ci->u.l.savedpc++); /* go to next instruction */ - ra = RA(i); - lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - goto l_tforloop; - } - vmcase(OP_TFORLOOP) { - l_tforloop: - if (!ttisnil(ra + 1)) { /* continue loop? */ - setobjs2s(L, ra, ra + 1); /* save control variable */ - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - } - vmbreak; - } - vmcase(OP_SETLIST) { - int n = GETARG_B(i); - int c = GETARG_C(i); - unsigned int last; - Table *h; - if (n == 0) n = cast_int(L->top - ra) - 1; - if (c == 0) { - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); - c = GETARG_Ax(*ci->u.l.savedpc++); - } - h = hvalue(ra); - last = ((c-1)*LFIELDS_PER_FLUSH) + n; - if (last > h->sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* preallocate it at once */ - for (; n > 0; n--) { - TValue *val = ra+n; - luaH_setint(L, h, last--, val); - luaC_barrierback(L, h, val); - } - L->top = ci->top; /* correct top (in case of previous open call) */ - vmbreak; - } - vmcase(OP_CLOSURE) { - Proto *p = cl->p->p[GETARG_Bx(i)]; - LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ - if (ncl == NULL) /* no match? */ - pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ - else - setclLvalue(L, ra, ncl); /* push cashed closure */ - checkGC(L, ra + 1); - vmbreak; - } - vmcase(OP_VARARG) { - int b = GETARG_B(i) - 1; /* required results */ - int j; - int n = cast_int(base - ci->func) - cl->p->numparams - 1; - if (n < 0) /* less arguments than parameters? */ - n = 0; /* no vararg arguments */ - if (b < 0) { /* B == 0? */ - b = n; /* get all var. arguments */ - Protect(luaD_checkstack(L, n)); - ra = RA(i); /* previous call may change the stack */ - L->top = ra + n; - } - for (j = 0; j < b && j < n; j++) - setobjs2s(L, ra + j, base - n + j); - for (; j < b; j++) /* complete required results with nil */ - setnilvalue(ra + j); - vmbreak; - } - vmcase(OP_EXTRAARG) { - lua_assert(0); - vmbreak; - } - } - } +void luaV_execute(lua_State* L) +{ + CallInfo* ci = L->ci; + LClosure* cl; + TValue* k; + StkId base; + ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ +newframe: /* reentry point when frame changes (call/return) */ + lua_assert(ci == L->ci); + cl = clLvalue(ci->func); /* local reference to function's closure */ + k = cl->p->k; /* local reference to function's constant table */ + base = ci->u.l.base; /* local copy of function's base */ + /* main loop of interpreter */ + for (;;) + { + Instruction i; + StkId ra; + vmfetch(); + vmdispatch(GET_OPCODE(i)) + { + vmcase(OP_MOVE) + { + setobjs2s(L, ra, RB(i)); + vmbreak; + } + vmcase(OP_LOADK) + { + TValue* rb = k + GETARG_Bx(i); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADKX) + { + TValue* rb; + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + rb = k + GETARG_Ax(*ci->u.l.savedpc++); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADBOOL) + { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ + vmbreak; + } + vmcase(OP_LOADNIL) + { + int b = GETARG_B(i); + do + { + setnilvalue(ra++); + } + while (b--); + vmbreak; + } + vmcase(OP_GETUPVAL) + { + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v); + vmbreak; + } + vmcase(OP_GETTABUP) + { + TValue* upval = cl->upvals[GETARG_B(i)]->v; + TValue* rc = RKC(i); + gettableProtected(L, upval, rc, ra); + vmbreak; + } + vmcase(OP_GETTABLE) + { + StkId rb = RB(i); + TValue* rc = RKC(i); + gettableProtected(L, rb, rc, ra); + vmbreak; + } + vmcase(OP_SETTABUP) + { + TValue* upval = cl->upvals[GETARG_A(i)]->v; + TValue* rb = RKB(i); + TValue* rc = RKC(i); + settableProtected(L, upval, rb, rc); + vmbreak; + } + vmcase(OP_SETUPVAL) + { + UpVal* uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_upvalbarrier(L, uv); + vmbreak; + } + vmcase(OP_SETTABLE) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + settableProtected(L, ra, rb, rc); + vmbreak; + } + vmcase(OP_NEWTABLE) + { + int b = GETARG_B(i); + int c = GETARG_C(i); + Table* t = luaH_new(L); + sethvalue(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_SELF) + { + const TValue* aux; + StkId rb = RB(i); + TValue* rc = RKC(i); + TString* key = tsvalue(rc); /* key must be a string */ + setobjs2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, aux, luaH_getstr)) + { + setobj2s(L, ra, aux); + } + else Protect(luaV_finishget(L, rb, rc, ra, aux)); + vmbreak; + } + vmcase(OP_ADD) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) + { + lua_Integer ib = ivalue(rb); + lua_Integer ic = ivalue(rc); + setivalue(ra, intop(+, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + setfltvalue(ra, luai_numadd(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } + vmbreak; + } + vmcase(OP_SUB) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) + { + lua_Integer ib = ivalue(rb); + lua_Integer ic = ivalue(rc); + setivalue(ra, intop(-, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + setfltvalue(ra, luai_numsub(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } + vmbreak; + } + vmcase(OP_MUL) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) + { + lua_Integer ib = ivalue(rb); + lua_Integer ic = ivalue(rc); + setivalue(ra, intop(*, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + setfltvalue(ra, luai_nummul(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } + vmbreak; + } + vmcase(OP_DIV) + { + /* float division (always with floats) */ + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + setfltvalue(ra, luai_numdiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } + vmbreak; + } + vmcase(OP_BAND) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Integer ib; + lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) + { + setivalue(ra, intop(&, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } + vmbreak; + } + vmcase(OP_BOR) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Integer ib; + lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) + { + setivalue(ra, intop(|, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } + vmbreak; + } + vmcase(OP_BXOR) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Integer ib; + lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) + { + setivalue(ra, intop(^, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } + vmbreak; + } + vmcase(OP_SHL) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Integer ib; + lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) + { + setivalue(ra, luaV_shiftl(ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } + vmbreak; + } + vmcase(OP_SHR) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Integer ib; + lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) + { + setivalue(ra, luaV_shiftl(ib, -ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } + vmbreak; + } + vmcase(OP_MOD) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) + { + lua_Integer ib = ivalue(rb); + lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_mod(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + lua_Number m; + luai_nummod(L, nb, nc, m); + setfltvalue(ra, m); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } + vmbreak; + } + vmcase(OP_IDIV) + { + /* floor division */ + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) + { + lua_Integer ib = ivalue(rb); + lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_div(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + setfltvalue(ra, luai_numidiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } + vmbreak; + } + vmcase(OP_POW) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + lua_Number nb; + lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) + { + setfltvalue(ra, luai_numpow(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } + vmbreak; + } + vmcase(OP_UNM) + { + TValue* rb = RB(i); + lua_Number nb; + if (ttisinteger(rb)) + { + lua_Integer ib = ivalue(rb); + setivalue(ra, intop(-, 0, ib)); + } + else if (tonumber(rb, &nb)) + { + setfltvalue(ra, luai_numunm(L, nb)); + } + else + { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); + } + vmbreak; + } + vmcase(OP_BNOT) + { + TValue* rb = RB(i); + lua_Integer ib; + if (tointeger(rb, &ib)) + { + setivalue(ra, intop(^, ~l_castS2U(0), ib)); + } + else + { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + } + vmbreak; + } + vmcase(OP_NOT) + { + TValue* rb = RB(i); + int res = l_isfalse(rb); /* next assignment may change this value */ + setbvalue(ra, res); + vmbreak; + } + vmcase(OP_LEN) + { + Protect(luaV_objlen(L, ra, RB(i))); + vmbreak; + } + vmcase(OP_CONCAT) + { + int b = GETARG_B(i); + int c = GETARG_C(i); + StkId rb; + L->top = base + c + 1; /* mark the end of concat operands */ + Protect(luaV_concat(L, c - b + 1)); + ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ + rb = base + b; + setobjs2s(L, ra, rb); + checkGC(L, (ra >= rb ? ra + 1 : rb)); + L->top = ci->top; /* restore top */ + vmbreak; + } + vmcase(OP_JMP) + { + dojump(ci, i, 0); + vmbreak; + } + vmcase(OP_EQ) + { + TValue* rb = RKB(i); + TValue* rc = RKC(i); + Protect( + if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_LT) + { + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_LE) + { + Protect( + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_TEST) + { + if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) + ci->u.l.savedpc++; + else + donextjump(ci); + vmbreak; + } + vmcase(OP_TESTSET) + { + TValue* rb = RB(i); + if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + ci->u.l.savedpc++; + else + { + setobjs2s(L, ra, rb); + donextjump(ci); + } + vmbreak; + } + vmcase(OP_CALL) + { + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L->top = ra + b; /* else previous instruction set top */ + if (luaD_precall(L, ra, nresults)) + { + /* C function? */ + if (nresults >= 0) + L->top = ci->top; /* adjust results */ + Protect((void)0); /* update 'base' */ + } + else + { + /* Lua function */ + ci = L->ci; + goto newframe; /* restart luaV_execute over new Lua function */ + } + vmbreak; + } + vmcase(OP_TAILCALL) + { + int b = GETARG_B(i); + if (b != 0) L->top = ra + b; /* else previous instruction set top */ + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + if (luaD_precall(L, ra, LUA_MULTRET)) + { + /* C function? */ + Protect((void)0); /* update 'base' */ + } + else + { + /* tail call: put called frame (n) in place of caller one (o) */ + CallInfo* nci = L->ci; /* called frame */ + CallInfo* oci = nci->previous; /* caller frame */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ + /* last stack slot filled by 'precall' */ + StkId lim = nci->u.l.base + getproto(nfunc)->numparams; + int aux; + /* close all upvalues from previous call */ + if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); + /* move new frame into old one */ + for (aux = 0; nfunc + aux < lim; aux++) + setobjs2s(L, ofunc + aux, nfunc + aux); + oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ + oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ + oci->u.l.savedpc = nci->u.l.savedpc; + oci->callstatus |= CIST_TAIL; /* function was tail called */ + ci = L->ci = oci; /* remove new frame */ + lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); + goto newframe; /* restart luaV_execute over new Lua function */ + } + vmbreak; + } + vmcase(OP_RETURN) + { + int b = GETARG_B(i); + if (cl->p->sizep > 0) luaF_close(L, base); + b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); + if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ + return; /* external invocation: return */ + else + { + /* invocation via reentry: continue execution */ + ci = L->ci; + if (b) L->top = ci->top; + lua_assert(isLua(ci)); + lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); + goto newframe; /* restart luaV_execute over new Lua function */ + } + } + vmcase(OP_FORLOOP) + { + if (ttisinteger(ra)) + { + /* integer loop? */ + lua_Integer step = ivalue(ra + 2); + lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ + lua_Integer limit = ivalue(ra + 1); + if ((0 < step) ? (idx <= limit) : (limit <= idx)) + { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgivalue(ra, idx); /* update internal index... */ + setivalue(ra + 3, idx); /* ...and external index */ + } + } + else + { + /* floating loop */ + lua_Number step = fltvalue(ra + 2); + lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ + lua_Number limit = fltvalue(ra + 1); + if (luai_numlt(0, step) + ? luai_numle(idx, limit) + : luai_numle(limit, idx)) + { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgfltvalue(ra, idx); /* update internal index... */ + setfltvalue(ra + 3, idx); /* ...and external index */ + } + } + vmbreak; + } + vmcase(OP_FORPREP) + { + TValue* init = ra; + TValue* plimit = ra + 1; + TValue* pstep = ra + 2; + lua_Integer ilimit; + int stopnow; + if (ttisinteger(init) && ttisinteger(pstep) && + forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) + { + /* all values are integer */ + lua_Integer initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, ivalue(pstep))); + } + else + { + /* try making all values floats */ + lua_Number ninit; + lua_Number nlimit; + lua_Number nstep; + if (!tonumber(plimit, &nlimit)) + luaG_runerror(L, "'for' limit must be a number"); + setfltvalue(plimit, nlimit); + if (!tonumber(pstep, &nstep)) + luaG_runerror(L, "'for' step must be a number"); + setfltvalue(pstep, nstep); + if (!tonumber(init, &ninit)) + luaG_runerror(L, "'for' initial value must be a number"); + setfltvalue(init, luai_numsub(L, ninit, nstep)); + } + ci->u.l.savedpc += GETARG_sBx(i); + vmbreak; + } + vmcase(OP_TFORCALL) + { + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); + L->top = cb + 3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i))); + L->top = ci->top; + i = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(i); + lua_assert(GET_OPCODE(i) == OP_TFORLOOP); + goto l_tforloop; + } + vmcase(OP_TFORLOOP) + { + l_tforloop: + if (!ttisnil(ra + 1)) + { + /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + } + vmbreak; + } + vmcase(OP_SETLIST) + { + int n = GETARG_B(i); + int c = GETARG_C(i); + unsigned int last; + Table* h; + if (n == 0) n = cast_int(L->top - ra) - 1; + if (c == 0) + { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + c = GETARG_Ax(*ci->u.l.savedpc++); + } + h = hvalue(ra); + last = ((c - 1) * LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* preallocate it at once */ + for (; n > 0; n--) + { + TValue* val = ra + n; + luaH_setint(L, h, last--, val); + luaC_barrierback(L, h, val); + } + L->top = ci->top; /* correct top (in case of previous open call) */ + vmbreak; + } + vmcase(OP_CLOSURE) + { + Proto* p = cl->p->p[GETARG_Bx(i)]; + LClosure* ncl = getcached(p, cl->upvals, base); /* cached closure */ + if (ncl == NULL) /* no match? */ + pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ + else + setclLvalue(L, ra, ncl); /* push cashed closure */ + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_VARARG) + { + int b = GETARG_B(i) - 1; /* required results */ + int j; + int n = cast_int(base - ci->func) - cl->p->numparams - 1; + if (n < 0) /* less arguments than parameters? */ + n = 0; /* no vararg arguments */ + if (b < 0) + { + /* B == 0? */ + b = n; /* get all var. arguments */ + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ + L->top = ra + n; + } + for (j = 0; j < b && j < n; j++) + setobjs2s(L, ra + j, base - n + j); + for (; j < b; j++) /* complete required results with nil */ + setnilvalue(ra + j); + vmbreak; + } + vmcase(OP_EXTRAARG) + { + lua_assert(0); + vmbreak; + } + } + } } /* }================================================================== */ - diff --git a/Lua/lvm.h b/Lua/lvm.h index 422f871..753be47 100644 --- a/Lua/lvm.h +++ b/Lua/lvm.h @@ -92,22 +92,21 @@ luaV_finishset(L,t,k,v,slot); } - -LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); -LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); -LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); -LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, - StkId val, const TValue *slot); -LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, - StkId val, const TValue *slot); -LUAI_FUNC void luaV_finishOp (lua_State *L); -LUAI_FUNC void luaV_execute (lua_State *L); -LUAI_FUNC void luaV_concat (lua_State *L, int total); -LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); -LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); -LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); -LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); +LUAI_FUNC int luaV_equalobj(lua_State* L, const TValue* t1, const TValue* t2); +LUAI_FUNC int luaV_lessthan(lua_State* L, const TValue* l, const TValue* r); +LUAI_FUNC int luaV_lessequal(lua_State* L, const TValue* l, const TValue* r); +LUAI_FUNC int luaV_tonumber_(const TValue* obj, lua_Number* n); +LUAI_FUNC int luaV_tointeger(const TValue* obj, lua_Integer* p, int mode); +LUAI_FUNC void luaV_finishget(lua_State* L, const TValue* t, TValue* key, + StkId val, const TValue* slot); +LUAI_FUNC void luaV_finishset(lua_State* L, const TValue* t, TValue* key, + StkId val, const TValue* slot); +LUAI_FUNC void luaV_finishOp(lua_State* L); +LUAI_FUNC void luaV_execute(lua_State* L); +LUAI_FUNC void luaV_concat(lua_State* L, int total); +LUAI_FUNC lua_Integer luaV_div(lua_State* L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod(lua_State* L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_shiftl(lua_Integer x, lua_Integer y); +LUAI_FUNC void luaV_objlen(lua_State* L, StkId ra, const TValue* rb); #endif diff --git a/Lua/lzio.c b/Lua/lzio.c index c9e1f49..2d0242e 100644 --- a/Lua/lzio.c +++ b/Lua/lzio.c @@ -20,49 +20,55 @@ #include "lzio.h" -int luaZ_fill (ZIO *z) { - size_t size; - lua_State *L = z->L; - const char *buff; - lua_unlock(L); - buff = z->reader(L, z->data, &size); - lua_lock(L); - if (buff == NULL || size == 0) - return EOZ; - z->n = size - 1; /* discount char being returned */ - z->p = buff; - return cast_uchar(*(z->p++)); +int luaZ_fill(ZIO* z) +{ + size_t size; + lua_State* L = z->L; + const char* buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) + return EOZ; + z->n = size - 1; /* discount char being returned */ + z->p = buff; + return cast_uchar(*(z->p++)); } -void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { - z->L = L; - z->reader = reader; - z->data = data; - z->n = 0; - z->p = NULL; +void luaZ_init(lua_State* L, ZIO* z, lua_Reader reader, void* data) +{ + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; } /* --------------------------------------------------------------- read --- */ -size_t luaZ_read (ZIO *z, void *b, size_t n) { - while (n) { - size_t m; - if (z->n == 0) { /* no bytes in buffer? */ - if (luaZ_fill(z) == EOZ) /* try to read more */ - return n; /* no more input; return number of missing bytes */ - else { - z->n++; /* luaZ_fill consumed first byte; put it back */ - z->p--; - } - } - m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ - memcpy(b, z->p, m); - z->n -= m; - z->p += m; - b = (char *)b + m; - n -= m; - } - return 0; +size_t luaZ_read(ZIO* z, void* b, size_t n) +{ + while (n) + { + size_t m; + if (z->n == 0) + { + /* no bytes in buffer? */ + if (luaZ_fill(z) == EOZ) /* try to read more */ + return n; /* no more input; return number of missing bytes */ + else + { + z->n++; /* luaZ_fill consumed first byte; put it back */ + z->p--; + } + } + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char*)b + m; + n -= m; + } + return 0; } - diff --git a/Lua/lzio.h b/Lua/lzio.h index e7b6f34..b3e4179 100644 --- a/Lua/lzio.h +++ b/Lua/lzio.h @@ -20,10 +20,11 @@ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) -typedef struct Mbuffer { - char *buffer; - size_t n; - size_t buffsize; +typedef struct Mbuffer +{ + char* buffer; + size_t n; + size_t buffsize; } Mbuffer; #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) @@ -44,23 +45,23 @@ typedef struct Mbuffer { #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) -LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, - void *data); -LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ - +LUAI_FUNC void luaZ_init(lua_State* L, ZIO* z, lua_Reader reader, + void* data); +LUAI_FUNC size_t luaZ_read(ZIO* z, void* b, size_t n); /* read next n bytes */ /* --------- Private Part ------------------ */ -struct Zio { - size_t n; /* bytes still unread */ - const char *p; /* current position in buffer */ - lua_Reader reader; /* reader function */ - void *data; /* additional data */ - lua_State *L; /* Lua state (for reader) */ +struct Zio +{ + size_t n; /* bytes still unread */ + const char* p; /* current position in buffer */ + lua_Reader reader; /* reader function */ + void* data; /* additional data */ + lua_State* L; /* Lua state (for reader) */ }; -LUAI_FUNC int luaZ_fill (ZIO *z); +LUAI_FUNC int luaZ_fill(ZIO* z); #endif diff --git a/Lua/mime.c b/Lua/mime.c index 338ecd4..c29cd1a 100644 --- a/Lua/mime.c +++ b/Lua/mime.c @@ -20,39 +20,39 @@ static const char EQCRLF[] = "=\r\n"; /*=========================================================================*\ * Internal function prototypes. \*=========================================================================*/ -static int mime_global_wrp(lua_State *L); -static int mime_global_b64(lua_State *L); -static int mime_global_unb64(lua_State *L); -static int mime_global_qp(lua_State *L); -static int mime_global_unqp(lua_State *L); -static int mime_global_qpwrp(lua_State *L); -static int mime_global_eol(lua_State *L); -static int mime_global_dot(lua_State *L); +static int mime_global_wrp(lua_State* L); +static int mime_global_b64(lua_State* L); +static int mime_global_unb64(lua_State* L); +static int mime_global_qp(lua_State* L); +static int mime_global_unqp(lua_State* L); +static int mime_global_qpwrp(lua_State* L); +static int mime_global_eol(lua_State* L); +static int mime_global_dot(lua_State* L); -static size_t dot(int c, size_t state, luaL_Buffer *buffer); -static void b64setup(UC *base); -static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); -static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); -static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t dot(int c, size_t state, luaL_Buffer* buffer); +static void b64setup(UC* base); +static size_t b64encode(UC c, UC* input, size_t size, luaL_Buffer* buffer); +static size_t b64pad(const UC* input, size_t size, luaL_Buffer* buffer); +static size_t b64decode(UC c, UC* input, size_t size, luaL_Buffer* buffer); -static void qpsetup(UC *class, UC *unbase); -static void qpquote(UC c, luaL_Buffer *buffer); -static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); -static size_t qpencode(UC c, UC *input, size_t size, - const char *marker, luaL_Buffer *buffer); -static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); +static void qpsetup(UC* class, UC* unbase); +static void qpquote(UC c, luaL_Buffer* buffer); +static size_t qpdecode(UC c, UC* input, size_t size, luaL_Buffer* buffer); +static size_t qpencode(UC c, UC* input, size_t size, + const char* marker, luaL_Buffer* buffer); +static size_t qppad(UC* input, size_t size, luaL_Buffer* buffer); /* code support functions */ static luaL_Reg func[] = { - { "dot", mime_global_dot }, - { "b64", mime_global_b64 }, - { "eol", mime_global_eol }, - { "qp", mime_global_qp }, - { "qpwrp", mime_global_qpwrp }, - { "unb64", mime_global_unb64 }, - { "unqp", mime_global_unqp }, - { "wrp", mime_global_wrp }, - { NULL, NULL } + {"dot", mime_global_dot}, + {"b64", mime_global_b64}, + {"eol", mime_global_eol}, + {"qp", mime_global_qp}, + {"qpwrp", mime_global_qpwrp}, + {"unb64", mime_global_unb64}, + {"unqp", mime_global_unqp}, + {"wrp", mime_global_wrp}, + {NULL, NULL} }; /*-------------------------------------------------------------------------*\ @@ -61,13 +61,14 @@ static luaL_Reg func[] = { static UC qpclass[256]; static UC qpbase[] = "0123456789ABCDEF"; static UC qpunbase[256]; -enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; + +enum { QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST }; /*-------------------------------------------------------------------------*\ * Base64 globals \*-------------------------------------------------------------------------*/ static const UC b64base[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static UC b64unbase[256]; /*=========================================================================*\ @@ -76,18 +77,18 @@ static UC b64unbase[256]; /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -MIME_API int luaopen_mime_core(lua_State *L) +MIME_API int luaopen_mime_core(lua_State* L) { - lua_newtable(L); - luaL_setfuncs(L, func, 0); - /* make version string available to scripts */ - lua_pushstring(L, "_VERSION"); - lua_pushstring(L, MIME_VERSION); - lua_rawset(L, -3); - /* initialize lookup tables */ - qpsetup(qpclass, qpunbase); - b64setup(b64unbase); - return 1; + lua_newtable(L); + luaL_setfuncs(L, func, 0); + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, MIME_VERSION); + lua_rawset(L, -3); + /* initialize lookup tables */ + qpsetup(qpclass, qpunbase); + b64setup(b64unbase); + return 1; } /*=========================================================================*\ @@ -100,57 +101,61 @@ MIME_API int luaopen_mime_core(lua_State *L) * 'l' is how many bytes are left for the first line of B. * 'n' is the number of bytes left in the last line of A. \*-------------------------------------------------------------------------*/ -static int mime_global_wrp(lua_State *L) +static int mime_global_wrp(lua_State* L) { - size_t size = 0; - int left = (int) luaL_checknumber(L, 1); - const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size); - const UC *last = input + size; - int length = (int) luaL_optnumber(L, 3, 76); - luaL_Buffer buffer; - /* end of input black-hole */ - if (!input) { - /* if last line has not been terminated, add a line break */ - if (left < length) lua_pushstring(L, CRLF); - /* otherwise, we are done */ - else lua_pushnil(L); - lua_pushnumber(L, length); - return 2; - } - luaL_buffinit(L, &buffer); - while (input < last) { - switch (*input) { - case '\r': - break; - case '\n': - luaL_addstring(&buffer, CRLF); - left = length; - break; - default: - if (left <= 0) { - left = length; - luaL_addstring(&buffer, CRLF); - } - luaL_addchar(&buffer, *input); - left--; - break; - } - input++; - } - luaL_pushresult(&buffer); - lua_pushnumber(L, left); - return 2; + size_t size = 0; + int left = (int)luaL_checknumber(L, 1); + const UC* input = (const UC*)luaL_optlstring(L, 2, NULL, &size); + const UC* last = input + size; + int length = (int)luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end of input black-hole */ + if (!input) + { + /* if last line has not been terminated, add a line break */ + if (left < length) lua_pushstring(L, CRLF); + /* otherwise, we are done */ + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + luaL_buffinit(L, &buffer); + while (input < last) + { + switch (*input) + { + case '\r': + break; + case '\n': + luaL_addstring(&buffer, CRLF); + left = length; + break; + default: + if (left <= 0) + { + left = length; + luaL_addstring(&buffer, CRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; } /*-------------------------------------------------------------------------*\ * Fill base64 decode map. \*-------------------------------------------------------------------------*/ -static void b64setup(UC *unbase) +static void b64setup(UC* unbase) { - int i; - for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; - for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; - unbase['='] = 0; + int i; + for (i = 0; i <= 255; i++) unbase[i] = (UC)255; + for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC)i; + unbase['='] = 0; } /*-------------------------------------------------------------------------*\ @@ -158,24 +163,30 @@ static void b64setup(UC *unbase) * Translate the 3 bytes into Base64 form and append to buffer. * Returns new number of bytes in buffer. \*-------------------------------------------------------------------------*/ -static size_t b64encode(UC c, UC *input, size_t size, - luaL_Buffer *buffer) +static size_t b64encode(UC c, UC* input, size_t size, + luaL_Buffer* buffer) { - input[size++] = c; - if (size == 3) { - UC code[4]; - unsigned long value = 0; - value += input[0]; value <<= 8; - value += input[1]; value <<= 8; - value += input[2]; - code[3] = b64base[value & 0x3f]; value >>= 6; - code[2] = b64base[value & 0x3f]; value >>= 6; - code[1] = b64base[value & 0x3f]; value >>= 6; - code[0] = b64base[value]; - luaL_addlstring(buffer, (char *) code, 4); - size = 0; - } - return size; + input[size++] = c; + if (size == 3) + { + UC code[4]; + unsigned long value = 0; + value += input[0]; + value <<= 8; + value += input[1]; + value <<= 8; + value += input[2]; + code[3] = b64base[value & 0x3f]; + value >>= 6; + code[2] = b64base[value & 0x3f]; + value >>= 6; + code[1] = b64base[value & 0x3f]; + value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char*)code, 4); + size = 0; + } + return size; } /*-------------------------------------------------------------------------*\ @@ -183,30 +194,36 @@ static size_t b64encode(UC c, UC *input, size_t size, * Result, if any, is appended to buffer. * Returns 0. \*-------------------------------------------------------------------------*/ -static size_t b64pad(const UC *input, size_t size, - luaL_Buffer *buffer) +static size_t b64pad(const UC* input, size_t size, + luaL_Buffer* buffer) { - unsigned long value = 0; - UC code[4] = {'=', '=', '=', '='}; - switch (size) { - case 1: - value = input[0] << 4; - code[1] = b64base[value & 0x3f]; value >>= 6; - code[0] = b64base[value]; - luaL_addlstring(buffer, (char *) code, 4); - break; - case 2: - value = input[0]; value <<= 8; - value |= input[1]; value <<= 2; - code[2] = b64base[value & 0x3f]; value >>= 6; - code[1] = b64base[value & 0x3f]; value >>= 6; - code[0] = b64base[value]; - luaL_addlstring(buffer, (char *) code, 4); - break; - default: - break; - } - return 0; + unsigned long value = 0; + UC code[4] = {'=', '=', '=', '='}; + switch (size) + { + case 1: + value = input[0] << 4; + code[1] = b64base[value & 0x3f]; + value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char*)code, 4); + break; + case 2: + value = input[0]; + value <<= 8; + value |= input[1]; + value <<= 2; + code[2] = b64base[value & 0x3f]; + value >>= 6; + code[1] = b64base[value & 0x3f]; + value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char*)code, 4); + break; + default: + break; + } + return 0; } /*-------------------------------------------------------------------------*\ @@ -214,29 +231,36 @@ static size_t b64pad(const UC *input, size_t size, * Translate the 4 bytes from Base64 form and append to buffer. * Returns new number of bytes in buffer. \*-------------------------------------------------------------------------*/ -static size_t b64decode(UC c, UC *input, size_t size, - luaL_Buffer *buffer) +static size_t b64decode(UC c, UC* input, size_t size, + luaL_Buffer* buffer) { - /* ignore invalid characters */ - if (b64unbase[c] > 64) return size; - input[size++] = c; - /* decode atom */ - if (size == 4) { - UC decoded[3]; - int valid, value = 0; - value = b64unbase[input[0]]; value <<= 6; - value |= b64unbase[input[1]]; value <<= 6; - value |= b64unbase[input[2]]; value <<= 6; - value |= b64unbase[input[3]]; - decoded[2] = (UC) (value & 0xff); value >>= 8; - decoded[1] = (UC) (value & 0xff); value >>= 8; - decoded[0] = (UC) value; - /* take care of paddding */ - valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; - luaL_addlstring(buffer, (char *) decoded, valid); - return 0; - /* need more data */ - } else return size; + /* ignore invalid characters */ + if (b64unbase[c] > 64) return size; + input[size++] = c; + /* decode atom */ + if (size == 4) + { + UC decoded[3]; + int valid, value = 0; + value = b64unbase[input[0]]; + value <<= 6; + value |= b64unbase[input[1]]; + value <<= 6; + value |= b64unbase[input[2]]; + value <<= 6; + value |= b64unbase[input[3]]; + decoded[2] = (UC)(value & 0xff); + value >>= 8; + decoded[1] = (UC)(value & 0xff); + value >>= 8; + decoded[0] = (UC)value; + /* take care of paddding */ + valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; + luaL_addlstring(buffer, (char*)decoded, valid); + return 0; + /* need more data */ + } + else return size; } /*-------------------------------------------------------------------------*\ @@ -248,44 +272,46 @@ static size_t b64decode(UC c, UC *input, size_t size, * encode the result, but we can't afford that or Lua would dupplicate * every chunk we received. \*-------------------------------------------------------------------------*/ -static int mime_global_b64(lua_State *L) +static int mime_global_b64(lua_State* L) { - UC atom[3]; - size_t isize = 0, asize = 0; - const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* make sure we don't confuse buffer stuff with arguments */ - lua_settop(L, 2); - /* process first part of the input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = b64encode(*input++, atom, asize, &buffer); - input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second part is nil, we are done */ - if (!input) { - size_t osize = 0; - asize = b64pad(atom, asize, &buffer); - luaL_pushresult(&buffer); - /* if the output is empty and the input is nil, return nil */ - lua_tolstring(L, -1, &osize); - if (osize == 0) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise process the second part */ - last = input + isize; - while (input < last) - asize = b64encode(*input++, atom, asize, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; + UC atom[3]; + size_t isize = 0, asize = 0; + const UC* input = (const UC*)luaL_optlstring(L, 1, NULL, &isize); + const UC* last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) + { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + input = (const UC*)luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) + { + size_t osize = 0; + asize = b64pad(atom, asize, &buffer); + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process the second part */ + last = input + isize; + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char*)atom, asize); + return 2; } /*-------------------------------------------------------------------------*\ @@ -294,43 +320,45 @@ static int mime_global_b64(lua_State *L) * A is the encoded version of the largest prefix of C .. D that is * divisible by 4. B has the remaining bytes of C .. D, *without* encoding. \*-------------------------------------------------------------------------*/ -static int mime_global_unb64(lua_State *L) +static int mime_global_unb64(lua_State* L) { - UC atom[4]; - size_t isize = 0, asize = 0; - const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* make sure we don't confuse buffer stuff with arguments */ - lua_settop(L, 2); - /* process first part of the input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = b64decode(*input++, atom, asize, &buffer); - input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second is nil, we are done */ - if (!input) { - size_t osize = 0; - luaL_pushresult(&buffer); - /* if the output is empty and the input is nil, return nil */ - lua_tolstring(L, -1, &osize); - if (osize == 0) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise, process the rest of the input */ - last = input + isize; - while (input < last) - asize = b64decode(*input++, atom, asize, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; + UC atom[4]; + size_t isize = 0, asize = 0; + const UC* input = (const UC*)luaL_optlstring(L, 1, NULL, &isize); + const UC* last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) + { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + input = (const UC*)luaL_optlstring(L, 2, NULL, &isize); + /* if second is nil, we are done */ + if (!input) + { + size_t osize = 0; + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise, process the rest of the input */ + last = input + isize; + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char*)atom, asize); + return 2; } /*-------------------------------------------------------------------------*\ @@ -349,92 +377,116 @@ static int mime_global_unb64(lua_State *L) * Split quoted-printable characters into classes * Precompute reverse map for encoding \*-------------------------------------------------------------------------*/ -static void qpsetup(UC *cl, UC *unbase) +static void qpsetup(UC* cl, UC* unbase) { - int i; - for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; - for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; - for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN; - cl['\t'] = QP_IF_LAST; - cl[' '] = QP_IF_LAST; - cl['\r'] = QP_CR; - for (i = 0; i < 256; i++) unbase[i] = 255; - unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2; - unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5; - unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8; - unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10; - unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12; - unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; - unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; - unbase['f'] = 15; + int i; + for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; + for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; + for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN; + cl['\t'] = QP_IF_LAST; + cl[' '] = QP_IF_LAST; + cl['\r'] = QP_CR; + for (i = 0; i < 256; i++) unbase[i] = 255; + unbase['0'] = 0; + unbase['1'] = 1; + unbase['2'] = 2; + unbase['3'] = 3; + unbase['4'] = 4; + unbase['5'] = 5; + unbase['6'] = 6; + unbase['7'] = 7; + unbase['8'] = 8; + unbase['9'] = 9; + unbase['A'] = 10; + unbase['a'] = 10; + unbase['B'] = 11; + unbase['b'] = 11; + unbase['C'] = 12; + unbase['c'] = 12; + unbase['D'] = 13; + unbase['d'] = 13; + unbase['E'] = 14; + unbase['e'] = 14; + unbase['F'] = 15; + unbase['f'] = 15; } /*-------------------------------------------------------------------------*\ * Output one character in form =XX \*-------------------------------------------------------------------------*/ -static void qpquote(UC c, luaL_Buffer *buffer) +static void qpquote(UC c, luaL_Buffer* buffer) { - luaL_addchar(buffer, '='); - luaL_addchar(buffer, qpbase[c >> 4]); - luaL_addchar(buffer, qpbase[c & 0x0F]); + luaL_addchar(buffer, '='); + luaL_addchar(buffer, qpbase[c >> 4]); + luaL_addchar(buffer, qpbase[c & 0x0F]); } /*-------------------------------------------------------------------------*\ * Accumulate characters until we are sure about how to deal with them. * Once we are sure, output to the buffer, in the correct form. \*-------------------------------------------------------------------------*/ -static size_t qpencode(UC c, UC *input, size_t size, - const char *marker, luaL_Buffer *buffer) +static size_t qpencode(UC c, UC* input, size_t size, + const char* marker, luaL_Buffer* buffer) { - input[size++] = c; - /* deal with all characters we can have */ - while (size > 0) { - switch (qpclass[input[0]]) { - /* might be the CR of a CRLF sequence */ - case QP_CR: - if (size < 2) return size; - if (input[1] == '\n') { - luaL_addstring(buffer, marker); - return 0; - } else qpquote(input[0], buffer); - break; - /* might be a space and that has to be quoted if last in line */ - case QP_IF_LAST: - if (size < 3) return size; - /* if it is the last, quote it and we are done */ - if (input[1] == '\r' && input[2] == '\n') { - qpquote(input[0], buffer); - luaL_addstring(buffer, marker); - return 0; - } else luaL_addchar(buffer, input[0]); - break; - /* might have to be quoted always */ - case QP_QUOTED: - qpquote(input[0], buffer); - break; - /* might never have to be quoted */ - default: - luaL_addchar(buffer, input[0]); - break; - } - input[0] = input[1]; input[1] = input[2]; - size--; - } - return 0; + input[size++] = c; + /* deal with all characters we can have */ + while (size > 0) + { + switch (qpclass[input[0]]) + { + /* might be the CR of a CRLF sequence */ + case QP_CR: + if (size < 2) return size; + if (input[1] == '\n') + { + luaL_addstring(buffer, marker); + return 0; + } + else qpquote(input[0], buffer); + break; + /* might be a space and that has to be quoted if last in line */ + case QP_IF_LAST: + if (size < 3) return size; + /* if it is the last, quote it and we are done */ + if (input[1] == '\r' && input[2] == '\n') + { + qpquote(input[0], buffer); + luaL_addstring(buffer, marker); + return 0; + } + else + luaL_addchar(buffer, input[0]); + break; + /* might have to be quoted always */ + case QP_QUOTED: + qpquote(input[0], buffer); + break; + /* might never have to be quoted */ + default: + luaL_addchar(buffer, input[0]); + break; + } + input[0] = input[1]; + input[1] = input[2]; + size--; + } + return 0; } /*-------------------------------------------------------------------------*\ * Deal with the final characters \*-------------------------------------------------------------------------*/ -static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) +static size_t qppad(UC* input, size_t size, luaL_Buffer* buffer) { - size_t i; - for (i = 0; i < size; i++) { - if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]); - else qpquote(input[i], buffer); - } - if (size > 0) luaL_addstring(buffer, EQCRLF); - return 0; + size_t i; + for (i = 0; i < size; i++) + { + if (qpclass[input[i]] == QP_PLAIN) + luaL_addchar(buffer, input[i]); + else qpquote(input[i], buffer); + } + if (size > 0) luaL_addstring(buffer, EQCRLF); + return 0; } /*-------------------------------------------------------------------------*\ @@ -445,74 +497,79 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) * can be encoded without doubts. * B has the remaining bytes of C .. D, *without* encoding. \*-------------------------------------------------------------------------*/ -static int mime_global_qp(lua_State *L) +static int mime_global_qp(lua_State* L) { - - size_t asize = 0, isize = 0; - UC atom[3]; - const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - const char *marker = luaL_optstring(L, 3, CRLF); - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* make sure we don't confuse buffer stuff with arguments */ - lua_settop(L, 3); - /* process first part of input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = qpencode(*input++, atom, asize, marker, &buffer); - input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second part is nil, we are done */ - if (!input) { - asize = qppad(atom, asize, &buffer); - luaL_pushresult(&buffer); - if (!(*lua_tostring(L, -1))) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise process rest of input */ - last = input + isize; - while (input < last) - asize = qpencode(*input++, atom, asize, marker, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; + size_t asize = 0, isize = 0; + UC atom[3]; + const UC* input = (const UC*)luaL_optlstring(L, 1, NULL, &isize); + const UC* last = input + isize; + const char* marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) + { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 3); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + input = (const UC*)luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) + { + asize = qppad(atom, asize, &buffer); + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char*)atom, asize); + return 2; } /*-------------------------------------------------------------------------*\ * Accumulate characters until we are sure about how to deal with them. * Once we are sure, output the to the buffer, in the correct form. \*-------------------------------------------------------------------------*/ -static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { - int d; - input[size++] = c; - /* deal with all characters we can deal */ - switch (input[0]) { - /* if we have an escape character */ - case '=': - if (size < 3) return size; - /* eliminate soft line break */ - if (input[1] == '\r' && input[2] == '\n') return 0; - /* decode quoted representation */ - c = qpunbase[input[1]]; d = qpunbase[input[2]]; - /* if it is an invalid, do not decode */ - if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); - else luaL_addchar(buffer, (char) ((c << 4) + d)); - return 0; - case '\r': - if (size < 2) return size; - if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); - return 0; - default: - if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) - luaL_addchar(buffer, input[0]); - return 0; - } +static size_t qpdecode(UC c, UC* input, size_t size, luaL_Buffer* buffer) +{ + int d; + input[size++] = c; + /* deal with all characters we can deal */ + switch (input[0]) + { + /* if we have an escape character */ + case '=': + if (size < 3) return size; + /* eliminate soft line break */ + if (input[1] == '\r' && input[2] == '\n') return 0; + /* decode quoted representation */ + c = qpunbase[input[1]]; + d = qpunbase[input[2]]; + /* if it is an invalid, do not decode */ + if (c > 15 || d > 15) luaL_addlstring(buffer, (char*)input, 3); + else + luaL_addchar(buffer, (char) ((c << 4) + d)); + return 0; + case '\r': + if (size < 2) return size; + if (input[1] == '\n') luaL_addlstring(buffer, (char*)input, 2); + return 0; + default: + if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) + luaL_addchar(buffer, input[0]); + return 0; + } } /*-------------------------------------------------------------------------*\ @@ -522,40 +579,42 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { * can be decoded without doubts. * B has the remaining bytes of C .. D, *without* decoding. \*-------------------------------------------------------------------------*/ -static int mime_global_unqp(lua_State *L) +static int mime_global_unqp(lua_State* L) { - size_t asize = 0, isize = 0; - UC atom[3]; - const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* make sure we don't confuse buffer stuff with arguments */ - lua_settop(L, 2); - /* process first part of input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = qpdecode(*input++, atom, asize, &buffer); - input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second part is nil, we are done */ - if (!input) { - luaL_pushresult(&buffer); - if (!(*lua_tostring(L, -1))) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise process rest of input */ - last = input + isize; - while (input < last) - asize = qpdecode(*input++, atom, asize, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; + size_t asize = 0, isize = 0; + UC atom[3]; + const UC* input = (const UC*)luaL_optlstring(L, 1, NULL, &isize); + const UC* last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) + { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + input = (const UC*)luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) + { + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char*)atom, asize); + return 2; } /*-------------------------------------------------------------------------*\ @@ -567,53 +626,58 @@ static int mime_global_unqp(lua_State *L) * There are two complications: lines can't be broken in the middle * of an encoded =XX, and there might be line breaks already \*-------------------------------------------------------------------------*/ -static int mime_global_qpwrp(lua_State *L) +static int mime_global_qpwrp(lua_State* L) { - size_t size = 0; - int left = (int) luaL_checknumber(L, 1); - const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size); - const UC *last = input + size; - int length = (int) luaL_optnumber(L, 3, 76); - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - if (left < length) lua_pushstring(L, EQCRLF); - else lua_pushnil(L); - lua_pushnumber(L, length); - return 2; - } - /* process all input */ - luaL_buffinit(L, &buffer); - while (input < last) { - switch (*input) { - case '\r': - break; - case '\n': - left = length; - luaL_addstring(&buffer, CRLF); - break; - case '=': - if (left <= 3) { - left = length; - luaL_addstring(&buffer, EQCRLF); - } - luaL_addchar(&buffer, *input); - left--; - break; - default: - if (left <= 1) { - left = length; - luaL_addstring(&buffer, EQCRLF); - } - luaL_addchar(&buffer, *input); - left--; - break; - } - input++; - } - luaL_pushresult(&buffer); - lua_pushnumber(L, left); - return 2; + size_t size = 0; + int left = (int)luaL_checknumber(L, 1); + const UC* input = (const UC*)luaL_optlstring(L, 2, NULL, &size); + const UC* last = input + size; + int length = (int)luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) + { + if (left < length) lua_pushstring(L, EQCRLF); + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) + { + switch (*input) + { + case '\r': + break; + case '\n': + left = length; + luaL_addstring(&buffer, CRLF); + break; + case '=': + if (left <= 3) + { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + default: + if (left <= 1) + { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; } /*-------------------------------------------------------------------------*\ @@ -628,21 +692,28 @@ static int mime_global_qpwrp(lua_State *L) * last is the previous character \*-------------------------------------------------------------------------*/ #define eolcandidate(c) (c == '\r' || c == '\n') -static int eolprocess(int c, int last, const char *marker, - luaL_Buffer *buffer) + +static int eolprocess(int c, int last, const char* marker, + luaL_Buffer* buffer) { - if (eolcandidate(c)) { - if (eolcandidate(last)) { - if (c == last) luaL_addstring(buffer, marker); - return 0; - } else { - luaL_addstring(buffer, marker); - return c; - } - } else { - luaL_addchar(buffer, (char) c); - return 0; - } + if (eolcandidate(c)) + { + if (eolcandidate(last)) + { + if (c == last) luaL_addstring(buffer, marker); + return 0; + } + else + { + luaL_addstring(buffer, marker); + return c; + } + } + else + { + luaL_addchar(buffer, (char) c); + return 0; + } } /*-------------------------------------------------------------------------*\ @@ -652,71 +723,73 @@ static int eolprocess(int c, int last, const char *marker, * converted unambiguously. 'o' is the context returned by the previous * call. 'n' is the new context. \*-------------------------------------------------------------------------*/ -static int mime_global_eol(lua_State *L) +static int mime_global_eol(lua_State* L) { - int ctx = (int) luaL_checkinteger(L, 1); - size_t isize = 0; - const char *input = luaL_optlstring(L, 2, NULL, &isize); - const char *last = input + isize; - const char *marker = luaL_optstring(L, 3, CRLF); - luaL_Buffer buffer; - luaL_buffinit(L, &buffer); - /* end of input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnumber(L, 0); - return 2; - } - /* process all input */ - while (input < last) - ctx = eolprocess(*input++, ctx, marker, &buffer); - luaL_pushresult(&buffer); - lua_pushnumber(L, ctx); - return 2; + int ctx = (int)luaL_checkinteger(L, 1); + size_t isize = 0; + const char* input = luaL_optlstring(L, 2, NULL, &isize); + const char* last = input + isize; + const char* marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + /* end of input blackhole */ + if (!input) + { + lua_pushnil(L); + lua_pushnumber(L, 0); + return 2; + } + /* process all input */ + while (input < last) + ctx = eolprocess(*input++, ctx, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, ctx); + return 2; } /*-------------------------------------------------------------------------*\ * Takes one byte and stuff it if needed. \*-------------------------------------------------------------------------*/ -static size_t dot(int c, size_t state, luaL_Buffer *buffer) +static size_t dot(int c, size_t state, luaL_Buffer* buffer) { - luaL_addchar(buffer, (char) c); - switch (c) { - case '\r': - return 1; - case '\n': - return (state == 1)? 2: 0; - case '.': - if (state == 2) - luaL_addchar(buffer, '.'); - /* Falls through. */ - default: - return 0; - } + luaL_addchar(buffer, (char) c); + switch (c) + { + case '\r': + return 1; + case '\n': + return (state == 1) ? 2 : 0; + case '.': + if (state == 2) + luaL_addchar(buffer, '.'); + /* Falls through. */ + default: + return 0; + } } /*-------------------------------------------------------------------------*\ * Incrementally applies smtp stuffing to a string * A, n = dot(l, D) \*-------------------------------------------------------------------------*/ -static int mime_global_dot(lua_State *L) +static int mime_global_dot(lua_State* L) { - size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); - const char *input = luaL_optlstring(L, 2, NULL, &isize); - const char *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnumber(L, 2); - return 2; - } - /* process all input */ - luaL_buffinit(L, &buffer); - while (input < last) - state = dot(*input++, state, &buffer); - luaL_pushresult(&buffer); - lua_pushnumber(L, (lua_Number) state); - return 2; + size_t isize = 0, state = (size_t)luaL_checknumber(L, 1); + const char* input = luaL_optlstring(L, 2, NULL, &isize); + const char* last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) + { + lua_pushnil(L); + lua_pushnumber(L, 2); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) + state = dot(*input++, state, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, (lua_Number)state); + return 2; } - diff --git a/Lua/mime.h b/Lua/mime.h index 99968a5..94a380f 100644 --- a/Lua/mime.h +++ b/Lua/mime.h @@ -1,4 +1,4 @@ -#ifndef MIME_H +#ifndef MIME_H #define MIME_H /*=========================================================================*\ * Core MIME support @@ -24,6 +24,6 @@ #define MIME_API extern #endif -MIME_API int luaopen_mime_core(lua_State *L); +MIME_API int luaopen_mime_core(lua_State* L); #endif /* MIME_H */ diff --git a/Lua/options.c b/Lua/options.c index fabfe8c..1b09d7f 100644 --- a/Lua/options.c +++ b/Lua/options.c @@ -14,16 +14,16 @@ /*=========================================================================*\ * Internal functions prototypes \*=========================================================================*/ -static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); -static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name); -static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); -static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); -static int opt_setint(lua_State *L, p_socket ps, int level, int name); -static int opt_getint(lua_State *L, p_socket ps, int level, int name); -static int opt_set(lua_State *L, p_socket ps, int level, int name, - void *val, int len); -static int opt_get(lua_State *L, p_socket ps, int level, int name, - void *val, int* len); +static int opt_setmembership(lua_State* L, p_socket ps, int level, int name); +static int opt_ip6_setmembership(lua_State* L, p_socket ps, int level, int name); +static int opt_setboolean(lua_State* L, p_socket ps, int level, int name); +static int opt_getboolean(lua_State* L, p_socket ps, int level, int name); +static int opt_setint(lua_State* L, p_socket ps, int level, int name); +static int opt_getint(lua_State* L, p_socket ps, int level, int name); +static int opt_set(lua_State* L, p_socket ps, int level, int name, + void* val, int len); +static int opt_get(lua_State* L, p_socket ps, int level, int name, + void* val, int* len); /*=========================================================================*\ * Exported functions @@ -31,344 +31,353 @@ static int opt_get(lua_State *L, p_socket ps, int level, int name, /*-------------------------------------------------------------------------*\ * Calls appropriate option handler \*-------------------------------------------------------------------------*/ -int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) +int opt_meth_setoption(lua_State* L, p_opt opt, p_socket ps) { - const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ - while (opt->name && strcmp(name, opt->name)) - opt++; - if (!opt->func) { - char msg[57]; - sprintf(msg, "unsupported option `%.35s'", name); - luaL_argerror(L, 2, msg); - } - return opt->func(L, ps); + const char* name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) + { + char msg[57]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); } -int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) +int opt_meth_getoption(lua_State* L, p_opt opt, p_socket ps) { - const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ - while (opt->name && strcmp(name, opt->name)) - opt++; - if (!opt->func) { - char msg[57]; - sprintf(msg, "unsupported option `%.35s'", name); - luaL_argerror(L, 2, msg); - } - return opt->func(L, ps); + const char* name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) + { + char msg[57]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); } /* enables reuse of local address */ -int opt_set_reuseaddr(lua_State *L, p_socket ps) +int opt_set_reuseaddr(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); } -int opt_get_reuseaddr(lua_State *L, p_socket ps) +int opt_get_reuseaddr(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); } /* enables reuse of local port */ -int opt_set_reuseport(lua_State *L, p_socket ps) +int opt_set_reuseport(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); } -int opt_get_reuseport(lua_State *L, p_socket ps) +int opt_get_reuseport(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); } /* disables the Naggle algorithm */ -int opt_set_tcp_nodelay(lua_State *L, p_socket ps) +int opt_set_tcp_nodelay(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); + return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); } -int opt_get_tcp_nodelay(lua_State *L, p_socket ps) +int opt_get_tcp_nodelay(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); + return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); } -int opt_set_keepalive(lua_State *L, p_socket ps) +int opt_set_keepalive(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); + return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); } -int opt_get_keepalive(lua_State *L, p_socket ps) +int opt_get_keepalive(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); + return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); } -int opt_set_dontroute(lua_State *L, p_socket ps) +int opt_set_dontroute(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); + return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); } -int opt_get_dontroute(lua_State *L, p_socket ps) +int opt_get_dontroute(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); + return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); } -int opt_set_broadcast(lua_State *L, p_socket ps) +int opt_set_broadcast(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); + return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); } -int opt_get_broadcast(lua_State *L, p_socket ps) +int opt_get_broadcast(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); + return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); } -int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) +int opt_set_ip6_unicast_hops(lua_State* L, p_socket ps) { - return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); + return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); } -int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps) +int opt_get_ip6_unicast_hops(lua_State* L, p_socket ps) { - return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); + return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); } -int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) +int opt_set_ip6_multicast_hops(lua_State* L, p_socket ps) { - return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); + return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); } -int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps) +int opt_get_ip6_multicast_hops(lua_State* L, p_socket ps) { - return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); + return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); } -int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) +int opt_set_ip_multicast_loop(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); + return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); } -int opt_get_ip_multicast_loop(lua_State *L, p_socket ps) +int opt_get_ip_multicast_loop(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); + return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); } -int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) +int opt_set_ip6_multicast_loop(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); } -int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps) +int opt_get_ip6_multicast_loop(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); + return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); } -int opt_set_linger(lua_State *L, p_socket ps) +int opt_set_linger(lua_State* L, p_socket ps) { - struct linger li; /* obj, name, table */ - if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); - lua_pushstring(L, "on"); - lua_gettable(L, 3); - if (!lua_isboolean(L, -1)) - luaL_argerror(L, 3, "boolean 'on' field expected"); - li.l_onoff = (u_short) lua_toboolean(L, -1); - lua_pushstring(L, "timeout"); - lua_gettable(L, 3); - if (!lua_isnumber(L, -1)) - luaL_argerror(L, 3, "number 'timeout' field expected"); - li.l_linger = (u_short) lua_tonumber(L, -1); - return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); + struct linger li; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L, 3, lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "on"); + lua_gettable(L, 3); + if (!lua_isboolean(L, -1)) + luaL_argerror(L, 3, "boolean 'on' field expected"); + li.l_onoff = (u_short)lua_toboolean(L, -1); + lua_pushstring(L, "timeout"); + lua_gettable(L, 3); + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 3, "number 'timeout' field expected"); + li.l_linger = (u_short)lua_tonumber(L, -1); + return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char*)&li, sizeof(li)); } -int opt_get_linger(lua_State *L, p_socket ps) +int opt_get_linger(lua_State* L, p_socket ps) { - struct linger li; /* obj, name */ - int len = sizeof(li); - int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len); - if (err) - return err; - lua_newtable(L); - lua_pushboolean(L, li.l_onoff); - lua_setfield(L, -2, "on"); - lua_pushinteger(L, li.l_linger); - lua_setfield(L, -2, "timeout"); - return 1; + struct linger li; /* obj, name */ + int len = sizeof(li); + int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char*)&li, &len); + if (err) + return err; + lua_newtable(L); + lua_pushboolean(L, li.l_onoff); + lua_setfield(L, -2, "on"); + lua_pushinteger(L, li.l_linger); + lua_setfield(L, -2, "timeout"); + return 1; } -int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) +int opt_set_ip_multicast_ttl(lua_State* L, p_socket ps) { - return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); + return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); } -int opt_set_ip_multicast_if(lua_State *L, p_socket ps) +int opt_set_ip_multicast_if(lua_State* L, p_socket ps) { - const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ - struct in_addr val; - val.s_addr = htonl(INADDR_ANY); - if (strcmp(address, "*") && !inet_aton(address, &val)) - luaL_argerror(L, 3, "ip expected"); - return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, - (char *) &val, sizeof(val)); + const char* address = luaL_checkstring(L, 3); /* obj, name, ip */ + struct in_addr val; + val.s_addr = htonl(INADDR_ANY); + if (strcmp(address, "*") && !inet_aton(address, &val)) + luaL_argerror(L, 3, "ip expected"); + return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, + (char*)&val, sizeof(val)); } -int opt_get_ip_multicast_if(lua_State *L, p_socket ps) +int opt_get_ip_multicast_if(lua_State* L, p_socket ps) { - struct in_addr val; - socklen_t len = sizeof(val); - if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) { - lua_pushnil(L); - lua_pushstring(L, "getsockopt failed"); - return 2; - } - lua_pushstring(L, inet_ntoa(val)); - return 1; + struct in_addr val; + socklen_t len = sizeof(val); + if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char*)&val, &len) < 0) + { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, inet_ntoa(val)); + return 1; } -int opt_set_ip_add_membership(lua_State *L, p_socket ps) +int opt_set_ip_add_membership(lua_State* L, p_socket ps) { - return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); + return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); } -int opt_set_ip_drop_membersip(lua_State *L, p_socket ps) +int opt_set_ip_drop_membersip(lua_State* L, p_socket ps) { - return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); + return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); } -int opt_set_ip6_add_membership(lua_State *L, p_socket ps) +int opt_set_ip6_add_membership(lua_State* L, p_socket ps) { - return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); + return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); } -int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps) +int opt_set_ip6_drop_membersip(lua_State* L, p_socket ps) { - return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); + return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); } -int opt_get_ip6_v6only(lua_State *L, p_socket ps) +int opt_get_ip6_v6only(lua_State* L, p_socket ps) { - return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); + return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); } -int opt_set_ip6_v6only(lua_State *L, p_socket ps) +int opt_set_ip6_v6only(lua_State* L, p_socket ps) { - return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); } /*=========================================================================*\ * Auxiliar functions \*=========================================================================*/ -static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) +static int opt_setmembership(lua_State* L, p_socket ps, int level, int name) { - struct ip_mreq val; /* obj, name, table */ - if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); - lua_pushstring(L, "multiaddr"); - lua_gettable(L, 3); - if (!lua_isstring(L, -1)) - luaL_argerror(L, 3, "string 'multiaddr' field expected"); - if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) - luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); - lua_pushstring(L, "interface"); - lua_gettable(L, 3); - if (!lua_isstring(L, -1)) - luaL_argerror(L, 3, "string 'interface' field expected"); - val.imr_interface.s_addr = htonl(INADDR_ANY); - if (strcmp(lua_tostring(L, -1), "*") && - !inet_aton(lua_tostring(L, -1), &val.imr_interface)) - luaL_argerror(L, 3, "invalid 'interface' ip address"); - return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); + struct ip_mreq val; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L, 3, lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'interface' field expected"); + val.imr_interface.s_addr = htonl(INADDR_ANY); + if (strcmp(lua_tostring(L, -1), "*") && + !inet_aton(lua_tostring(L, -1), &val.imr_interface)) + luaL_argerror(L, 3, "invalid 'interface' ip address"); + return opt_set(L, ps, level, name, (char*)&val, sizeof(val)); } -static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name) +static int opt_ip6_setmembership(lua_State* L, p_socket ps, int level, int name) { - struct ipv6_mreq val; /* obj, opt-name, table */ - memset(&val, 0, sizeof(val)); - if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); - lua_pushstring(L, "multiaddr"); - lua_gettable(L, 3); - if (!lua_isstring(L, -1)) - luaL_argerror(L, 3, "string 'multiaddr' field expected"); - if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) - luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); - lua_pushstring(L, "interface"); - lua_gettable(L, 3); - /* By default we listen to interface on default route - * (sigh). However, interface= can override it. We should - * support either number, or name for it. Waiting for - * windows port of if_nametoindex */ - if (!lua_isnil(L, -1)) { - if (lua_isnumber(L, -1)) { - val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1); - } else - luaL_argerror(L, -1, "number 'interface' field expected"); - } - return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); + struct ipv6_mreq val; /* obj, opt-name, table */ + memset(&val, 0, sizeof(val)); + if (!lua_istable(L, 3)) auxiliar_typeerror(L, 3, lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + /* By default we listen to interface on default route + * (sigh). However, interface= can override it. We should + * support either number, or name for it. Waiting for + * windows port of if_nametoindex */ + if (!lua_isnil(L, -1)) + { + if (lua_isnumber(L, -1)) + { + val.ipv6mr_interface = (unsigned int)lua_tonumber(L, -1); + } + else + luaL_argerror(L, -1, "number 'interface' field expected"); + } + return opt_set(L, ps, level, name, (char*)&val, sizeof(val)); } static -int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) +int opt_get(lua_State* L, p_socket ps, int level, int name, void* val, int* len) { - socklen_t socklen = *len; - if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) { - lua_pushnil(L); - lua_pushstring(L, "getsockopt failed"); - return 2; - } - *len = socklen; - return 0; + socklen_t socklen = *len; + if (getsockopt(*ps, level, name, (char*)val, &socklen) < 0) + { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + *len = socklen; + return 0; } static -int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) +int opt_set(lua_State* L, p_socket ps, int level, int name, void* val, int len) { - if (setsockopt(*ps, level, name, (char *) val, len) < 0) { - lua_pushnil(L); - lua_pushstring(L, "setsockopt failed"); - return 2; - } - lua_pushnumber(L, 1); - return 1; + if (setsockopt(*ps, level, name, (char*)val, len) < 0) + { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; } -static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) +static int opt_getboolean(lua_State* L, p_socket ps, int level, int name) { - int val = 0; - int len = sizeof(val); - int err = opt_get(L, ps, level, name, (char *) &val, &len); - if (err) - return err; - lua_pushboolean(L, val); - return 1; + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char*)&val, &len); + if (err) + return err; + lua_pushboolean(L, val); + return 1; } -int opt_get_error(lua_State *L, p_socket ps) +int opt_get_error(lua_State* L, p_socket ps) { - int val = 0; - socklen_t len = sizeof(val); - if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) { - lua_pushnil(L); - lua_pushstring(L, "getsockopt failed"); - return 2; - } - lua_pushstring(L, socket_strerror(val)); - return 1; + int val = 0; + socklen_t len = sizeof(val); + if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char*)&val, &len) < 0) + { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, socket_strerror(val)); + return 1; } -static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) +static int opt_setboolean(lua_State* L, p_socket ps, int level, int name) { - int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ - return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); + int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ + return opt_set(L, ps, level, name, (char*)&val, sizeof(val)); } -static int opt_getint(lua_State *L, p_socket ps, int level, int name) +static int opt_getint(lua_State* L, p_socket ps, int level, int name) { - int val = 0; - int len = sizeof(val); - int err = opt_get(L, ps, level, name, (char *) &val, &len); - if (err) - return err; - lua_pushnumber(L, val); - return 1; + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char*)&val, &len); + if (err) + return err; + lua_pushnumber(L, val); + return 1; } -static int opt_setint(lua_State *L, p_socket ps, int level, int name) +static int opt_setint(lua_State* L, p_socket ps, int level, int name) { - int val = (int) lua_tonumber(L, 3); /* obj, name, int */ - return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); + int val = (int)lua_tonumber(L, 3); /* obj, name, int */ + return opt_set(L, ps, level, name, (char*)&val, sizeof(val)); } diff --git a/Lua/options.h b/Lua/options.h index 19ba0df..7c30f4e 100644 --- a/Lua/options.h +++ b/Lua/options.h @@ -12,51 +12,53 @@ #include "socket.h" /* option registry */ -typedef struct t_opt { - const char *name; - int (*func)(lua_State *L, p_socket ps); +typedef struct t_opt +{ + const char* name; + int (*func)(lua_State* L, p_socket ps); } t_opt; -typedef t_opt *p_opt; + +typedef t_opt* p_opt; /* supported options for setoption */ -int opt_set_dontroute(lua_State *L, p_socket ps); -int opt_set_broadcast(lua_State *L, p_socket ps); -int opt_set_tcp_nodelay(lua_State *L, p_socket ps); -int opt_set_keepalive(lua_State *L, p_socket ps); -int opt_set_linger(lua_State *L, p_socket ps); -int opt_set_reuseaddr(lua_State *L, p_socket ps); -int opt_set_reuseport(lua_State *L, p_socket ps); -int opt_set_ip_multicast_if(lua_State *L, p_socket ps); -int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); -int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); -int opt_set_ip_add_membership(lua_State *L, p_socket ps); -int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); -int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps); -int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps); -int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps); -int opt_set_ip6_add_membership(lua_State *L, p_socket ps); -int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps); -int opt_set_ip6_v6only(lua_State *L, p_socket ps); +int opt_set_dontroute(lua_State* L, p_socket ps); +int opt_set_broadcast(lua_State* L, p_socket ps); +int opt_set_tcp_nodelay(lua_State* L, p_socket ps); +int opt_set_keepalive(lua_State* L, p_socket ps); +int opt_set_linger(lua_State* L, p_socket ps); +int opt_set_reuseaddr(lua_State* L, p_socket ps); +int opt_set_reuseport(lua_State* L, p_socket ps); +int opt_set_ip_multicast_if(lua_State* L, p_socket ps); +int opt_set_ip_multicast_ttl(lua_State* L, p_socket ps); +int opt_set_ip_multicast_loop(lua_State* L, p_socket ps); +int opt_set_ip_add_membership(lua_State* L, p_socket ps); +int opt_set_ip_drop_membersip(lua_State* L, p_socket ps); +int opt_set_ip6_unicast_hops(lua_State* L, p_socket ps); +int opt_set_ip6_multicast_hops(lua_State* L, p_socket ps); +int opt_set_ip6_multicast_loop(lua_State* L, p_socket ps); +int opt_set_ip6_add_membership(lua_State* L, p_socket ps); +int opt_set_ip6_drop_membersip(lua_State* L, p_socket ps); +int opt_set_ip6_v6only(lua_State* L, p_socket ps); /* supported options for getoption */ -int opt_get_dontroute(lua_State *L, p_socket ps); -int opt_get_broadcast(lua_State *L, p_socket ps); -int opt_get_reuseaddr(lua_State *L, p_socket ps); -int opt_get_reuseport(lua_State *L, p_socket ps); -int opt_get_tcp_nodelay(lua_State *L, p_socket ps); -int opt_get_keepalive(lua_State *L, p_socket ps); -int opt_get_linger(lua_State *L, p_socket ps); -int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); -int opt_get_ip_multicast_if(lua_State *L, p_socket ps); -int opt_get_error(lua_State *L, p_socket ps); -int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps); -int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps); -int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps); -int opt_get_ip6_v6only(lua_State *L, p_socket ps); -int opt_get_reuseport(lua_State *L, p_socket ps); +int opt_get_dontroute(lua_State* L, p_socket ps); +int opt_get_broadcast(lua_State* L, p_socket ps); +int opt_get_reuseaddr(lua_State* L, p_socket ps); +int opt_get_reuseport(lua_State* L, p_socket ps); +int opt_get_tcp_nodelay(lua_State* L, p_socket ps); +int opt_get_keepalive(lua_State* L, p_socket ps); +int opt_get_linger(lua_State* L, p_socket ps); +int opt_get_ip_multicast_loop(lua_State* L, p_socket ps); +int opt_get_ip_multicast_if(lua_State* L, p_socket ps); +int opt_get_error(lua_State* L, p_socket ps); +int opt_get_ip6_multicast_loop(lua_State* L, p_socket ps); +int opt_get_ip6_multicast_hops(lua_State* L, p_socket ps); +int opt_get_ip6_unicast_hops(lua_State* L, p_socket ps); +int opt_get_ip6_v6only(lua_State* L, p_socket ps); +int opt_get_reuseport(lua_State* L, p_socket ps); /* invokes the appropriate option handler */ -int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); -int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); +int opt_meth_setoption(lua_State* L, p_opt opt, p_socket ps); +int opt_meth_getoption(lua_State* L, p_opt opt, p_socket ps); #endif diff --git a/Lua/select.c b/Lua/select.c index 9d133b7..4bc8c47 100644 --- a/Lua/select.c +++ b/Lua/select.c @@ -15,20 +15,20 @@ /*=========================================================================*\ * Internal function prototypes. \*=========================================================================*/ -static t_socket getfd(lua_State *L); -static int dirty(lua_State *L); -static void collect_fd(lua_State *L, int tab, int itab, - fd_set *set, t_socket *max_fd); -static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); -static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, - int itab, int tab, int start); -static void make_assoc(lua_State *L, int tab); -static int global_select(lua_State *L); +static t_socket getfd(lua_State* L); +static int dirty(lua_State* L); +static void collect_fd(lua_State* L, int tab, int itab, + fd_set* set, t_socket* max_fd); +static int check_dirty(lua_State* L, int tab, int dtab, fd_set* set); +static void return_fd(lua_State* L, fd_set* set, t_socket max_fd, + int itab, int tab, int start); +static void make_assoc(lua_State* L, int tab); +static int global_select(lua_State* L); /* functions in library namespace */ static luaL_Reg func[] = { - {"select", global_select}, - {NULL, NULL} + {"select", global_select}, + {NULL, NULL} }; /*=========================================================================*\ @@ -37,15 +37,16 @@ static luaL_Reg func[] = { /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int select_open(lua_State *L) { - lua_pushstring(L, "_SETSIZE"); - lua_pushinteger(L, FD_SETSIZE); - lua_rawset(L, -3); - lua_pushstring(L, "_SOCKETINVALID"); - lua_pushinteger(L, SOCKET_INVALID); - lua_rawset(L, -3); - luaL_setfuncs(L, func, 0); - return 0; +int select_open(lua_State* L) +{ + lua_pushstring(L, "_SETSIZE"); + lua_pushinteger(L, FD_SETSIZE); + lua_rawset(L, -3); + lua_pushstring(L, "_SOCKETINVALID"); + lua_pushinteger(L, SOCKET_INVALID); + lua_rawset(L, -3); + luaL_setfuncs(L, func, 0); + return 0; } /*=========================================================================*\ @@ -54,167 +55,198 @@ int select_open(lua_State *L) { /*-------------------------------------------------------------------------*\ * Waits for a set of sockets until a condition is met or timeout. \*-------------------------------------------------------------------------*/ -static int global_select(lua_State *L) { - int rtab, wtab, itab, ret, ndirty; - t_socket max_fd = SOCKET_INVALID; - fd_set rset, wset; - t_timeout tm; - double t = luaL_optnumber(L, 3, -1); - FD_ZERO(&rset); FD_ZERO(&wset); - lua_settop(L, 3); - lua_newtable(L); itab = lua_gettop(L); - lua_newtable(L); rtab = lua_gettop(L); - lua_newtable(L); wtab = lua_gettop(L); - collect_fd(L, 1, itab, &rset, &max_fd); - collect_fd(L, 2, itab, &wset, &max_fd); - ndirty = check_dirty(L, 1, rtab, &rset); - t = ndirty > 0? 0.0: t; - timeout_init(&tm, t, -1); - timeout_markstart(&tm); - ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); - if (ret > 0 || ndirty > 0) { - return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); - return_fd(L, &wset, max_fd+1, itab, wtab, 0); - make_assoc(L, rtab); - make_assoc(L, wtab); - return 2; - } else if (ret == 0) { - lua_pushstring(L, "timeout"); - return 3; - } else { - luaL_error(L, "select failed"); - return 3; - } +static int global_select(lua_State* L) +{ + int rtab, wtab, itab, ret, ndirty; + t_socket max_fd = SOCKET_INVALID; + fd_set rset, wset; + t_timeout tm; + double t = luaL_optnumber(L, 3, -1); + FD_ZERO(&rset); + FD_ZERO(&wset); + lua_settop(L, 3); + lua_newtable(L); + itab = lua_gettop(L); + lua_newtable(L); + rtab = lua_gettop(L); + lua_newtable(L); + wtab = lua_gettop(L); + collect_fd(L, 1, itab, &rset, &max_fd); + collect_fd(L, 2, itab, &wset, &max_fd); + ndirty = check_dirty(L, 1, rtab, &rset); + t = ndirty > 0 ? 0.0 : t; + timeout_init(&tm, t, -1); + timeout_markstart(&tm); + ret = socket_select(max_fd + 1, &rset, &wset, NULL, &tm); + if (ret > 0 || ndirty > 0) + { + return_fd(L, &rset, max_fd + 1, itab, rtab, ndirty); + return_fd(L, &wset, max_fd + 1, itab, wtab, 0); + make_assoc(L, rtab); + make_assoc(L, wtab); + return 2; + } + else if (ret == 0) + { + lua_pushstring(L, "timeout"); + return 3; + } + else + { + luaL_error(L, "select failed"); + return 3; + } } /*=========================================================================*\ * Internal functions \*=========================================================================*/ -static t_socket getfd(lua_State *L) { - t_socket fd = SOCKET_INVALID; - lua_pushstring(L, "getfd"); - lua_gettable(L, -2); - if (!lua_isnil(L, -1)) { - lua_pushvalue(L, -2); - lua_call(L, 1, 1); - if (lua_isnumber(L, -1)) { - double numfd = lua_tonumber(L, -1); - fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID; - } - } - lua_pop(L, 1); - return fd; +static t_socket getfd(lua_State* L) +{ + t_socket fd = SOCKET_INVALID; + lua_pushstring(L, "getfd"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) + { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + if (lua_isnumber(L, -1)) + { + double numfd = lua_tonumber(L, -1); + fd = (numfd >= 0.0) ? (t_socket)numfd : SOCKET_INVALID; + } + } + lua_pop(L, 1); + return fd; } -static int dirty(lua_State *L) { - int is = 0; - lua_pushstring(L, "dirty"); - lua_gettable(L, -2); - if (!lua_isnil(L, -1)) { - lua_pushvalue(L, -2); - lua_call(L, 1, 1); - is = lua_toboolean(L, -1); - } - lua_pop(L, 1); - return is; +static int dirty(lua_State* L) +{ + int is = 0; + lua_pushstring(L, "dirty"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) + { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + is = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return is; } -static void collect_fd(lua_State *L, int tab, int itab, - fd_set *set, t_socket *max_fd) { - int i = 1, n = 0; - /* nil is the same as an empty table */ - if (lua_isnil(L, tab)) return; - /* otherwise we need it to be a table */ - luaL_checktype(L, tab, LUA_TTABLE); - for ( ;; ) { - t_socket fd; - lua_pushnumber(L, i); - lua_gettable(L, tab); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - break; - } - /* getfd figures out if this is a socket */ - fd = getfd(L); - if (fd != SOCKET_INVALID) { - /* make sure we don't overflow the fd_set */ +static void collect_fd(lua_State* L, int tab, int itab, + fd_set* set, t_socket* max_fd) +{ + int i = 1, n = 0; + /* nil is the same as an empty table */ + if (lua_isnil(L, tab)) return; + /* otherwise we need it to be a table */ + luaL_checktype(L, tab, LUA_TTABLE); + for (;;) + { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + break; + } + /* getfd figures out if this is a socket */ + fd = getfd(L); + if (fd != SOCKET_INVALID) + { + /* make sure we don't overflow the fd_set */ #ifdef _WIN32 - if (n >= FD_SETSIZE) - luaL_argerror(L, tab, "too many sockets"); + if (n >= FD_SETSIZE) + luaL_argerror(L, tab, "too many sockets"); #else if (fd >= FD_SETSIZE) luaL_argerror(L, tab, "descriptor too large for set size"); #endif - FD_SET(fd, set); - n++; - /* keep track of the largest descriptor so far */ - if (*max_fd == SOCKET_INVALID || *max_fd < fd) - *max_fd = fd; - /* make sure we can map back from descriptor to the object */ - lua_pushnumber(L, (lua_Number) fd); - lua_pushvalue(L, -2); - lua_settable(L, itab); - } - lua_pop(L, 1); - i = i + 1; - } + FD_SET(fd, set); + n++; + /* keep track of the largest descriptor so far */ + if (*max_fd == SOCKET_INVALID || *max_fd < fd) + *max_fd = fd; + /* make sure we can map back from descriptor to the object */ + lua_pushnumber(L, (lua_Number)fd); + lua_pushvalue(L, -2); + lua_settable(L, itab); + } + lua_pop(L, 1); + i = i + 1; + } } -static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { - int ndirty = 0, i = 1; - if (lua_isnil(L, tab)) - return 0; - for ( ;; ) { - t_socket fd; - lua_pushnumber(L, i); - lua_gettable(L, tab); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - break; - } - fd = getfd(L); - if (fd != SOCKET_INVALID && dirty(L)) { - lua_pushnumber(L, ++ndirty); - lua_pushvalue(L, -2); - lua_settable(L, dtab); - FD_CLR(fd, set); - } - lua_pop(L, 1); - i = i + 1; - } - return ndirty; +static int check_dirty(lua_State* L, int tab, int dtab, fd_set* set) +{ + int ndirty = 0, i = 1; + if (lua_isnil(L, tab)) + return 0; + for (;;) + { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + break; + } + fd = getfd(L); + if (fd != SOCKET_INVALID && dirty(L)) + { + lua_pushnumber(L, ++ndirty); + lua_pushvalue(L, -2); + lua_settable(L, dtab); + FD_CLR(fd, set); + } + lua_pop(L, 1); + i = i + 1; + } + return ndirty; } -static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, - int itab, int tab, int start) { - t_socket fd; - for (fd = 0; fd < max_fd; fd++) { - if (FD_ISSET(fd, set)) { - lua_pushnumber(L, ++start); - lua_pushnumber(L, (lua_Number) fd); - lua_gettable(L, itab); - lua_settable(L, tab); - } - } +static void return_fd(lua_State* L, fd_set* set, t_socket max_fd, + int itab, int tab, int start) +{ + t_socket fd; + for (fd = 0; fd < max_fd; fd++) + { + if (FD_ISSET(fd, set)) + { + lua_pushnumber(L, ++start); + lua_pushnumber(L, (lua_Number)fd); + lua_gettable(L, itab); + lua_settable(L, tab); + } + } } -static void make_assoc(lua_State *L, int tab) { - int i = 1, atab; - lua_newtable(L); atab = lua_gettop(L); - for ( ;; ) { - lua_pushnumber(L, i); - lua_gettable(L, tab); - if (!lua_isnil(L, -1)) { - lua_pushnumber(L, i); - lua_pushvalue(L, -2); - lua_settable(L, atab); - lua_pushnumber(L, i); - lua_settable(L, atab); - } else { - lua_pop(L, 1); - break; - } - i = i+1; - } +static void make_assoc(lua_State* L, int tab) +{ + int i = 1, atab; + lua_newtable(L); + atab = lua_gettop(L); + for (;;) + { + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (!lua_isnil(L, -1)) + { + lua_pushnumber(L, i); + lua_pushvalue(L, -2); + lua_settable(L, atab); + lua_pushnumber(L, i); + lua_settable(L, atab); + } + else + { + lua_pop(L, 1); + break; + } + i = i + 1; + } } - diff --git a/Lua/select.h b/Lua/select.h index 8750200..0ff43b9 100644 --- a/Lua/select.h +++ b/Lua/select.h @@ -10,6 +10,6 @@ * true if there is data ready for reading (required for buffered input). \*=========================================================================*/ -int select_open(lua_State *L); +int select_open(lua_State* L); #endif /* SELECT_H */ diff --git a/Lua/socket.h b/Lua/socket.h index 63573de..c3ffe22 100644 --- a/Lua/socket.h +++ b/Lua/socket.h @@ -38,41 +38,41 @@ typedef struct sockaddr SA; int socket_open(void); int socket_close(void); void socket_destroy(p_socket ps); -void socket_shutdown(p_socket ps, int how); -int socket_sendto(p_socket ps, const char *data, size_t count, - size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm); -int socket_recvfrom(p_socket ps, char *data, size_t count, - size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm); +void socket_shutdown(p_socket ps, int how); +int socket_sendto(p_socket ps, const char* data, size_t count, + size_t* sent, SA* addr, socklen_t addr_len, p_timeout tm); +int socket_recvfrom(p_socket ps, char* data, size_t count, + size_t* got, SA* addr, socklen_t* addr_len, p_timeout tm); void socket_setnonblocking(p_socket ps); void socket_setblocking(p_socket ps); int socket_waitfd(p_socket ps, int sw, p_timeout tm); -int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, - p_timeout tm); +int socket_select(t_socket n, fd_set* rfds, fd_set* wfds, fd_set* efds, + p_timeout tm); -int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_connect(p_socket ps, SA* addr, socklen_t addr_len, p_timeout tm); int socket_create(p_socket ps, int domain, int type, int protocol); -int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); +int socket_bind(p_socket ps, SA* addr, socklen_t addr_len); int socket_listen(p_socket ps, int backlog); -int socket_accept(p_socket ps, p_socket pa, SA *addr, - socklen_t *addr_len, p_timeout tm); +int socket_accept(p_socket ps, p_socket pa, SA* addr, + socklen_t* addr_len, p_timeout tm); -const char *socket_hoststrerror(int err); -const char *socket_gaistrerror(int err); -const char *socket_strerror(int err); +const char* socket_hoststrerror(int err); +const char* socket_gaistrerror(int err); +const char* socket_strerror(int err); /* these are perfect to use with the io abstraction module and the buffered input module */ -int socket_send(p_socket ps, const char *data, size_t count, - size_t *sent, p_timeout tm); -int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); -int socket_write(p_socket ps, const char *data, size_t count, - size_t *sent, p_timeout tm); -int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); -const char *socket_ioerror(p_socket ps, int err); +int socket_send(p_socket ps, const char* data, size_t count, + size_t* sent, p_timeout tm); +int socket_recv(p_socket ps, char* data, size_t count, size_t* got, p_timeout tm); +int socket_write(p_socket ps, const char* data, size_t count, + size_t* sent, p_timeout tm); +int socket_read(p_socket ps, char* data, size_t count, size_t* got, p_timeout tm); +const char* socket_ioerror(p_socket ps, int err); -int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); -int socket_gethostbyname(const char *addr, struct hostent **hp); +int socket_gethostbyaddr(const char* addr, socklen_t len, struct hostent** hp); +int socket_gethostbyname(const char* addr, struct hostent** hp); #endif /* SOCKET_H */ diff --git a/Lua/tcp.c b/Lua/tcp.c index ef9ee6f..f8d4f74 100644 --- a/Lua/tcp.c +++ b/Lua/tcp.c @@ -17,106 +17,106 @@ /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ -static int global_create(lua_State *L); -static int global_create4(lua_State *L); -static int global_create6(lua_State *L); -static int global_connect(lua_State *L); -static int meth_connect(lua_State *L); -static int meth_listen(lua_State *L); -static int meth_getfamily(lua_State *L); -static int meth_bind(lua_State *L); -static int meth_send(lua_State *L); -static int meth_getstats(lua_State *L); -static int meth_setstats(lua_State *L); -static int meth_getsockname(lua_State *L); -static int meth_getpeername(lua_State *L); -static int meth_shutdown(lua_State *L); -static int meth_receive(lua_State *L); -static int meth_accept(lua_State *L); -static int meth_close(lua_State *L); -static int meth_getoption(lua_State *L); -static int meth_setoption(lua_State *L); -static int meth_gettimeout(lua_State *L); -static int meth_settimeout(lua_State *L); -static int meth_getfd(lua_State *L); -static int meth_setfd(lua_State *L); -static int meth_dirty(lua_State *L); +static int global_create(lua_State* L); +static int global_create4(lua_State* L); +static int global_create6(lua_State* L); +static int global_connect(lua_State* L); +static int meth_connect(lua_State* L); +static int meth_listen(lua_State* L); +static int meth_getfamily(lua_State* L); +static int meth_bind(lua_State* L); +static int meth_send(lua_State* L); +static int meth_getstats(lua_State* L); +static int meth_setstats(lua_State* L); +static int meth_getsockname(lua_State* L); +static int meth_getpeername(lua_State* L); +static int meth_shutdown(lua_State* L); +static int meth_receive(lua_State* L); +static int meth_accept(lua_State* L); +static int meth_close(lua_State* L); +static int meth_getoption(lua_State* L); +static int meth_setoption(lua_State* L); +static int meth_gettimeout(lua_State* L); +static int meth_settimeout(lua_State* L); +static int meth_getfd(lua_State* L); +static int meth_setfd(lua_State* L); +static int meth_dirty(lua_State* L); /* tcp object methods */ static luaL_Reg tcp_methods[] = { - {"__gc", meth_close}, - {"__tostring", auxiliar_tostring}, - {"accept", meth_accept}, - {"bind", meth_bind}, - {"close", meth_close}, - {"connect", meth_connect}, - {"dirty", meth_dirty}, - {"getfamily", meth_getfamily}, - {"getfd", meth_getfd}, - {"getoption", meth_getoption}, - {"getpeername", meth_getpeername}, - {"getsockname", meth_getsockname}, - {"getstats", meth_getstats}, - {"setstats", meth_setstats}, - {"listen", meth_listen}, - {"receive", meth_receive}, - {"send", meth_send}, - {"setfd", meth_setfd}, - {"setoption", meth_setoption}, - {"setpeername", meth_connect}, - {"setsockname", meth_bind}, - {"settimeout", meth_settimeout}, - {"gettimeout", meth_gettimeout}, - {"shutdown", meth_shutdown}, - {NULL, NULL} + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getoption", meth_getoption}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} }; /* socket option handlers */ static t_opt optget[] = { - {"keepalive", opt_get_keepalive}, - {"reuseaddr", opt_get_reuseaddr}, - {"reuseport", opt_get_reuseport}, - {"tcp-nodelay", opt_get_tcp_nodelay}, - {"linger", opt_get_linger}, - {"error", opt_get_error}, - {NULL, NULL} + {"keepalive", opt_get_keepalive}, + {"reuseaddr", opt_get_reuseaddr}, + {"reuseport", opt_get_reuseport}, + {"tcp-nodelay", opt_get_tcp_nodelay}, + {"linger", opt_get_linger}, + {"error", opt_get_error}, + {NULL, NULL} }; static t_opt optset[] = { - {"keepalive", opt_set_keepalive}, - {"reuseaddr", opt_set_reuseaddr}, - {"reuseport", opt_set_reuseport}, - {"tcp-nodelay", opt_set_tcp_nodelay}, - {"ipv6-v6only", opt_set_ip6_v6only}, - {"linger", opt_set_linger}, - {NULL, NULL} + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"tcp-nodelay", opt_set_tcp_nodelay}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {"linger", opt_set_linger}, + {NULL, NULL} }; /* functions in library namespace */ static luaL_Reg func[] = { - {"tcp", global_create}, - {"tcp4", global_create4}, - {"tcp6", global_create6}, - {"connect", global_connect}, - {NULL, NULL} + {"tcp", global_create}, + {"tcp4", global_create4}, + {"tcp6", global_create6}, + {"connect", global_connect}, + {NULL, NULL} }; /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int tcp_open(lua_State *L) +int tcp_open(lua_State* L) { - /* create classes */ - auxiliar_newclass(L, "tcp{master}", tcp_methods); - auxiliar_newclass(L, "tcp{client}", tcp_methods); - auxiliar_newclass(L, "tcp{server}", tcp_methods); - /* create class groups */ - auxiliar_add2group(L, "tcp{master}", "tcp{any}"); - auxiliar_add2group(L, "tcp{client}", "tcp{any}"); - auxiliar_add2group(L, "tcp{server}", "tcp{any}"); - /* define library functions */ - luaL_setfuncs(L, func, 0); - return 0; + /* create classes */ + auxiliar_newclass(L, "tcp{master}", tcp_methods); + auxiliar_newclass(L, "tcp{client}", tcp_methods); + auxiliar_newclass(L, "tcp{server}", tcp_methods); + /* create class groups */ + auxiliar_add2group(L, "tcp{master}", "tcp{any}"); + auxiliar_add2group(L, "tcp{client}", "tcp{any}"); + auxiliar_add2group(L, "tcp{server}", "tcp{any}"); + /* define library functions */ + luaL_setfuncs(L, func, 0); + return 0; } /*=========================================================================*\ @@ -125,237 +125,254 @@ int tcp_open(lua_State *L) /*-------------------------------------------------------------------------*\ * Just call buffered IO methods \*-------------------------------------------------------------------------*/ -static int meth_send(lua_State *L) { - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); - return buffer_meth_send(L, &tcp->buf); +static int meth_send(lua_State* L) +{ + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_send(L, &tcp->buf); } -static int meth_receive(lua_State *L) { - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); - return buffer_meth_receive(L, &tcp->buf); +static int meth_receive(lua_State* L) +{ + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_receive(L, &tcp->buf); } -static int meth_getstats(lua_State *L) { - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); - return buffer_meth_getstats(L, &tcp->buf); +static int meth_getstats(lua_State* L) +{ + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_getstats(L, &tcp->buf); } -static int meth_setstats(lua_State *L) { - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); - return buffer_meth_setstats(L, &tcp->buf); +static int meth_setstats(lua_State* L) +{ + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_setstats(L, &tcp->buf); } /*-------------------------------------------------------------------------*\ * Just call option handler \*-------------------------------------------------------------------------*/ -static int meth_getoption(lua_State *L) +static int meth_getoption(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return opt_meth_getoption(L, optget, &tcp->sock); + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_getoption(L, optget, &tcp->sock); } -static int meth_setoption(lua_State *L) +static int meth_setoption(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return opt_meth_setoption(L, optset, &tcp->sock); + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_setoption(L, optset, &tcp->sock); } /*-------------------------------------------------------------------------*\ * Select support methods \*-------------------------------------------------------------------------*/ -static int meth_getfd(lua_State *L) +static int meth_getfd(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - lua_pushnumber(L, (int) tcp->sock); - return 1; + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushnumber(L, (int)tcp->sock); + return 1; } /* this is very dangerous, but can be handy for those that are brave enough */ -static int meth_setfd(lua_State *L) +static int meth_setfd(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - tcp->sock = (t_socket) luaL_checknumber(L, 2); - return 0; + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + tcp->sock = (t_socket)luaL_checknumber(L, 2); + return 0; } -static int meth_dirty(lua_State *L) +static int meth_dirty(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - lua_pushboolean(L, !buffer_isempty(&tcp->buf)); - return 1; + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushboolean(L, !buffer_isempty(&tcp->buf)); + return 1; } /*-------------------------------------------------------------------------*\ * Waits for and returns a client object attempting connection to the * server object \*-------------------------------------------------------------------------*/ -static int meth_accept(lua_State *L) +static int meth_accept(lua_State* L) { - p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); - p_timeout tm = timeout_markstart(&server->tm); - t_socket sock; - const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm); - /* if successful, push client socket */ - if (err == NULL) { - p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); - auxiliar_setclass(L, "tcp{client}", -1); - /* initialize structure fields */ - memset(clnt, 0, sizeof(t_tcp)); - socket_setnonblocking(&sock); - clnt->sock = sock; - io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, - (p_error) socket_ioerror, &clnt->sock); - timeout_init(&clnt->tm, -1, -1); - buffer_init(&clnt->buf, &clnt->io, &clnt->tm); - clnt->family = server->family; - return 1; - } else { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } + p_tcp server = (p_tcp)auxiliar_checkclass(L, "tcp{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + const char* err = inet_tryaccept(&server->sock, server->family, &sock, tm); + /* if successful, push client socket */ + if (err == NULL) + { + p_tcp clnt = (p_tcp)lua_newuserdata(L, sizeof(t_tcp)); + auxiliar_setclass(L, "tcp{client}", -1); + /* initialize structure fields */ + memset(clnt, 0, sizeof(t_tcp)); + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, + (p_error)socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + clnt->family = server->family; + return 1; + } + else + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } } /*-------------------------------------------------------------------------*\ * Binds an object to an address \*-------------------------------------------------------------------------*/ -static int meth_bind(lua_State *L) { - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); - const char *address = luaL_checkstring(L, 2); - const char *port = luaL_checkstring(L, 3); - const char *err; - struct addrinfo bindhints; - memset(&bindhints, 0, sizeof(bindhints)); - bindhints.ai_socktype = SOCK_STREAM; - bindhints.ai_family = tcp->family; - bindhints.ai_flags = AI_PASSIVE; - err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); - if (err) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - lua_pushnumber(L, 1); - return 1; +static int meth_bind(lua_State* L) +{ + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{master}", 1); + const char* address = luaL_checkstring(L, 2); + const char* port = luaL_checkstring(L, 3); + const char* err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = tcp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Turns a master tcp object into a client object. \*-------------------------------------------------------------------------*/ -static int meth_connect(lua_State *L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - const char *address = luaL_checkstring(L, 2); - const char *port = luaL_checkstring(L, 3); - struct addrinfo connecthints; - const char *err; - memset(&connecthints, 0, sizeof(connecthints)); - connecthints.ai_socktype = SOCK_STREAM; - /* make sure we try to connect only to the same family */ - connecthints.ai_family = tcp->family; - timeout_markstart(&tcp->tm); - err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, - &tcp->tm, &connecthints); - /* have to set the class even if it failed due to non-blocking connects */ - auxiliar_setclass(L, "tcp{client}", 1); - if (err) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - lua_pushnumber(L, 1); - return 1; +static int meth_connect(lua_State* L) +{ + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + const char* address = luaL_checkstring(L, 2); + const char* port = luaL_checkstring(L, 3); + struct addrinfo connecthints; + const char* err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + timeout_markstart(&tcp->tm); + err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, + &tcp->tm, &connecthints); + /* have to set the class even if it failed due to non-blocking connects */ + auxiliar_setclass(L, "tcp{client}", 1); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Closes socket used by object \*-------------------------------------------------------------------------*/ -static int meth_close(lua_State *L) +static int meth_close(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - socket_destroy(&tcp->sock); - lua_pushnumber(L, 1); - return 1; + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + socket_destroy(&tcp->sock); + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Returns family as string \*-------------------------------------------------------------------------*/ -static int meth_getfamily(lua_State *L) +static int meth_getfamily(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - if (tcp->family == AF_INET6) { - lua_pushliteral(L, "inet6"); - return 1; - } else if (tcp->family == AF_INET) { - lua_pushliteral(L, "inet4"); - return 1; - } else { - lua_pushliteral(L, "inet4"); - return 1; - } + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + if (tcp->family == AF_INET6) + { + lua_pushliteral(L, "inet6"); + return 1; + } + else if (tcp->family == AF_INET) + { + lua_pushliteral(L, "inet4"); + return 1; + } + else + { + lua_pushliteral(L, "inet4"); + return 1; + } } /*-------------------------------------------------------------------------*\ * Puts the sockt in listen mode \*-------------------------------------------------------------------------*/ -static int meth_listen(lua_State *L) +static int meth_listen(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); - int backlog = (int) luaL_optnumber(L, 2, 32); - int err = socket_listen(&tcp->sock, backlog); - if (err != IO_DONE) { - lua_pushnil(L); - lua_pushstring(L, socket_strerror(err)); - return 2; - } - /* turn master object into a server object */ - auxiliar_setclass(L, "tcp{server}", 1); - lua_pushnumber(L, 1); - return 1; + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{master}", 1); + int backlog = (int)luaL_optnumber(L, 2, 32); + int err = socket_listen(&tcp->sock, backlog); + if (err != IO_DONE) + { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "tcp{server}", 1); + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Shuts the connection down partially \*-------------------------------------------------------------------------*/ -static int meth_shutdown(lua_State *L) +static int meth_shutdown(lua_State* L) { - /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ - static const char* methods[] = { "receive", "send", "both", NULL }; - p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); - int how = luaL_checkoption(L, 2, "both", methods); - socket_shutdown(&tcp->sock, how); - lua_pushnumber(L, 1); - return 1; + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = {"receive", "send", "both", NULL}; + p_tcp tcp = (p_tcp)auxiliar_checkclass(L, "tcp{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&tcp->sock, how); + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Just call inet methods \*-------------------------------------------------------------------------*/ -static int meth_getpeername(lua_State *L) +static int meth_getpeername(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return inet_meth_getpeername(L, &tcp->sock, tcp->family); + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getpeername(L, &tcp->sock, tcp->family); } -static int meth_getsockname(lua_State *L) +static int meth_getsockname(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return inet_meth_getsockname(L, &tcp->sock, tcp->family); + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getsockname(L, &tcp->sock, tcp->family); } /*-------------------------------------------------------------------------*\ * Just call tm methods \*-------------------------------------------------------------------------*/ -static int meth_settimeout(lua_State *L) +static int meth_settimeout(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return timeout_meth_settimeout(L, &tcp->tm); + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_settimeout(L, &tcp->tm); } -static int meth_gettimeout(lua_State *L) +static int meth_gettimeout(lua_State* L) { - p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return timeout_meth_gettimeout(L, &tcp->tm); + p_tcp tcp = (p_tcp)auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_gettimeout(L, &tcp->tm); } /*=========================================================================*\ @@ -364,88 +381,98 @@ static int meth_gettimeout(lua_State *L) /*-------------------------------------------------------------------------*\ * Creates a master tcp object \*-------------------------------------------------------------------------*/ -static int tcp_create(lua_State *L, int family) { - p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); - memset(tcp, 0, sizeof(t_tcp)); - /* set its type as master object */ - auxiliar_setclass(L, "tcp{master}", -1); - /* if family is AF_UNSPEC, we leave the socket invalid and - * store AF_UNSPEC into family. This will allow it to later be - * replaced with an AF_INET6 or AF_INET socket upon first use. */ - tcp->sock = SOCKET_INVALID; - tcp->family = family; - io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, - (p_error) socket_ioerror, &tcp->sock); - timeout_init(&tcp->tm, -1, -1); - buffer_init(&tcp->buf, &tcp->io, &tcp->tm); - if (family != AF_UNSPEC) { - const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); - if (err != NULL) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - socket_setnonblocking(&tcp->sock); - } - return 1; +static int tcp_create(lua_State* L, int family) +{ + p_tcp tcp = (p_tcp)lua_newuserdata(L, sizeof(t_tcp)); + memset(tcp, 0, sizeof(t_tcp)); + /* set its type as master object */ + auxiliar_setclass(L, "tcp{master}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + tcp->sock = SOCKET_INVALID; + tcp->family = family; + io_init(&tcp->io, (p_send)socket_send, (p_recv)socket_recv, + (p_error)socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + if (family != AF_UNSPEC) + { + const char* err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); + if (err != NULL) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + socket_setnonblocking(&tcp->sock); + } + return 1; } -static int global_create(lua_State *L) { - return tcp_create(L, AF_UNSPEC); +static int global_create(lua_State* L) +{ + return tcp_create(L, AF_UNSPEC); } -static int global_create4(lua_State *L) { - return tcp_create(L, AF_INET); +static int global_create4(lua_State* L) +{ + return tcp_create(L, AF_INET); } -static int global_create6(lua_State *L) { - return tcp_create(L, AF_INET6); +static int global_create6(lua_State* L) +{ + return tcp_create(L, AF_INET6); } -static int global_connect(lua_State *L) { - const char *remoteaddr = luaL_checkstring(L, 1); - const char *remoteserv = luaL_checkstring(L, 2); - const char *localaddr = luaL_optstring(L, 3, NULL); - const char *localserv = luaL_optstring(L, 4, "0"); - int family = inet_optfamily(L, 5, "unspec"); - p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); - struct addrinfo bindhints, connecthints; - const char *err = NULL; - /* initialize tcp structure */ - memset(tcp, 0, sizeof(t_tcp)); - io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, - (p_error) socket_ioerror, &tcp->sock); - timeout_init(&tcp->tm, -1, -1); - buffer_init(&tcp->buf, &tcp->io, &tcp->tm); - tcp->sock = SOCKET_INVALID; - tcp->family = AF_UNSPEC; - /* allow user to pick local address and port */ - memset(&bindhints, 0, sizeof(bindhints)); - bindhints.ai_socktype = SOCK_STREAM; - bindhints.ai_family = family; - bindhints.ai_flags = AI_PASSIVE; - if (localaddr) { - err = inet_trybind(&tcp->sock, &tcp->family, localaddr, - localserv, &bindhints); - if (err) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - } - /* try to connect to remote address and port */ - memset(&connecthints, 0, sizeof(connecthints)); - connecthints.ai_socktype = SOCK_STREAM; - /* make sure we try to connect only to the same family */ - connecthints.ai_family = tcp->family; - err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, - &tcp->tm, &connecthints); - if (err) { - socket_destroy(&tcp->sock); - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - auxiliar_setclass(L, "tcp{client}", -1); - return 1; +static int global_connect(lua_State* L) +{ + const char* remoteaddr = luaL_checkstring(L, 1); + const char* remoteserv = luaL_checkstring(L, 2); + const char* localaddr = luaL_optstring(L, 3, NULL); + const char* localserv = luaL_optstring(L, 4, "0"); + int family = inet_optfamily(L, 5, "unspec"); + p_tcp tcp = (p_tcp)lua_newuserdata(L, sizeof(t_tcp)); + struct addrinfo bindhints, connecthints; + const char* err = NULL; + /* initialize tcp structure */ + memset(tcp, 0, sizeof(t_tcp)); + io_init(&tcp->io, (p_send)socket_send, (p_recv)socket_recv, + (p_error)socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + tcp->sock = SOCKET_INVALID; + tcp->family = AF_UNSPEC; + /* allow user to pick local address and port */ + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = family; + bindhints.ai_flags = AI_PASSIVE; + if (localaddr) + { + err = inet_trybind(&tcp->sock, &tcp->family, localaddr, + localserv, &bindhints); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + } + /* try to connect to remote address and port */ + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, + &tcp->tm, &connecthints); + if (err) + { + socket_destroy(&tcp->sock); + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "tcp{client}", -1); + return 1; } diff --git a/Lua/tcp.h b/Lua/tcp.h index eded620..583ee2f 100644 --- a/Lua/tcp.h +++ b/Lua/tcp.h @@ -20,16 +20,17 @@ #include "timeout.h" #include "socket.h" -typedef struct t_tcp_ { - t_socket sock; - t_io io; - t_buffer buf; - t_timeout tm; - int family; +typedef struct t_tcp_ +{ + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; + int family; } t_tcp; -typedef t_tcp *p_tcp; +typedef t_tcp* p_tcp; -int tcp_open(lua_State *L); +int tcp_open(lua_State* L); #endif /* TCP_H */ diff --git a/Lua/timeout.c b/Lua/timeout.c index 5a601d5..2ea4253 100644 --- a/Lua/timeout.c +++ b/Lua/timeout.c @@ -31,13 +31,13 @@ /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ -static int timeout_lua_gettime(lua_State *L); -static int timeout_lua_sleep(lua_State *L); +static int timeout_lua_gettime(lua_State* L); +static int timeout_lua_sleep(lua_State* L); static luaL_Reg func[] = { - { "gettime", timeout_lua_gettime }, - { "sleep", timeout_lua_sleep }, - { NULL, NULL } + {"gettime", timeout_lua_gettime}, + {"sleep", timeout_lua_sleep}, + {NULL, NULL} }; /*=========================================================================*\ @@ -46,9 +46,10 @@ static luaL_Reg func[] = { /*-------------------------------------------------------------------------*\ * Initialize structure \*-------------------------------------------------------------------------*/ -void timeout_init(p_timeout tm, double block, double total) { - tm->block = block; - tm->total = total; +void timeout_init(p_timeout tm, double block, double total) +{ + tm->block = block; + tm->total = total; } /*-------------------------------------------------------------------------*\ @@ -59,18 +60,26 @@ void timeout_init(p_timeout tm, double block, double total) { * Returns * the number of ms left or -1 if there is no time limit \*-------------------------------------------------------------------------*/ -double timeout_get(p_timeout tm) { - if (tm->block < 0.0 && tm->total < 0.0) { - return -1; - } else if (tm->block < 0.0) { - double t = tm->total - timeout_gettime() + tm->start; - return MAX(t, 0.0); - } else if (tm->total < 0.0) { - return tm->block; - } else { - double t = tm->total - timeout_gettime() + tm->start; - return MIN(tm->block, MAX(t, 0.0)); - } +double timeout_get(p_timeout tm) +{ + if (tm->block < 0.0 && tm->total < 0.0) + { + return -1; + } + else if (tm->block < 0.0) + { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } + else if (tm->total < 0.0) + { + return tm->block; + } + else + { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } } /*-------------------------------------------------------------------------*\ @@ -80,8 +89,9 @@ double timeout_get(p_timeout tm) { * Returns * start field of structure \*-------------------------------------------------------------------------*/ -double timeout_getstart(p_timeout tm) { - return tm->start; +double timeout_getstart(p_timeout tm) +{ + return tm->start; } /*-------------------------------------------------------------------------*\ @@ -92,19 +102,27 @@ double timeout_getstart(p_timeout tm) { * Returns * the number of ms left or -1 if there is no time limit \*-------------------------------------------------------------------------*/ -double timeout_getretry(p_timeout tm) { - if (tm->block < 0.0 && tm->total < 0.0) { - return -1; - } else if (tm->block < 0.0) { - double t = tm->total - timeout_gettime() + tm->start; - return MAX(t, 0.0); - } else if (tm->total < 0.0) { - double t = tm->block - timeout_gettime() + tm->start; - return MAX(t, 0.0); - } else { - double t = tm->total - timeout_gettime() + tm->start; - return MIN(tm->block, MAX(t, 0.0)); - } +double timeout_getretry(p_timeout tm) +{ + if (tm->block < 0.0 && tm->total < 0.0) + { + return -1; + } + else if (tm->block < 0.0) + { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } + else if (tm->total < 0.0) + { + double t = tm->block - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } + else + { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } } /*-------------------------------------------------------------------------*\ @@ -112,9 +130,10 @@ double timeout_getretry(p_timeout tm) { * Input * tm: timeout control structure \*-------------------------------------------------------------------------*/ -p_timeout timeout_markstart(p_timeout tm) { - tm->start = timeout_gettime(); - return tm; +p_timeout timeout_markstart(p_timeout tm) +{ + tm->start = timeout_gettime(); + return tm; } /*-------------------------------------------------------------------------*\ @@ -123,14 +142,15 @@ p_timeout timeout_markstart(p_timeout tm) { * time in s. \*-------------------------------------------------------------------------*/ #ifdef _WIN32 -double timeout_gettime(void) { - FILETIME ft; - double t; - GetSystemTimeAsFileTime(&ft); - /* Windows file time (time since January 1, 1601 (UTC)) */ - t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); - /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ - return (t - 11644473600.0); +double timeout_gettime(void) +{ + FILETIME ft; + double t; + GetSystemTimeAsFileTime(&ft); + /* Windows file time (time since January 1, 1601 (UTC)) */ + t = ft.dwLowDateTime / 1.0e7 + ft.dwHighDateTime * (4294967296.0 / 1.0e7); + /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ + return (t - 11644473600.0); } #else double timeout_gettime(void) { @@ -144,9 +164,10 @@ double timeout_gettime(void) { /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int timeout_open(lua_State *L) { - luaL_setfuncs(L, func, 0); - return 0; +int timeout_open(lua_State* L) +{ + luaL_setfuncs(L, func, 0); + return 0; } /*-------------------------------------------------------------------------*\ @@ -155,32 +176,36 @@ int timeout_open(lua_State *L) { * time: time out value in seconds * mode: "b" for block timeout, "t" for total timeout. (default: b) \*-------------------------------------------------------------------------*/ -int timeout_meth_settimeout(lua_State *L, p_timeout tm) { - double t = luaL_optnumber(L, 2, -1); - const char *mode = luaL_optstring(L, 3, "b"); - switch (*mode) { - case 'b': - tm->block = t; - break; - case 'r': case 't': - tm->total = t; - break; - default: - luaL_argcheck(L, 0, 3, "invalid timeout mode"); - break; - } - lua_pushnumber(L, 1); - return 1; +int timeout_meth_settimeout(lua_State* L, p_timeout tm) +{ + double t = luaL_optnumber(L, 2, -1); + const char* mode = luaL_optstring(L, 3, "b"); + switch (*mode) + { + case 'b': + tm->block = t; + break; + case 'r': + case 't': + tm->total = t; + break; + default: + luaL_argcheck(L, 0, 3, "invalid timeout mode"); + break; + } + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Gets timeout values for IO operations * Lua Output: block, total \*-------------------------------------------------------------------------*/ -int timeout_meth_gettimeout(lua_State *L, p_timeout tm) { - lua_pushnumber(L, tm->block); - lua_pushnumber(L, tm->total); - return 2; +int timeout_meth_gettimeout(lua_State* L, p_timeout tm) +{ + lua_pushnumber(L, tm->block); + lua_pushnumber(L, tm->total); + return 2; } /*=========================================================================*\ @@ -189,24 +214,24 @@ int timeout_meth_gettimeout(lua_State *L, p_timeout tm) { /*-------------------------------------------------------------------------*\ * Returns the time the system has been up, in secconds. \*-------------------------------------------------------------------------*/ -static int timeout_lua_gettime(lua_State *L) +static int timeout_lua_gettime(lua_State* L) { - lua_pushnumber(L, timeout_gettime()); - return 1; + lua_pushnumber(L, timeout_gettime()); + return 1; } /*-------------------------------------------------------------------------*\ * Sleep for n seconds. \*-------------------------------------------------------------------------*/ #ifdef _WIN32 -int timeout_lua_sleep(lua_State *L) +int timeout_lua_sleep(lua_State* L) { - double n = luaL_checknumber(L, 1); - if (n < 0.0) n = 0.0; - if (n < DBL_MAX/1000.0) n *= 1000.0; - if (n > INT_MAX) n = INT_MAX; - Sleep((int)n); - return 0; + double n = luaL_checknumber(L, 1); + if (n < 0.0) n = 0.0; + if (n < DBL_MAX / 1000.0) n *= 1000.0; + if (n > INT_MAX) n = INT_MAX; + Sleep((int)n); + return 0; } #else int timeout_lua_sleep(lua_State *L) diff --git a/Lua/timeout.h b/Lua/timeout.h index af90231..f10065f 100644 --- a/Lua/timeout.h +++ b/Lua/timeout.h @@ -7,22 +7,24 @@ #include "lua.h" /* timeout control structure */ -typedef struct t_timeout_ { - double block; /* maximum time for blocking calls */ - double total; /* total number of miliseconds for operation */ - double start; /* time of start of operation */ +typedef struct t_timeout_ +{ + double block; /* maximum time for blocking calls */ + double total; /* total number of miliseconds for operation */ + double start; /* time of start of operation */ } t_timeout; -typedef t_timeout *p_timeout; -int timeout_open(lua_State *L); +typedef t_timeout* p_timeout; + +int timeout_open(lua_State* L); void timeout_init(p_timeout tm, double block, double total); double timeout_get(p_timeout tm); double timeout_getretry(p_timeout tm); p_timeout timeout_markstart(p_timeout tm); double timeout_getstart(p_timeout tm); double timeout_gettime(void); -int timeout_meth_settimeout(lua_State *L, p_timeout tm); -int timeout_meth_gettimeout(lua_State *L, p_timeout tm); +int timeout_meth_settimeout(lua_State* L, p_timeout tm); +int timeout_meth_gettimeout(lua_State* L, p_timeout tm); #define timeout_iszero(tm) ((tm)->block == 0.0) diff --git a/Lua/udp.c b/Lua/udp.c index a47ed75..4bb045b 100644 --- a/Lua/udp.c +++ b/Lua/udp.c @@ -26,420 +26,459 @@ /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ -static int global_create(lua_State *L); -static int global_create4(lua_State *L); -static int global_create6(lua_State *L); -static int meth_send(lua_State *L); -static int meth_sendto(lua_State *L); -static int meth_receive(lua_State *L); -static int meth_receivefrom(lua_State *L); -static int meth_getfamily(lua_State *L); -static int meth_getsockname(lua_State *L); -static int meth_getpeername(lua_State *L); -static int meth_gettimeout(lua_State *L); -static int meth_setsockname(lua_State *L); -static int meth_setpeername(lua_State *L); -static int meth_close(lua_State *L); -static int meth_setoption(lua_State *L); -static int meth_getoption(lua_State *L); -static int meth_settimeout(lua_State *L); -static int meth_getfd(lua_State *L); -static int meth_setfd(lua_State *L); -static int meth_dirty(lua_State *L); +static int global_create(lua_State* L); +static int global_create4(lua_State* L); +static int global_create6(lua_State* L); +static int meth_send(lua_State* L); +static int meth_sendto(lua_State* L); +static int meth_receive(lua_State* L); +static int meth_receivefrom(lua_State* L); +static int meth_getfamily(lua_State* L); +static int meth_getsockname(lua_State* L); +static int meth_getpeername(lua_State* L); +static int meth_gettimeout(lua_State* L); +static int meth_setsockname(lua_State* L); +static int meth_setpeername(lua_State* L); +static int meth_close(lua_State* L); +static int meth_setoption(lua_State* L); +static int meth_getoption(lua_State* L); +static int meth_settimeout(lua_State* L); +static int meth_getfd(lua_State* L); +static int meth_setfd(lua_State* L); +static int meth_dirty(lua_State* L); /* udp object methods */ static luaL_Reg udp_methods[] = { - {"__gc", meth_close}, - {"__tostring", auxiliar_tostring}, - {"close", meth_close}, - {"dirty", meth_dirty}, - {"getfamily", meth_getfamily}, - {"getfd", meth_getfd}, - {"getpeername", meth_getpeername}, - {"getsockname", meth_getsockname}, - {"receive", meth_receive}, - {"receivefrom", meth_receivefrom}, - {"send", meth_send}, - {"sendto", meth_sendto}, - {"setfd", meth_setfd}, - {"setoption", meth_setoption}, - {"getoption", meth_getoption}, - {"setpeername", meth_setpeername}, - {"setsockname", meth_setsockname}, - {"settimeout", meth_settimeout}, - {"gettimeout", meth_gettimeout}, - {NULL, NULL} + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"close", meth_close}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"receive", meth_receive}, + {"receivefrom", meth_receivefrom}, + {"send", meth_send}, + {"sendto", meth_sendto}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"getoption", meth_getoption}, + {"setpeername", meth_setpeername}, + {"setsockname", meth_setsockname}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {NULL, NULL} }; /* socket options for setoption */ static t_opt optset[] = { - {"dontroute", opt_set_dontroute}, - {"broadcast", opt_set_broadcast}, - {"reuseaddr", opt_set_reuseaddr}, - {"reuseport", opt_set_reuseport}, - {"ip-multicast-if", opt_set_ip_multicast_if}, - {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, - {"ip-multicast-loop", opt_set_ip_multicast_loop}, - {"ip-add-membership", opt_set_ip_add_membership}, - {"ip-drop-membership", opt_set_ip_drop_membersip}, - {"ipv6-unicast-hops", opt_set_ip6_unicast_hops}, - {"ipv6-multicast-hops", opt_set_ip6_unicast_hops}, - {"ipv6-multicast-loop", opt_set_ip6_multicast_loop}, - {"ipv6-add-membership", opt_set_ip6_add_membership}, - {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, - {"ipv6-v6only", opt_set_ip6_v6only}, - {NULL, NULL} + {"dontroute", opt_set_dontroute}, + {"broadcast", opt_set_broadcast}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"ip-multicast-if", opt_set_ip_multicast_if}, + {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, + {"ip-multicast-loop", opt_set_ip_multicast_loop}, + {"ip-add-membership", opt_set_ip_add_membership}, + {"ip-drop-membership", opt_set_ip_drop_membersip}, + {"ipv6-unicast-hops", opt_set_ip6_unicast_hops}, + {"ipv6-multicast-hops", opt_set_ip6_unicast_hops}, + {"ipv6-multicast-loop", opt_set_ip6_multicast_loop}, + {"ipv6-add-membership", opt_set_ip6_add_membership}, + {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {NULL, NULL} }; /* socket options for getoption */ static t_opt optget[] = { - {"dontroute", opt_get_dontroute}, - {"broadcast", opt_get_broadcast}, - {"reuseaddr", opt_get_reuseaddr}, - {"reuseport", opt_get_reuseport}, - {"ip-multicast-if", opt_get_ip_multicast_if}, - {"ip-multicast-loop", opt_get_ip_multicast_loop}, - {"error", opt_get_error}, - {"ipv6-unicast-hops", opt_get_ip6_unicast_hops}, - {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, - {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, - {"ipv6-v6only", opt_get_ip6_v6only}, - {NULL, NULL} + {"dontroute", opt_get_dontroute}, + {"broadcast", opt_get_broadcast}, + {"reuseaddr", opt_get_reuseaddr}, + {"reuseport", opt_get_reuseport}, + {"ip-multicast-if", opt_get_ip_multicast_if}, + {"ip-multicast-loop", opt_get_ip_multicast_loop}, + {"error", opt_get_error}, + {"ipv6-unicast-hops", opt_get_ip6_unicast_hops}, + {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, + {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, + {"ipv6-v6only", opt_get_ip6_v6only}, + {NULL, NULL} }; /* functions in library namespace */ static luaL_Reg func[] = { - {"udp", global_create}, - {"udp4", global_create4}, - {"udp6", global_create6}, - {NULL, NULL} + {"udp", global_create}, + {"udp4", global_create4}, + {"udp6", global_create6}, + {NULL, NULL} }; /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int udp_open(lua_State *L) { - /* create classes */ - auxiliar_newclass(L, "udp{connected}", udp_methods); - auxiliar_newclass(L, "udp{unconnected}", udp_methods); - /* create class groups */ - auxiliar_add2group(L, "udp{connected}", "udp{any}"); - auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); - auxiliar_add2group(L, "udp{connected}", "select{able}"); - auxiliar_add2group(L, "udp{unconnected}", "select{able}"); - /* define library functions */ - luaL_setfuncs(L, func, 0); - /* export default UDP size */ - lua_pushliteral(L, "_DATAGRAMSIZE"); - lua_pushinteger(L, UDP_DATAGRAMSIZE); - lua_rawset(L, -3); - return 0; +int udp_open(lua_State* L) +{ + /* create classes */ + auxiliar_newclass(L, "udp{connected}", udp_methods); + auxiliar_newclass(L, "udp{unconnected}", udp_methods); + /* create class groups */ + auxiliar_add2group(L, "udp{connected}", "udp{any}"); + auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); + auxiliar_add2group(L, "udp{connected}", "select{able}"); + auxiliar_add2group(L, "udp{unconnected}", "select{able}"); + /* define library functions */ + luaL_setfuncs(L, func, 0); + /* export default UDP size */ + lua_pushliteral(L, "_DATAGRAMSIZE"); + lua_pushinteger(L, UDP_DATAGRAMSIZE); + lua_rawset(L, -3); + return 0; } /*=========================================================================*\ * Lua methods \*=========================================================================*/ -static const char *udp_strerror(int err) { - /* a 'closed' error on an unconnected means the target address was not - * accepted by the transport layer */ - if (err == IO_CLOSED) return "refused"; - else return socket_strerror(err); +static const char* udp_strerror(int err) +{ + /* a 'closed' error on an unconnected means the target address was not + * accepted by the transport layer */ + if (err == IO_CLOSED) return "refused"; + else return socket_strerror(err); } /*-------------------------------------------------------------------------*\ * Send data through connected udp socket \*-------------------------------------------------------------------------*/ -static int meth_send(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); - p_timeout tm = &udp->tm; - size_t count, sent = 0; - int err; - const char *data = luaL_checklstring(L, 2, &count); - timeout_markstart(tm); - err = socket_send(&udp->sock, data, count, &sent, tm); - if (err != IO_DONE) { - lua_pushnil(L); - lua_pushstring(L, udp_strerror(err)); - return 2; - } - lua_pushnumber(L, (lua_Number) sent); - return 1; +static int meth_send(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkclass(L, "udp{connected}", 1); + p_timeout tm = &udp->tm; + size_t count, sent = 0; + int err; + const char* data = luaL_checklstring(L, 2, &count); + timeout_markstart(tm); + err = socket_send(&udp->sock, data, count, &sent, tm); + if (err != IO_DONE) + { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number)sent); + return 1; } /*-------------------------------------------------------------------------*\ * Send data through unconnected udp socket \*-------------------------------------------------------------------------*/ -static int meth_sendto(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); - size_t count, sent = 0; - const char *data = luaL_checklstring(L, 2, &count); - const char *ip = luaL_checkstring(L, 3); - const char *port = luaL_checkstring(L, 4); - p_timeout tm = &udp->tm; - int err; - struct addrinfo aihint; - struct addrinfo *ai; - memset(&aihint, 0, sizeof(aihint)); - aihint.ai_family = udp->family; - aihint.ai_socktype = SOCK_DGRAM; - aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; - err = getaddrinfo(ip, port, &aihint, &ai); - if (err) { - lua_pushnil(L); - lua_pushstring(L, gai_strerrorA(err)); - return 2; - } +static int meth_sendto(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkclass(L, "udp{unconnected}", 1); + size_t count, sent = 0; + const char* data = luaL_checklstring(L, 2, &count); + const char* ip = luaL_checkstring(L, 3); + const char* port = luaL_checkstring(L, 4); + p_timeout tm = &udp->tm; + int err; + struct addrinfo aihint; + struct addrinfo* ai; + memset(&aihint, 0, sizeof(aihint)); + aihint.ai_family = udp->family; + aihint.ai_socktype = SOCK_DGRAM; + aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + err = getaddrinfo(ip, port, &aihint, &ai); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, gai_strerrorA(err)); + return 2; + } - /* create socket if on first sendto if AF_UNSPEC was set */ - if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) { - struct addrinfo *ap; - const char *errstr = NULL; - for (ap = ai; ap != NULL; ap = ap->ai_next) { - errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0); - if (errstr == NULL) { - socket_setnonblocking(&udp->sock); - udp->family = ap->ai_family; - break; - } - } - if (errstr != NULL) { - lua_pushnil(L); - lua_pushstring(L, errstr); - freeaddrinfo(ai); - return 2; - } - } + /* create socket if on first sendto if AF_UNSPEC was set */ + if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) + { + struct addrinfo* ap; + const char* errstr = NULL; + for (ap = ai; ap != NULL; ap = ap->ai_next) + { + errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0); + if (errstr == NULL) + { + socket_setnonblocking(&udp->sock); + udp->family = ap->ai_family; + break; + } + } + if (errstr != NULL) + { + lua_pushnil(L); + lua_pushstring(L, errstr); + freeaddrinfo(ai); + return 2; + } + } - timeout_markstart(tm); - err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, - (socklen_t) ai->ai_addrlen, tm); - freeaddrinfo(ai); - if (err != IO_DONE) { - lua_pushnil(L); - lua_pushstring(L, udp_strerror(err)); - return 2; - } - lua_pushnumber(L, (lua_Number) sent); - return 1; + timeout_markstart(tm); + err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, + (socklen_t)ai->ai_addrlen, tm); + freeaddrinfo(ai); + if (err != IO_DONE) + { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number)sent); + return 1; } /*-------------------------------------------------------------------------*\ * Receives data from a UDP socket \*-------------------------------------------------------------------------*/ -static int meth_receive(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - char buf[UDP_DATAGRAMSIZE]; - size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); - char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; - int err; - p_timeout tm = &udp->tm; - timeout_markstart(tm); - if (!dgram) { - lua_pushnil(L); - lua_pushliteral(L, "out of memory"); - return 2; - } - err = socket_recv(&udp->sock, dgram, wanted, &got, tm); - /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ - if (err != IO_DONE && err != IO_CLOSED) { - lua_pushnil(L); - lua_pushstring(L, udp_strerror(err)); - if (wanted > sizeof(buf)) free(dgram); - return 2; - } - lua_pushlstring(L, dgram, got); - if (wanted > sizeof(buf)) free(dgram); - return 1; +static int meth_receive(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + char buf[UDP_DATAGRAMSIZE]; + size_t got, wanted = (size_t)luaL_optnumber(L, 2, sizeof(buf)); + char* dgram = wanted > sizeof(buf) ? (char*)malloc(wanted) : buf; + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + if (!dgram) + { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recv(&udp->sock, dgram, wanted, &got, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) + { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + if (wanted > sizeof(buf)) free(dgram); + return 1; } /*-------------------------------------------------------------------------*\ * Receives data and sender from a UDP socket \*-------------------------------------------------------------------------*/ -static int meth_receivefrom(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); - char buf[UDP_DATAGRAMSIZE]; - size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); - char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; - struct sockaddr_storage addr; - socklen_t addr_len = sizeof(addr); - char addrstr[INET6_ADDRSTRLEN]; - char portstr[6]; - int err; - p_timeout tm = &udp->tm; - timeout_markstart(tm); - if (!dgram) { - lua_pushnil(L); - lua_pushliteral(L, "out of memory"); - return 2; - } - err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, - &addr_len, tm); - /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ - if (err != IO_DONE && err != IO_CLOSED) { - lua_pushnil(L); - lua_pushstring(L, udp_strerror(err)); - if (wanted > sizeof(buf)) free(dgram); - return 2; - } - err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, - INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); - if (err) { - lua_pushnil(L); - lua_pushstring(L, gai_strerrorA(err)); - if (wanted > sizeof(buf)) free(dgram); - return 2; - } - lua_pushlstring(L, dgram, got); - lua_pushstring(L, addrstr); - lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); - if (wanted > sizeof(buf)) free(dgram); - return 3; +static int meth_receivefrom(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkclass(L, "udp{unconnected}", 1); + char buf[UDP_DATAGRAMSIZE]; + size_t got, wanted = (size_t)luaL_optnumber(L, 2, sizeof(buf)); + char* dgram = wanted > sizeof(buf) ? (char*)malloc(wanted) : buf; + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + char addrstr[INET6_ADDRSTRLEN]; + char portstr[6]; + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + if (!dgram) + { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA*)&addr, + &addr_len, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) + { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + err = getnameinfo((struct sockaddr*)&addr, addr_len, addrstr, + INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, gai_strerrorA(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + lua_pushstring(L, addrstr); + lua_pushinteger(L, (int)strtol(portstr, (char**)NULL, 10)); + if (wanted > sizeof(buf)) free(dgram); + return 3; } /*-------------------------------------------------------------------------*\ * Returns family as string \*-------------------------------------------------------------------------*/ -static int meth_getfamily(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - if (udp->family == AF_INET6) { - lua_pushliteral(L, "inet6"); - return 1; - } else { - lua_pushliteral(L, "inet4"); - return 1; - } +static int meth_getfamily(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + if (udp->family == AF_INET6) + { + lua_pushliteral(L, "inet6"); + return 1; + } + else + { + lua_pushliteral(L, "inet4"); + return 1; + } } /*-------------------------------------------------------------------------*\ * Select support methods \*-------------------------------------------------------------------------*/ -static int meth_getfd(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - lua_pushnumber(L, (int) udp->sock); - return 1; +static int meth_getfd(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + lua_pushnumber(L, (int)udp->sock); + return 1; } /* this is very dangerous, but can be handy for those that are brave enough */ -static int meth_setfd(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - udp->sock = (t_socket) luaL_checknumber(L, 2); - return 0; +static int meth_setfd(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + udp->sock = (t_socket)luaL_checknumber(L, 2); + return 0; } -static int meth_dirty(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - (void) udp; - lua_pushboolean(L, 0); - return 1; +static int meth_dirty(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + (void)udp; + lua_pushboolean(L, 0); + return 1; } /*-------------------------------------------------------------------------*\ * Just call inet methods \*-------------------------------------------------------------------------*/ -static int meth_getpeername(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); - return inet_meth_getpeername(L, &udp->sock, udp->family); +static int meth_getpeername(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkclass(L, "udp{connected}", 1); + return inet_meth_getpeername(L, &udp->sock, udp->family); } -static int meth_getsockname(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - return inet_meth_getsockname(L, &udp->sock, udp->family); +static int meth_getsockname(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + return inet_meth_getsockname(L, &udp->sock, udp->family); } /*-------------------------------------------------------------------------*\ * Just call option handler \*-------------------------------------------------------------------------*/ -static int meth_setoption(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - return opt_meth_setoption(L, optset, &udp->sock); +static int meth_setoption(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_setoption(L, optset, &udp->sock); } /*-------------------------------------------------------------------------*\ * Just call option handler \*-------------------------------------------------------------------------*/ -static int meth_getoption(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - return opt_meth_getoption(L, optget, &udp->sock); +static int meth_getoption(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_getoption(L, optget, &udp->sock); } /*-------------------------------------------------------------------------*\ * Just call tm methods \*-------------------------------------------------------------------------*/ -static int meth_settimeout(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - return timeout_meth_settimeout(L, &udp->tm); +static int meth_settimeout(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_settimeout(L, &udp->tm); } -static int meth_gettimeout(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - return timeout_meth_gettimeout(L, &udp->tm); +static int meth_gettimeout(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_gettimeout(L, &udp->tm); } /*-------------------------------------------------------------------------*\ * Turns a master udp object into a client object. \*-------------------------------------------------------------------------*/ -static int meth_setpeername(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - p_timeout tm = &udp->tm; - const char *address = luaL_checkstring(L, 2); - int connecting = strcmp(address, "*"); - const char *port = connecting? luaL_checkstring(L, 3): "0"; - struct addrinfo connecthints; - const char *err; - memset(&connecthints, 0, sizeof(connecthints)); - connecthints.ai_socktype = SOCK_DGRAM; - /* make sure we try to connect only to the same family */ - connecthints.ai_family = udp->family; - if (connecting) { - err = inet_tryconnect(&udp->sock, &udp->family, address, - port, tm, &connecthints); - if (err) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - auxiliar_setclass(L, "udp{connected}", 1); - } else { - /* we ignore possible errors because Mac OS X always - * returns EAFNOSUPPORT */ - inet_trydisconnect(&udp->sock, udp->family, tm); - auxiliar_setclass(L, "udp{unconnected}", 1); - } - lua_pushnumber(L, 1); - return 1; +static int meth_setpeername(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + p_timeout tm = &udp->tm; + const char* address = luaL_checkstring(L, 2); + int connecting = strcmp(address, "*"); + const char* port = connecting ? luaL_checkstring(L, 3) : "0"; + struct addrinfo connecthints; + const char* err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_DGRAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = udp->family; + if (connecting) + { + err = inet_tryconnect(&udp->sock, &udp->family, address, + port, tm, &connecthints); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "udp{connected}", 1); + } + else + { + /* we ignore possible errors because Mac OS X always + * returns EAFNOSUPPORT */ + inet_trydisconnect(&udp->sock, udp->family, tm); + auxiliar_setclass(L, "udp{unconnected}", 1); + } + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Closes socket used by object \*-------------------------------------------------------------------------*/ -static int meth_close(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - socket_destroy(&udp->sock); - lua_pushnumber(L, 1); - return 1; +static int meth_close(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkgroup(L, "udp{any}", 1); + socket_destroy(&udp->sock); + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ * Turns a master object into a server object \*-------------------------------------------------------------------------*/ -static int meth_setsockname(lua_State *L) { - p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); - const char *address = luaL_checkstring(L, 2); - const char *port = luaL_checkstring(L, 3); - const char *err; - struct addrinfo bindhints; - memset(&bindhints, 0, sizeof(bindhints)); - bindhints.ai_socktype = SOCK_DGRAM; - bindhints.ai_family = udp->family; - bindhints.ai_flags = AI_PASSIVE; - err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints); - if (err) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - lua_pushnumber(L, 1); - return 1; +static int meth_setsockname(lua_State* L) +{ + p_udp udp = (p_udp)auxiliar_checkclass(L, "udp{unconnected}", 1); + const char* address = luaL_checkstring(L, 2); + const char* port = luaL_checkstring(L, 3); + const char* err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_DGRAM; + bindhints.ai_family = udp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints); + if (err) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; } /*=========================================================================*\ @@ -448,36 +487,42 @@ static int meth_setsockname(lua_State *L) { /*-------------------------------------------------------------------------*\ * Creates a master udp object \*-------------------------------------------------------------------------*/ -static int udp_create(lua_State *L, int family) { - /* allocate udp object */ - p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); - auxiliar_setclass(L, "udp{unconnected}", -1); - /* if family is AF_UNSPEC, we leave the socket invalid and - * store AF_UNSPEC into family. This will allow it to later be - * replaced with an AF_INET6 or AF_INET socket upon first use. */ - udp->sock = SOCKET_INVALID; - timeout_init(&udp->tm, -1, -1); - udp->family = family; - if (family != AF_UNSPEC) { - const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0); - if (err != NULL) { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - socket_setnonblocking(&udp->sock); - } - return 1; +static int udp_create(lua_State* L, int family) +{ + /* allocate udp object */ + p_udp udp = (p_udp)lua_newuserdata(L, sizeof(t_udp)); + auxiliar_setclass(L, "udp{unconnected}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + udp->sock = SOCKET_INVALID; + timeout_init(&udp->tm, -1, -1); + udp->family = family; + if (family != AF_UNSPEC) + { + const char* err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0); + if (err != NULL) + { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + socket_setnonblocking(&udp->sock); + } + return 1; } -static int global_create(lua_State *L) { - return udp_create(L, AF_UNSPEC); +static int global_create(lua_State* L) +{ + return udp_create(L, AF_UNSPEC); } -static int global_create4(lua_State *L) { - return udp_create(L, AF_INET); +static int global_create4(lua_State* L) +{ + return udp_create(L, AF_INET); } -static int global_create6(lua_State *L) { - return udp_create(L, AF_INET6); +static int global_create6(lua_State* L) +{ + return udp_create(L, AF_INET6); } diff --git a/Lua/udp.h b/Lua/udp.h index be9b6a5..162ae04 100644 --- a/Lua/udp.h +++ b/Lua/udp.h @@ -19,13 +19,15 @@ #define UDP_DATAGRAMSIZE 8192 -typedef struct t_udp_ { - t_socket sock; - t_timeout tm; - int family; +typedef struct t_udp_ +{ + t_socket sock; + t_timeout tm; + int family; } t_udp; -typedef t_udp *p_udp; -int udp_open(lua_State *L); +typedef t_udp* p_udp; + +int udp_open(lua_State* L); #endif /* UDP_H */ diff --git a/Lua/usocket.c b/Lua/usocket.c index cc4dd23..3239f85 100644 --- a/Lua/usocket.c +++ b/Lua/usocket.c @@ -451,4 +451,4 @@ const char *socket_gaistrerror(int err) { } } -#endif \ No newline at end of file +#endif diff --git a/Lua/usocket.h b/Lua/usocket.h index 45f2f99..1595c02 100644 --- a/Lua/usocket.h +++ b/Lua/usocket.h @@ -51,7 +51,7 @@ #endif /* !IPV6_DROP_MEMBERSHIP */ typedef int t_socket; -typedef t_socket *p_socket; +typedef t_socket* p_socket; typedef struct sockaddr_storage t_sockaddr_storage; #define SOCKET_INVALID (-1) diff --git a/Lua/wsocket.c b/Lua/wsocket.c index 1a985dc..bd58105 100644 --- a/Lua/wsocket.c +++ b/Lua/wsocket.c @@ -13,30 +13,33 @@ #include "pierror.h" /* WinSock doesn't have a strerror... */ -static const char *wstrerror(int err); +static const char* wstrerror(int err); /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int socket_open(void) { - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(2, 0); - int err = WSAStartup(wVersionRequested, &wsaData ); - if (err != 0) return 0; - if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) && - (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) { - WSACleanup(); - return 0; - } - return 1; +int socket_open(void) +{ + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + int err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) return 0; + if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) && + (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) + { + WSACleanup(); + return 0; + } + return 1; } /*-------------------------------------------------------------------------*\ * Close module \*-------------------------------------------------------------------------*/ -int socket_close(void) { - WSACleanup(); - return 1; +int socket_close(void) +{ + WSACleanup(); + return 1; } /*-------------------------------------------------------------------------*\ @@ -47,143 +50,169 @@ int socket_close(void) { #define WAITFD_E 4 #define WAITFD_C (WAITFD_E|WAITFD_W) -int socket_waitfd(p_socket ps, int sw, p_timeout tm) { - int ret; - fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; - struct timeval tv, *tp = NULL; - double t; - if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ - if (sw & WAITFD_R) { - FD_ZERO(&rfds); - FD_SET(*ps, &rfds); - rp = &rfds; - } - if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } - if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; } - if ((t = timeout_get(tm)) >= 0.0) { - tv.tv_sec = (int) t; - tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); - tp = &tv; - } - ret = select(0, rp, wp, ep, tp); - if (ret == -1) return WSAGetLastError(); - if (ret == 0) return IO_TIMEOUT; - if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; - return IO_DONE; +int socket_waitfd(p_socket ps, int sw, p_timeout tm) +{ + int ret; + fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; + struct timeval tv, *tp = NULL; + double t; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + if (sw & WAITFD_R) + { + FD_ZERO(&rfds); + FD_SET(*ps, &rfds); + rp = &rfds; + } + if (sw & WAITFD_W) + { + FD_ZERO(&wfds); + FD_SET(*ps, &wfds); + wp = &wfds; + } + if (sw & WAITFD_C) + { + FD_ZERO(&efds); + FD_SET(*ps, &efds); + ep = &efds; + } + if ((t = timeout_get(tm)) >= 0.0) + { + tv.tv_sec = (int)t; + tv.tv_usec = (int)((t - tv.tv_sec) * 1.0e6); + tp = &tv; + } + ret = select(0, rp, wp, ep, tp); + if (ret == -1) return WSAGetLastError(); + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; + return IO_DONE; } /*-------------------------------------------------------------------------*\ * Select with int timeout in ms \*-------------------------------------------------------------------------*/ -int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, - p_timeout tm) { - struct timeval tv; - double t = timeout_get(tm); - tv.tv_sec = (int) t; - tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); - if (n <= 0) { - Sleep((DWORD) (1000*t)); - return 0; - } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL); +int socket_select(t_socket n, fd_set* rfds, fd_set* wfds, fd_set* efds, + p_timeout tm) +{ + struct timeval tv; + double t = timeout_get(tm); + tv.tv_sec = (int)t; + tv.tv_usec = (int)((t - tv.tv_sec) * 1.0e6); + if (n <= 0) + { + Sleep((DWORD)(1000 * t)); + return 0; + } + else return select(0, rfds, wfds, efds, t >= 0.0 ? &tv : NULL); } /*-------------------------------------------------------------------------*\ * Close and inutilize socket \*-------------------------------------------------------------------------*/ -void socket_destroy(p_socket ps) { - if (*ps != SOCKET_INVALID) { - socket_setblocking(ps); /* close can take a long time on WIN32 */ - closesocket(*ps); - *ps = SOCKET_INVALID; - } +void socket_destroy(p_socket ps) +{ + if (*ps != SOCKET_INVALID) + { + socket_setblocking(ps); /* close can take a long time on WIN32 */ + closesocket(*ps); + *ps = SOCKET_INVALID; + } } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ -void socket_shutdown(p_socket ps, int how) { - socket_setblocking(ps); - shutdown(*ps, how); - socket_setnonblocking(ps); +void socket_shutdown(p_socket ps, int how) +{ + socket_setblocking(ps); + shutdown(*ps, how); + socket_setnonblocking(ps); } /*-------------------------------------------------------------------------*\ * Creates and sets up a socket \*-------------------------------------------------------------------------*/ -int socket_create(p_socket ps, int domain, int type, int protocol) { - *ps = socket(domain, type, protocol); - if (*ps != SOCKET_INVALID) return IO_DONE; - else return WSAGetLastError(); +int socket_create(p_socket ps, int domain, int type, int protocol) +{ + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return WSAGetLastError(); } /*-------------------------------------------------------------------------*\ * Connects or returns error message \*-------------------------------------------------------------------------*/ -int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { - int err; - /* don't call on closed socket */ - if (*ps == SOCKET_INVALID) return IO_CLOSED; - /* ask system to connect */ - if (connect(*ps, addr, len) == 0) return IO_DONE; - /* make sure the system is trying to connect */ - err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; - /* zero timeout case optimization */ - if (timeout_iszero(tm)) return IO_TIMEOUT; - /* we wait until something happens */ - err = socket_waitfd(ps, WAITFD_C, tm); - if (err == IO_CLOSED) { - int elen = sizeof(err); - /* give windows time to set the error (yes, disgusting) */ - Sleep(10); - /* find out why we failed */ - getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &elen); - /* we KNOW there was an error. if 'why' is 0, we will return - * "unknown error", but it's not really our fault */ - return err > 0? err: IO_UNKNOWN; - } else return err; - +int socket_connect(p_socket ps, SA* addr, socklen_t len, p_timeout tm) +{ + int err; + /* don't call on closed socket */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* ask system to connect */ + if (connect(*ps, addr, len) == 0) return IO_DONE; + /* make sure the system is trying to connect */ + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* we wait until something happens */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) + { + int elen = sizeof(err); + /* give windows time to set the error (yes, disgusting) */ + Sleep(10); + /* find out why we failed */ + getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char*)&err, &elen); + /* we KNOW there was an error. if 'why' is 0, we will return + * "unknown error", but it's not really our fault */ + return err > 0 ? err : IO_UNKNOWN; + } + else return err; } /*-------------------------------------------------------------------------*\ * Binds or returns error message \*-------------------------------------------------------------------------*/ -int socket_bind(p_socket ps, SA *addr, socklen_t len) { - int err = IO_DONE; - socket_setblocking(ps); - if (bind(*ps, addr, len) < 0) err = WSAGetLastError(); - socket_setnonblocking(ps); - return err; +int socket_bind(p_socket ps, SA* addr, socklen_t len) +{ + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; } /*-------------------------------------------------------------------------*\ * \*-------------------------------------------------------------------------*/ -int socket_listen(p_socket ps, int backlog) { - int err = IO_DONE; - socket_setblocking(ps); - if (listen(*ps, backlog) < 0) err = WSAGetLastError(); - socket_setnonblocking(ps); - return err; +int socket_listen(p_socket ps, int backlog) +{ + int err = IO_DONE; + socket_setblocking(ps); + if (listen(*ps, backlog) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; } /*-------------------------------------------------------------------------*\ * Accept with timeout \*-------------------------------------------------------------------------*/ -int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, - p_timeout tm) { - if (*ps == SOCKET_INVALID) return IO_CLOSED; - for ( ;; ) { - int err; - /* try to get client socket */ - if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; - /* find out why we failed */ - err = WSAGetLastError(); - /* if we failed because there was no connectoin, keep trying */ - if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; - /* call select to avoid busy wait */ - if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; - } +int socket_accept(p_socket ps, p_socket pa, SA* addr, socklen_t* len, + p_timeout tm) +{ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for (;;) + { + int err; + /* try to get client socket */ + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + /* find out why we failed */ + err = WSAGetLastError(); + /* if we failed because there was no connectoin, keep trying */ + if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; + /* call select to avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } } /*-------------------------------------------------------------------------*\ @@ -192,245 +221,268 @@ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, * this can take an awful lot of time and we will end up blocked. * Therefore, whoever calls this function should not pass a huge buffer. \*-------------------------------------------------------------------------*/ -int socket_send(p_socket ps, const char *data, size_t count, - size_t *sent, p_timeout tm) +int socket_send(p_socket ps, const char* data, size_t count, + size_t* sent, p_timeout tm) { - int err; - *sent = 0; - /* avoid making system calls on closed sockets */ - if (*ps == SOCKET_INVALID) return IO_CLOSED; - /* loop until we send something or we give up on error */ - for ( ;; ) { - /* try to send something */ - int put = send(*ps, data, (int) count, 0); - /* if we sent something, we are done */ - if (put > 0) { - *sent = put; - return IO_DONE; - } - /* deal with failure */ - err = WSAGetLastError(); - /* we can only proceed if there was no serious error */ - if (err != WSAEWOULDBLOCK) return err; - /* avoid busy wait */ - if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; - } + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for (;;) + { + /* try to send something */ + int put = send(*ps, data, (int)count, 0); + /* if we sent something, we are done */ + if (put > 0) + { + *sent = put; + return IO_DONE; + } + /* deal with failure */ + err = WSAGetLastError(); + /* we can only proceed if there was no serious error */ + if (err != WSAEWOULDBLOCK) return err; + /* avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } } /*-------------------------------------------------------------------------*\ * Sendto with timeout \*-------------------------------------------------------------------------*/ -int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, - SA *addr, socklen_t len, p_timeout tm) +int socket_sendto(p_socket ps, const char* data, size_t count, size_t* sent, + SA* addr, socklen_t len, p_timeout tm) { - int err; - *sent = 0; - if (*ps == SOCKET_INVALID) return IO_CLOSED; - for ( ;; ) { - int put = sendto(*ps, data, (int) count, 0, addr, len); - if (put > 0) { - *sent = put; - return IO_DONE; - } - err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK) return err; - if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; - } + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for (;;) + { + int put = sendto(*ps, data, (int)count, 0, addr, len); + if (put > 0) + { + *sent = put; + return IO_DONE; + } + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } } /*-------------------------------------------------------------------------*\ * Receive with timeout \*-------------------------------------------------------------------------*/ -int socket_recv(p_socket ps, char *data, size_t count, size_t *got, - p_timeout tm) +int socket_recv(p_socket ps, char* data, size_t count, size_t* got, + p_timeout tm) { - int err, prev = IO_DONE; - *got = 0; - if (*ps == SOCKET_INVALID) return IO_CLOSED; - for ( ;; ) { - int taken = recv(*ps, data, (int) count, 0); - if (taken > 0) { - *got = taken; - return IO_DONE; - } - if (taken == 0) return IO_CLOSED; - err = WSAGetLastError(); - /* On UDP, a connreset simply means the previous send failed. - * So we try again. - * On TCP, it means our socket is now useless, so the error passes. - * (We will loop again, exiting because the same error will happen) */ - if (err != WSAEWOULDBLOCK) { - if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; - prev = err; - } - if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; - } + int err, prev = IO_DONE; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for (;;) + { + int taken = recv(*ps, data, (int)count, 0); + if (taken > 0) + { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + /* On UDP, a connreset simply means the previous send failed. + * So we try again. + * On TCP, it means our socket is now useless, so the error passes. + * (We will loop again, exiting because the same error will happen) */ + if (err != WSAEWOULDBLOCK) + { + if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; + prev = err; + } + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } } /*-------------------------------------------------------------------------*\ * Recvfrom with timeout \*-------------------------------------------------------------------------*/ -int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, - SA *addr, socklen_t *len, p_timeout tm) +int socket_recvfrom(p_socket ps, char* data, size_t count, size_t* got, + SA* addr, socklen_t* len, p_timeout tm) { - int err, prev = IO_DONE; - *got = 0; - if (*ps == SOCKET_INVALID) return IO_CLOSED; - for ( ;; ) { - int taken = recvfrom(*ps, data, (int) count, 0, addr, len); - if (taken > 0) { - *got = taken; - return IO_DONE; - } - if (taken == 0) return IO_CLOSED; - err = WSAGetLastError(); - /* On UDP, a connreset simply means the previous send failed. - * So we try again. - * On TCP, it means our socket is now useless, so the error passes. - * (We will loop again, exiting because the same error will happen) */ - if (err != WSAEWOULDBLOCK) { - if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; - prev = err; - } - if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; - } + int err, prev = IO_DONE; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for (;;) + { + int taken = recvfrom(*ps, data, (int)count, 0, addr, len); + if (taken > 0) + { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + /* On UDP, a connreset simply means the previous send failed. + * So we try again. + * On TCP, it means our socket is now useless, so the error passes. + * (We will loop again, exiting because the same error will happen) */ + if (err != WSAEWOULDBLOCK) + { + if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; + prev = err; + } + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } } /*-------------------------------------------------------------------------*\ * Put socket into blocking mode \*-------------------------------------------------------------------------*/ -void socket_setblocking(p_socket ps) { - u_long argp = 0; - ioctlsocket(*ps, FIONBIO, &argp); +void socket_setblocking(p_socket ps) +{ + u_long argp = 0; + ioctlsocket(*ps, FIONBIO, &argp); } /*-------------------------------------------------------------------------*\ * Put socket into non-blocking mode \*-------------------------------------------------------------------------*/ -void socket_setnonblocking(p_socket ps) { - u_long argp = 1; - ioctlsocket(*ps, FIONBIO, &argp); +void socket_setnonblocking(p_socket ps) +{ + u_long argp = 1; + ioctlsocket(*ps, FIONBIO, &argp); } /*-------------------------------------------------------------------------*\ * DNS helpers \*-------------------------------------------------------------------------*/ -int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { - *hp = gethostbyaddr(addr, len, AF_INET); - if (*hp) return IO_DONE; - else return WSAGetLastError(); +int socket_gethostbyaddr(const char* addr, socklen_t len, struct hostent** hp) +{ + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else return WSAGetLastError(); } -int socket_gethostbyname(const char *addr, struct hostent **hp) { - *hp = gethostbyname(addr); - if (*hp) return IO_DONE; - else return WSAGetLastError(); +int socket_gethostbyname(const char* addr, struct hostent** hp) +{ + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else return WSAGetLastError(); } /*-------------------------------------------------------------------------*\ * Error translation functions \*-------------------------------------------------------------------------*/ -const char *socket_hoststrerror(int err) { - if (err <= 0) return io_strerror(err); - switch (err) { - case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; - default: return wstrerror(err); - } +const char* socket_hoststrerror(int err) +{ + if (err <= 0) return io_strerror(err); + switch (err) + { + case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; + default: return wstrerror(err); + } } -const char *socket_strerror(int err) { - if (err <= 0) return io_strerror(err); - switch (err) { - case WSAEADDRINUSE: return PIE_ADDRINUSE; - case WSAECONNREFUSED : return PIE_CONNREFUSED; - case WSAEISCONN: return PIE_ISCONN; - case WSAEACCES: return PIE_ACCESS; - case WSAECONNABORTED: return PIE_CONNABORTED; - case WSAECONNRESET: return PIE_CONNRESET; - case WSAETIMEDOUT: return PIE_TIMEDOUT; - default: return wstrerror(err); - } +const char* socket_strerror(int err) +{ + if (err <= 0) return io_strerror(err); + switch (err) + { + case WSAEADDRINUSE: return PIE_ADDRINUSE; + case WSAECONNREFUSED: return PIE_CONNREFUSED; + case WSAEISCONN: return PIE_ISCONN; + case WSAEACCES: return PIE_ACCESS; + case WSAECONNABORTED: return PIE_CONNABORTED; + case WSAECONNRESET: return PIE_CONNRESET; + case WSAETIMEDOUT: return PIE_TIMEDOUT; + default: return wstrerror(err); + } } -const char *socket_ioerror(p_socket ps, int err) { - (void) ps; - return socket_strerror(err); +const char* socket_ioerror(p_socket ps, int err) +{ + (void)ps; + return socket_strerror(err); } -static const char *wstrerror(int err) { - switch (err) { - case WSAEINTR: return "Interrupted function call"; - case WSAEACCES: return PIE_ACCESS; // "Permission denied"; - case WSAEFAULT: return "Bad address"; - case WSAEINVAL: return "Invalid argument"; - case WSAEMFILE: return "Too many open files"; - case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; - case WSAEINPROGRESS: return "Operation now in progress"; - case WSAEALREADY: return "Operation already in progress"; - case WSAENOTSOCK: return "Socket operation on nonsocket"; - case WSAEDESTADDRREQ: return "Destination address required"; - case WSAEMSGSIZE: return "Message too long"; - case WSAEPROTOTYPE: return "Protocol wrong type for socket"; - case WSAENOPROTOOPT: return "Bad protocol option"; - case WSAEPROTONOSUPPORT: return "Protocol not supported"; - case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; // "Socket type not supported"; - case WSAEOPNOTSUPP: return "Operation not supported"; - case WSAEPFNOSUPPORT: return "Protocol family not supported"; - case WSAEAFNOSUPPORT: return PIE_FAMILY; // "Address family not supported by protocol family"; - case WSAEADDRINUSE: return PIE_ADDRINUSE; // "Address already in use"; - case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; - case WSAENETDOWN: return "Network is down"; - case WSAENETUNREACH: return "Network is unreachable"; - case WSAENETRESET: return "Network dropped connection on reset"; - case WSAECONNABORTED: return "Software caused connection abort"; - case WSAECONNRESET: return PIE_CONNRESET; // "Connection reset by peer"; - case WSAENOBUFS: return "No buffer space available"; - case WSAEISCONN: return PIE_ISCONN; // "Socket is already connected"; - case WSAENOTCONN: return "Socket is not connected"; - case WSAESHUTDOWN: return "Cannot send after socket shutdown"; - case WSAETIMEDOUT: return PIE_TIMEDOUT; // "Connection timed out"; - case WSAECONNREFUSED: return PIE_CONNREFUSED; // "Connection refused"; - case WSAEHOSTDOWN: return "Host is down"; - case WSAEHOSTUNREACH: return "No route to host"; - case WSAEPROCLIM: return "Too many processes"; - case WSASYSNOTREADY: return "Network subsystem is unavailable"; - case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range"; - case WSANOTINITIALISED: - return "Successful WSAStartup not yet performed"; - case WSAEDISCON: return "Graceful shutdown in progress"; - case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; // "Host not found"; - case WSATRY_AGAIN: return "Nonauthoritative host not found"; - case WSANO_RECOVERY: return PIE_FAIL; // "Nonrecoverable name lookup error"; - case WSANO_DATA: return "Valid name, no data record of requested type"; - default: return "Unknown error"; - } +static const char* wstrerror(int err) +{ + switch (err) + { + case WSAEINTR: return "Interrupted function call"; + case WSAEACCES: return PIE_ACCESS; // "Permission denied"; + case WSAEFAULT: return "Bad address"; + case WSAEINVAL: return "Invalid argument"; + case WSAEMFILE: return "Too many open files"; + case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; + case WSAEINPROGRESS: return "Operation now in progress"; + case WSAEALREADY: return "Operation already in progress"; + case WSAENOTSOCK: return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: return "Destination address required"; + case WSAEMSGSIZE: return "Message too long"; + case WSAEPROTOTYPE: return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: return "Bad protocol option"; + case WSAEPROTONOSUPPORT: return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; // "Socket type not supported"; + case WSAEOPNOTSUPP: return "Operation not supported"; + case WSAEPFNOSUPPORT: return "Protocol family not supported"; + case WSAEAFNOSUPPORT: return PIE_FAMILY; // "Address family not supported by protocol family"; + case WSAEADDRINUSE: return PIE_ADDRINUSE; // "Address already in use"; + case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; + case WSAENETDOWN: return "Network is down"; + case WSAENETUNREACH: return "Network is unreachable"; + case WSAENETRESET: return "Network dropped connection on reset"; + case WSAECONNABORTED: return "Software caused connection abort"; + case WSAECONNRESET: return PIE_CONNRESET; // "Connection reset by peer"; + case WSAENOBUFS: return "No buffer space available"; + case WSAEISCONN: return PIE_ISCONN; // "Socket is already connected"; + case WSAENOTCONN: return "Socket is not connected"; + case WSAESHUTDOWN: return "Cannot send after socket shutdown"; + case WSAETIMEDOUT: return PIE_TIMEDOUT; // "Connection timed out"; + case WSAECONNREFUSED: return PIE_CONNREFUSED; // "Connection refused"; + case WSAEHOSTDOWN: return "Host is down"; + case WSAEHOSTUNREACH: return "No route to host"; + case WSAEPROCLIM: return "Too many processes"; + case WSASYSNOTREADY: return "Network subsystem is unavailable"; + case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range"; + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performed"; + case WSAEDISCON: return "Graceful shutdown in progress"; + case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; // "Host not found"; + case WSATRY_AGAIN: return "Nonauthoritative host not found"; + case WSANO_RECOVERY: return PIE_FAIL; // "Nonrecoverable name lookup error"; + case WSANO_DATA: return "Valid name, no data record of requested type"; + default: return "Unknown error"; + } } -const char *socket_gaistrerror(int err) { - if (err == 0) return NULL; - switch (err) { - case EAI_AGAIN: return PIE_AGAIN; - case EAI_BADFLAGS: return PIE_BADFLAGS; +const char* socket_gaistrerror(int err) +{ + if (err == 0) return NULL; + switch (err) + { + case EAI_AGAIN: return PIE_AGAIN; + case EAI_BADFLAGS: return PIE_BADFLAGS; #ifdef EAI_BADHINTS case EAI_BADHINTS: return PIE_BADHINTS; #endif - case EAI_FAIL: return PIE_FAIL; - case EAI_FAMILY: return PIE_FAMILY; - case EAI_MEMORY: return PIE_MEMORY; - case EAI_NONAME: return PIE_NONAME; + case EAI_FAIL: return PIE_FAIL; + case EAI_FAMILY: return PIE_FAMILY; + case EAI_MEMORY: return PIE_MEMORY; + case EAI_NONAME: return PIE_NONAME; #ifdef EAI_OVERFLOW case EAI_OVERFLOW: return PIE_OVERFLOW; #endif #ifdef EAI_PROTOCOL case EAI_PROTOCOL: return PIE_PROTOCOL; #endif - case EAI_SERVICE: return PIE_SERVICE; - case EAI_SOCKTYPE: return PIE_SOCKTYPE; + case EAI_SERVICE: return PIE_SERVICE; + case EAI_SOCKTYPE: return PIE_SOCKTYPE; #ifdef EAI_SYSTEM case EAI_SYSTEM: return strerror(errno); #endif - default: return gai_strerrorA(err); - } + default: return gai_strerrorA(err); + } } -#endif \ No newline at end of file +#endif diff --git a/Lua/wsocket.h b/Lua/wsocket.h index 3986640..d47323f 100644 --- a/Lua/wsocket.h +++ b/Lua/wsocket.h @@ -14,7 +14,7 @@ typedef int socklen_t; typedef SOCKADDR_STORAGE t_sockaddr_storage; typedef SOCKET t_socket; -typedef t_socket *p_socket; +typedef t_socket* p_socket; #ifndef IPV6_V6ONLY #define IPV6_V6ONLY 27 diff --git a/PGOHelper/PGOHelper.cpp b/PGOHelper/PGOHelper.cpp index ca190c1..50224ba 100644 --- a/PGOHelper/PGOHelper.cpp +++ b/PGOHelper/PGOHelper.cpp @@ -3,8 +3,8 @@ #include #include #if __has_include() - #include - namespace fs = std::filesystem; +#include +namespace fs = std::filesystem; #elif __has_include() #include namespace fs = std::experimental::filesystem; @@ -14,24 +14,28 @@ using std::string; using std::vector; extern "C" { - void __stdcall PgoRunTest(vector testRoms, bool enableDebugger); +void __stdcall PgoRunTest(vector testRoms, bool enableDebugger); } vector GetFilesInFolder(string rootFolder, std::unordered_set extensions) { vector files; - vector folders = { { rootFolder } }; + vector folders = {{rootFolder}}; std::error_code errorCode; - if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) { + if (!fs::is_directory(fs::u8path(rootFolder), errorCode)) + { return files; } - for(string folder : folders) { - for(fs::directory_iterator i(fs::u8path(folder.c_str())), end; i != end; i++) { + for (string folder : folders) + { + for (fs::directory_iterator i(fs::u8path(folder.c_str())), end; i != end; i++) + { string extension = i->path().extension().u8string(); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if(extensions.find(extension) != extensions.end()) { + if (extensions.find(extension) != extensions.end()) + { files.push_back(i->path().u8string()); } } @@ -43,12 +47,12 @@ vector GetFilesInFolder(string rootFolder, std::unordered_set ex int main(int argc, char* argv[]) { string romFolder = "../PGOGames"; - if(argc >= 2) { + if (argc >= 2) + { romFolder = argv[1]; } - vector testRoms = GetFilesInFolder(romFolder, { {".sfc", ".gb", ".gbc"} }); + vector testRoms = GetFilesInFolder(romFolder, {{".sfc", ".gb", ".gbc"}}); PgoRunTest(testRoms, true); return 0; } - diff --git a/SevenZip/7z.h b/SevenZip/7z.h index 4768151..1d5edf2 100644 --- a/SevenZip/7z.h +++ b/SevenZip/7z.h @@ -15,24 +15,24 @@ extern const Byte k7zSignature[k7zSignatureSize]; typedef struct { - const Byte *Data; - size_t Size; + const Byte* Data; + size_t Size; } CSzData; /* CSzCoderInfo & CSzFolder support only default methods */ typedef struct { - size_t PropsOffset; - UInt32 MethodID; - Byte NumStreams; - Byte PropsSize; + size_t PropsOffset; + UInt32 MethodID; + Byte NumStreams; + Byte PropsSize; } CSzCoderInfo; typedef struct { - UInt32 InIndex; - UInt32 OutIndex; + UInt32 InIndex; + UInt32 OutIndex; } CSzBond; #define SZ_NUM_CODERS_IN_FOLDER_MAX 4 @@ -41,35 +41,35 @@ typedef struct typedef struct { - UInt32 NumCoders; - UInt32 NumBonds; - UInt32 NumPackStreams; - UInt32 UnpackStream; - UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; - CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; - CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; + UInt32 NumCoders; + UInt32 NumBonds; + UInt32 NumPackStreams; + UInt32 UnpackStream; + UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; + CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; + CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; } CSzFolder; -SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); +SRes SzGetNextFolderItem(CSzFolder* f, CSzData* sd); typedef struct { - UInt32 Low; - UInt32 High; + UInt32 Low; + UInt32 High; } CNtfsFileTime; typedef struct { - Byte *Defs; /* MSB 0 bit numbering */ - UInt32 *Vals; + Byte* Defs; /* MSB 0 bit numbering */ + UInt32* Vals; } CSzBitUi32s; typedef struct { - Byte *Defs; /* MSB 0 bit numbering */ - // UInt64 *Vals; - CNtfsFileTime *Vals; + Byte* Defs; /* MSB 0 bit numbering */ + // UInt64 *Vals; + CNtfsFileTime* Vals; } CSzBitUi64s; #define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) @@ -78,62 +78,62 @@ typedef struct typedef struct { - UInt32 NumPackStreams; - UInt32 NumFolders; + UInt32 NumPackStreams; + UInt32 NumFolders; - UInt64 *PackPositions; // NumPackStreams + 1 - CSzBitUi32s FolderCRCs; // NumFolders + UInt64* PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders - size_t *FoCodersOffsets; // NumFolders + 1 - UInt32 *FoStartPackStreamIndex; // NumFolders + 1 - UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 - Byte *FoToMainUnpackSizeIndex; // NumFolders - UInt64 *CoderUnpackSizes; // for all coders in all folders + size_t* FoCodersOffsets; // NumFolders + 1 + UInt32* FoStartPackStreamIndex; // NumFolders + 1 + UInt32* FoToCoderUnpackSizes; // NumFolders + 1 + Byte* FoToMainUnpackSizeIndex; // NumFolders + UInt64* CoderUnpackSizes; // for all coders in all folders - Byte *CodersData; + Byte* CodersData; } CSzAr; -UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); +UInt64 SzAr_GetFolderUnpackSize(const CSzAr* p, UInt32 folderIndex); -SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, - ILookInStream *stream, UInt64 startPos, - Byte *outBuffer, size_t outSize, - ISzAlloc *allocMain); +SRes SzAr_DecodeFolder(const CSzAr* p, UInt32 folderIndex, + ILookInStream* stream, UInt64 startPos, + Byte* outBuffer, size_t outSize, + ISzAlloc* allocMain); typedef struct { - CSzAr db; + CSzAr db; - UInt64 startPosAfterHeader; - UInt64 dataPos; - - UInt32 NumFiles; + UInt64 startPosAfterHeader; + UInt64 dataPos; - UInt64 *UnpackPositions; // NumFiles + 1 - // Byte *IsEmptyFiles; - Byte *IsDirs; - CSzBitUi32s CRCs; + UInt32 NumFiles; - CSzBitUi32s Attribs; - // CSzBitUi32s Parents; - CSzBitUi64s MTime; - CSzBitUi64s CTime; + UInt64* UnpackPositions; // NumFiles + 1 + // Byte *IsEmptyFiles; + Byte* IsDirs; + CSzBitUi32s CRCs; - UInt32 *FolderToFile; // NumFolders + 1 - UInt32 *FileToFolder; // NumFiles + CSzBitUi32s Attribs; + // CSzBitUi32s Parents; + CSzBitUi64s MTime; + CSzBitUi64s CTime; - size_t *FileNameOffsets; /* in 2-byte steps */ - Byte *FileNames; /* UTF-16-LE */ + UInt32* FolderToFile; // NumFolders + 1 + UInt32* FileToFolder; // NumFiles + + size_t* FileNameOffsets; /* in 2-byte steps */ + Byte* FileNames; /* UTF-16-LE */ } CSzArEx; #define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) #define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) -void SzArEx_Init(CSzArEx *p); -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); +void SzArEx_Init(CSzArEx* p); +void SzArEx_Free(CSzArEx* p, ISzAlloc* alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx* p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx* p, UInt32 folderIndex, UInt64* resSize); /* if dest == NULL, the return value specifies the required size of the buffer, @@ -141,7 +141,7 @@ if dest == NULL, the return value specifies the required size of the buffer, if dest != NULL, the return value specifies the number of 16-bit characters that are written to the dest, including the null-terminating character. */ -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +size_t SzArEx_GetFileNameUtf16(const CSzArEx* p, size_t fileIndex, UInt16* dest); /* size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); @@ -149,7 +149,6 @@ UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 */ - /* SzArEx_Extract extracts file from archive @@ -171,16 +170,16 @@ UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 */ SRes SzArEx_Extract( - const CSzArEx *db, - ILookInStream *inStream, - UInt32 fileIndex, /* index of file */ - UInt32 *blockIndex, /* index of solid block */ - Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ - size_t *outBufferSize, /* buffer size for output buffer */ - size_t *offset, /* offset of stream for required file in *outBuffer */ - size_t *outSizeProcessed, /* size of file in *outBuffer */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp); + const CSzArEx* db, + ILookInStream* inStream, + UInt32 fileIndex, /* index of file */ + UInt32* blockIndex, /* index of solid block */ + Byte** outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t* outBufferSize, /* buffer size for output buffer */ + size_t* offset, /* offset of stream for required file in *outBuffer */ + size_t* outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc* allocMain, + ISzAlloc* allocTemp); /* @@ -194,8 +193,8 @@ SZ_ERROR_INPUT_EOF SZ_ERROR_FAIL */ -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, - ISzAlloc *allocMain, ISzAlloc *allocTemp); +SRes SzArEx_Open(CSzArEx* p, ILookInStream* inStream, + ISzAlloc* allocMain, ISzAlloc* allocTemp); EXTERN_C_END diff --git a/SevenZip/7zAlloc.c b/SevenZip/7zAlloc.c index 3e848c9..5947927 100644 --- a/SevenZip/7zAlloc.c +++ b/SevenZip/7zAlloc.c @@ -20,59 +20,59 @@ int g_allocCountTemp = 0; #endif -void *SzAlloc(void *p, size_t size) +void* SzAlloc(void* p, size_t size) { - UNUSED_VAR(p); - if (size == 0) - return 0; - #ifdef _SZ_ALLOC_DEBUG + UNUSED_VAR(p); + if (size == 0) + return 0; +#ifdef _SZ_ALLOC_DEBUG fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount); g_allocCount++; - #endif - return malloc(size); +#endif + return malloc(size); } -void SzFree(void *p, void *address) +void SzFree(void* p, void* address) { - UNUSED_VAR(p); - #ifdef _SZ_ALLOC_DEBUG + UNUSED_VAR(p); +#ifdef _SZ_ALLOC_DEBUG if (address != 0) { g_allocCount--; fprintf(stderr, "\nFree; count = %10d", g_allocCount); } - #endif - free(address); +#endif + free(address); } -void *SzAllocTemp(void *p, size_t size) +void* SzAllocTemp(void* p, size_t size) { - UNUSED_VAR(p); - if (size == 0) - return 0; - #ifdef _SZ_ALLOC_DEBUG + UNUSED_VAR(p); + if (size == 0) + return 0; +#ifdef _SZ_ALLOC_DEBUG fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp); g_allocCountTemp++; - #ifdef _WIN32 +#ifdef _WIN32 return HeapAlloc(GetProcessHeap(), 0, size); - #endif - #endif - return malloc(size); +#endif +#endif + return malloc(size); } -void SzFreeTemp(void *p, void *address) +void SzFreeTemp(void* p, void* address) { - UNUSED_VAR(p); - #ifdef _SZ_ALLOC_DEBUG + UNUSED_VAR(p); +#ifdef _SZ_ALLOC_DEBUG if (address != 0) { g_allocCountTemp--; fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); } - #ifdef _WIN32 +#ifdef _WIN32 HeapFree(GetProcessHeap(), 0, address); return; - #endif - #endif - free(address); +#endif +#endif + free(address); } diff --git a/SevenZip/7zAlloc.h b/SevenZip/7zAlloc.h index 2fd5bdb..974174d 100644 --- a/SevenZip/7zAlloc.h +++ b/SevenZip/7zAlloc.h @@ -10,11 +10,11 @@ extern "C" { #endif -void *SzAlloc(void *p, size_t size); -void SzFree(void *p, void *address); +void* SzAlloc(void* p, size_t size); +void SzFree(void* p, void* address); -void *SzAllocTemp(void *p, size_t size); -void SzFreeTemp(void *p, void *address); +void* SzAllocTemp(void* p, size_t size); +void SzFreeTemp(void* p, void* address); #ifdef __cplusplus } diff --git a/SevenZip/7zArcIn.c b/SevenZip/7zArcIn.c index 2beed3d..01b0839 100644 --- a/SevenZip/7zArcIn.c +++ b/SevenZip/7zArcIn.c @@ -25,157 +25,161 @@ enum EIdEnum { - k7zIdEnd, - k7zIdHeader, - k7zIdArchiveProperties, - k7zIdAdditionalStreamsInfo, - k7zIdMainStreamsInfo, - k7zIdFilesInfo, - k7zIdPackInfo, - k7zIdUnpackInfo, - k7zIdSubStreamsInfo, - k7zIdSize, - k7zIdCRC, - k7zIdFolder, - k7zIdCodersUnpackSize, - k7zIdNumUnpackStream, - k7zIdEmptyStream, - k7zIdEmptyFile, - k7zIdAnti, - k7zIdName, - k7zIdCTime, - k7zIdATime, - k7zIdMTime, - k7zIdWinAttrib, - k7zIdComment, - k7zIdEncodedHeader, - k7zIdStartPos, - k7zIdDummy - // k7zNtSecure, - // k7zParent, - // k7zIsReal + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttrib, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy + // k7zNtSecure, + // k7zParent, + // k7zIsReal }; const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; #define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } -static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc) +static SRes SzBitUi32s_Alloc(CSzBitUi32s* p, size_t num, ISzAlloc* alloc) { - if (num == 0) - { - p->Defs = NULL; - p->Vals = NULL; - } - else - { - MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); - MY_ALLOC(UInt32, p->Vals, num, alloc); - } - return SZ_OK; + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); + MY_ALLOC(UInt32, p->Vals, num, alloc); + } + return SZ_OK; } -void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc) +void SzBitUi32s_Free(CSzBitUi32s* p, ISzAlloc* alloc) { - IAlloc_Free(alloc, p->Defs); p->Defs = NULL; - IAlloc_Free(alloc, p->Vals); p->Vals = NULL; + IAlloc_Free(alloc, p->Defs); + p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); + p->Vals = NULL; } #define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } -void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc) +void SzBitUi64s_Free(CSzBitUi64s* p, ISzAlloc* alloc) { - IAlloc_Free(alloc, p->Defs); p->Defs = NULL; - IAlloc_Free(alloc, p->Vals); p->Vals = NULL; + IAlloc_Free(alloc, p->Defs); + p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); + p->Vals = NULL; } -static void SzAr_Init(CSzAr *p) +static void SzAr_Init(CSzAr* p) { - p->NumPackStreams = 0; - p->NumFolders = 0; - - p->PackPositions = NULL; - SzBitUi32s_Init(&p->FolderCRCs); + p->NumPackStreams = 0; + p->NumFolders = 0; - p->FoCodersOffsets = NULL; - p->FoStartPackStreamIndex = NULL; - p->FoToCoderUnpackSizes = NULL; - p->FoToMainUnpackSizeIndex = NULL; - p->CoderUnpackSizes = NULL; + p->PackPositions = NULL; + SzBitUi32s_Init(&p->FolderCRCs); - p->CodersData = NULL; + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; + + p->CodersData = NULL; } -static void SzAr_Free(CSzAr *p, ISzAlloc *alloc) +static void SzAr_Free(CSzAr* p, ISzAlloc* alloc) { - IAlloc_Free(alloc, p->PackPositions); - SzBitUi32s_Free(&p->FolderCRCs, alloc); - - IAlloc_Free(alloc, p->FoCodersOffsets); - IAlloc_Free(alloc, p->FoStartPackStreamIndex); - IAlloc_Free(alloc, p->FoToCoderUnpackSizes); - IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); - IAlloc_Free(alloc, p->CoderUnpackSizes); - - IAlloc_Free(alloc, p->CodersData); + IAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); - SzAr_Init(p); + IAlloc_Free(alloc, p->FoCodersOffsets); + IAlloc_Free(alloc, p->FoStartPackStreamIndex); + IAlloc_Free(alloc, p->FoToCoderUnpackSizes); + IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + IAlloc_Free(alloc, p->CoderUnpackSizes); + + IAlloc_Free(alloc, p->CodersData); + + SzAr_Init(p); } -void SzArEx_Init(CSzArEx *p) +void SzArEx_Init(CSzArEx* p) { - SzAr_Init(&p->db); - - p->NumFiles = 0; - p->dataPos = 0; - - p->UnpackPositions = NULL; - p->IsDirs = NULL; - - p->FolderToFile = NULL; - p->FileToFolder = NULL; - - p->FileNameOffsets = NULL; - p->FileNames = NULL; - - SzBitUi32s_Init(&p->CRCs); - SzBitUi32s_Init(&p->Attribs); - // SzBitUi32s_Init(&p->Parents); - SzBitUi64s_Init(&p->MTime); - SzBitUi64s_Init(&p->CTime); + SzAr_Init(&p->db); + + p->NumFiles = 0; + p->dataPos = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + + SzBitUi32s_Init(&p->CRCs); + SzBitUi32s_Init(&p->Attribs); + // SzBitUi32s_Init(&p->Parents); + SzBitUi64s_Init(&p->MTime); + SzBitUi64s_Init(&p->CTime); } -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) +void SzArEx_Free(CSzArEx* p, ISzAlloc* alloc) { - IAlloc_Free(alloc, p->UnpackPositions); - IAlloc_Free(alloc, p->IsDirs); + IAlloc_Free(alloc, p->UnpackPositions); + IAlloc_Free(alloc, p->IsDirs); - IAlloc_Free(alloc, p->FolderToFile); - IAlloc_Free(alloc, p->FileToFolder); + IAlloc_Free(alloc, p->FolderToFile); + IAlloc_Free(alloc, p->FileToFolder); - IAlloc_Free(alloc, p->FileNameOffsets); - IAlloc_Free(alloc, p->FileNames); + IAlloc_Free(alloc, p->FileNameOffsets); + IAlloc_Free(alloc, p->FileNames); - SzBitUi32s_Free(&p->CRCs, alloc); - SzBitUi32s_Free(&p->Attribs, alloc); - // SzBitUi32s_Free(&p->Parents, alloc); - SzBitUi64s_Free(&p->MTime, alloc); - SzBitUi64s_Free(&p->CTime, alloc); - - SzAr_Free(&p->db, alloc); - SzArEx_Init(p); + SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); + // SzBitUi32s_Free(&p->Parents, alloc); + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); } -static int TestSignatureCandidate(const Byte *testBytes) +static int TestSignatureCandidate(const Byte* testBytes) { - unsigned i; - for (i = 0; i < k7zSignatureSize; i++) - if (testBytes[i] != k7zSignature[i]) - return 0; - return 1; + unsigned i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; } #define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } @@ -190,232 +194,232 @@ static int TestSignatureCandidate(const Byte *testBytes) #define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); -static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +static MY_NO_INLINE SRes ReadNumber(CSzData* sd, UInt64* value) { - Byte firstByte, mask; - unsigned i; - UInt32 v; + Byte firstByte, mask; + unsigned i; + UInt32 v; - SZ_READ_BYTE(firstByte); - if ((firstByte & 0x80) == 0) - { - *value = firstByte; - return SZ_OK; - } - SZ_READ_BYTE(v); - if ((firstByte & 0x40) == 0) - { - *value = (((UInt32)firstByte & 0x3F) << 8) | v; - return SZ_OK; - } - SZ_READ_BYTE(mask); - *value = v | ((UInt32)mask << 8); - mask = 0x20; - for (i = 2; i < 8; i++) - { - Byte b; - if ((firstByte & mask) == 0) - { - UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); - *value |= (highPart << (8 * i)); - return SZ_OK; - } - SZ_READ_BYTE(b); - *value |= ((UInt64)b << (8 * i)); - mask >>= 1; - } - return SZ_OK; + SZ_READ_BYTE(firstByte); + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + return SZ_OK; + } + SZ_READ_BYTE(v); + if ((firstByte & 0x40) == 0) + { + *value = (((UInt32)firstByte & 0x3F) << 8) | v; + return SZ_OK; + } + SZ_READ_BYTE(mask); + *value = v | ((UInt32)mask << 8); + mask = 0x20; + for (i = 2; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + *value |= (highPart << (8 * i)); + return SZ_OK; + } + SZ_READ_BYTE(b); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; } -static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +static MY_NO_INLINE SRes SzReadNumber32(CSzData* sd, UInt32* value) { - Byte firstByte; - UInt64 value64; - if (sd->Size == 0) - return SZ_ERROR_ARCHIVE; - firstByte = *sd->Data; - if ((firstByte & 0x80) == 0) - { - *value = firstByte; - sd->Data++; - sd->Size--; - return SZ_OK; - } - RINOK(ReadNumber(sd, &value64)); - if (value64 >= (UInt32)0x80000000 - 1) - return SZ_ERROR_UNSUPPORTED; - if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) - return SZ_ERROR_UNSUPPORTED; - *value = (UInt32)value64; - return SZ_OK; + Byte firstByte; + UInt64 value64; + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + firstByte = *sd->Data; + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + sd->Data++; + sd->Size--; + return SZ_OK; + } + RINOK(ReadNumber(sd, &value64)); + if (value64 >= (UInt32)0x80000000 - 1) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; } #define ReadID(sd, value) ReadNumber(sd, value) -static SRes SkipData(CSzData *sd) +static SRes SkipData(CSzData* sd) { - UInt64 size; - RINOK(ReadNumber(sd, &size)); - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA(sd, size); - return SZ_OK; + UInt64 size; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, size); + return SZ_OK; } -static SRes WaitId(CSzData *sd, UInt32 id) +static SRes WaitId(CSzData* sd, UInt32 id) { - for (;;) - { - UInt64 type; - RINOK(ReadID(sd, &type)); - if (type == id) - return SZ_OK; - if (type == k7zIdEnd) - return SZ_ERROR_ARCHIVE; - RINOK(SkipData(sd)); - } + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == id) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SkipData(sd)); + } } -static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) +static SRes RememberBitVector(CSzData* sd, UInt32 numItems, const Byte** v) { - UInt32 numBytes = (numItems + 7) >> 3; - if (numBytes > sd->Size) - return SZ_ERROR_ARCHIVE; - *v = sd->Data; - SKIP_DATA(sd, numBytes); - return SZ_OK; + UInt32 numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + *v = sd->Data; + SKIP_DATA(sd, numBytes); + return SZ_OK; } -static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) +static UInt32 CountDefinedBits(const Byte* bits, UInt32 numItems) { - Byte b = 0; - unsigned m = 0; - UInt32 sum = 0; - for (; numItems != 0; numItems--) - { - if (m == 0) - { - b = *bits++; - m = 8; - } - m--; - sum += ((b >> m) & 1); - } - return sum; + Byte b = 0; + unsigned m = 0; + UInt32 sum = 0; + for (; numItems != 0; numItems--) + { + if (m == 0) + { + b = *bits++; + m = 8; + } + m--; + sum += ((b >> m) & 1); + } + return sum; } -static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc) +static MY_NO_INLINE SRes ReadBitVector(CSzData* sd, UInt32 numItems, Byte** v, ISzAlloc* alloc) { - Byte allAreDefined; - Byte *v2; - UInt32 numBytes = (numItems + 7) >> 3; - *v = NULL; - SZ_READ_BYTE(allAreDefined); - if (numBytes == 0) - return SZ_OK; - if (allAreDefined == 0) - { - if (numBytes > sd->Size) - return SZ_ERROR_ARCHIVE; - MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); - SKIP_DATA(sd, numBytes); - return SZ_OK; - } - MY_ALLOC(Byte, *v, numBytes, alloc); - v2 = *v; - memset(v2, 0xFF, (size_t)numBytes); - { - unsigned numBits = (unsigned)numItems & 7; - if (numBits != 0) - v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); - } - return SZ_OK; + Byte allAreDefined; + Byte* v2; + UInt32 numBytes = (numItems + 7) >> 3; + *v = NULL; + SZ_READ_BYTE(allAreDefined); + if (numBytes == 0) + return SZ_OK; + if (allAreDefined == 0) + { + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); + SKIP_DATA(sd, numBytes); + return SZ_OK; + } + MY_ALLOC(Byte, *v, numBytes, alloc); + v2 = *v; + memset(v2, 0xFF, (size_t)numBytes); + { + unsigned numBits = (unsigned)numItems & 7; + if (numBits != 0) + v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); + } + return SZ_OK; } -static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc) +static MY_NO_INLINE SRes ReadUi32s(CSzData* sd2, UInt32 numItems, CSzBitUi32s* crcs, ISzAlloc* alloc) { - UInt32 i; - CSzData sd; - UInt32 *vals; - const Byte *defs; - MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); - sd = *sd2; - defs = crcs->Defs; - vals = crcs->Vals; - for (i = 0; i < numItems; i++) - if (SzBitArray_Check(defs, i)) - { - SZ_READ_32(vals[i]); - } - else - vals[i] = 0; - *sd2 = sd; - return SZ_OK; + UInt32 i; + CSzData sd; + UInt32* vals; + const Byte* defs; + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); + sd = *sd2; + defs = crcs->Defs; + vals = crcs->Vals; + for (i = 0; i < numItems; i++) + if (SzBitArray_Check(defs, i)) + { + SZ_READ_32(vals[i]); + } + else + vals[i] = 0; + *sd2 = sd; + return SZ_OK; } -static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc) +static SRes ReadBitUi32s(CSzData* sd, UInt32 numItems, CSzBitUi32s* crcs, ISzAlloc* alloc) { - SzBitUi32s_Free(crcs, alloc); - RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); - return ReadUi32s(sd, numItems, crcs, alloc); + SzBitUi32s_Free(crcs, alloc); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); + return ReadUi32s(sd, numItems, crcs, alloc); } -static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) +static SRes SkipBitUi32s(CSzData* sd, UInt32 numItems) { - Byte allAreDefined; - UInt32 numDefined = numItems; - SZ_READ_BYTE(allAreDefined); - if (!allAreDefined) - { - size_t numBytes = (numItems + 7) >> 3; - if (numBytes > sd->Size) - return SZ_ERROR_ARCHIVE; - numDefined = CountDefinedBits(sd->Data, numItems); - SKIP_DATA(sd, numBytes); - } - if (numDefined > (sd->Size >> 2)) - return SZ_ERROR_ARCHIVE; - SKIP_DATA(sd, (size_t)numDefined * 4); - return SZ_OK; + Byte allAreDefined; + UInt32 numDefined = numItems; + SZ_READ_BYTE(allAreDefined); + if (!allAreDefined) + { + size_t numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + numDefined = CountDefinedBits(sd->Data, numItems); + SKIP_DATA(sd, numBytes); + } + if (numDefined > (sd->Size >> 2)) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, (size_t)numDefined * 4); + return SZ_OK; } -static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc) +static SRes ReadPackInfo(CSzAr* p, CSzData* sd, ISzAlloc* alloc) { - RINOK(SzReadNumber32(sd, &p->NumPackStreams)); + RINOK(SzReadNumber32(sd, &p->NumPackStreams)); - RINOK(WaitId(sd, k7zIdSize)); - MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); - { - UInt64 sum = 0; - UInt32 i; - UInt32 numPackStreams = p->NumPackStreams; - for (i = 0; i < numPackStreams; i++) - { - UInt64 packSize; - p->PackPositions[i] = sum; - RINOK(ReadNumber(sd, &packSize)); - sum += packSize; - if (sum < packSize) - return SZ_ERROR_ARCHIVE; - } - p->PackPositions[i] = sum; - } + RINOK(WaitId(sd, k7zIdSize)); + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); + { + UInt64 sum = 0; + UInt32 i; + UInt32 numPackStreams = p->NumPackStreams; + for (i = 0; i < numPackStreams; i++) + { + UInt64 packSize; + p->PackPositions[i] = sum; + RINOK(ReadNumber(sd, &packSize)); + sum += packSize; + if (sum < packSize) + return SZ_ERROR_ARCHIVE; + } + p->PackPositions[i] = sum; + } - for (;;) - { - UInt64 type; - RINOK(ReadID(sd, &type)); - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - /* CRC of packed streams is unused now */ - RINOK(SkipBitUi32s(sd, p->NumPackStreams)); - continue; - } - RINOK(SkipData(sd)); - } + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + /* CRC of packed streams is unused now */ + RINOK(SkipBitUi32s(sd, p->NumPackStreams)); + continue; + } + RINOK(SkipData(sd)); + } } /* @@ -429,201 +433,201 @@ static SRes SzReadSwitch(CSzData *sd) #define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) -SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) +SRes SzGetNextFolderItem(CSzFolder* f, CSzData* sd) { - UInt32 numCoders, i; - UInt32 numInStreams = 0; - const Byte *dataStart = sd->Data; + UInt32 numCoders, i; + UInt32 numInStreams = 0; + const Byte* dataStart = sd->Data; - f->NumCoders = 0; - f->NumBonds = 0; - f->NumPackStreams = 0; - f->UnpackStream = 0; - - RINOK(SzReadNumber32(sd, &numCoders)); - if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - - for (i = 0; i < numCoders; i++) - { - Byte mainByte; - CSzCoderInfo *coder = f->Coders + i; - unsigned idSize, j; - UInt64 id; - - SZ_READ_BYTE(mainByte); - if ((mainByte & 0xC0) != 0) - return SZ_ERROR_UNSUPPORTED; - - idSize = (unsigned)(mainByte & 0xF); - if (idSize > sizeof(id)) - return SZ_ERROR_UNSUPPORTED; - if (idSize > sd->Size) - return SZ_ERROR_ARCHIVE; - id = 0; - for (j = 0; j < idSize; j++) - { - id = ((id << 8) | *sd->Data); - sd->Data++; - sd->Size--; - } - if (id > (UInt32)0xFFFFFFFF) - return SZ_ERROR_UNSUPPORTED; - coder->MethodID = (UInt32)id; - - coder->NumStreams = 1; - coder->PropsOffset = 0; - coder->PropsSize = 0; - - if ((mainByte & 0x10) != 0) - { - UInt32 numStreams; - - RINOK(SzReadNumber32(sd, &numStreams)); - if (numStreams > k_NumCodersStreams_in_Folder_MAX) - return SZ_ERROR_UNSUPPORTED; - coder->NumStreams = (Byte)numStreams; + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; - RINOK(SzReadNumber32(sd, &numStreams)); - if (numStreams != 1) - return SZ_ERROR_UNSUPPORTED; - } + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; - numInStreams += coder->NumStreams; + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo* coder = f->Coders + i; + unsigned idSize, j; + UInt64 id; - if (numInStreams > k_NumCodersStreams_in_Folder_MAX) - return SZ_ERROR_UNSUPPORTED; + SZ_READ_BYTE(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; - if ((mainByte & 0x20) != 0) - { - UInt32 propsSize = 0; - RINOK(SzReadNumber32(sd, &propsSize)); - if (propsSize > sd->Size) - return SZ_ERROR_ARCHIVE; - if (propsSize >= 0x80) - return SZ_ERROR_UNSUPPORTED; - coder->PropsOffset = sd->Data - dataStart; - coder->PropsSize = (Byte)propsSize; - sd->Data += (size_t)propsSize; - sd->Size -= (size_t)propsSize; - } - } + idSize = (unsigned)(mainByte & 0xF); + if (idSize > sizeof(id)) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd->Size) + return SZ_ERROR_ARCHIVE; + id = 0; + for (j = 0; j < idSize; j++) + { + id = ((id << 8) | *sd->Data); + sd->Data++; + sd->Size--; + } + if (id > (UInt32)0xFFFFFFFF) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = (UInt32)id; - /* - if (numInStreams == 1 && numCoders == 1) - { - f->NumPackStreams = 1; - f->PackStreams[0] = 0; - } - else - */ - { - Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; - UInt32 numBonds, numPackStreams; - - numBonds = numCoders - 1; - if (numInStreams < numBonds) - return SZ_ERROR_ARCHIVE; - if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - f->NumBonds = numBonds; - - numPackStreams = numInStreams - numBonds; - if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - f->NumPackStreams = numPackStreams; - - for (i = 0; i < numInStreams; i++) - streamUsed[i] = False; - - if (numBonds != 0) - { - Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + coder->NumStreams = 1; + coder->PropsOffset = 0; + coder->PropsSize = 0; - for (i = 0; i < numCoders; i++) - coderUsed[i] = False; - - for (i = 0; i < numBonds; i++) - { - CSzBond *bp = f->Bonds + i; - - RINOK(SzReadNumber32(sd, &bp->InIndex)); - if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) - return SZ_ERROR_ARCHIVE; - streamUsed[bp->InIndex] = True; - - RINOK(SzReadNumber32(sd, &bp->OutIndex)); - if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) - return SZ_ERROR_ARCHIVE; - coderUsed[bp->OutIndex] = True; - } - - for (i = 0; i < numCoders; i++) - if (!coderUsed[i]) - { - f->UnpackStream = i; - break; - } - - if (i == numCoders) - return SZ_ERROR_ARCHIVE; - } - - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams; i++) - if (!streamUsed[i]) - break; - if (i == numInStreams) - return SZ_ERROR_ARCHIVE; - f->PackStreams[0] = i; - } - else - for (i = 0; i < numPackStreams; i++) - { - UInt32 index; - RINOK(SzReadNumber32(sd, &index)); - if (index >= numInStreams || streamUsed[index]) - return SZ_ERROR_ARCHIVE; - streamUsed[index] = True; - f->PackStreams[i] = index; - } - } + if ((mainByte & 0x10) != 0) + { + UInt32 numStreams; - f->NumCoders = numCoders; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + coder->NumStreams = (Byte)numStreams; - return SZ_OK; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize = 0; + RINOK(SzReadNumber32(sd, &propsSize)); + if (propsSize > sd->Size) + return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; + coder->PropsOffset = sd->Data - dataStart; + coder->PropsSize = (Byte)propsSize; + sd->Data += (size_t)propsSize; + sd->Size -= (size_t)propsSize; + } + } + + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ + { + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond* bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)); + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) + return SZ_ERROR_ARCHIVE; + f->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; + } + } + + f->NumCoders = numCoders; + + return SZ_OK; } -static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +static MY_NO_INLINE SRes SkipNumbers(CSzData* sd2, UInt32 num) { - CSzData sd; - sd = *sd2; - for (; num != 0; num--) - { - Byte firstByte, mask; - unsigned i; - SZ_READ_BYTE_2(firstByte); - if ((firstByte & 0x80) == 0) - continue; - if ((firstByte & 0x40) == 0) - { - if (sd.Size == 0) - return SZ_ERROR_ARCHIVE; - sd.Size--; - sd.Data++; - continue; - } - mask = 0x20; - for (i = 2; i < 8 && (firstByte & mask) != 0; i++) - mask >>= 1; - if (i > sd.Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, i); - } - *sd2 = sd; - return SZ_OK; + CSzData sd; + sd = *sd2; + for (; num != 0; num--) + { + Byte firstByte, mask; + unsigned i; + SZ_READ_BYTE_2(firstByte); + if ((firstByte & 0x80) == 0) + continue; + if ((firstByte & 0x40) == 0) + { + if (sd.Size == 0) + return SZ_ERROR_ARCHIVE; + sd.Size--; + sd.Data++; + continue; + } + mask = 0x20; + for (i = 2; i < 8 && (firstByte & mask) != 0; i++) + mask >>= 1; + if (i > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, i); + } + *sd2 = sd; + return SZ_OK; } @@ -631,460 +635,460 @@ static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) #define k_Scan_NumCodersStreams_in_Folder_MAX 64 -static SRes ReadUnpackInfo(CSzAr *p, - CSzData *sd2, - UInt32 numFoldersMax, - const CBuf *tempBufs, UInt32 numTempBufs, - ISzAlloc *alloc) +static SRes ReadUnpackInfo(CSzAr* p, + CSzData* sd2, + UInt32 numFoldersMax, + const CBuf* tempBufs, UInt32 numTempBufs, + ISzAlloc* alloc) { - CSzData sd; - - UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; - const Byte *startBufPtr; - Byte external; - - RINOK(WaitId(sd2, k7zIdFolder)); - - RINOK(SzReadNumber32(sd2, &numFolders)); - if (numFolders > numFoldersMax) - return SZ_ERROR_UNSUPPORTED; - p->NumFolders = numFolders; + CSzData sd; - SZ_READ_BYTE_SD(sd2, external); - if (external == 0) - sd = *sd2; - else - { - UInt32 index; - RINOK(SzReadNumber32(sd2, &index)); - if (index >= numTempBufs) - return SZ_ERROR_ARCHIVE; - sd.Data = tempBufs[index].data; - sd.Size = tempBufs[index].size; - } - - MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); - MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); - MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); - MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); - - startBufPtr = sd.Data; - - packStreamIndex = 0; - numCodersOutStreams = 0; + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; + const Byte* startBufPtr; + Byte external; - for (fo = 0; fo < numFolders; fo++) - { - UInt32 numCoders, ci, numInStreams = 0; - - p->FoCodersOffsets[fo] = sd.Data - startBufPtr; - - RINOK(SzReadNumber32(&sd, &numCoders)); - if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) - return SZ_ERROR_UNSUPPORTED; - - for (ci = 0; ci < numCoders; ci++) - { - Byte mainByte; - unsigned idSize; - UInt32 coderInStreams; - - SZ_READ_BYTE_2(mainByte); - if ((mainByte & 0xC0) != 0) - return SZ_ERROR_UNSUPPORTED; - idSize = (mainByte & 0xF); - if (idSize > 8) - return SZ_ERROR_UNSUPPORTED; - if (idSize > sd.Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, idSize); - - coderInStreams = 1; - - if ((mainByte & 0x10) != 0) - { - UInt32 coderOutStreams; - RINOK(SzReadNumber32(&sd, &coderInStreams)); - RINOK(SzReadNumber32(&sd, &coderOutStreams)); - if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) - return SZ_ERROR_UNSUPPORTED; - } - - numInStreams += coderInStreams; + RINOK(WaitId(sd2, k7zIdFolder)); - if ((mainByte & 0x20) != 0) - { - UInt32 propsSize; - RINOK(SzReadNumber32(&sd, &propsSize)); - if (propsSize > sd.Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, propsSize); - } - } - - { - UInt32 indexOfMainStream = 0; - UInt32 numPackStreams = 1; - - if (numCoders != 1 || numInStreams != 1) - { - Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; - Byte coderUsed[k_Scan_NumCoders_MAX]; - - UInt32 i; - UInt32 numBonds = numCoders - 1; - if (numInStreams < numBonds) - return SZ_ERROR_ARCHIVE; - - if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) - return SZ_ERROR_UNSUPPORTED; - - for (i = 0; i < numInStreams; i++) - streamUsed[i] = False; - for (i = 0; i < numCoders; i++) - coderUsed[i] = False; - - for (i = 0; i < numBonds; i++) - { - UInt32 index; - - RINOK(SzReadNumber32(&sd, &index)); - if (index >= numInStreams || streamUsed[index]) - return SZ_ERROR_ARCHIVE; - streamUsed[index] = True; - - RINOK(SzReadNumber32(&sd, &index)); - if (index >= numCoders || coderUsed[index]) - return SZ_ERROR_ARCHIVE; - coderUsed[index] = True; - } - - numPackStreams = numInStreams - numBonds; - - if (numPackStreams != 1) - for (i = 0; i < numPackStreams; i++) - { - UInt32 index; - RINOK(SzReadNumber32(&sd, &index)); - if (index >= numInStreams || streamUsed[index]) - return SZ_ERROR_ARCHIVE; - streamUsed[index] = True; - } - - for (i = 0; i < numCoders; i++) - if (!coderUsed[i]) - { - indexOfMainStream = i; - break; - } - - if (i == numCoders) - return SZ_ERROR_ARCHIVE; - } - - p->FoStartPackStreamIndex[fo] = packStreamIndex; - p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; - p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; - numCodersOutStreams += numCoders; - if (numCodersOutStreams < numCoders) - return SZ_ERROR_UNSUPPORTED; - if (numPackStreams > p->NumPackStreams - packStreamIndex) - return SZ_ERROR_ARCHIVE; - packStreamIndex += numPackStreams; - } - } + RINOK(SzReadNumber32(sd2, &numFolders)); + if (numFolders > numFoldersMax) + return SZ_ERROR_UNSUPPORTED; + p->NumFolders = numFolders; - p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; - - { - size_t dataSize = sd.Data - startBufPtr; - p->FoStartPackStreamIndex[fo] = packStreamIndex; - p->FoCodersOffsets[fo] = dataSize; - MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); - } - - if (external != 0) - { - if (sd.Size != 0) - return SZ_ERROR_ARCHIVE; - sd = *sd2; - } - - RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); - - MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); - { - UInt32 i; - for (i = 0; i < numCodersOutStreams; i++) - { - RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); - } - } + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } - for (;;) - { - UInt64 type; - RINOK(ReadID(&sd, &type)); - if (type == k7zIdEnd) - { - *sd2 = sd; - return SZ_OK; - } - if (type == k7zIdCRC) - { - RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); - continue; - } - RINOK(SkipData(&sd)); - } + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); + MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); + + startBufPtr = sd.Data; + + packStreamIndex = 0; + numCodersOutStreams = 0; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 numCoders, ci, numInStreams = 0; + + p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + + RINOK(SzReadNumber32(&sd, &numCoders)); + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (ci = 0; ci < numCoders; ci++) + { + Byte mainByte; + unsigned idSize; + UInt32 coderInStreams; + + SZ_READ_BYTE_2(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + idSize = (mainByte & 0xF); + if (idSize > 8) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, idSize); + + coderInStreams = 1; + + if ((mainByte & 0x10) != 0) + { + UInt32 coderOutStreams; + RINOK(SzReadNumber32(&sd, &coderInStreams)); + RINOK(SzReadNumber32(&sd, &coderOutStreams)); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coderInStreams; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize; + RINOK(SzReadNumber32(&sd, &propsSize)); + if (propsSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, propsSize); + } + } + + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 1; + + if (numCoders != 1 || numInStreams != 1) + { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + + UInt32 i; + UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + UInt32 index; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numCoders || coderUsed[index]) + return SZ_ERROR_ARCHIVE; + coderUsed[index] = True; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) + return SZ_ERROR_UNSUPPORTED; + if (numPackStreams > p->NumPackStreams - packStreamIndex) + return SZ_ERROR_ARCHIVE; + packStreamIndex += numPackStreams; + } + } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + + { + size_t dataSize = sd.Data - startBufPtr; + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoCodersOffsets[fo] = dataSize; + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); + } + + if (external != 0) + { + if (sd.Size != 0) + return SZ_ERROR_ARCHIVE; + sd = *sd2; + } + + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); + + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + { + UInt32 i; + for (i = 0; i < numCodersOutStreams; i++) + { + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + } + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(&sd, &type)); + if (type == k7zIdEnd) + { + *sd2 = sd; + return SZ_OK; + } + if (type == k7zIdCRC) + { + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); + continue; + } + RINOK(SkipData(&sd)); + } } -UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +UInt64 SzAr_GetFolderUnpackSize(const CSzAr* p, UInt32 folderIndex) { - return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; } typedef struct { - UInt32 NumTotalSubStreams; - UInt32 NumSubDigests; - CSzData sdNumSubStreams; - CSzData sdSizes; - CSzData sdCRCs; + UInt32 NumTotalSubStreams; + UInt32 NumSubDigests; + CSzData sdNumSubStreams; + CSzData sdSizes; + CSzData sdCRCs; } CSubStreamInfo; -static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) +static SRes ReadSubStreamsInfo(CSzAr* p, CSzData* sd, CSubStreamInfo* ssi) { - UInt64 type = 0; - UInt32 numSubDigests = 0; - UInt32 numFolders = p->NumFolders; - UInt32 numUnpackStreams = numFolders; - UInt32 numUnpackSizesInData = 0; + UInt64 type = 0; + UInt32 numSubDigests = 0; + UInt32 numFolders = p->NumFolders; + UInt32 numUnpackStreams = numFolders; + UInt32 numUnpackSizesInData = 0; - for (;;) - { - RINOK(ReadID(sd, &type)); - if (type == k7zIdNumUnpackStream) - { - UInt32 i; - ssi->sdNumSubStreams.Data = sd->Data; - numUnpackStreams = 0; - numSubDigests = 0; - for (i = 0; i < numFolders; i++) - { - UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); - if (numUnpackStreams > numUnpackStreams + numStreams) - return SZ_ERROR_UNSUPPORTED; - numUnpackStreams += numStreams; - if (numStreams != 0) - numUnpackSizesInData += (numStreams - 1); - if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) - numSubDigests += numStreams; - } - ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; - continue; - } - if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) - break; - RINOK(SkipData(sd)); - } + for (;;) + { + RINOK(ReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + UInt32 i; + ssi->sdNumSubStreams.Data = sd->Data; + numUnpackStreams = 0; + numSubDigests = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numUnpackStreams > numUnpackStreams + numStreams) + return SZ_ERROR_UNSUPPORTED; + numUnpackStreams += numStreams; + if (numStreams != 0) + numUnpackSizesInData += (numStreams - 1); + if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) + numSubDigests += numStreams; + } + ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; + continue; + } + if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } - if (!ssi->sdNumSubStreams.Data) - { - numSubDigests = numFolders; - if (p->FolderCRCs.Defs) - numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); - } - - ssi->NumTotalSubStreams = numUnpackStreams; - ssi->NumSubDigests = numSubDigests; + if (!ssi->sdNumSubStreams.Data) + { + numSubDigests = numFolders; + if (p->FolderCRCs.Defs) + numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); + } - if (type == k7zIdSize) - { - ssi->sdSizes.Data = sd->Data; - RINOK(SkipNumbers(sd, numUnpackSizesInData)); - ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; - RINOK(ReadID(sd, &type)); - } + ssi->NumTotalSubStreams = numUnpackStreams; + ssi->NumSubDigests = numSubDigests; - for (;;) - { - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - ssi->sdCRCs.Data = sd->Data; - RINOK(SkipBitUi32s(sd, numSubDigests)); - ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; - } - else - { - RINOK(SkipData(sd)); - } - RINOK(ReadID(sd, &type)); - } + if (type == k7zIdSize) + { + ssi->sdSizes.Data = sd->Data; + RINOK(SkipNumbers(sd, numUnpackSizesInData)); + ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; + RINOK(ReadID(sd, &type)); + } + + for (;;) + { + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + ssi->sdCRCs.Data = sd->Data; + RINOK(SkipBitUi32s(sd, numSubDigests)); + ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; + } + else + { + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } } -static SRes SzReadStreamsInfo(CSzAr *p, - CSzData *sd, - UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, - UInt64 *dataOffset, - CSubStreamInfo *ssi, - ISzAlloc *alloc) +static SRes SzReadStreamsInfo(CSzAr* p, + CSzData* sd, + UInt32 numFoldersMax, const CBuf* tempBufs, UInt32 numTempBufs, + UInt64* dataOffset, + CSubStreamInfo* ssi, + ISzAlloc* alloc) { - UInt64 type; + UInt64 type; - SzData_Clear(&ssi->sdSizes); - SzData_Clear(&ssi->sdCRCs); - SzData_Clear(&ssi->sdNumSubStreams); + SzData_Clear(&ssi->sdSizes); + SzData_Clear(&ssi->sdCRCs); + SzData_Clear(&ssi->sdNumSubStreams); - *dataOffset = 0; - RINOK(ReadID(sd, &type)); - if (type == k7zIdPackInfo) - { - RINOK(ReadNumber(sd, dataOffset)); - RINOK(ReadPackInfo(p, sd, alloc)); - RINOK(ReadID(sd, &type)); - } - if (type == k7zIdUnpackInfo) - { - RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); - RINOK(ReadID(sd, &type)); - } - if (type == k7zIdSubStreamsInfo) - { - RINOK(ReadSubStreamsInfo(p, sd, ssi)); - RINOK(ReadID(sd, &type)); - } - else - { - ssi->NumTotalSubStreams = p->NumFolders; - // ssi->NumSubDigests = 0; - } + *dataOffset = 0; + RINOK(ReadID(sd, &type)); + if (type == k7zIdPackInfo) + { + RINOK(ReadNumber(sd, dataOffset)); + RINOK(ReadPackInfo(p, sd, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdUnpackInfo) + { + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdSubStreamsInfo) + { + RINOK(ReadSubStreamsInfo(p, sd, ssi)); + RINOK(ReadID(sd, &type)); + } + else + { + ssi->NumTotalSubStreams = p->NumFolders; + // ssi->NumSubDigests = 0; + } - return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); + return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); } static SRes SzReadAndDecodePackedStreams( - ILookInStream *inStream, - CSzData *sd, - CBuf *tempBufs, - UInt32 numFoldersMax, - UInt64 baseOffset, - CSzAr *p, - ISzAlloc *allocTemp) + ILookInStream* inStream, + CSzData* sd, + CBuf* tempBufs, + UInt32 numFoldersMax, + UInt64 baseOffset, + CSzAr* p, + ISzAlloc* allocTemp) { - UInt64 dataStartPos; - UInt32 fo; - CSubStreamInfo ssi; + UInt64 dataStartPos; + UInt32 fo; + CSubStreamInfo ssi; - RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); - - dataStartPos += baseOffset; - if (p->NumFolders == 0) - return SZ_ERROR_ARCHIVE; - - for (fo = 0; fo < p->NumFolders; fo++) - Buf_Init(tempBufs + fo); - - for (fo = 0; fo < p->NumFolders; fo++) - { - CBuf *tempBuf = tempBufs + fo; - UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); - if ((size_t)unpackSize != unpackSize) - return SZ_ERROR_MEM; - if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) - return SZ_ERROR_MEM; - } - - for (fo = 0; fo < p->NumFolders; fo++) - { - const CBuf *tempBuf = tempBufs + fo; - RINOK(LookInStream_SeekTo(inStream, dataStartPos)); - RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); - } - - return SZ_OK; + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders == 0) + return SZ_ERROR_ARCHIVE; + + for (fo = 0; fo < p->NumFolders; fo++) + Buf_Init(tempBufs + fo); + + for (fo = 0; fo < p->NumFolders; fo++) + { + CBuf* tempBuf = tempBufs + fo; + UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + if ((size_t)unpackSize != unpackSize) + return SZ_ERROR_MEM; + if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + } + + for (fo = 0; fo < p->NumFolders; fo++) + { + const CBuf* tempBuf = tempBufs + fo; + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); + } + + return SZ_OK; } -static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) +static SRes SzReadFileNames(const Byte* data, size_t size, UInt32 numFiles, size_t* offsets) { - size_t pos = 0; - *offsets++ = 0; - if (numFiles == 0) - return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; - if (size < 2) - return SZ_ERROR_ARCHIVE; - if (data[size - 2] != 0 || data[size - 1] != 0) - return SZ_ERROR_ARCHIVE; - do - { - const Byte *p; - if (pos == size) - return SZ_ERROR_ARCHIVE; - for (p = data + pos; - #ifdef _WIN32 - *(const UInt16 *)p != 0 - #else + size_t pos = 0; + *offsets++ = 0; + if (numFiles == 0) + return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; + if (data[size - 2] != 0 || data[size - 1] != 0) + return SZ_ERROR_ARCHIVE; + do + { + const Byte* p; + if (pos == size) + return SZ_ERROR_ARCHIVE; + for (p = data + pos; +#ifdef _WIN32 + *(const UInt16*)p != 0 +#else p[0] != 0 || p[1] != 0 - #endif - ; p += 2); - pos = p - data + 2; - *offsets++ = (pos >> 1); - } - while (--numFiles); - return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +#endif + ; p += 2); + pos = p - data + 2; + *offsets++ = (pos >> 1); + } + while (--numFiles); + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; } -static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, - CSzData *sd2, - const CBuf *tempBufs, UInt32 numTempBufs, - ISzAlloc *alloc) +static MY_NO_INLINE SRes ReadTime(CSzBitUi64s* p, UInt32 num, + CSzData* sd2, + const CBuf* tempBufs, UInt32 numTempBufs, + ISzAlloc* alloc) { - CSzData sd; - UInt32 i; - CNtfsFileTime *vals; - Byte *defs; - Byte external; - - RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); - - SZ_READ_BYTE_SD(sd2, external); - if (external == 0) - sd = *sd2; - else - { - UInt32 index; - RINOK(SzReadNumber32(sd2, &index)); - if (index >= numTempBufs) - return SZ_ERROR_ARCHIVE; - sd.Data = tempBufs[index].data; - sd.Size = tempBufs[index].size; - } - - MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); - vals = p->Vals; - defs = p->Defs; - for (i = 0; i < num; i++) - if (SzBitArray_Check(defs, i)) - { - if (sd.Size < 8) - return SZ_ERROR_ARCHIVE; - vals[i].Low = GetUi32(sd.Data); - vals[i].High = GetUi32(sd.Data + 4); - SKIP_DATA2(sd, 8); - } - else - vals[i].High = vals[i].Low = 0; - - if (external == 0) - *sd2 = sd; - - return SZ_OK; + CSzData sd; + UInt32 i; + CNtfsFileTime* vals; + Byte* defs; + Byte external; + + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); + vals = p->Vals; + defs = p->Defs; + for (i = 0; i < num; i++) + if (SzBitArray_Check(defs, i)) + { + if (sd.Size < 8) + return SZ_ERROR_ARCHIVE; + vals[i].Low = GetUi32(sd.Data); + vals[i].High = GetUi32(sd.Data + 4); + SKIP_DATA2(sd, 8); + } + else + vals[i].High = vals[i].Low = 0; + + if (external == 0) + *sd2 = sd; + + return SZ_OK; } @@ -1092,635 +1096,638 @@ static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, static SRes SzReadHeader2( - CSzArEx *p, /* allocMain */ - CSzData *sd, - ILookInStream *inStream, - CBuf *tempBufs, UInt32 *numTempBufs, - ISzAlloc *allocMain, - ISzAlloc *allocTemp - ) + CSzArEx* p, /* allocMain */ + CSzData* sd, + ILookInStream* inStream, + CBuf* tempBufs, UInt32* numTempBufs, + ISzAlloc* allocMain, + ISzAlloc* allocTemp +) { - CSubStreamInfo ssi; + CSubStreamInfo ssi; -{ - UInt64 type; - - SzData_Clear(&ssi.sdSizes); - SzData_Clear(&ssi.sdCRCs); - SzData_Clear(&ssi.sdNumSubStreams); + { + UInt64 type; - ssi.NumSubDigests = 0; - ssi.NumTotalSubStreams = 0; + SzData_Clear(&ssi.sdSizes); + SzData_Clear(&ssi.sdCRCs); + SzData_Clear(&ssi.sdNumSubStreams); - RINOK(ReadID(sd, &type)); + ssi.NumSubDigests = 0; + ssi.NumTotalSubStreams = 0; - if (type == k7zIdArchiveProperties) - { - for (;;) - { - UInt64 type2; - RINOK(ReadID(sd, &type2)); - if (type2 == k7zIdEnd) - break; - RINOK(SkipData(sd)); - } - RINOK(ReadID(sd, &type)); - } + RINOK(ReadID(sd, &type)); - if (type == k7zIdAdditionalStreamsInfo) - { - CSzAr tempAr; - SRes res; - - SzAr_Init(&tempAr); - res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, - p->startPosAfterHeader, &tempAr, allocTemp); - *numTempBufs = tempAr.NumFolders; - SzAr_Free(&tempAr, allocTemp); - - if (res != SZ_OK) - return res; - RINOK(ReadID(sd, &type)); - } + if (type == k7zIdArchiveProperties) + { + for (;;) + { + UInt64 type2; + RINOK(ReadID(sd, &type2)); + if (type2 == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } - if (type == k7zIdMainStreamsInfo) - { - RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, - &p->dataPos, &ssi, allocMain)); - p->dataPos += p->startPosAfterHeader; - RINOK(ReadID(sd, &type)); - } + if (type == k7zIdAdditionalStreamsInfo) + { + CSzAr tempAr; + SRes res; - if (type == k7zIdEnd) - { - return SZ_OK; - } + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, + p->startPosAfterHeader, &tempAr, allocTemp); + *numTempBufs = tempAr.NumFolders; + SzAr_Free(&tempAr, allocTemp); - if (type != k7zIdFilesInfo) - return SZ_ERROR_ARCHIVE; -} + if (res != SZ_OK) + return res; + RINOK(ReadID(sd, &type)); + } -{ - UInt32 numFiles = 0; - UInt32 numEmptyStreams = 0; - const Byte *emptyStreams = NULL; - const Byte *emptyFiles = NULL; - - RINOK(SzReadNumber32(sd, &numFiles)); - p->NumFiles = numFiles; + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, + &p->dataPos, &ssi, allocMain)); + p->dataPos += p->startPosAfterHeader; + RINOK(ReadID(sd, &type)); + } - for (;;) - { - UInt64 type; - UInt64 size; - RINOK(ReadID(sd, &type)); - if (type == k7zIdEnd) - break; - RINOK(ReadNumber(sd, &size)); - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - - if (type >= ((UInt32)1 << 8)) - { - SKIP_DATA(sd, size); - } - else switch ((unsigned)type) - { - case k7zIdName: - { - size_t namesSize; - const Byte *namesData; - Byte external; + if (type == k7zIdEnd) + { + return SZ_OK; + } - SZ_READ_BYTE(external); - if (external == 0) - { - namesSize = (size_t)size - 1; - namesData = sd->Data; - } - else - { - UInt32 index; - RINOK(SzReadNumber32(sd, &index)); - if (index >= *numTempBufs) - return SZ_ERROR_ARCHIVE; - namesData = (tempBufs)[index].data; - namesSize = (tempBufs)[index].size; - } + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; + } - if ((namesSize & 1) != 0) - return SZ_ERROR_ARCHIVE; - MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); - MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); - RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) - if (external == 0) - { - SKIP_DATA(sd, namesSize); - } - break; - } - case k7zIdEmptyStream: - { - RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); - numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); - emptyFiles = NULL; - break; - } - case k7zIdEmptyFile: - { - RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); - break; - } - case k7zIdWinAttrib: - { - Byte external; - CSzData sdSwitch; - CSzData *sdPtr; - SzBitUi32s_Free(&p->Attribs, allocMain); - RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); + { + UInt32 numFiles = 0; + UInt32 numEmptyStreams = 0; + const Byte* emptyStreams = NULL; + const Byte* emptyFiles = NULL; - SZ_READ_BYTE(external); - if (external == 0) - sdPtr = sd; - else - { - UInt32 index; - RINOK(SzReadNumber32(sd, &index)); - if (index >= *numTempBufs) - return SZ_ERROR_ARCHIVE; - sdSwitch.Data = (tempBufs)[index].data; - sdSwitch.Size = (tempBufs)[index].size; - sdPtr = &sdSwitch; - } - RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); - break; - } - /* - case k7zParent: - { - SzBitUi32s_Free(&p->Parents, allocMain); - RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); - RINOK(SzReadSwitch(sd)); - RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); - break; - } - */ - case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; - case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; - default: - { - SKIP_DATA(sd, size); - } - } - } + RINOK(SzReadNumber32(sd, &numFiles)); + p->NumFiles = numFiles; - if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) - return SZ_ERROR_ARCHIVE; + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; - for (;;) - { - UInt64 type; - RINOK(ReadID(sd, &type)); - if (type == k7zIdEnd) - break; - RINOK(SkipData(sd)); - } + if (type >= ((UInt32)1 << 8)) + { + SKIP_DATA(sd, size); + } + else + switch ((unsigned)type) + { + case k7zIdName: + { + size_t namesSize; + const Byte* namesData; + Byte external; - { - UInt32 i; - UInt32 emptyFileIndex = 0; - UInt32 folderIndex = 0; - UInt32 remSubStreams = 0; - UInt32 numSubStreams = 0; - UInt64 unpackPos = 0; - const Byte *digestsDefs = NULL; - const Byte *digestsVals = NULL; - UInt32 digestsValsIndex = 0; - UInt32 digestIndex; - Byte allDigestsDefined = 0; - Byte isDirMask = 0; - Byte crcMask = 0; - Byte mask = 0x80; - - MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); - MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); - MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); - MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + SZ_READ_BYTE(external); + if (external == 0) + { + namesSize = (size_t)size - 1; + namesData = sd->Data; + } + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + namesData = (tempBufs)[index].data; + namesSize = (tempBufs)[index].size; + } - RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); + RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) + if (external == 0) + { + SKIP_DATA(sd, namesSize); + } + break; + } + case k7zIdEmptyStream: + { + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); + numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; + break; + } + case k7zIdEmptyFile: + { + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); + break; + } + case k7zIdWinAttrib: + { + Byte external; + CSzData sdSwitch; + CSzData* sdPtr; + SzBitUi32s_Free(&p->Attribs, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); - if (ssi.sdCRCs.Size != 0) - { - SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); - if (allDigestsDefined) - digestsVals = ssi.sdCRCs.Data; - else - { - size_t numBytes = (ssi.NumSubDigests + 7) >> 3; - digestsDefs = ssi.sdCRCs.Data; - digestsVals = digestsDefs + numBytes; - } - } + SZ_READ_BYTE(external); + if (external == 0) + sdPtr = sd; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + sdSwitch.Data = (tempBufs)[index].data; + sdSwitch.Size = (tempBufs)[index].size; + sdPtr = &sdSwitch; + } + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); + break; + } + /* + case k7zParent: + { + SzBitUi32s_Free(&p->Parents, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); + RINOK(SzReadSwitch(sd)); + RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); + break; + } + */ + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); + break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); + break; + default: + { + SKIP_DATA(sd, size); + } + } + } - digestIndex = 0; - - for (i = 0; i < numFiles; i++, mask >>= 1) - { - if (mask == 0) - { - UInt32 byteIndex = (i - 1) >> 3; - p->IsDirs[byteIndex] = isDirMask; - p->CRCs.Defs[byteIndex] = crcMask; - isDirMask = 0; - crcMask = 0; - mask = 0x80; - } + if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) + return SZ_ERROR_ARCHIVE; - p->UnpackPositions[i] = unpackPos; - p->CRCs.Vals[i] = 0; - - if (emptyStreams && SzBitArray_Check(emptyStreams, i)) - { - if (emptyFiles) - { - if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) - isDirMask |= mask; - emptyFileIndex++; - } - else - isDirMask |= mask; - if (remSubStreams == 0) - { - p->FileToFolder[i] = (UInt32)-1; - continue; - } - } - - if (remSubStreams == 0) - { - for (;;) - { - if (folderIndex >= p->db.NumFolders) - return SZ_ERROR_ARCHIVE; - p->FolderToFile[folderIndex] = i; - numSubStreams = 1; - if (ssi.sdNumSubStreams.Data) - { - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); - } - remSubStreams = numSubStreams; - if (numSubStreams != 0) - break; - { - UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - unpackPos += folderUnpackSize; - if (unpackPos < folderUnpackSize) - return SZ_ERROR_ARCHIVE; - } + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } - folderIndex++; - } - } - - p->FileToFolder[i] = folderIndex; - - if (emptyStreams && SzBitArray_Check(emptyStreams, i)) - continue; - - if (--remSubStreams == 0) - { - UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; - if (folderUnpackSize < unpackPos - startFolderUnpackPos) - return SZ_ERROR_ARCHIVE; - unpackPos = startFolderUnpackPos + folderUnpackSize; - if (unpackPos < folderUnpackSize) - return SZ_ERROR_ARCHIVE; + { + UInt32 i; + UInt32 emptyFileIndex = 0; + UInt32 folderIndex = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; + UInt64 unpackPos = 0; + const Byte* digestsDefs = NULL; + const Byte* digestsVals = NULL; + UInt32 digestsValsIndex = 0; + UInt32 digestIndex; + Byte allDigestsDefined = 0; + Byte isDirMask = 0; + Byte crcMask = 0; + Byte mask = 0x80; - if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) - { - p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; - crcMask |= mask; - } - else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) - { - p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); - digestsValsIndex++; - crcMask |= mask; - } - - folderIndex++; - } - else - { - UInt64 v; - RINOK(ReadNumber(&ssi.sdSizes, &v)); - unpackPos += v; - if (unpackPos < v) - return SZ_ERROR_ARCHIVE; - if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) - { - p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); - digestsValsIndex++; - crcMask |= mask; - } - } - } + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); - if (mask != 0x80) - { - UInt32 byteIndex = (i - 1) >> 3; - p->IsDirs[byteIndex] = isDirMask; - p->CRCs.Defs[byteIndex] = crcMask; - } - - p->UnpackPositions[i] = unpackPos; + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); - if (remSubStreams != 0) - return SZ_ERROR_ARCHIVE; + if (ssi.sdCRCs.Size != 0) + { + SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); + if (allDigestsDefined) + digestsVals = ssi.sdCRCs.Data; + else + { + size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + digestsDefs = ssi.sdCRCs.Data; + digestsVals = digestsDefs + numBytes; + } + } - for (;;) - { - p->FolderToFile[folderIndex] = i; - if (folderIndex >= p->db.NumFolders) - break; - if (!ssi.sdNumSubStreams.Data) - return SZ_ERROR_ARCHIVE; - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); - if (numSubStreams != 0) - return SZ_ERROR_ARCHIVE; - /* - { - UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - unpackPos += folderUnpackSize; - if (unpackPos < folderUnpackSize) - return SZ_ERROR_ARCHIVE; - } - */ - folderIndex++; - } + digestIndex = 0; - if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) - return SZ_ERROR_ARCHIVE; - } -} - return SZ_OK; + for (i = 0; i < numFiles; i++, mask >>= 1) + { + if (mask == 0) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + isDirMask = 0; + crcMask = 0; + mask = 0x80; + } + + p->UnpackPositions[i] = unpackPos; + p->CRCs.Vals[i] = 0; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + { + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else + isDirMask |= mask; + if (remSubStreams == 0) + { + p->FileToFolder[i] = (UInt32)-1; + continue; + } + } + + if (remSubStreams == 0) + { + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) + { + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + } + remSubStreams = numSubStreams; + if (numSubStreams != 0) + break; + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + + folderIndex++; + } + } + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + continue; + + if (--remSubStreams == 0) + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + if (folderUnpackSize < unpackPos - startFolderUnpackPos) + return SZ_ERROR_ARCHIVE; + unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + { + p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; + crcMask |= mask; + } + else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + + folderIndex++; + } + else + { + UInt64 v; + RINOK(ReadNumber(&ssi.sdSizes, &v)); + unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; + if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + } + } + + if (mask != 0x80) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + } + + p->UnpackPositions[i] = unpackPos; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; + } + } + return SZ_OK; } static SRes SzReadHeader( - CSzArEx *p, - CSzData *sd, - ILookInStream *inStream, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) + CSzArEx* p, + CSzData* sd, + ILookInStream* inStream, + ISzAlloc* allocMain, + ISzAlloc* allocTemp) { - UInt32 i; - UInt32 numTempBufs = 0; - SRes res; - CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; + UInt32 i; + UInt32 numTempBufs = 0; + SRes res; + CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; - for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) - Buf_Init(tempBufs + i); - - res = SzReadHeader2(p, sd, inStream, - tempBufs, &numTempBufs, - allocMain, allocTemp); - - for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) - Buf_Free(tempBufs + i, allocTemp); + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Init(tempBufs + i); - RINOK(res); + res = SzReadHeader2(p, sd, inStream, + tempBufs, &numTempBufs, + allocMain, allocTemp); - if (sd->Size != 0) - return SZ_ERROR_FAIL; + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Free(tempBufs + i, allocTemp); - return res; + RINOK(res); + + if (sd->Size != 0) + return SZ_ERROR_FAIL; + + return res; } static SRes SzArEx_Open2( - CSzArEx *p, - ILookInStream *inStream, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) + CSzArEx* p, + ILookInStream* inStream, + ISzAlloc* allocMain, + ISzAlloc* allocTemp) { - Byte header[k7zStartHeaderSize]; - Int64 startArcPos; - UInt64 nextHeaderOffset, nextHeaderSize; - size_t nextHeaderSizeT; - UInt32 nextHeaderCRC; - CBuf buf; - SRes res; + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buf; + SRes res; - startArcPos = 0; - RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + startArcPos = 0; + RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); - RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); - if (!TestSignatureCandidate(header)) - return SZ_ERROR_NO_ARCHIVE; - if (header[6] != k7zMajorVersion) - return SZ_ERROR_UNSUPPORTED; + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; - nextHeaderOffset = GetUi64(header + 12); - nextHeaderSize = GetUi64(header + 20); - nextHeaderCRC = GetUi32(header + 28); + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); - p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; - - if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) - return SZ_ERROR_CRC; + p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; - nextHeaderSizeT = (size_t)nextHeaderSize; - if (nextHeaderSizeT != nextHeaderSize) - return SZ_ERROR_MEM; - if (nextHeaderSizeT == 0) - return SZ_OK; - if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || - nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) - return SZ_ERROR_NO_ARCHIVE; + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; - { - Int64 pos = 0; - RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); - if ((UInt64)pos < startArcPos + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) - return SZ_ERROR_INPUT_EOF; - } + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; - RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + { + Int64 pos = 0; + RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < startArcPos + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } - if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) - return SZ_ERROR_MEM; + RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); - res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); - - if (res == SZ_OK) - { - res = SZ_ERROR_ARCHIVE; - if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) - { - CSzData sd; - UInt64 type; - sd.Data = buf.data; - sd.Size = buf.size; - - res = ReadID(&sd, &type); - - if (res == SZ_OK && type == k7zIdEncodedHeader) - { - CSzAr tempAr; - CBuf tempBuf; - Buf_Init(&tempBuf); - - SzAr_Init(&tempAr); - res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); - SzAr_Free(&tempAr, allocTemp); - - if (res != SZ_OK) - { - Buf_Free(&tempBuf, allocTemp); - } - else - { - Buf_Free(&buf, allocTemp); - buf.data = tempBuf.data; - buf.size = tempBuf.size; - sd.Data = buf.data; - sd.Size = buf.size; - res = ReadID(&sd, &type); - } - } - - if (res == SZ_OK) - { - if (type == k7zIdHeader) - { - /* - CSzData sd2; - unsigned ttt; - for (ttt = 0; ttt < 40000; ttt++) - { - SzArEx_Free(p, allocMain); - sd2 = sd; - res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); - if (res != SZ_OK) - break; - } - */ - res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); - } - else - res = SZ_ERROR_UNSUPPORTED; - } - } - } - - Buf_Free(&buf, allocTemp); - return res; + if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buf.data; + sd.Size = buf.size; + + res = ReadID(&sd, &type); + + if (res == SZ_OK && type == k7zIdEncodedHeader) + { + CSzAr tempAr; + CBuf tempBuf; + Buf_Init(&tempBuf); + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + { + Buf_Free(&tempBuf, allocTemp); + } + else + { + Buf_Free(&buf, allocTemp); + buf.data = tempBuf.data; + buf.size = tempBuf.size; + sd.Data = buf.data; + sd.Size = buf.size; + res = ReadID(&sd, &type); + } + } + + if (res == SZ_OK) + { + if (type == k7zIdHeader) + { + /* + CSzData sd2; + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) + { + SzArEx_Free(p, allocMain); + sd2 = sd; + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); + if (res != SZ_OK) + break; + } + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); + } + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + + Buf_Free(&buf, allocTemp); + return res; } -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, - ISzAlloc *allocMain, ISzAlloc *allocTemp) +SRes SzArEx_Open(CSzArEx* p, ILookInStream* inStream, + ISzAlloc* allocMain, ISzAlloc* allocTemp) { - SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); - if (res != SZ_OK) - SzArEx_Free(p, allocMain); - return res; + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; } SRes SzArEx_Extract( - const CSzArEx *p, - ILookInStream *inStream, - UInt32 fileIndex, - UInt32 *blockIndex, - Byte **tempBuf, - size_t *outBufferSize, - size_t *offset, - size_t *outSizeProcessed, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) + const CSzArEx* p, + ILookInStream* inStream, + UInt32 fileIndex, + UInt32* blockIndex, + Byte** tempBuf, + size_t* outBufferSize, + size_t* offset, + size_t* outSizeProcessed, + ISzAlloc* allocMain, + ISzAlloc* allocTemp) { - UInt32 folderIndex = p->FileToFolder[fileIndex]; - SRes res = SZ_OK; - - *offset = 0; - *outSizeProcessed = 0; - - if (folderIndex == (UInt32)-1) - { - IAlloc_Free(allocMain, *tempBuf); - *blockIndex = folderIndex; - *tempBuf = NULL; - *outBufferSize = 0; - return SZ_OK; - } + UInt32 folderIndex = p->FileToFolder[fileIndex]; + SRes res = SZ_OK; - if (*tempBuf == NULL || *blockIndex != folderIndex) - { - UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - /* - UInt64 unpackSizeSpec = - p->UnpackPositions[p->FolderToFile[folderIndex + 1]] - - p->UnpackPositions[p->FolderToFile[folderIndex]]; - */ - size_t unpackSize = (size_t)unpackSizeSpec; + *offset = 0; + *outSizeProcessed = 0; - if (unpackSize != unpackSizeSpec) - return SZ_ERROR_MEM; - *blockIndex = folderIndex; - IAlloc_Free(allocMain, *tempBuf); - *tempBuf = NULL; - - if (res == SZ_OK) - { - *outBufferSize = unpackSize; - if (unpackSize != 0) - { - *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize); - if (*tempBuf == NULL) - res = SZ_ERROR_MEM; - } - - if (res == SZ_OK) - { - res = SzAr_DecodeFolder(&p->db, folderIndex, - inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); - } - } - } + if (folderIndex == (UInt32)-1) + { + IAlloc_Free(allocMain, *tempBuf); + *blockIndex = folderIndex; + *tempBuf = NULL; + *outBufferSize = 0; + return SZ_OK; + } - if (res == SZ_OK) - { - UInt64 unpackPos = p->UnpackPositions[fileIndex]; - *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); - *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos); - if (*offset + *outSizeProcessed > *outBufferSize) - return SZ_ERROR_FAIL; - if (SzBitWithVals_Check(&p->CRCs, fileIndex)) - if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) - res = SZ_ERROR_CRC; - } + if (*tempBuf == NULL || *blockIndex != folderIndex) + { + UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* + UInt64 unpackSizeSpec = + p->UnpackPositions[p->FolderToFile[folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ + size_t unpackSize = (size_t)unpackSizeSpec; - return res; + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + IAlloc_Free(allocMain, *tempBuf); + *tempBuf = NULL; + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *tempBuf = (Byte*)IAlloc_Alloc(allocMain, unpackSize); + if (*tempBuf == NULL) + res = SZ_ERROR_MEM; + } + + if (res == SZ_OK) + { + res = SzAr_DecodeFolder(&p->db, folderIndex, + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); + } + } + } + + if (res == SZ_OK) + { + UInt64 unpackPos = p->UnpackPositions[fileIndex]; + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); + *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos); + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; + } + + return res; } -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +size_t SzArEx_GetFileNameUtf16(const CSzArEx* p, size_t fileIndex, UInt16* dest) { - size_t offs = p->FileNameOffsets[fileIndex]; - size_t len = p->FileNameOffsets[fileIndex + 1] - offs; - if (dest != 0) - { - size_t i; - const Byte *src = p->FileNames + offs * 2; - for (i = 0; i < len; i++) - dest[i] = GetUi16(src + i * 2); - } - return len; + size_t offs = p->FileNameOffsets[fileIndex]; + size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + if (dest != 0) + { + size_t i; + const Byte* src = p->FileNames + offs * 2; + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; } /* diff --git a/SevenZip/7zBuf.c b/SevenZip/7zBuf.c index 089a5c4..c0b0e05 100644 --- a/SevenZip/7zBuf.c +++ b/SevenZip/7zBuf.c @@ -5,32 +5,32 @@ #include "7zBuf.h" -void Buf_Init(CBuf *p) +void Buf_Init(CBuf* p) { - p->data = 0; - p->size = 0; + p->data = 0; + p->size = 0; } -int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc) +int Buf_Create(CBuf* p, size_t size, ISzAlloc* alloc) { - p->size = 0; - if (size == 0) - { - p->data = 0; - return 1; - } - p->data = (Byte *)alloc->Alloc(alloc, size); - if (p->data != 0) - { - p->size = size; - return 1; - } - return 0; + p->size = 0; + if (size == 0) + { + p->data = 0; + return 1; + } + p->data = (Byte*)alloc->Alloc(alloc, size); + if (p->data != 0) + { + p->size = size; + return 1; + } + return 0; } -void Buf_Free(CBuf *p, ISzAlloc *alloc) +void Buf_Free(CBuf* p, ISzAlloc* alloc) { - alloc->Free(alloc, p->data); - p->data = 0; - p->size = 0; + alloc->Free(alloc, p->data); + p->data = 0; + p->size = 0; } diff --git a/SevenZip/7zBuf.h b/SevenZip/7zBuf.h index 65f1d7a..9e0e91c 100644 --- a/SevenZip/7zBuf.h +++ b/SevenZip/7zBuf.h @@ -10,25 +10,25 @@ EXTERN_C_BEGIN typedef struct { - Byte *data; - size_t size; + Byte* data; + size_t size; } CBuf; -void Buf_Init(CBuf *p); -int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc); -void Buf_Free(CBuf *p, ISzAlloc *alloc); +void Buf_Init(CBuf* p); +int Buf_Create(CBuf* p, size_t size, ISzAlloc* alloc); +void Buf_Free(CBuf* p, ISzAlloc* alloc); typedef struct { - Byte *data; - size_t size; - size_t pos; + Byte* data; + size_t size; + size_t pos; } CDynBuf; -void DynBuf_Construct(CDynBuf *p); -void DynBuf_SeekToBeg(CDynBuf *p); -int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); -void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); +void DynBuf_Construct(CDynBuf* p); +void DynBuf_SeekToBeg(CDynBuf* p); +int DynBuf_Write(CDynBuf* p, const Byte* buf, size_t size, ISzAlloc* alloc); +void DynBuf_Free(CDynBuf* p, ISzAlloc* alloc); EXTERN_C_END diff --git a/SevenZip/7zCrc.c b/SevenZip/7zCrc.c index dc6d6ab..d7e72a3 100644 --- a/SevenZip/7zCrc.c +++ b/SevenZip/7zCrc.c @@ -9,7 +9,7 @@ #define kCrcPoly 0xEDB88320 #ifdef MY_CPU_LE - #define CRC_NUM_TABLES 8 +#define CRC_NUM_TABLES 8 #else #define CRC_NUM_TABLES 9 @@ -20,11 +20,11 @@ #endif #ifndef MY_CPU_BE - UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); - UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void* data, size_t size, const UInt32* table); +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void* data, size_t size, const UInt32* table); #endif -typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); +typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void* data, size_t size, const UInt32* table); CRC_FUNC g_CrcUpdateT4; CRC_FUNC g_CrcUpdateT8; @@ -32,82 +32,82 @@ CRC_FUNC g_CrcUpdate; UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; -UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) +UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void* data, size_t size) { - return g_CrcUpdate(v, data, size, g_CrcTable); + return g_CrcUpdate(v, data, size, g_CrcTable); } -UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) +UInt32 MY_FAST_CALL CrcCalc(const void* data, size_t size) { - return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; + return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void* data, size_t size, const UInt32* table) { - const Byte *p = (const Byte *)data; - const Byte *pEnd = p + size; - for (; p != pEnd; p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + const Byte* p = (const Byte*)data; + const Byte* pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; } void MY_FAST_CALL CrcGenerateTable() { - UInt32 i; - for (i = 0; i < 256; i++) - { - UInt32 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); - g_CrcTable[i] = r; - } - for (; i < 256 * CRC_NUM_TABLES; i++) - { - UInt32 r = g_CrcTable[i - 256]; - g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); - } + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + g_CrcTable[i] = r; + } + for (; i < 256 * CRC_NUM_TABLES; i++) + { + UInt32 r = g_CrcTable[i - 256]; + g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); + } - #if CRC_NUM_TABLES < 4 +#if CRC_NUM_TABLES < 4 g_CrcUpdate = CrcUpdateT1; - #else - - #ifdef MY_CPU_LE +#else - g_CrcUpdateT4 = CrcUpdateT4; - g_CrcUpdate = CrcUpdateT4; +#ifdef MY_CPU_LE - #if CRC_NUM_TABLES >= 8 - g_CrcUpdateT8 = CrcUpdateT8; - - #ifdef MY_CPU_X86_OR_AMD64 - if (!CPU_Is_InOrder()) - g_CrcUpdate = CrcUpdateT8; - #endif - #endif + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; - #else +#if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + +#ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + g_CrcUpdate = CrcUpdateT8; +#endif +#endif + +#else { - #ifndef MY_CPU_BE +#ifndef MY_CPU_BE UInt32 k = 0x01020304; const Byte *p = (const Byte *)&k; if (p[0] == 4 && p[1] == 3) { g_CrcUpdateT4 = CrcUpdateT4; g_CrcUpdate = CrcUpdateT4; - #if CRC_NUM_TABLES >= 8 +#if CRC_NUM_TABLES >= 8 g_CrcUpdateT8 = CrcUpdateT8; // g_CrcUpdate = CrcUpdateT8; - #endif +#endif } else if (p[0] != 1 || p[1] != 2) g_CrcUpdate = CrcUpdateT1; else - #endif +#endif { for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) { @@ -116,13 +116,13 @@ void MY_FAST_CALL CrcGenerateTable() } g_CrcUpdateT4 = CrcUpdateT1_BeT4; g_CrcUpdate = CrcUpdateT1_BeT4; - #if CRC_NUM_TABLES >= 8 +#if CRC_NUM_TABLES >= 8 g_CrcUpdateT8 = CrcUpdateT1_BeT8; // g_CrcUpdate = CrcUpdateT1_BeT8; - #endif +#endif } } - #endif +#endif - #endif +#endif } diff --git a/SevenZip/7zCrc.h b/SevenZip/7zCrc.h index 8fd5795..9ab331e 100644 --- a/SevenZip/7zCrc.h +++ b/SevenZip/7zCrc.h @@ -17,8 +17,8 @@ void MY_FAST_CALL CrcGenerateTable(void); #define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) #define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); -UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); +UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void* data, size_t size); +UInt32 MY_FAST_CALL CrcCalc(const void* data, size_t size); EXTERN_C_END diff --git a/SevenZip/7zCrcOpt.c b/SevenZip/7zCrcOpt.c index d1e1cd7..37239ba 100644 --- a/SevenZip/7zCrcOpt.c +++ b/SevenZip/7zCrcOpt.c @@ -9,49 +9,49 @@ #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void* data, size_t size, const UInt32* table) { - const Byte *p = (const Byte *)data; - for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - for (; size >= 4; size -= 4, p += 4) - { - v ^= *(const UInt32 *)p; - v = - table[0x300 + ((v ) & 0xFF)] - ^ table[0x200 + ((v >> 8) & 0xFF)] - ^ table[0x100 + ((v >> 16) & 0xFF)] - ^ table[0x000 + ((v >> 24))]; - } - for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + const Byte* p = (const Byte*)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32*)p; + v = + table[0x300 + ((v) & 0xFF)] + ^ table[0x200 + ((v >> 8) & 0xFF)] + ^ table[0x100 + ((v >> 16) & 0xFF)] + ^ table[0x000 + ((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; } -UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void* data, size_t size, const UInt32* table) { - const Byte *p = (const Byte *)data; - for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - for (; size >= 8; size -= 8, p += 8) - { - UInt32 d; - v ^= *(const UInt32 *)p; - v = - table[0x700 + ((v ) & 0xFF)] - ^ table[0x600 + ((v >> 8) & 0xFF)] - ^ table[0x500 + ((v >> 16) & 0xFF)] - ^ table[0x400 + ((v >> 24))]; - d = *((const UInt32 *)p + 1); - v ^= - table[0x300 + ((d ) & 0xFF)] - ^ table[0x200 + ((d >> 8) & 0xFF)] - ^ table[0x100 + ((d >> 16) & 0xFF)] - ^ table[0x000 + ((d >> 24))]; - } - for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + const Byte* p = (const Byte*)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32*)p; + v = + table[0x700 + ((v) & 0xFF)] + ^ table[0x600 + ((v >> 8) & 0xFF)] + ^ table[0x500 + ((v >> 16) & 0xFF)] + ^ table[0x400 + ((v >> 24))]; + d = *((const UInt32*)p + 1); + v ^= + table[0x300 + ((d) & 0xFF)] + ^ table[0x200 + ((d >> 8) & 0xFF)] + ^ table[0x100 + ((d >> 16) & 0xFF)] + ^ table[0x000 + ((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; } #endif diff --git a/SevenZip/7zDec.c b/SevenZip/7zDec.c index c45d6bf..19b6469 100644 --- a/SevenZip/7zDec.c +++ b/SevenZip/7zDec.c @@ -131,461 +131,467 @@ static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, I #endif -static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +static SRes SzDecodeLzma(const Byte* props, unsigned propsSize, UInt64 inSize, ILookInStream* inStream, + Byte* outBuffer, SizeT outSize, ISzAlloc* allocMain) { - CLzmaDec state; - SRes res = SZ_OK; + CLzmaDec state; + SRes res = SZ_OK; - LzmaDec_Construct(&state); - RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); - state.dic = outBuffer; - state.dicBufSize = outSize; - LzmaDec_Init(&state); + LzmaDec_Construct(&state); + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); + state.dic = outBuffer; + state.dicBufSize = outSize; + LzmaDec_Init(&state); - for (;;) - { - const void *inBuf = NULL; - size_t lookahead = (1 << 18); - if (lookahead > inSize) - lookahead = (size_t)inSize; - res = inStream->Look(inStream, &inBuf, &lookahead); - if (res != SZ_OK) - break; + for (;;) + { + const void* inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = inStream->Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; - { - SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; - ELzmaStatus status; - res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); - lookahead -= inProcessed; - inSize -= inProcessed; - if (res != SZ_OK) - break; + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; + ELzmaStatus status; + res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - { - if (outSize != state.dicPos || inSize != 0) - res = SZ_ERROR_DATA; - break; - } + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } - if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - break; + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; - if (inProcessed == 0 && dicPos == state.dicPos) - { - res = SZ_ERROR_DATA; - break; - } + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } - res = inStream->Skip((void *)inStream, inProcessed); - if (res != SZ_OK) - break; - } - } + res = inStream->Skip((void*)inStream, inProcessed); + if (res != SZ_OK) + break; + } + } - LzmaDec_FreeProbs(&state, allocMain); - return res; + LzmaDec_FreeProbs(&state, allocMain); + return res; } #ifndef _7Z_NO_METHOD_LZMA2 -static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) +static SRes SzDecodeLzma2(const Byte* props, unsigned propsSize, UInt64 inSize, ILookInStream* inStream, + Byte* outBuffer, SizeT outSize, ISzAlloc* allocMain) { - CLzma2Dec state; - SRes res = SZ_OK; + CLzma2Dec state; + SRes res = SZ_OK; - Lzma2Dec_Construct(&state); - if (propsSize != 1) - return SZ_ERROR_DATA; - RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); - state.decoder.dic = outBuffer; - state.decoder.dicBufSize = outSize; - Lzma2Dec_Init(&state); + Lzma2Dec_Construct(&state); + if (propsSize != 1) + return SZ_ERROR_DATA; + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); + state.decoder.dic = outBuffer; + state.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&state); - for (;;) - { - const void *inBuf = NULL; - size_t lookahead = (1 << 18); - if (lookahead > inSize) - lookahead = (size_t)inSize; - res = inStream->Look(inStream, &inBuf, &lookahead); - if (res != SZ_OK) - break; + for (;;) + { + const void* inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = inStream->Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; - { - SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; - ELzmaStatus status; - res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); - lookahead -= inProcessed; - inSize -= inProcessed; - if (res != SZ_OK) - break; + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; + ELzmaStatus status; + res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - { - if (outSize != state.decoder.dicPos || inSize != 0) - res = SZ_ERROR_DATA; - break; - } + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.decoder.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } - if (inProcessed == 0 && dicPos == state.decoder.dicPos) - { - res = SZ_ERROR_DATA; - break; - } + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } - res = inStream->Skip((void *)inStream, inProcessed); - if (res != SZ_OK) - break; - } - } + res = inStream->Skip((void*)inStream, inProcessed); + if (res != SZ_OK) + break; + } + } - Lzma2Dec_FreeProbs(&state, allocMain); - return res; + Lzma2Dec_FreeProbs(&state, allocMain); + return res; } #endif -static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) +static SRes SzDecodeCopy(UInt64 inSize, ILookInStream* inStream, Byte* outBuffer) { - while (inSize > 0) - { - const void *inBuf; - size_t curSize = (1 << 18); - if (curSize > inSize) - curSize = (size_t)inSize; - RINOK(inStream->Look(inStream, &inBuf, &curSize)); - if (curSize == 0) - return SZ_ERROR_INPUT_EOF; - memcpy(outBuffer, inBuf, curSize); - outBuffer += curSize; - inSize -= curSize; - RINOK(inStream->Skip((void *)inStream, curSize)); - } - return SZ_OK; + while (inSize > 0) + { + const void* inBuf; + size_t curSize = (1 << 18); + if (curSize > inSize) + curSize = (size_t)inSize; + RINOK(inStream->Look(inStream, &inBuf, &curSize)); + if (curSize == 0) + return SZ_ERROR_INPUT_EOF; + memcpy(outBuffer, inBuf, curSize); + outBuffer += curSize; + inSize -= curSize; + RINOK(inStream->Skip((void *)inStream, curSize)); + } + return SZ_OK; } static Bool IS_MAIN_METHOD(UInt32 m) { - switch (m) - { - case k_Copy: - case k_LZMA: - #ifndef _7Z_NO_METHOD_LZMA2 - case k_LZMA2: - #endif - #ifdef _7ZIP_PPMD_SUPPPORT + switch (m) + { + case k_Copy: + case k_LZMA: +#ifndef _7Z_NO_METHOD_LZMA2 + case k_LZMA2: +#endif +#ifdef _7ZIP_PPMD_SUPPPORT case k_PPMD: - #endif - return True; - } - return False; +#endif + return True; + } + return False; } -static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) +static Bool IS_SUPPORTED_CODER(const CSzCoderInfo* c) { - return - c->NumStreams == 1 - /* && c->MethodID <= (UInt32)0xFFFFFFFF */ - && IS_MAIN_METHOD((UInt32)c->MethodID); + return + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); } #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) -static SRes CheckSupportedFolder(const CSzFolder *f) +static SRes CheckSupportedFolder(const CSzFolder* f) { - if (f->NumCoders < 1 || f->NumCoders > 4) - return SZ_ERROR_UNSUPPORTED; - if (!IS_SUPPORTED_CODER(&f->Coders[0])) - return SZ_ERROR_UNSUPPORTED; - if (f->NumCoders == 1) - { - if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) - return SZ_ERROR_UNSUPPORTED; - return SZ_OK; - } - - - #ifndef _7Z_NO_METHODS_FILTERS + if (f->NumCoders < 1 || f->NumCoders > 4) + return SZ_ERROR_UNSUPPORTED; + if (!IS_SUPPORTED_CODER(&f->Coders[0])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 1) + { + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } - if (f->NumCoders == 2) - { - const CSzCoderInfo *c = &f->Coders[1]; - if ( - /* c->MethodID > (UInt32)0xFFFFFFFF || */ - c->NumStreams != 1 - || f->NumPackStreams != 1 - || f->PackStreams[0] != 0 - || f->NumBonds != 1 - || f->Bonds[0].InIndex != 1 - || f->Bonds[0].OutIndex != 0) - return SZ_ERROR_UNSUPPORTED; - switch ((UInt32)c->MethodID) - { - case k_Delta: - case k_BCJ: - case k_PPC: - case k_IA64: - case k_SPARC: - case k_ARM: - case k_ARMT: - break; - default: - return SZ_ERROR_UNSUPPORTED; - } - return SZ_OK; - } - #endif +#ifndef _7Z_NO_METHODS_FILTERS - - if (f->NumCoders == 4) - { - if (!IS_SUPPORTED_CODER(&f->Coders[1]) - || !IS_SUPPORTED_CODER(&f->Coders[2]) - || !IS_BCJ2(&f->Coders[3])) - return SZ_ERROR_UNSUPPORTED; - if (f->NumPackStreams != 4 - || f->PackStreams[0] != 2 - || f->PackStreams[1] != 6 - || f->PackStreams[2] != 1 - || f->PackStreams[3] != 0 - || f->NumBonds != 3 - || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 - || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 - || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) - return SZ_ERROR_UNSUPPORTED; - return SZ_OK; - } - - return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 2) + { + const CSzCoderInfo* c = &f->Coders[1]; + if ( + /* c->MethodID > (UInt32)0xFFFFFFFF || */ + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) + return SZ_ERROR_UNSUPPORTED; + switch ((UInt32)c->MethodID) + { + case k_Delta: + case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: + case k_ARM: + case k_ARMT: + break; + default: + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; + } + +#endif + + + if (f->NumCoders == 4) + { + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + return SZ_ERROR_UNSUPPORTED; } #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; -static SRes SzFolder_Decode2(const CSzFolder *folder, - const Byte *propsData, - const UInt64 *unpackSizes, - const UInt64 *packPositions, - ILookInStream *inStream, UInt64 startPos, - Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, - Byte *tempBuf[]) +static SRes SzFolder_Decode2(const CSzFolder* folder, + const Byte* propsData, + const UInt64* unpackSizes, + const UInt64* packPositions, + ILookInStream* inStream, UInt64 startPos, + Byte* outBuffer, SizeT outSize, ISzAlloc* allocMain, + Byte* tempBuf[]) { - UInt32 ci; - SizeT tempSizes[3] = { 0, 0, 0}; - SizeT tempSize3 = 0; - Byte *tempBuf3 = 0; + UInt32 ci; + SizeT tempSizes[3] = {0, 0, 0}; + SizeT tempSize3 = 0; + Byte* tempBuf3 = 0; - RINOK(CheckSupportedFolder(folder)); + RINOK(CheckSupportedFolder(folder)); - for (ci = 0; ci < folder->NumCoders; ci++) - { - const CSzCoderInfo *coder = &folder->Coders[ci]; + for (ci = 0; ci < folder->NumCoders; ci++) + { + const CSzCoderInfo* coder = &folder->Coders[ci]; - if (IS_MAIN_METHOD((UInt32)coder->MethodID)) - { - UInt32 si = 0; - UInt64 offset; - UInt64 inSize; - Byte *outBufCur = outBuffer; - SizeT outSizeCur = outSize; - if (folder->NumCoders == 4) - { - UInt32 indices[] = { 3, 2, 0 }; - UInt64 unpackSize = unpackSizes[ci]; - si = indices[ci]; - if (ci < 2) - { - Byte *temp; - outSizeCur = (SizeT)unpackSize; - if (outSizeCur != unpackSize) - return SZ_ERROR_MEM; - temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); - if (!temp && outSizeCur != 0) - return SZ_ERROR_MEM; - outBufCur = tempBuf[1 - ci] = temp; - tempSizes[1 - ci] = outSizeCur; - } - else if (ci == 2) - { - if (unpackSize > outSize) /* check it */ - return SZ_ERROR_PARAM; - tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); - tempSize3 = outSizeCur = (SizeT)unpackSize; - } - else - return SZ_ERROR_UNSUPPORTED; - } - offset = packPositions[si]; - inSize = packPositions[si + 1] - offset; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + if (IS_MAIN_METHOD((UInt32)coder->MethodID)) + { + UInt32 si = 0; + UInt64 offset; + UInt64 inSize; + Byte* outBufCur = outBuffer; + SizeT outSizeCur = outSize; + if (folder->NumCoders == 4) + { + UInt32 indices[] = {3, 2, 0}; + UInt64 unpackSize = unpackSizes[ci]; + si = indices[ci]; + if (ci < 2) + { + Byte* temp; + outSizeCur = (SizeT)unpackSize; + if (outSizeCur != unpackSize) + return SZ_ERROR_MEM; + temp = (Byte*)IAlloc_Alloc(allocMain, outSizeCur); + if (!temp && outSizeCur != 0) + return SZ_ERROR_MEM; + outBufCur = tempBuf[1 - ci] = temp; + tempSizes[1 - ci] = outSizeCur; + } + else if (ci == 2) + { + if (unpackSize > outSize) /* check it */ + return SZ_ERROR_PARAM; + tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); + tempSize3 = outSizeCur = (SizeT)unpackSize; + } + else + return SZ_ERROR_UNSUPPORTED; + } + offset = packPositions[si]; + inSize = packPositions[si + 1] - offset; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); - if (coder->MethodID == k_Copy) - { - if (inSize != outSizeCur) /* check it */ - return SZ_ERROR_DATA; - RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); - } - else if (coder->MethodID == k_LZMA) - { - RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); - } - #ifndef _7Z_NO_METHOD_LZMA2 - else if (coder->MethodID == k_LZMA2) - { - RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); - } - #endif - #ifdef _7ZIP_PPMD_SUPPPORT + if (coder->MethodID == k_Copy) + { + if (inSize != outSizeCur) /* check it */ + return SZ_ERROR_DATA; + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); + } + else if (coder->MethodID == k_LZMA) + { + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur + , allocMain)); + } +#ifndef _7Z_NO_METHOD_LZMA2 + else if (coder->MethodID == k_LZMA2) + { + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, + outSizeCur, allocMain)); + } +#endif +#ifdef _7ZIP_PPMD_SUPPPORT else if (coder->MethodID == k_PPMD) { RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } - #endif - else - return SZ_ERROR_UNSUPPORTED; - } - else if (coder->MethodID == k_BCJ2) - { - UInt64 offset = packPositions[1]; - UInt64 s3Size = packPositions[2] - offset; - - if (ci != 3) - return SZ_ERROR_UNSUPPORTED; - - tempSizes[2] = (SizeT)s3Size; - if (tempSizes[2] != s3Size) - return SZ_ERROR_MEM; - tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); - if (!tempBuf[2] && tempSizes[2] != 0) - return SZ_ERROR_MEM; - - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); - RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); +#endif + else + return SZ_ERROR_UNSUPPORTED; + } + else if (coder->MethodID == k_BCJ2) + { + UInt64 offset = packPositions[1]; + UInt64 s3Size = packPositions[2] - offset; - if ((tempSizes[0] & 3) != 0 || - (tempSizes[1] & 3) != 0 || - tempSize3 + tempSizes[0] + tempSizes[1] != outSize) - return SZ_ERROR_DATA; + if (ci != 3) + return SZ_ERROR_UNSUPPORTED; - { - CBcj2Dec p; - - p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; - p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; - p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; - p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; - - p.dest = outBuffer; - p.destLim = outBuffer + outSize; - - Bcj2Dec_Init(&p); - RINOK(Bcj2Dec_Decode(&p)); + tempSizes[2] = (SizeT)s3Size; + if (tempSizes[2] != s3Size) + return SZ_ERROR_MEM; + tempBuf[2] = (Byte*)IAlloc_Alloc(allocMain, tempSizes[2]); + if (!tempBuf[2] && tempSizes[2] != 0) + return SZ_ERROR_MEM; - { - unsigned i; - for (i = 0; i < 4; i++) - if (p.bufs[i] != p.lims[i]) - return SZ_ERROR_DATA; - - if (!Bcj2Dec_IsFinished(&p)) - return SZ_ERROR_DATA; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); - if (p.dest != p.destLim - || p.state != BCJ2_STREAM_MAIN) - return SZ_ERROR_DATA; - } - } - } - #ifndef _7Z_NO_METHODS_FILTERS - else if (ci == 1) - { - if (coder->MethodID == k_Delta) - { - if (coder->PropsSize != 1) - return SZ_ERROR_UNSUPPORTED; - { - Byte state[DELTA_STATE_SIZE]; - Delta_Init(state); - Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); - } - } - else - { - if (coder->PropsSize != 0) - return SZ_ERROR_UNSUPPORTED; - switch (coder->MethodID) - { - case k_BCJ: - { - UInt32 state; - x86_Convert_Init(state); - x86_Convert(outBuffer, outSize, 0, &state, 0); - break; - } - CASE_BRA_CONV(PPC) - CASE_BRA_CONV(IA64) - CASE_BRA_CONV(SPARC) - CASE_BRA_CONV(ARM) - CASE_BRA_CONV(ARMT) - default: - return SZ_ERROR_UNSUPPORTED; - } - } - } - #endif - else - return SZ_ERROR_UNSUPPORTED; - } + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; - return SZ_OK; + { + CBcj2Dec p; + + p.bufs[0] = tempBuf3; + p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; + p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; + p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; + p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)); + + { + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + + if (!Bcj2Dec_IsFinished(&p)) + return SZ_ERROR_DATA; + + if (p.dest != p.destLim + || p.state != BCJ2_STREAM_MAIN) + return SZ_ERROR_DATA; + } + } + } +#ifndef _7Z_NO_METHODS_FILTERS + else if (ci == 1) + { + if (coder->MethodID == k_Delta) + { + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); + } + } + else + { + if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + switch (coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + default: + return SZ_ERROR_UNSUPPORTED; + } + } + } +#endif + else + return SZ_ERROR_UNSUPPORTED; + } + + return SZ_OK; } -SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, - ILookInStream *inStream, UInt64 startPos, - Byte *outBuffer, size_t outSize, - ISzAlloc *allocMain) +SRes SzAr_DecodeFolder(const CSzAr* p, UInt32 folderIndex, + ILookInStream* inStream, UInt64 startPos, + Byte* outBuffer, size_t outSize, + ISzAlloc* allocMain) { - SRes res; - CSzFolder folder; - CSzData sd; - - const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; - sd.Data = data; - sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex]; - - res = SzGetNextFolderItem(&folder, &sd); - - if (res != SZ_OK) - return res; + SRes res; + CSzFolder folder; + CSzData sd; - if (sd.Size != 0 - || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] - || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) - return SZ_ERROR_FAIL; - { - unsigned i; - Byte *tempBuf[3] = { 0, 0, 0}; + const Byte* data = p->CodersData + p->FoCodersOffsets[folderIndex]; + sd.Data = data; + sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex]; - res = SzFolder_Decode2(&folder, data, - &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], - p->PackPositions + p->FoStartPackStreamIndex[folderIndex], - inStream, startPos, - outBuffer, (SizeT)outSize, allocMain, tempBuf); - - for (i = 0; i < 3; i++) - IAlloc_Free(allocMain, tempBuf[i]); + res = SzGetNextFolderItem(&folder, &sd); - if (res == SZ_OK) - if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) - if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) - res = SZ_ERROR_CRC; + if (res != SZ_OK) + return res; - return res; - } + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) + return SZ_ERROR_FAIL; + { + unsigned i; + Byte* tempBuf[3] = {0, 0, 0}; + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], + p->PackPositions + p->FoStartPackStreamIndex[folderIndex], + inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + + for (i = 0; i < 3; i++) + IAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + + return res; + } } diff --git a/SevenZip/7zFile.c b/SevenZip/7zFile.c index 041e5b1..d230b67 100644 --- a/SevenZip/7zFile.c +++ b/SevenZip/7zFile.c @@ -27,64 +27,65 @@ #endif -void File_Construct(CSzFile *p) +void File_Construct(CSzFile* p) { - #ifdef USE_WINDOWS_FILE - p->handle = INVALID_HANDLE_VALUE; - #else +#ifdef USE_WINDOWS_FILE + p->handle = INVALID_HANDLE_VALUE; +#else p->file = NULL; - #endif +#endif } #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) -static WRes File_Open(CSzFile *p, const char *name, int writeMode) +static WRes File_Open(CSzFile* p, const char* name, int writeMode) { - #ifdef USE_WINDOWS_FILE - p->handle = CreateFileA(name, - writeMode ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, NULL, - writeMode ? CREATE_ALWAYS : OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); - #else +#ifdef USE_WINDOWS_FILE + p->handle = CreateFileA(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); +#else p->file = fopen(name, writeMode ? "wb+" : "rb"); return (p->file != 0) ? 0 : - #ifdef UNDER_CE +#ifdef UNDER_CE 2; /* ENOENT */ - #else +#else errno; - #endif - #endif +#endif +#endif } -WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } -WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } +WRes InFile_Open(CSzFile* p, const char* name) { return File_Open(p, name, 0); } +WRes OutFile_Open(CSzFile* p, const char* name) { return File_Open(p, name, 1); } #endif #ifdef USE_WINDOWS_FILE -static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) +static WRes File_OpenW(CSzFile* p, const WCHAR* name, int writeMode) { - p->handle = CreateFileW(name, - writeMode ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, NULL, - writeMode ? CREATE_ALWAYS : OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); + p->handle = CreateFileW(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); } -WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } -WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } + +WRes InFile_OpenW(CSzFile* p, const WCHAR* name) { return File_OpenW(p, name, 0); } +WRes OutFile_OpenW(CSzFile* p, const WCHAR* name) { return File_OpenW(p, name, 1); } #endif -WRes File_Close(CSzFile *p) +WRes File_Close(CSzFile* p) { - #ifdef USE_WINDOWS_FILE - if (p->handle != INVALID_HANDLE_VALUE) - { - if (!CloseHandle(p->handle)) - return GetLastError(); - p->handle = INVALID_HANDLE_VALUE; - } - #else +#ifdef USE_WINDOWS_FILE + if (p->handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(p->handle)) + return GetLastError(); + p->handle = INVALID_HANDLE_VALUE; + } +#else if (p->file != NULL) { int res = fclose(p->file); @@ -92,106 +93,109 @@ WRes File_Close(CSzFile *p) return res; p->file = NULL; } - #endif - return 0; +#endif + return 0; } -WRes File_Read(CSzFile *p, void *data, size_t *size) +WRes File_Read(CSzFile* p, void* data, size_t* size) { - size_t originalSize = *size; - if (originalSize == 0) - return 0; + size_t originalSize = *size; + if (originalSize == 0) + return 0; - #ifdef USE_WINDOWS_FILE +#ifdef USE_WINDOWS_FILE - *size = 0; - do - { - DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; - DWORD processed = 0; - BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); - data = (void *)((Byte *)data + processed); - originalSize -= processed; - *size += processed; - if (!res) - return GetLastError(); - if (processed == 0) - break; - } - while (originalSize > 0); - return 0; + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); + data = (void*)((Byte*)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; - #else +#else *size = fread(data, 1, originalSize, p->file); if (*size == originalSize) return 0; return ferror(p->file); - #endif +#endif } -WRes File_Write(CSzFile *p, const void *data, size_t *size) +WRes File_Write(CSzFile* p, const void* data, size_t* size) { - size_t originalSize = *size; - if (originalSize == 0) - return 0; - - #ifdef USE_WINDOWS_FILE + size_t originalSize = *size; + if (originalSize == 0) + return 0; - *size = 0; - do - { - DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; - DWORD processed = 0; - BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); - data = (void *)((Byte *)data + processed); - originalSize -= processed; - *size += processed; - if (!res) - return GetLastError(); - if (processed == 0) - break; - } - while (originalSize > 0); - return 0; +#ifdef USE_WINDOWS_FILE - #else + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); + data = (void*)((Byte*)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + +#else *size = fwrite(data, 1, originalSize, p->file); if (*size == originalSize) return 0; return ferror(p->file); - #endif +#endif } -WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) +WRes File_Seek(CSzFile* p, Int64* pos, ESzSeek origin) { - #ifdef USE_WINDOWS_FILE +#ifdef USE_WINDOWS_FILE - LARGE_INTEGER value; - DWORD moveMethod; - value.LowPart = (DWORD)*pos; - value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ - switch (origin) - { - case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; - case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; - case SZ_SEEK_END: moveMethod = FILE_END; break; - default: return ERROR_INVALID_PARAMETER; - } - value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); - if (value.LowPart == 0xFFFFFFFF) - { - WRes res = GetLastError(); - if (res != NO_ERROR) - return res; - } - *pos = ((Int64)value.HighPart << 32) | value.LowPart; - return 0; + LARGE_INTEGER value; + DWORD moveMethod; + value.LowPart = (DWORD)*pos; + value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ + switch (origin) + { + case SZ_SEEK_SET: moveMethod = FILE_BEGIN; + break; + case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; + break; + case SZ_SEEK_END: moveMethod = FILE_END; + break; + default: return ERROR_INVALID_PARAMETER; + } + value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); + if (value.LowPart == 0xFFFFFFFF) + { + WRes res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *pos = ((Int64)value.HighPart << 32) | value.LowPart; + return 0; - #else +#else int moveMethod; int res; @@ -206,25 +210,25 @@ WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) *pos = ftell(p->file); return res; - #endif +#endif } -WRes File_GetLength(CSzFile *p, UInt64 *length) +WRes File_GetLength(CSzFile* p, UInt64* length) { - #ifdef USE_WINDOWS_FILE - - DWORD sizeHigh; - DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); - if (sizeLow == 0xFFFFFFFF) - { - DWORD res = GetLastError(); - if (res != NO_ERROR) - return res; - } - *length = (((UInt64)sizeHigh) << 32) + sizeLow; - return 0; - - #else +#ifdef USE_WINDOWS_FILE + + DWORD sizeHigh; + DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + { + DWORD res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *length = (((UInt64)sizeHigh) << 32) + sizeLow; + return 0; + +#else long pos = ftell(p->file); int res = fseek(p->file, 0, SEEK_END); @@ -232,55 +236,55 @@ WRes File_GetLength(CSzFile *p, UInt64 *length) fseek(p->file, pos, SEEK_SET); return res; - #endif +#endif } /* ---------- FileSeqInStream ---------- */ -static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) +static SRes FileSeqInStream_Read(void* pp, void* buf, size_t* size) { - CFileSeqInStream *p = (CFileSeqInStream *)pp; - return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; + CFileSeqInStream* p = (CFileSeqInStream*)pp; + return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; } -void FileSeqInStream_CreateVTable(CFileSeqInStream *p) +void FileSeqInStream_CreateVTable(CFileSeqInStream* p) { - p->s.Read = FileSeqInStream_Read; + p->s.Read = FileSeqInStream_Read; } /* ---------- FileInStream ---------- */ -static SRes FileInStream_Read(void *pp, void *buf, size_t *size) +static SRes FileInStream_Read(void* pp, void* buf, size_t* size) { - CFileInStream *p = (CFileInStream *)pp; - return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; + CFileInStream* p = (CFileInStream*)pp; + return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; } -static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) +static SRes FileInStream_Seek(void* pp, Int64* pos, ESzSeek origin) { - CFileInStream *p = (CFileInStream *)pp; - return File_Seek(&p->file, pos, origin); + CFileInStream* p = (CFileInStream*)pp; + return File_Seek(&p->file, pos, origin); } -void FileInStream_CreateVTable(CFileInStream *p) +void FileInStream_CreateVTable(CFileInStream* p) { - p->s.Read = FileInStream_Read; - p->s.Seek = FileInStream_Seek; + p->s.Read = FileInStream_Read; + p->s.Seek = FileInStream_Seek; } /* ---------- FileOutStream ---------- */ -static size_t FileOutStream_Write(void *pp, const void *data, size_t size) +static size_t FileOutStream_Write(void* pp, const void* data, size_t size) { - CFileOutStream *p = (CFileOutStream *)pp; - File_Write(&p->file, data, &size); - return size; + CFileOutStream* p = (CFileOutStream*)pp; + File_Write(&p->file, data, &size); + return size; } -void FileOutStream_CreateVTable(CFileOutStream *p) +void FileOutStream_CreateVTable(CFileOutStream* p) { - p->s.Write = FileOutStream_Write; + p->s.Write = FileOutStream_Write; } diff --git a/SevenZip/7zFile.h b/SevenZip/7zFile.h index 658987e..b78a9c4 100644 --- a/SevenZip/7zFile.h +++ b/SevenZip/7zFile.h @@ -22,61 +22,61 @@ EXTERN_C_BEGIN typedef struct { - #ifdef USE_WINDOWS_FILE - HANDLE handle; - #else +#ifdef USE_WINDOWS_FILE + HANDLE handle; +#else FILE *file; - #endif +#endif } CSzFile; -void File_Construct(CSzFile *p); +void File_Construct(CSzFile* p); #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) -WRes InFile_Open(CSzFile *p, const char *name); -WRes OutFile_Open(CSzFile *p, const char *name); +WRes InFile_Open(CSzFile* p, const char* name); +WRes OutFile_Open(CSzFile* p, const char* name); #endif #ifdef USE_WINDOWS_FILE -WRes InFile_OpenW(CSzFile *p, const WCHAR *name); -WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); +WRes InFile_OpenW(CSzFile* p, const WCHAR* name); +WRes OutFile_OpenW(CSzFile* p, const WCHAR* name); #endif -WRes File_Close(CSzFile *p); +WRes File_Close(CSzFile* p); /* reads max(*size, remain file's size) bytes */ -WRes File_Read(CSzFile *p, void *data, size_t *size); +WRes File_Read(CSzFile* p, void* data, size_t* size); /* writes *size bytes */ -WRes File_Write(CSzFile *p, const void *data, size_t *size); +WRes File_Write(CSzFile* p, const void* data, size_t* size); -WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); -WRes File_GetLength(CSzFile *p, UInt64 *length); +WRes File_Seek(CSzFile* p, Int64* pos, ESzSeek origin); +WRes File_GetLength(CSzFile* p, UInt64* length); /* ---------- FileInStream ---------- */ typedef struct { - ISeqInStream s; - CSzFile file; + ISeqInStream s; + CSzFile file; } CFileSeqInStream; -void FileSeqInStream_CreateVTable(CFileSeqInStream *p); +void FileSeqInStream_CreateVTable(CFileSeqInStream* p); typedef struct { - ISeekInStream s; - CSzFile file; + ISeekInStream s; + CSzFile file; } CFileInStream; -void FileInStream_CreateVTable(CFileInStream *p); +void FileInStream_CreateVTable(CFileInStream* p); typedef struct { - ISeqOutStream s; - CSzFile file; + ISeqOutStream s; + CSzFile file; } CFileOutStream; -void FileOutStream_CreateVTable(CFileOutStream *p); +void FileOutStream_CreateVTable(CFileOutStream* p); EXTERN_C_END diff --git a/SevenZip/7zMemBuffer.c b/SevenZip/7zMemBuffer.c index e2dbd0f..51e97b1 100644 --- a/SevenZip/7zMemBuffer.c +++ b/SevenZip/7zMemBuffer.c @@ -2,10 +2,10 @@ #include "7zMemBuffer.h" #include -WRes MemBuffer_Read(CSzMemBuffer *p, void *data, size_t *size) +WRes MemBuffer_Read(CSzMemBuffer* p, void* data, size_t* size) { size_t originalSize = *size; - if(originalSize == 0) + if (originalSize == 0) return 0; size_t length = (size_t)(p->pos + (Int64)(*size) > p->size ? p->size - p->pos - 1 : *size); @@ -14,31 +14,35 @@ WRes MemBuffer_Read(CSzMemBuffer *p, void *data, size_t *size) return 0; } -WRes MemBuffer_Seek(CSzMemBuffer *p, Int64 *pos, ESzSeek origin) +WRes MemBuffer_Seek(CSzMemBuffer* p, Int64* pos, ESzSeek origin) { - switch(origin) { - case SZ_SEEK_SET: p->pos = 0 + *pos; break; - case SZ_SEEK_CUR: p->pos += *pos; break; - case SZ_SEEK_END: p->pos = p->size - *pos; break; - default: return 1; + switch (origin) + { + case SZ_SEEK_SET: p->pos = 0 + *pos; + break; + case SZ_SEEK_CUR: p->pos += *pos; + break; + case SZ_SEEK_END: p->pos = p->size - *pos; + break; + default: return 1; } *pos = p->pos; return 0; } -static SRes MemBufferInStream_Read(void *pp, void *buf, size_t *size) +static SRes MemBufferInStream_Read(void* pp, void* buf, size_t* size) { - CMemBufferInStream *p = (CMemBufferInStream *)pp; + CMemBufferInStream* p = (CMemBufferInStream*)pp; return (MemBuffer_Read(&p->buffer, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; } -static SRes MemBufferInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) +static SRes MemBufferInStream_Seek(void* pp, Int64* pos, ESzSeek origin) { - CMemBufferInStream *p = (CMemBufferInStream *)pp; + CMemBufferInStream* p = (CMemBufferInStream*)pp; return MemBuffer_Seek(&p->buffer, pos, origin); } -void MemBufferInit(CMemBufferInStream *memBuferStream, CLookToRead *lookStream, void* buffer, size_t size) +void MemBufferInit(CMemBufferInStream* memBuferStream, CLookToRead* lookStream, void* buffer, size_t size) { memBuferStream->buffer.buffer = buffer; memBuferStream->buffer.pos = 0; @@ -50,4 +54,4 @@ void MemBufferInit(CMemBufferInStream *memBuferStream, CLookToRead *lookStream, LookToRead_CreateVTable(lookStream, False); lookStream->realStream = &memBuferStream->s; LookToRead_Init(lookStream); -} \ No newline at end of file +} diff --git a/SevenZip/7zMemBuffer.h b/SevenZip/7zMemBuffer.h index 6226ade..4537d89 100644 --- a/SevenZip/7zMemBuffer.h +++ b/SevenZip/7zMemBuffer.h @@ -14,16 +14,16 @@ typedef struct } CSzMemBuffer; /* reads max(*size, remain file's size) bytes */ -WRes MemBuffer_Read(CSzMemBuffer *p, void *data, size_t *size); -WRes MemBuffer_Seek(CSzMemBuffer *p, Int64 *pos, ESzSeek origin); +WRes MemBuffer_Read(CSzMemBuffer* p, void* data, size_t* size); +WRes MemBuffer_Seek(CSzMemBuffer* p, Int64* pos, ESzSeek origin); /* ---------- FileInStream ---------- */ typedef struct { - ISeekInStream s; - CSzMemBuffer buffer; + ISeekInStream s; + CSzMemBuffer buffer; } CMemBufferInStream; -void MemBufferInit(CMemBufferInStream *memBuferStream, CLookToRead *lookStream, void* buffer, size_t size); +void MemBufferInit(CMemBufferInStream* memBuferStream, CLookToRead* lookStream, void* buffer, size_t size); EXTERN_C_END diff --git a/SevenZip/7zStream.c b/SevenZip/7zStream.c index 88f9c42..019df76 100644 --- a/SevenZip/7zStream.c +++ b/SevenZip/7zStream.c @@ -7,165 +7,163 @@ #include "7zTypes.h" -SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) +SRes SeqInStream_Read2(ISeqInStream* stream, void* buf, size_t size, SRes errorType) { - while (size != 0) - { - size_t processed = size; - RINOK(stream->Read(stream, buf, &processed)); - if (processed == 0) - return errorType; - buf = (void *)((Byte *)buf + processed); - size -= processed; - } - return SZ_OK; + while (size != 0) + { + size_t processed = size; + RINOK(stream->Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void*)((Byte*)buf + processed); + size -= processed; + } + return SZ_OK; } -SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) +SRes SeqInStream_Read(ISeqInStream* stream, void* buf, size_t size) { - return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); + return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } -SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) +SRes SeqInStream_ReadByte(ISeqInStream* stream, Byte* buf) { - size_t processed = 1; - RINOK(stream->Read(stream, buf, &processed)); - return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; + size_t processed = 1; + RINOK(stream->Read(stream, buf, &processed)); + return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; } -SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) +SRes LookInStream_SeekTo(ILookInStream* stream, UInt64 offset) { - Int64 t = offset; - return stream->Seek(stream, &t, SZ_SEEK_SET); + Int64 t = offset; + return stream->Seek(stream, &t, SZ_SEEK_SET); } -SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) +SRes LookInStream_LookRead(ILookInStream* stream, void* buf, size_t* size) { - const void *lookBuf; - if (*size == 0) - return SZ_OK; - RINOK(stream->Look(stream, &lookBuf, size)); - memcpy(buf, lookBuf, *size); - return stream->Skip(stream, *size); + const void* lookBuf; + if (*size == 0) + return SZ_OK; + RINOK(stream->Look(stream, &lookBuf, size)); + memcpy(buf, lookBuf, *size); + return stream->Skip(stream, *size); } -SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) +SRes LookInStream_Read2(ILookInStream* stream, void* buf, size_t size, SRes errorType) { - while (size != 0) - { - size_t processed = size; - RINOK(stream->Read(stream, buf, &processed)); - if (processed == 0) - return errorType; - buf = (void *)((Byte *)buf + processed); - size -= processed; - } - return SZ_OK; + while (size != 0) + { + size_t processed = size; + RINOK(stream->Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void*)((Byte*)buf + processed); + size -= processed; + } + return SZ_OK; } -SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) +SRes LookInStream_Read(ILookInStream* stream, void* buf, size_t size) { - return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); + return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); } -static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size) +static SRes LookToRead_Look_Lookahead(void* pp, const void** buf, size_t* size) { - SRes res = SZ_OK; - CLookToRead *p = (CLookToRead *)pp; - size_t size2 = p->size - p->pos; - if (size2 == 0 && *size > 0) - { - p->pos = 0; - size2 = LookToRead_BUF_SIZE; - res = p->realStream->Read(p->realStream, p->buf, &size2); - p->size = size2; - } - if (size2 < *size) - *size = size2; - *buf = p->buf + p->pos; - return res; + SRes res = SZ_OK; + CLookToRead* p = (CLookToRead*)pp; + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size > 0) + { + p->pos = 0; + size2 = LookToRead_BUF_SIZE; + res = p->realStream->Read(p->realStream, p->buf, &size2); + p->size = size2; + } + if (size2 < *size) + *size = size2; + *buf = p->buf + p->pos; + return res; } -static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size) +static SRes LookToRead_Look_Exact(void* pp, const void** buf, size_t* size) { - SRes res = SZ_OK; - CLookToRead *p = (CLookToRead *)pp; - size_t size2 = p->size - p->pos; - if (size2 == 0 && *size > 0) - { - p->pos = 0; - if (*size > LookToRead_BUF_SIZE) - *size = LookToRead_BUF_SIZE; - res = p->realStream->Read(p->realStream, p->buf, size); - size2 = p->size = *size; - } - if (size2 < *size) - *size = size2; - *buf = p->buf + p->pos; - return res; + SRes res = SZ_OK; + CLookToRead* p = (CLookToRead*)pp; + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size > 0) + { + p->pos = 0; + if (*size > LookToRead_BUF_SIZE) + *size = LookToRead_BUF_SIZE; + res = p->realStream->Read(p->realStream, p->buf, size); + size2 = p->size = *size; + } + if (size2 < *size) + *size = size2; + *buf = p->buf + p->pos; + return res; } -static SRes LookToRead_Skip(void *pp, size_t offset) +static SRes LookToRead_Skip(void* pp, size_t offset) { - CLookToRead *p = (CLookToRead *)pp; - p->pos += offset; - return SZ_OK; + CLookToRead* p = (CLookToRead*)pp; + p->pos += offset; + return SZ_OK; } -static SRes LookToRead_Read(void *pp, void *buf, size_t *size) +static SRes LookToRead_Read(void* pp, void* buf, size_t* size) { - CLookToRead *p = (CLookToRead *)pp; - size_t rem = p->size - p->pos; - if (rem == 0) - return p->realStream->Read(p->realStream, buf, size); - if (rem > *size) - rem = *size; - memcpy(buf, p->buf + p->pos, rem); - p->pos += rem; - *size = rem; - return SZ_OK; + CLookToRead* p = (CLookToRead*)pp; + size_t rem = p->size - p->pos; + if (rem == 0) + return p->realStream->Read(p->realStream, buf, size); + if (rem > *size) + rem = *size; + memcpy(buf, p->buf + p->pos, rem); + p->pos += rem; + *size = rem; + return SZ_OK; } -static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) +static SRes LookToRead_Seek(void* pp, Int64* pos, ESzSeek origin) { - CLookToRead *p = (CLookToRead *)pp; - p->pos = p->size = 0; - return p->realStream->Seek(p->realStream, pos, origin); + CLookToRead* p = (CLookToRead*)pp; + p->pos = p->size = 0; + return p->realStream->Seek(p->realStream, pos, origin); } -void LookToRead_CreateVTable(CLookToRead *p, int lookahead) +void LookToRead_CreateVTable(CLookToRead* p, int lookahead) { - p->s.Look = lookahead ? - LookToRead_Look_Lookahead : - LookToRead_Look_Exact; - p->s.Skip = LookToRead_Skip; - p->s.Read = LookToRead_Read; - p->s.Seek = LookToRead_Seek; + p->s.Look = lookahead ? LookToRead_Look_Lookahead : LookToRead_Look_Exact; + p->s.Skip = LookToRead_Skip; + p->s.Read = LookToRead_Read; + p->s.Seek = LookToRead_Seek; } -void LookToRead_Init(CLookToRead *p) +void LookToRead_Init(CLookToRead* p) { - p->pos = p->size = 0; + p->pos = p->size = 0; } -static SRes SecToLook_Read(void *pp, void *buf, size_t *size) +static SRes SecToLook_Read(void* pp, void* buf, size_t* size) { - CSecToLook *p = (CSecToLook *)pp; - return LookInStream_LookRead(p->realStream, buf, size); + CSecToLook* p = (CSecToLook*)pp; + return LookInStream_LookRead(p->realStream, buf, size); } -void SecToLook_CreateVTable(CSecToLook *p) +void SecToLook_CreateVTable(CSecToLook* p) { - p->s.Read = SecToLook_Read; + p->s.Read = SecToLook_Read; } -static SRes SecToRead_Read(void *pp, void *buf, size_t *size) +static SRes SecToRead_Read(void* pp, void* buf, size_t* size) { - CSecToRead *p = (CSecToRead *)pp; - return p->realStream->Read(p->realStream, buf, size); + CSecToRead* p = (CSecToRead*)pp; + return p->realStream->Read(p->realStream, buf, size); } -void SecToRead_CreateVTable(CSecToRead *p) +void SecToRead_CreateVTable(CSecToRead* p) { - p->s.Read = SecToRead_Read; + p->s.Read = SecToRead_Read; } diff --git a/SevenZip/7zTypes.h b/SevenZip/7zTypes.h index 778413e..557e6cb 100644 --- a/SevenZip/7zTypes.h +++ b/SevenZip/7zTypes.h @@ -128,108 +128,108 @@ typedef int Bool; typedef struct { - Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ + Byte (*Read)(void* p); /* reads one byte, returns 0 in case of EOF or error */ } IByteIn; typedef struct { - void (*Write)(void *p, Byte b); + void (*Write)(void* p, Byte b); } IByteOut; typedef struct { - SRes (*Read)(void *p, void *buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) < input(*size)) is allowed */ + SRes (*Read)(void* p, void* buf, size_t* size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ } ISeqInStream; /* it can return SZ_ERROR_INPUT_EOF */ -SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); -SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); -SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); +SRes SeqInStream_Read(ISeqInStream* stream, void* buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream* stream, void* buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream* stream, Byte* buf); typedef struct { - size_t (*Write)(void *p, const void *buf, size_t size); - /* Returns: result - the number of actually written bytes. - (result < size) means error */ + size_t (*Write)(void* p, const void* buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ } ISeqOutStream; typedef enum { - SZ_SEEK_SET = 0, - SZ_SEEK_CUR = 1, - SZ_SEEK_END = 2 + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 } ESzSeek; typedef struct { - SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); + SRes (*Read)(void* p, void* buf, size_t* size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void* p, Int64* pos, ESzSeek origin); } ISeekInStream; typedef struct { - SRes (*Look)(void *p, const void **buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) > input(*size)) is not allowed - (output(*size) < input(*size)) is allowed */ - SRes (*Skip)(void *p, size_t offset); - /* offset must be <= output(*size) of Look */ + SRes (*Look)(void* p, const void** buf, size_t* size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void* p, size_t offset); + /* offset must be <= output(*size) of Look */ - SRes (*Read)(void *p, void *buf, size_t *size); - /* reads directly (without buffer). It's same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); + SRes (*Read)(void* p, void* buf, size_t* size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void* p, Int64* pos, ESzSeek origin); } ILookInStream; -SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); -SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); +SRes LookInStream_LookRead(ILookInStream* stream, void* buf, size_t* size); +SRes LookInStream_SeekTo(ILookInStream* stream, UInt64 offset); /* reads via ILookInStream::Read */ -SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); -SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); +SRes LookInStream_Read2(ILookInStream* stream, void* buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream* stream, void* buf, size_t size); #define LookToRead_BUF_SIZE (1 << 14) typedef struct { - ILookInStream s; - ISeekInStream *realStream; - size_t pos; - size_t size; - Byte buf[LookToRead_BUF_SIZE]; + ILookInStream s; + ISeekInStream* realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; } CLookToRead; -void LookToRead_CreateVTable(CLookToRead *p, int lookahead); -void LookToRead_Init(CLookToRead *p); +void LookToRead_CreateVTable(CLookToRead* p, int lookahead); +void LookToRead_Init(CLookToRead* p); typedef struct { - ISeqInStream s; - ILookInStream *realStream; + ISeqInStream s; + ILookInStream* realStream; } CSecToLook; -void SecToLook_CreateVTable(CSecToLook *p); +void SecToLook_CreateVTable(CSecToLook* p); typedef struct { - ISeqInStream s; - ILookInStream *realStream; + ISeqInStream s; + ILookInStream* realStream; } CSecToRead; -void SecToRead_CreateVTable(CSecToRead *p); +void SecToRead_CreateVTable(CSecToRead* p); typedef struct { - SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); - /* Returns: result. (result != SZ_OK) means break. - Value (UInt64)(Int64)-1 for size means unknown value. */ + SRes (*Progress)(void* p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ } ICompressProgress; typedef struct { - void *(*Alloc)(void *p, size_t size); - void (*Free)(void *p, void *address); /* address can be 0 */ + void*(*Alloc)(void* p, size_t size); + void (*Free)(void* p, void* address); /* address can be 0 */ } ISzAlloc; #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) diff --git a/SevenZip/Bcj2.c b/SevenZip/Bcj2.c index 3c88e44..9174d55 100644 --- a/SevenZip/Bcj2.c +++ b/SevenZip/Bcj2.c @@ -17,240 +17,240 @@ #define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); #define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); -void Bcj2Dec_Init(CBcj2Dec *p) +void Bcj2Dec_Init(CBcj2Dec* p) { - unsigned i; + unsigned i; - p->state = BCJ2_DEC_STATE_OK; - p->ip = 0; - p->temp[3] = 0; - p->range = 0; - p->code = 0; - for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) - p->probs[i] = kBitModelTotal >> 1; + p->state = BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp[3] = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; } -SRes Bcj2Dec_Decode(CBcj2Dec *p) +SRes Bcj2Dec_Decode(CBcj2Dec* p) { - if (p->range <= 5) - { - p->state = BCJ2_DEC_STATE_OK; - for (; p->range != 5; p->range++) - { - if (p->range == 1 && p->code != 0) - return SZ_ERROR_DATA; - - if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) - { - p->state = BCJ2_STREAM_RC; - return SZ_OK; - } + if (p->range <= 5) + { + p->state = BCJ2_DEC_STATE_OK; + for (; p->range != 5; p->range++) + { + if (p->range == 1 && p->code != 0) + return SZ_ERROR_DATA; - p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; - } - - if (p->code == 0xFFFFFFFF) - return SZ_ERROR_DATA; - - p->range = 0xFFFFFFFF; - } - else if (p->state >= BCJ2_DEC_STATE_ORIG_0) - { - while (p->state <= BCJ2_DEC_STATE_ORIG_3) - { - Byte *dest = p->dest; - if (dest == p->destLim) - return SZ_OK; - *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0]; - p->dest = dest + 1; - } - } + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } - /* - if (BCJ2_IS_32BIT_STREAM(p->state)) - { - const Byte *cur = p->bufs[p->state]; - if (cur == p->lims[p->state]) - return SZ_OK; - p->bufs[p->state] = cur + 4; - - { - UInt32 val; - Byte *dest; - SizeT rem; - - p->ip += 4; - val = GetBe32(cur) - p->ip; - dest = p->dest; - rem = p->destLim - dest; - if (rem < 4) - { - SizeT i; - SetUi32(p->temp, val); - for (i = 0; i < rem; i++) - dest[i] = p->temp[i]; - p->dest = dest + rem; - p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; - return SZ_OK; - } - SetUi32(dest, val); - p->temp[3] = (Byte)(val >> 24); - p->dest = dest + 4; - p->state = BCJ2_DEC_STATE_OK; - } - } - */ + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } - for (;;) - { - if (BCJ2_IS_32BIT_STREAM(p->state)) - p->state = BCJ2_DEC_STATE_OK; - else - { - if (p->range < kTopValue) - { - if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) - { - p->state = BCJ2_STREAM_RC; - return SZ_OK; - } - p->range <<= 8; - p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; - } + if (p->code == 0xFFFFFFFF) + return SZ_ERROR_DATA; - { - const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; - const Byte *srcLim; - Byte *dest; - SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; - - if (num == 0) - { - p->state = BCJ2_STREAM_MAIN; - return SZ_OK; - } - - dest = p->dest; - if (num > (SizeT)(p->destLim - dest)) - { - num = p->destLim - dest; - if (num == 0) - { - p->state = BCJ2_DEC_STATE_ORIG; - return SZ_OK; - } - } - - srcLim = src + num; + p->range = 0xFFFFFFFF; + } + else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + { + while (p->state <= BCJ2_DEC_STATE_ORIG_3) + { + Byte* dest = p->dest; + if (dest == p->destLim) + return SZ_OK; + *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0]; + p->dest = dest + 1; + } + } - if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) - *dest = src[0]; - else for (;;) - { - Byte b = *src; - *dest = b; - if (b != 0x0F) - { - if ((b & 0xFE) == 0xE8) - break; - dest++; - if (++src != srcLim) - continue; - break; - } - dest++; - if (++src == srcLim) - break; - if ((*src & 0xF0) != 0x80) - continue; - *dest = *src; - break; - } - - num = src - p->bufs[BCJ2_STREAM_MAIN]; - - if (src == srcLim) - { - p->temp[3] = src[-1]; - p->bufs[BCJ2_STREAM_MAIN] = src; - p->ip += (UInt32)num; - p->dest += num; - p->state = - p->bufs[BCJ2_STREAM_MAIN] == - p->lims[BCJ2_STREAM_MAIN] ? - (unsigned)BCJ2_STREAM_MAIN : - (unsigned)BCJ2_DEC_STATE_ORIG; - return SZ_OK; - } - - { - UInt32 bound, ttt; - CProb *prob; - Byte b = src[0]; - Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); - - p->temp[3] = b; - p->bufs[BCJ2_STREAM_MAIN] = src + 1; - num++; - p->ip += (UInt32)num; - p->dest += num; - - prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); - - _IF_BIT_0 - { - _UPDATE_0 - continue; - } - _UPDATE_1 - - } - } - } + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + const Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return SZ_OK; + p->bufs[p->state] = cur + 4; + + { + UInt32 val; + Byte *dest; + SizeT rem; + + p->ip += 4; + val = GetBe32(cur) - p->ip; + dest = p->dest; + rem = p->destLim - dest; + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + return SZ_OK; + } + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + p->state = BCJ2_DEC_STATE_OK; + } + } + */ - { - UInt32 val; - unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; - const Byte *cur = p->bufs[cj]; - Byte *dest; - SizeT rem; - - if (cur == p->lims[cj]) - { - p->state = cj; - break; - } - - val = GetBe32(cur); - p->bufs[cj] = cur + 4; + for (;;) + { + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; + else + { + if (p->range < kTopValue) + { + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } - p->ip += 4; - val -= p->ip; - dest = p->dest; - rem = p->destLim - dest; - - if (rem < 4) - { - SizeT i; - SetUi32(p->temp, val); - for (i = 0; i < rem; i++) - dest[i] = p->temp[i]; - p->dest = dest + rem; - p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; - break; - } - - SetUi32(dest, val); - p->temp[3] = (Byte)(val >> 24); - p->dest = dest + 4; - } - } + { + const Byte* src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte* srcLim; + Byte* dest; + SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; - if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) - { - p->range <<= 8; - p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; - } + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return SZ_OK; + } - return SZ_OK; + dest = p->dest; + if (num > (SizeT)(p->destLim - dest)) + { + num = p->destLim - dest; + if (num == 0) + { + p->state = BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + } + + srcLim = src + num; + + if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else + for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->bufs[BCJ2_STREAM_MAIN]; + + if (src == srcLim) + { + p->temp[3] = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = src; + p->ip += (UInt32)num; + p->dest += num; + p->state = + p->bufs[BCJ2_STREAM_MAIN] == + p->lims[BCJ2_STREAM_MAIN] + ? (unsigned)BCJ2_STREAM_MAIN + : (unsigned)BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + + { + UInt32 bound, ttt; + CProb* prob; + Byte b = src[0]; + Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); + + p->temp[3] = b; + p->bufs[BCJ2_STREAM_MAIN] = src + 1; + num++; + p->ip += (UInt32)num; + p->dest += num; + + prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); + + _IF_BIT_0 + { + _UPDATE_0 + continue; + } + _UPDATE_1 + } + } + } + + { + UInt32 val; + unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const Byte* cur = p->bufs[cj]; + Byte* dest; + SizeT rem; + + if (cur == p->lims[cj]) + { + p->state = cj; + break; + } + + val = GetBe32(cur); + p->bufs[cj] = cur + 4; + + p->ip += 4; + val -= p->ip; + dest = p->dest; + rem = p->destLim - dest; + + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + break; + } + + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + } + } + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + return SZ_OK; } diff --git a/SevenZip/Bcj2.h b/SevenZip/Bcj2.h index 8824080..5d0ba68 100644 --- a/SevenZip/Bcj2.h +++ b/SevenZip/Bcj2.h @@ -12,27 +12,27 @@ EXTERN_C_BEGIN enum { - BCJ2_STREAM_MAIN, - BCJ2_STREAM_CALL, - BCJ2_STREAM_JUMP, - BCJ2_STREAM_RC + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC }; enum { - BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, - BCJ2_DEC_STATE_ORIG_1, - BCJ2_DEC_STATE_ORIG_2, - BCJ2_DEC_STATE_ORIG_3, - - BCJ2_DEC_STATE_ORIG, - BCJ2_DEC_STATE_OK + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_OK }; enum { - BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, - BCJ2_ENC_STATE_OK + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_OK }; @@ -61,75 +61,74 @@ dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following condi typedef struct { - const Byte *bufs[BCJ2_NUM_STREAMS]; - const Byte *lims[BCJ2_NUM_STREAMS]; - Byte *dest; - const Byte *destLim; + const Byte* bufs[BCJ2_NUM_STREAMS]; + const Byte* lims[BCJ2_NUM_STREAMS]; + Byte* dest; + const Byte* destLim; - unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ - UInt32 ip; - Byte temp[4]; - UInt32 range; - UInt32 code; - UInt16 probs[2 + 256]; + UInt32 ip; + Byte temp[4]; + UInt32 range; + UInt32 code; + UInt16 probs[2 + 256]; } CBcj2Dec; -void Bcj2Dec_Init(CBcj2Dec *p); +void Bcj2Dec_Init(CBcj2Dec* p); /* Returns: SZ_OK or SZ_ERROR_DATA */ -SRes Bcj2Dec_Decode(CBcj2Dec *p); +SRes Bcj2Dec_Decode(CBcj2Dec* p); #define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) - typedef enum { - BCJ2_ENC_FINISH_MODE_CONTINUE, - BCJ2_ENC_FINISH_MODE_END_BLOCK, - BCJ2_ENC_FINISH_MODE_END_STREAM + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM } EBcj2Enc_FinishMode; typedef struct { - Byte *bufs[BCJ2_NUM_STREAMS]; - const Byte *lims[BCJ2_NUM_STREAMS]; - const Byte *src; - const Byte *srcLim; + Byte* bufs[BCJ2_NUM_STREAMS]; + const Byte* lims[BCJ2_NUM_STREAMS]; + const Byte* src; + const Byte* srcLim; - unsigned state; - EBcj2Enc_FinishMode finishMode; + unsigned state; + EBcj2Enc_FinishMode finishMode; - Byte prevByte; + Byte prevByte; - Byte cache; - UInt32 range; - UInt64 low; - UInt64 cacheSize; + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; - UInt32 ip; + UInt32 ip; - /* 32-bit ralative offset in JUMP/CALL commands is - - (mod 4 GB) in 32-bit mode - - signed Int32 in 64-bit mode - We use (mod 4 GB) check for fileSize. - Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ - UInt32 fileIp; - UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ - UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + /* 32-bit ralative offset in JUMP/CALL commands is + - (mod 4 GB) in 32-bit mode + - signed Int32 in 64-bit mode + We use (mod 4 GB) check for fileSize. + Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ + UInt32 fileIp; + UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ - UInt32 tempTarget; - unsigned tempPos; - Byte temp[4 * 2]; + UInt32 tempTarget; + unsigned tempPos; + Byte temp[4 * 2]; - unsigned flushPos; - - UInt16 probs[2 + 256]; + unsigned flushPos; + + UInt16 probs[2 + 256]; } CBcj2Enc; -void Bcj2Enc_Init(CBcj2Enc *p); -void Bcj2Enc_Encode(CBcj2Enc *p); +void Bcj2Enc_Init(CBcj2Enc* p); +void Bcj2Enc_Encode(CBcj2Enc* p); #define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) #define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) diff --git a/SevenZip/Bra.c b/SevenZip/Bra.c index cdb9456..008d0b5 100644 --- a/SevenZip/Bra.c +++ b/SevenZip/Bra.c @@ -5,131 +5,131 @@ #include "Bra.h" -SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +SizeT ARM_Convert(Byte* data, SizeT size, UInt32 ip, int encoding) { - SizeT i; - if (size < 4) - return 0; - size -= 4; - ip += 8; - for (i = 0; i <= size; i += 4) - { - if (data[i + 3] == 0xEB) - { - UInt32 dest; - UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); - src <<= 2; - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - dest >>= 2; - data[i + 2] = (Byte)(dest >> 16); - data[i + 1] = (Byte)(dest >> 8); - data[i + 0] = (Byte)dest; - } - } - return i; + SizeT i; + if (size < 4) + return 0; + size -= 4; + ip += 8; + for (i = 0; i <= size; i += 4) + { + if (data[i + 3] == 0xEB) + { + UInt32 dest; + UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); + src <<= 2; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + dest >>= 2; + data[i + 2] = (Byte)(dest >> 16); + data[i + 1] = (Byte)(dest >> 8); + data[i + 0] = (Byte)dest; + } + } + return i; } -SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +SizeT ARMT_Convert(Byte* data, SizeT size, UInt32 ip, int encoding) { - SizeT i; - if (size < 4) - return 0; - size -= 4; - ip += 4; - for (i = 0; i <= size; i += 2) - { - if ((data[i + 1] & 0xF8) == 0xF0 && - (data[i + 3] & 0xF8) == 0xF8) - { - UInt32 dest; - UInt32 src = - (((UInt32)data[i + 1] & 0x7) << 19) | - ((UInt32)data[i + 0] << 11) | - (((UInt32)data[i + 3] & 0x7) << 8) | - (data[i + 2]); - - src <<= 1; - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - dest >>= 1; - - data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); - data[i + 0] = (Byte)(dest >> 11); - data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); - data[i + 2] = (Byte)dest; - i += 2; - } - } - return i; + SizeT i; + if (size < 4) + return 0; + size -= 4; + ip += 4; + for (i = 0; i <= size; i += 2) + { + if ((data[i + 1] & 0xF8) == 0xF0 && + (data[i + 3] & 0xF8) == 0xF8) + { + UInt32 dest; + UInt32 src = + (((UInt32)data[i + 1] & 0x7) << 19) | + ((UInt32)data[i + 0] << 11) | + (((UInt32)data[i + 3] & 0x7) << 8) | + (data[i + 2]); + + src <<= 1; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + dest >>= 1; + + data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); + data[i + 0] = (Byte)(dest >> 11); + data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); + data[i + 2] = (Byte)dest; + i += 2; + } + } + return i; } -SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +SizeT PPC_Convert(Byte* data, SizeT size, UInt32 ip, int encoding) { - SizeT i; - if (size < 4) - return 0; - size -= 4; - for (i = 0; i <= size; i += 4) - { - if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) - { - UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | - ((UInt32)data[i + 1] << 16) | - ((UInt32)data[i + 2] << 8) | - ((UInt32)data[i + 3] & (~3)); - - UInt32 dest; - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); - data[i + 1] = (Byte)(dest >> 16); - data[i + 2] = (Byte)(dest >> 8); - data[i + 3] &= 0x3; - data[i + 3] |= dest; - } - } - return i; + SizeT i; + if (size < 4) + return 0; + size -= 4; + for (i = 0; i <= size; i += 4) + { + if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) + { + UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | + ((UInt32)data[i + 1] << 16) | + ((UInt32)data[i + 2] << 8) | + ((UInt32)data[i + 3] & (~3)); + + UInt32 dest; + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); + data[i + 1] = (Byte)(dest >> 16); + data[i + 2] = (Byte)(dest >> 8); + data[i + 3] &= 0x3; + data[i + 3] |= dest; + } + } + return i; } -SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +SizeT SPARC_Convert(Byte* data, SizeT size, UInt32 ip, int encoding) { - UInt32 i; - if (size < 4) - return 0; - size -= 4; - for (i = 0; i <= size; i += 4) - { - if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) || - (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)) - { - UInt32 src = - ((UInt32)data[i + 0] << 24) | - ((UInt32)data[i + 1] << 16) | - ((UInt32)data[i + 2] << 8) | - ((UInt32)data[i + 3]); - UInt32 dest; - - src <<= 2; - if (encoding) - dest = ip + i + src; - else - dest = src - (ip + i); - dest >>= 2; - - dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; + UInt32 i; + if (size < 4) + return 0; + size -= 4; + for (i = 0; i <= size; i += 4) + { + if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) || + (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)) + { + UInt32 src = + ((UInt32)data[i + 0] << 24) | + ((UInt32)data[i + 1] << 16) | + ((UInt32)data[i + 2] << 8) | + ((UInt32)data[i + 3]); + UInt32 dest; - data[i + 0] = (Byte)(dest >> 24); - data[i + 1] = (Byte)(dest >> 16); - data[i + 2] = (Byte)(dest >> 8); - data[i + 3] = (Byte)dest; - } - } - return i; + src <<= 2; + if (encoding) + dest = ip + i + src; + else + dest = src - (ip + i); + dest >>= 2; + + dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; + + data[i + 0] = (Byte)(dest >> 24); + data[i + 1] = (Byte)(dest >> 16); + data[i + 2] = (Byte)(dest >> 8); + data[i + 3] = (Byte)dest; + } + } + return i; } diff --git a/SevenZip/Bra.h b/SevenZip/Bra.h index 855e37a..a5f029c 100644 --- a/SevenZip/Bra.h +++ b/SevenZip/Bra.h @@ -52,12 +52,12 @@ in CALL instructions to increase the compression ratio. */ #define x86_Convert_Init(state) { state = 0; } -SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); -SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT x86_Convert(Byte* data, SizeT size, UInt32 ip, UInt32* state, int encoding); +SizeT ARM_Convert(Byte* data, SizeT size, UInt32 ip, int encoding); +SizeT ARMT_Convert(Byte* data, SizeT size, UInt32 ip, int encoding); +SizeT PPC_Convert(Byte* data, SizeT size, UInt32 ip, int encoding); +SizeT SPARC_Convert(Byte* data, SizeT size, UInt32 ip, int encoding); +SizeT IA64_Convert(Byte* data, SizeT size, UInt32 ip, int encoding); EXTERN_C_END diff --git a/SevenZip/Bra86.c b/SevenZip/Bra86.c index 6db15e7..5c61681 100644 --- a/SevenZip/Bra86.c +++ b/SevenZip/Bra86.c @@ -7,76 +7,76 @@ #define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) -SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) +SizeT x86_Convert(Byte* data, SizeT size, UInt32 ip, UInt32* state, int encoding) { - SizeT pos = 0; - UInt32 mask = *state & 7; - if (size < 5) - return 0; - size -= 4; - ip += 5; + SizeT pos = 0; + UInt32 mask = *state & 7; + if (size < 5) + return 0; + size -= 4; + ip += 5; - for (;;) - { - Byte *p = data + pos; - const Byte *limit = data + size; - for (; p < limit; p++) - if ((*p & 0xFE) == 0xE8) - break; + for (;;) + { + Byte* p = data + pos; + const Byte* limit = data + size; + for (; p < limit; p++) + if ((*p & 0xFE) == 0xE8) + break; - { - SizeT d = (SizeT)(p - data - pos); - pos = (SizeT)(p - data); - if (p >= limit) - { - *state = (d > 2 ? 0 : mask >> (unsigned)d); - return pos; - } - if (d > 2) - mask = 0; - else - { - mask >>= (unsigned)d; - if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1]))) - { - mask = (mask >> 1) | 4; - pos++; - continue; - } - } - } + { + SizeT d = (SizeT)(p - data - pos); + pos = (SizeT)(p - data); + if (p >= limit) + { + *state = (d > 2 ? 0 : mask >> (unsigned)d); + return pos; + } + if (d > 2) + mask = 0; + else + { + mask >>= (unsigned)d; + if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1]))) + { + mask = (mask >> 1) | 4; + pos++; + continue; + } + } + } - if (Test86MSByte(p[4])) - { - UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); - UInt32 cur = ip + (UInt32)pos; - pos += 5; - if (encoding) - v += cur; - else - v -= cur; - if (mask != 0) - { - unsigned sh = (mask & 6) << 2; - if (Test86MSByte((Byte)(v >> sh))) - { - v ^= (((UInt32)0x100 << sh) - 1); - if (encoding) - v += cur; - else - v -= cur; - } - mask = 0; - } - p[1] = (Byte)v; - p[2] = (Byte)(v >> 8); - p[3] = (Byte)(v >> 16); - p[4] = (Byte)(0 - ((v >> 24) & 1)); - } - else - { - mask = (mask >> 1) | 4; - pos++; - } - } + if (Test86MSByte(p[4])) + { + UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 cur = ip + (UInt32)pos; + pos += 5; + if (encoding) + v += cur; + else + v -= cur; + if (mask != 0) + { + unsigned sh = (mask & 6) << 2; + if (Test86MSByte((Byte)(v >> sh))) + { + v ^= (((UInt32)0x100 << sh) - 1); + if (encoding) + v += cur; + else + v -= cur; + } + mask = 0; + } + p[1] = (Byte)v; + p[2] = (Byte)(v >> 8); + p[3] = (Byte)(v >> 16); + p[4] = (Byte)(0 - ((v >> 24) & 1)); + } + else + { + mask = (mask >> 1) | 4; + pos++; + } + } } diff --git a/SevenZip/BraIA64.c b/SevenZip/BraIA64.c index fa60356..24dba28 100644 --- a/SevenZip/BraIA64.c +++ b/SevenZip/BraIA64.c @@ -7,63 +7,63 @@ static const Byte kBranchTable[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 4, 4, 6, 6, 0, 0, 7, 7, - 4, 4, 0, 0, 4, 4, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 }; -SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +SizeT IA64_Convert(Byte* data, SizeT size, UInt32 ip, int encoding) { - SizeT i; - if (size < 16) - return 0; - size -= 16; - for (i = 0; i <= size; i += 16) - { - UInt32 instrTemplate = data[i] & 0x1F; - UInt32 mask = kBranchTable[instrTemplate]; - UInt32 bitPos = 5; - int slot; - for (slot = 0; slot < 3; slot++, bitPos += 41) - { - UInt32 bytePos, bitRes; - UInt64 instruction, instNorm; - int j; - if (((mask >> slot) & 1) == 0) - continue; - bytePos = (bitPos >> 3); - bitRes = bitPos & 0x7; - instruction = 0; - for (j = 0; j < 6; j++) - instruction += (UInt64)data[i + j + bytePos] << (8 * j); + SizeT i; + if (size < 16) + return 0; + size -= 16; + for (i = 0; i <= size; i += 16) + { + UInt32 instrTemplate = data[i] & 0x1F; + UInt32 mask = kBranchTable[instrTemplate]; + UInt32 bitPos = 5; + int slot; + for (slot = 0; slot < 3; slot++, bitPos += 41) + { + UInt32 bytePos, bitRes; + UInt64 instruction, instNorm; + int j; + if (((mask >> slot) & 1) == 0) + continue; + bytePos = (bitPos >> 3); + bitRes = bitPos & 0x7; + instruction = 0; + for (j = 0; j < 6; j++) + instruction += (UInt64)data[i + j + bytePos] << (8 * j); - instNorm = instruction >> bitRes; - if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) - { - UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); - UInt32 dest; - src |= ((UInt32)(instNorm >> 36) & 1) << 20; - - src <<= 4; - - if (encoding) - dest = ip + (UInt32)i + src; - else - dest = src - (ip + (UInt32)i); - - dest >>= 4; - - instNorm &= ~((UInt64)(0x8FFFFF) << 13); - instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); - instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); - - instruction &= (1 << bitRes) - 1; - instruction |= (instNorm << bitRes); - for (j = 0; j < 6; j++) - data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); - } - } - } - return i; + instNorm = instruction >> bitRes; + if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) + { + UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); + UInt32 dest; + src |= ((UInt32)(instNorm >> 36) & 1) << 20; + + src <<= 4; + + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + + dest >>= 4; + + instNorm &= ~((UInt64)(0x8FFFFF) << 13); + instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); + instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); + + instruction &= (1 << bitRes) - 1; + instruction |= (instNorm << bitRes); + for (j = 0; j < 6; j++) + data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); + } + } + } + return i; } diff --git a/SevenZip/Compiler.h b/SevenZip/Compiler.h index 5bba7ee..ee04822 100644 --- a/SevenZip/Compiler.h +++ b/SevenZip/Compiler.h @@ -6,23 +6,23 @@ #ifdef _MSC_VER - #ifdef UNDER_CE +#ifdef UNDER_CE #define RPC_NO_WINDOWS_H /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int - #endif +#endif - #if _MSC_VER >= 1300 - #pragma warning(disable : 4996) // This function or variable may be unsafe - #else +#if _MSC_VER >= 1300 +#pragma warning(disable : 4996) // This function or variable may be unsafe +#else #pragma warning(disable : 4511) // copy constructor could not be generated #pragma warning(disable : 4512) // assignment operator could not be generated #pragma warning(disable : 4514) // unreferenced inline function has been removed #pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4710) // not inlined #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information - #endif +#endif #endif diff --git a/SevenZip/CpuArch.c b/SevenZip/CpuArch.c index 554ffa4..99376c3 100644 --- a/SevenZip/CpuArch.c +++ b/SevenZip/CpuArch.c @@ -18,7 +18,7 @@ #if defined(USE_ASM) && !defined(MY_CPU_AMD64) static UInt32 CheckFlag(UInt32 flag) { - #ifdef _MSC_VER +#ifdef _MSC_VER __asm pushfd; __asm pop EAX; __asm mov EDX, EAX; @@ -31,7 +31,7 @@ static UInt32 CheckFlag(UInt32 flag) __asm push EDX; __asm popfd; __asm and flag, EAX; - #else +#else __asm__ __volatile__ ( "pushf\n\t" "pop %%EAX\n\t" @@ -47,7 +47,7 @@ static UInt32 CheckFlag(UInt32 flag) "andl %%EAX, %0\n\t": "=c" (flag) : "c" (flag) : "%eax", "%edx"); - #endif +#endif return flag; } #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; @@ -55,11 +55,11 @@ static UInt32 CheckFlag(UInt32 flag) #define CHECK_CPUID_IS_SUPPORTED #endif -void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +void MyCPUID(UInt32 function, UInt32* a, UInt32* b, UInt32* c, UInt32* d) { - #ifdef USE_ASM +#ifdef USE_ASM - #ifdef _MSC_VER +#ifdef _MSC_VER UInt32 a2, b2, c2, d2; __asm xor EBX, EBX; @@ -77,100 +77,100 @@ void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) *c = c2; *d = d2; - #else +#else __asm__ __volatile__ ( - #if defined(MY_CPU_AMD64) && defined(__PIC__) +#if defined(MY_CPU_AMD64) && defined(__PIC__) "mov %%rbx, %%rdi;" "cpuid;" "xchg %%rbx, %%rdi;" : "=a" (*a) , "=D" (*b) , - #elif defined(MY_CPU_X86) && defined(__PIC__) +#elif defined(MY_CPU_X86) && defined(__PIC__) "mov %%ebx, %%edi;" "cpuid;" "xchgl %%ebx, %%edi;" : "=a" (*a) , "=D" (*b) , - #else +#else "cpuid" : "=a" (*a) , "=b" (*b) , - #endif +#endif "=c" (*c) , "=d" (*d) : "0" (function)) ; - #endif - - #else +#endif - int CPUInfo[4]; - __cpuid(CPUInfo, function); - *a = CPUInfo[0]; - *b = CPUInfo[1]; - *c = CPUInfo[2]; - *d = CPUInfo[3]; +#else - #endif + int CPUInfo[4]; + __cpuid(CPUInfo, function); + *a = CPUInfo[0]; + *b = CPUInfo[1]; + *c = CPUInfo[2]; + *d = CPUInfo[3]; + +#endif } -Bool x86cpuid_CheckAndRead(Cx86cpuid *p) +Bool x86cpuid_CheckAndRead(Cx86cpuid* p) { - CHECK_CPUID_IS_SUPPORTED - MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); - MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); - return True; + CHECK_CPUID_IS_SUPPORTED + MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); + MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + return True; } static const UInt32 kVendors[][3] = { - { 0x756E6547, 0x49656E69, 0x6C65746E}, - { 0x68747541, 0x69746E65, 0x444D4163}, - { 0x746E6543, 0x48727561, 0x736C7561} + {0x756E6547, 0x49656E69, 0x6C65746E}, + {0x68747541, 0x69746E65, 0x444D4163}, + {0x746E6543, 0x48727561, 0x736C7561} }; -int x86cpuid_GetFirm(const Cx86cpuid *p) +int x86cpuid_GetFirm(const Cx86cpuid* p) { - unsigned i; - for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) - { - const UInt32 *v = kVendors[i]; - if (v[0] == p->vendor[0] && - v[1] == p->vendor[1] && - v[2] == p->vendor[2]) - return (int)i; - } - return -1; + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + { + const UInt32* v = kVendors[i]; + if (v[0] == p->vendor[0] && + v[1] == p->vendor[1] && + v[2] == p->vendor[2]) + return (int)i; + } + return -1; } Bool CPU_Is_InOrder() { - Cx86cpuid p; - int firm; - UInt32 family, model; - if (!x86cpuid_CheckAndRead(&p)) - return True; + Cx86cpuid p; + int firm; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; - family = x86cpuid_GetFamily(p.ver); - model = x86cpuid_GetModel(p.ver); - - firm = x86cpuid_GetFirm(&p); + family = x86cpuid_GetFamily(p.ver); + model = x86cpuid_GetModel(p.ver); - switch (firm) - { - case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( - /* In-Order Atom CPU */ - model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ - || model == 0x26 /* 45 nm, Z6xx */ - || model == 0x27 /* 32 nm, Z2460 */ - || model == 0x35 /* 32 nm, Z2760 */ - || model == 0x36 /* 32 nm, N2xxx, D2xxx */ - ))); - case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); - case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); - } - return True; + firm = x86cpuid_GetFirm(&p); + + switch (firm) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + /* In-Order Atom CPU */ + model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x26 /* 45 nm, Z6xx */ + || model == 0x27 /* 32 nm, Z2460 */ + || model == 0x35 /* 32 nm, Z2760 */ + || model == 0x36 /* 32 nm, N2xxx, D2xxx */ + ))); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return True; } #if !defined(MY_CPU_AMD64) && defined(_WIN32) @@ -190,11 +190,11 @@ static Bool CPU_Sys_Is_SSE_Supported() Bool CPU_Is_Aes_Supported() { - Cx86cpuid p; - CHECK_SYS_SSE_SUPPORT - if (!x86cpuid_CheckAndRead(&p)) - return False; - return (p.c >> 25) & 1; + Cx86cpuid p; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_CheckAndRead(&p)) + return False; + return (p.c >> 25) & 1; } #endif diff --git a/SevenZip/CpuArch.h b/SevenZip/CpuArch.h index f6a28ba..6902f4d 100644 --- a/SevenZip/CpuArch.h +++ b/SevenZip/CpuArch.h @@ -21,14 +21,14 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem || defined(__x86_64__) \ || defined(__AMD64__) \ || defined(__amd64__) - #define MY_CPU_AMD64 +#define MY_CPU_AMD64 #endif #if defined(MY_CPU_AMD64) \ || defined(_M_IA64) \ || defined(__AARCH64EL__) \ || defined(__AARCH64EB__) - #define MY_CPU_64BIT +#define MY_CPU_64BIT #endif #if defined(_M_IX86) || defined(__i386__) @@ -67,7 +67,7 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem || defined(__MIPSEL) \ || defined(_MIPSEL) \ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - #define MY_CPU_LE +#define MY_CPU_LE #endif #if defined(__BIG_ENDIAN__) \ @@ -91,10 +91,10 @@ Stop_Compiling_Bad_Endian #ifdef MY_CPU_LE - #if defined(MY_CPU_X86_OR_AMD64) \ +#if defined(MY_CPU_X86_OR_AMD64) \ /* || defined(__AARCH64EL__) */ - #define MY_CPU_LE_UNALIGN - #endif +#define MY_CPU_LE_UNALIGN +#endif #endif @@ -183,30 +183,29 @@ Stop_Compiling_Bad_Endian ((const Byte *)(p))[1] )) - #ifdef MY_CPU_X86_OR_AMD64 typedef struct { - UInt32 maxFunc; - UInt32 vendor[3]; - UInt32 ver; - UInt32 b; - UInt32 c; - UInt32 d; + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; } Cx86cpuid; enum { - CPU_FIRM_INTEL, - CPU_FIRM_AMD, - CPU_FIRM_VIA + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA }; -void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); +void MyCPUID(UInt32 function, UInt32* a, UInt32* b, UInt32* c, UInt32* d); -Bool x86cpuid_CheckAndRead(Cx86cpuid *p); -int x86cpuid_GetFirm(const Cx86cpuid *p); +Bool x86cpuid_CheckAndRead(Cx86cpuid* p); +int x86cpuid_GetFirm(const Cx86cpuid* p); #define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) #define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) diff --git a/SevenZip/Delta.c b/SevenZip/Delta.c index e3edd21..37e4a60 100644 --- a/SevenZip/Delta.c +++ b/SevenZip/Delta.c @@ -5,60 +5,60 @@ #include "Delta.h" -void Delta_Init(Byte *state) +void Delta_Init(Byte* state) { - unsigned i; - for (i = 0; i < DELTA_STATE_SIZE; i++) - state[i] = 0; + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; } -static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) +static void MyMemCpy(Byte* dest, const Byte* src, unsigned size) { - unsigned i; - for (i = 0; i < size; i++) - dest[i] = src[i]; + unsigned i; + for (i = 0; i < size; i++) + dest[i] = src[i]; } -void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +void Delta_Encode(Byte* state, unsigned delta, Byte* data, SizeT size) { - Byte buf[DELTA_STATE_SIZE]; - unsigned j = 0; - MyMemCpy(buf, state, delta); - { - SizeT i; - for (i = 0; i < size;) - { - for (j = 0; j < delta && i < size; i++, j++) - { - Byte b = data[i]; - data[i] = (Byte)(b - buf[j]); - buf[j] = b; - } - } - } - if (j == delta) - j = 0; - MyMemCpy(state, buf + j, delta - j); - MyMemCpy(state + delta - j, buf, j); + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + Byte b = data[i]; + data[i] = (Byte)(b - buf[j]); + buf[j] = b; + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); } -void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +void Delta_Decode(Byte* state, unsigned delta, Byte* data, SizeT size) { - Byte buf[DELTA_STATE_SIZE]; - unsigned j = 0; - MyMemCpy(buf, state, delta); - { - SizeT i; - for (i = 0; i < size;) - { - for (j = 0; j < delta && i < size; i++, j++) - { - buf[j] = data[i] = (Byte)(buf[j] + data[i]); - } - } - } - if (j == delta) - j = 0; - MyMemCpy(state, buf + j, delta - j); - MyMemCpy(state + delta - j, buf, j); + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + buf[j] = data[i] = (Byte)(buf[j] + data[i]); + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); } diff --git a/SevenZip/Delta.h b/SevenZip/Delta.h index 2fa54ad..8675eeb 100644 --- a/SevenZip/Delta.h +++ b/SevenZip/Delta.h @@ -10,9 +10,9 @@ EXTERN_C_BEGIN #define DELTA_STATE_SIZE 256 -void Delta_Init(Byte *state); -void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); -void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Init(Byte* state); +void Delta_Encode(Byte* state, unsigned delta, Byte* data, SizeT size); +void Delta_Decode(Byte* state, unsigned delta, Byte* data, SizeT size); EXTERN_C_END diff --git a/SevenZip/Lzma2Dec.c b/SevenZip/Lzma2Dec.c index b84f88a..b42f1e2 100644 --- a/SevenZip/Lzma2Dec.c +++ b/SevenZip/Lzma2Dec.c @@ -48,331 +48,333 @@ typedef enum { - LZMA2_STATE_CONTROL, - LZMA2_STATE_UNPACK0, - LZMA2_STATE_UNPACK1, - LZMA2_STATE_PACK0, - LZMA2_STATE_PACK1, - LZMA2_STATE_PROP, - LZMA2_STATE_DATA, - LZMA2_STATE_DATA_CONT, - LZMA2_STATE_FINISHED, - LZMA2_STATE_ERROR + LZMA2_STATE_CONTROL, + LZMA2_STATE_UNPACK0, + LZMA2_STATE_UNPACK1, + LZMA2_STATE_PACK0, + LZMA2_STATE_PACK1, + LZMA2_STATE_PROP, + LZMA2_STATE_DATA, + LZMA2_STATE_DATA_CONT, + LZMA2_STATE_FINISHED, + LZMA2_STATE_ERROR } ELzma2State; -static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) +static SRes Lzma2Dec_GetOldProps(Byte prop, Byte* props) { - UInt32 dicSize; - if (prop > 40) - return SZ_ERROR_UNSUPPORTED; - dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); - props[0] = (Byte)LZMA2_LCLP_MAX; - props[1] = (Byte)(dicSize); - props[2] = (Byte)(dicSize >> 8); - props[3] = (Byte)(dicSize >> 16); - props[4] = (Byte)(dicSize >> 24); - return SZ_OK; + UInt32 dicSize; + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); + props[0] = (Byte)LZMA2_LCLP_MAX; + props[1] = (Byte)(dicSize); + props[2] = (Byte)(dicSize >> 8); + props[3] = (Byte)(dicSize >> 16); + props[4] = (Byte)(dicSize >> 24); + return SZ_OK; } -SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) +SRes Lzma2Dec_AllocateProbs(CLzma2Dec* p, Byte prop, ISzAlloc* alloc) { - Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)); - return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } -SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc) +SRes Lzma2Dec_Allocate(CLzma2Dec* p, Byte prop, ISzAlloc* alloc) { - Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)); - return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); } -void Lzma2Dec_Init(CLzma2Dec *p) +void Lzma2Dec_Init(CLzma2Dec* p) { - p->state = LZMA2_STATE_CONTROL; - p->needInitDic = True; - p->needInitState = True; - p->needInitProp = True; - LzmaDec_Init(&p->decoder); + p->state = LZMA2_STATE_CONTROL; + p->needInitDic = True; + p->needInitState = True; + p->needInitProp = True; + LzmaDec_Init(&p->decoder); } -static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec* p, Byte b) { - switch (p->state) - { - case LZMA2_STATE_CONTROL: - p->control = b; - PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos)); - PRF(printf(" %2X", (unsigned)b)); - if (p->control == 0) - return LZMA2_STATE_FINISHED; - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if ((p->control & 0x7F) > 2) - return LZMA2_STATE_ERROR; - p->unpackSize = 0; - } - else - p->unpackSize = (UInt32)(p->control & 0x1F) << 16; - return LZMA2_STATE_UNPACK0; - - case LZMA2_STATE_UNPACK0: - p->unpackSize |= (UInt32)b << 8; - return LZMA2_STATE_UNPACK1; - - case LZMA2_STATE_UNPACK1: - p->unpackSize |= (UInt32)b; - p->unpackSize++; - PRF(printf(" %8u", (unsigned)p->unpackSize)); - return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; - - case LZMA2_STATE_PACK0: - p->packSize = (UInt32)b << 8; - return LZMA2_STATE_PACK1; + switch (p->state) + { + case LZMA2_STATE_CONTROL: + p->control = b; + PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos)); + PRF(printf(" %2X", (unsigned)b)); + if (p->control == 0) + return LZMA2_STATE_FINISHED; + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if ((p->control & 0x7F) > 2) + return LZMA2_STATE_ERROR; + p->unpackSize = 0; + } + else + p->unpackSize = (UInt32)(p->control & 0x1F) << 16; + return LZMA2_STATE_UNPACK0; - case LZMA2_STATE_PACK1: - p->packSize |= (UInt32)b; - p->packSize++; - PRF(printf(" %8u", (unsigned)p->packSize)); - return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: - (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); + case LZMA2_STATE_UNPACK0: + p->unpackSize |= (UInt32)b << 8; + return LZMA2_STATE_UNPACK1; - case LZMA2_STATE_PROP: - { - unsigned lc, lp; - if (b >= (9 * 5 * 5)) - return LZMA2_STATE_ERROR; - lc = b % 9; - b /= 9; - p->decoder.prop.pb = b / 5; - lp = b % 5; - if (lc + lp > LZMA2_LCLP_MAX) - return LZMA2_STATE_ERROR; - p->decoder.prop.lc = lc; - p->decoder.prop.lp = lp; - p->needInitProp = False; - return LZMA2_STATE_DATA; - } - } - return LZMA2_STATE_ERROR; + case LZMA2_STATE_UNPACK1: + p->unpackSize |= (UInt32)b; + p->unpackSize++; + PRF(printf(" %8u", (unsigned)p->unpackSize)); + return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; + + case LZMA2_STATE_PACK0: + p->packSize = (UInt32)b << 8; + return LZMA2_STATE_PACK1; + + case LZMA2_STATE_PACK1: + p->packSize |= (UInt32)b; + p->packSize++; + PRF(printf(" %8u", (unsigned)p->packSize)); + return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) + ? LZMA2_STATE_PROP + : (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); + + case LZMA2_STATE_PROP: + { + unsigned lc, lp; + if (b >= (9 * 5 * 5)) + return LZMA2_STATE_ERROR; + lc = b % 9; + b /= 9; + p->decoder.prop.pb = b / 5; + lp = b % 5; + if (lc + lp > LZMA2_LCLP_MAX) + return LZMA2_STATE_ERROR; + p->decoder.prop.lc = lc; + p->decoder.prop.lp = lp; + p->needInitProp = False; + return LZMA2_STATE_DATA; + } + } + return LZMA2_STATE_ERROR; } -static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) +static void LzmaDec_UpdateWithUncompressed(CLzmaDec* p, const Byte* src, SizeT size) { - memcpy(p->dic + p->dicPos, src, size); - p->dicPos += size; - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) - p->checkDicSize = p->prop.dicSize; - p->processedPos += (UInt32)size; + memcpy(p->dic + p->dicPos, src, size); + p->dicPos += size; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) + p->checkDicSize = p->prop.dicSize; + p->processedPos += (UInt32)size; } -void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState); +void LzmaDec_InitDicAndState(CLzmaDec* p, Bool initDic, Bool initState); -SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +SRes Lzma2Dec_DecodeToDic(CLzma2Dec* p, SizeT dicLimit, + const Byte* src, SizeT* srcLen, ELzmaFinishMode finishMode, ELzmaStatus* status) { - SizeT inSize = *srcLen; - *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; + SizeT inSize = *srcLen; + *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; - while (p->state != LZMA2_STATE_FINISHED) - { - SizeT dicPos = p->decoder.dicPos; - - if (p->state == LZMA2_STATE_ERROR) - return SZ_ERROR_DATA; - - if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } + while (p->state != LZMA2_STATE_FINISHED) + { + SizeT dicPos = p->decoder.dicPos; - if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) - { - if (*srcLen == inSize) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - (*srcLen)++; - p->state = Lzma2Dec_UpdateState(p, *src++); + if (p->state == LZMA2_STATE_ERROR) + return SZ_ERROR_DATA; - if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) - { - p->state = LZMA2_STATE_ERROR; - return SZ_ERROR_DATA; - } - continue; - } - - { - SizeT destSizeCur = dicLimit - dicPos; - SizeT srcSizeCur = inSize - *srcLen; - ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; - - if (p->unpackSize <= destSizeCur) - { - destSizeCur = (SizeT)p->unpackSize; - curFinishMode = LZMA_FINISH_END; - } + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if (*srcLen == inSize) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->state = Lzma2Dec_UpdateState(p, *src++); - if (p->state == LZMA2_STATE_DATA) - { - Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); - if (initDic) - p->needInitProp = p->needInitState = True; - else if (p->needInitDic) - { - p->state = LZMA2_STATE_ERROR; - return SZ_ERROR_DATA; - } - p->needInitDic = False; - LzmaDec_InitDicAndState(&p->decoder, initDic, False); - } + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } + continue; + } - if (srcSizeCur > destSizeCur) - srcSizeCur = destSizeCur; + { + SizeT destSizeCur = dicLimit - dicPos; + SizeT srcSizeCur = inSize - *srcLen; + ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; - if (srcSizeCur == 0) - { - p->state = LZMA2_STATE_ERROR; - return SZ_ERROR_DATA; - } + if (p->unpackSize <= destSizeCur) + { + destSizeCur = (SizeT)p->unpackSize; + curFinishMode = LZMA_FINISH_END; + } - LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } - src += srcSizeCur; - *srcLen += srcSizeCur; - p->unpackSize -= (UInt32)srcSizeCur; - p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; - } - else - { - SizeT outSizeProcessed; - SRes res; + if (p->state == LZMA2_STATE_DATA) + { + Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); + if (initDic) + p->needInitProp = p->needInitState = True; + else if (p->needInitDic) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } + p->needInitDic = False; + LzmaDec_InitDicAndState(&p->decoder, initDic, False); + } - if (p->state == LZMA2_STATE_DATA) - { - unsigned mode = LZMA2_GET_LZMA_MODE(p); - Bool initDic = (mode == 3); - Bool initState = (mode != 0); - if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) - { - p->state = LZMA2_STATE_ERROR; - return SZ_ERROR_DATA; - } - - LzmaDec_InitDicAndState(&p->decoder, initDic, initState); - p->needInitDic = False; - p->needInitState = False; - p->state = LZMA2_STATE_DATA_CONT; - } - - if (srcSizeCur > p->packSize) - srcSizeCur = (SizeT)p->packSize; - - res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); - - src += srcSizeCur; - *srcLen += srcSizeCur; - p->packSize -= (UInt32)srcSizeCur; + if (srcSizeCur > destSizeCur) + srcSizeCur = destSizeCur; - outSizeProcessed = p->decoder.dicPos - dicPos; - p->unpackSize -= (UInt32)outSizeProcessed; + if (srcSizeCur == 0) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } - RINOK(res); - if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) - return res; + LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); - if (srcSizeCur == 0 && outSizeProcessed == 0) - { - if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - || p->unpackSize != 0 - || p->packSize != 0) - { - p->state = LZMA2_STATE_ERROR; - return SZ_ERROR_DATA; - } - p->state = LZMA2_STATE_CONTROL; - } - - if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - *status = LZMA_STATUS_NOT_FINISHED; - } - } - } - - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return SZ_OK; + src += srcSizeCur; + *srcLen += srcSizeCur; + p->unpackSize -= (UInt32)srcSizeCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + SizeT outSizeProcessed; + SRes res; + + if (p->state == LZMA2_STATE_DATA) + { + unsigned mode = LZMA2_GET_LZMA_MODE(p); + Bool initDic = (mode == 3); + Bool initState = (mode != 0); + if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } + + LzmaDec_InitDicAndState(&p->decoder, initDic, initState); + p->needInitDic = False; + p->needInitState = False; + p->state = LZMA2_STATE_DATA_CONT; + } + + if (srcSizeCur > p->packSize) + srcSizeCur = (SizeT)p->packSize; + + res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); + + src += srcSizeCur; + *srcLen += srcSizeCur; + p->packSize -= (UInt32)srcSizeCur; + + outSizeProcessed = p->decoder.dicPos - dicPos; + p->unpackSize -= (UInt32)outSizeProcessed; + + RINOK(res); + if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) + return res; + + if (srcSizeCur == 0 && outSizeProcessed == 0) + { + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } + p->state = LZMA2_STATE_CONTROL; + } + + if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + *status = LZMA_STATUS_NOT_FINISHED; + } + } + } + + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; } -SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec* p, Byte* dest, SizeT* destLen, const Byte* src, SizeT* srcLen, + ELzmaFinishMode finishMode, ELzmaStatus* status) { - SizeT outSize = *destLen, inSize = *srcLen; - *srcLen = *destLen = 0; - for (;;) - { - SizeT srcSizeCur = inSize, outSizeCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - if (p->decoder.dicPos == p->decoder.dicBufSize) - p->decoder.dicPos = 0; - dicPos = p->decoder.dicPos; - if (outSize > p->decoder.dicBufSize - dicPos) - { - outSizeCur = p->decoder.dicBufSize; - curFinishMode = LZMA_FINISH_ANY; - } - else - { - outSizeCur = dicPos + outSize; - curFinishMode = finishMode; - } + SizeT outSize = *destLen, inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT srcSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->decoder.dicPos == p->decoder.dicBufSize) + p->decoder.dicPos = 0; + dicPos = p->decoder.dicPos; + if (outSize > p->decoder.dicBufSize - dicPos) + { + outSizeCur = p->decoder.dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } - res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); - src += srcSizeCur; - inSize -= srcSizeCur; - *srcLen += srcSizeCur; - outSizeCur = p->decoder.dicPos - dicPos; - memcpy(dest, p->decoder.dic + dicPos, outSizeCur); - dest += outSizeCur; - outSize -= outSizeCur; - *destLen += outSizeCur; - if (res != 0) - return res; - if (outSizeCur == 0 || outSize == 0) - return SZ_OK; - } + res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); + src += srcSizeCur; + inSize -= srcSizeCur; + *srcLen += srcSizeCur; + outSizeCur = p->decoder.dicPos - dicPos; + memcpy(dest, p->decoder.dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } } -SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) +SRes Lzma2Decode(Byte* dest, SizeT* destLen, const Byte* src, SizeT* srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus* status, ISzAlloc* alloc) { - CLzma2Dec p; - SRes res; - SizeT outSize = *destLen, inSize = *srcLen; - *destLen = *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - Lzma2Dec_Construct(&p); - RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); - p.decoder.dic = dest; - p.decoder.dicBufSize = outSize; - Lzma2Dec_Init(&p); - *srcLen = inSize; - res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); - *destLen = p.decoder.dicPos; - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - Lzma2Dec_FreeProbs(&p, alloc); - return res; + CLzma2Dec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + Lzma2Dec_Construct(&p); + RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); + p.decoder.dic = dest; + p.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&p); + *srcLen = inSize; + res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.decoder.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + Lzma2Dec_FreeProbs(&p, alloc); + return res; } diff --git a/SevenZip/Lzma2Dec.h b/SevenZip/Lzma2Dec.h index e6a0f6e..35ebec4 100644 --- a/SevenZip/Lzma2Dec.h +++ b/SevenZip/Lzma2Dec.h @@ -12,23 +12,23 @@ EXTERN_C_BEGIN typedef struct { - CLzmaDec decoder; - UInt32 packSize; - UInt32 unpackSize; - unsigned state; - Byte control; - Bool needInitDic; - Bool needInitState; - Bool needInitProp; + CLzmaDec decoder; + UInt32 packSize; + UInt32 unpackSize; + unsigned state; + Byte control; + Bool needInitDic; + Bool needInitState; + Bool needInitProp; } CLzma2Dec; #define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) #define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc); #define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc); -SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); -SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc); -void Lzma2Dec_Init(CLzma2Dec *p); +SRes Lzma2Dec_AllocateProbs(CLzma2Dec* p, Byte prop, ISzAlloc* alloc); +SRes Lzma2Dec_Allocate(CLzma2Dec* p, Byte prop, ISzAlloc* alloc); +void Lzma2Dec_Init(CLzma2Dec* p); /* @@ -46,11 +46,11 @@ Returns: SZ_ERROR_DATA - Data error */ -SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +SRes Lzma2Dec_DecodeToDic(CLzma2Dec* p, SizeT dicLimit, + const Byte* src, SizeT* srcLen, ELzmaFinishMode finishMode, ELzmaStatus* status); -SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec* p, Byte* dest, SizeT* destLen, + const Byte* src, SizeT* srcLen, ELzmaFinishMode finishMode, ELzmaStatus* status); /* ---------- One Call Interface ---------- */ @@ -72,8 +72,8 @@ Returns: SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ -SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); +SRes Lzma2Decode(Byte* dest, SizeT* destLen, const Byte* src, SizeT* srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus* status, ISzAlloc* alloc); EXTERN_C_END diff --git a/SevenZip/LzmaDec.c b/SevenZip/LzmaDec.c index 12dce11..49a5435 100644 --- a/SevenZip/LzmaDec.c +++ b/SevenZip/LzmaDec.c @@ -137,70 +137,70 @@ Out: = kMatchSpecLenStart + 2 : State Init Marker (unused now) */ -static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec* p, SizeT limit, const Byte* bufLimit) { - CLzmaProb *probs = p->probs; + CLzmaProb* probs = p->probs; - unsigned state = p->state; - UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; - unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; - unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; - unsigned lc = p->prop.lc; + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; - Byte *dic = p->dic; - SizeT dicBufSize = p->dicBufSize; - SizeT dicPos = p->dicPos; - - UInt32 processedPos = p->processedPos; - UInt32 checkDicSize = p->checkDicSize; - unsigned len = 0; + Byte* dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; - const Byte *buf = p->buf; - UInt32 range = p->range; - UInt32 code = p->code; + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; - do - { - CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = processedPos & pbMask; + const Byte* buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; - prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - IF_BIT_0(prob) - { - unsigned symbol; - UPDATE_0(prob); - prob = probs + Literal; - if (processedPos != 0 || checkDicSize != 0) - prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + - (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); - processedPos++; + do + { + CLzmaProb* prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; - if (state < kNumLitStates) - { - state -= (state < 4) ? state : 3; - symbol = 1; - #ifdef _LZMA_SIZE_OPT + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (processedPos != 0 || checkDicSize != 0) + prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + processedPos++; + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; +#ifdef _LZMA_SIZE_OPT do { NORMAL_LITER_DEC } while (symbol < 0x100); - #else - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - #endif - } - else - { - unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - unsigned offs = 0x100; - state -= (state < 10) ? 3 : 6; - symbol = 1; - #ifdef _LZMA_SIZE_OPT +#else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC +#endif + } + else + { + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; +#ifdef _LZMA_SIZE_OPT do { unsigned bit; @@ -208,91 +208,91 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte MATCHED_LITER_DEC } while (symbol < 0x100); - #else - { - unsigned bit; - CLzmaProb *probLit; - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - } - #endif - } +#else + { + unsigned bit; + CLzmaProb* probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } +#endif + } - dic[dicPos++] = (Byte)symbol; - continue; - } - - { - UPDATE_1(prob); - prob = probs + IsRep + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - state += kNumStates; - prob = probs + LenCoder; - } - else - { - UPDATE_1(prob); - if (checkDicSize == 0 && processedPos == 0) - return SZ_ERROR_DATA; - prob = probs + IsRepG0 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; - IF_BIT_0(prob) - { - UPDATE_0(prob); - dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - dicPos++; - processedPos++; - state = state < kNumLitStates ? 9 : 11; - continue; - } - UPDATE_1(prob); - } - else - { - UInt32 distance; - UPDATE_1(prob); - prob = probs + IsRepG1 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - distance = rep1; - } - else - { - UPDATE_1(prob); - prob = probs + IsRepG2 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob); - distance = rep2; - } - else - { - UPDATE_1(prob); - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - state = state < kNumLitStates ? 8 : 11; - prob = probs + RepLenCoder; - } - - #ifdef _LZMA_SIZE_OPT + dic[dicPos++] = (Byte)symbol; + continue; + } + + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + +#ifdef _LZMA_SIZE_OPT { unsigned lim, offset; CLzmaProb *probLen = prob + LenChoice; @@ -325,776 +325,779 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte TREE_DECODE(probLen, lim, len); len += offset; } - #else - { - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0(probLen) - { - UPDATE_0(probLen); - probLen = prob + LenLow + (posState << kLenNumLowBits); - len = 1; - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); - len -= 8; - } - else - { - UPDATE_1(probLen); - probLen = prob + LenChoice2; - IF_BIT_0(probLen) - { - UPDATE_0(probLen); - probLen = prob + LenMid + (posState << kLenNumMidBits); - len = 1; - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); - TREE_GET_BIT(probLen, len); - } - else - { - UPDATE_1(probLen); - probLen = prob + LenHigh; - TREE_DECODE(probLen, (1 << kLenNumHighBits), len); - len += kLenNumLowSymbols + kLenNumMidSymbols; - } - } - } - #endif +#else + { + CLzmaProb* probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + len -= 8; + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + len += kLenNumLowSymbols + kLenNumMidSymbols; + } + } + } +#endif - if (state >= kNumStates) - { - UInt32 distance; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - TREE_6_DECODE(prob, distance); - if (distance >= kStartPosModelIndex) - { - unsigned posSlot = (unsigned)distance; - unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); - distance = (2 | (distance & 1)); - if (posSlot < kEndPosModelIndex) - { - distance <<= numDirectBits; - prob = probs + SpecPos + distance - posSlot - 1; - { - UInt32 mask = 1; - unsigned i = 1; - do - { - GET_BIT2(prob + i, i, ; , distance |= mask); - mask <<= 1; - } - while (--numDirectBits != 0); - } - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE - range >>= 1; - - { - UInt32 t; - code -= range; - t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ - distance = (distance << 1) + (t + 1); - code += range & t; - } - /* - distance <<= 1; - if (code >= range) - { - code -= range; - distance |= 1; - } - */ - } - while (--numDirectBits != 0); - prob = probs + Align; - distance <<= kNumAlignBits; - { - unsigned i = 1; - GET_BIT2(prob + i, i, ; , distance |= 1); - GET_BIT2(prob + i, i, ; , distance |= 2); - GET_BIT2(prob + i, i, ; , distance |= 4); - GET_BIT2(prob + i, i, ; , distance |= 8); - } - if (distance == (UInt32)0xFFFFFFFF) - { - len += kMatchSpecLenStart; - state -= kNumStates; - break; - } - } - } - - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - rep0 = distance + 1; - if (checkDicSize == 0) - { - if (distance >= processedPos) - { - p->dicPos = dicPos; - return SZ_ERROR_DATA; - } - } - else if (distance >= checkDicSize) - { - p->dicPos = dicPos; - return SZ_ERROR_DATA; - } - state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - } + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ;, distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; - len += kMatchMinLen; + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ;, distance |= 1); + GET_BIT2(prob + i, i, ;, distance |= 2); + GET_BIT2(prob + i, i, ;, distance |= 4); + GET_BIT2(prob + i, i, ;, distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } - { - SizeT rem; - unsigned curLen; - SizeT pos; - - if ((rem = limit - dicPos) == 0) - { - p->dicPos = dicPos; - return SZ_ERROR_DATA; - } - - curLen = ((rem < len) ? (unsigned)rem : len); - pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + } + else if (distance >= checkDicSize) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } - processedPos += curLen; + len += kMatchMinLen; - len -= curLen; - if (curLen <= dicBufSize - pos) - { - Byte *dest = dic + dicPos; - ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; - const Byte *lim = dest + curLen; - dicPos += curLen; - do - *(dest) = (Byte)*(dest + src); - while (++dest != lim); - } - else - { - do - { - dic[dicPos++] = dic[pos]; - if (++pos == dicBufSize) - pos = 0; - } - while (--curLen != 0); - } - } - } - } - while (dicPos < limit && buf < bufLimit); + { + SizeT rem; + unsigned curLen; + SizeT pos; - NORMALIZE; - - p->buf = buf; - p->range = range; - p->code = code; - p->remainLen = len; - p->dicPos = dicPos; - p->processedPos = processedPos; - p->reps[0] = rep0; - p->reps[1] = rep1; - p->reps[2] = rep2; - p->reps[3] = rep3; - p->state = state; + if ((rem = limit - dicPos) == 0) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } - return SZ_OK; + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (curLen <= dicBufSize - pos) + { + Byte* dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte* lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + + NORMALIZE; + + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; } -static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec* p, SizeT limit) { - if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) - { - Byte *dic = p->dic; - SizeT dicPos = p->dicPos; - SizeT dicBufSize = p->dicBufSize; - unsigned len = p->remainLen; - SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ - SizeT rem = limit - dicPos; - if (rem < len) - len = (unsigned)(rem); + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte* dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + SizeT rem = limit - dicPos; + if (rem < len) + len = (unsigned)(rem); - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) - p->checkDicSize = p->prop.dicSize; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; - p->processedPos += len; - p->remainLen -= len; - while (len != 0) - { - len--; - dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - dicPos++; - } - p->dicPos = dicPos; - } + p->processedPos += len; + p->remainLen -= len; + while (len != 0) + { + len--; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } } -static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec* p, SizeT limit, const Byte* bufLimit) { - do - { - SizeT limit2 = limit; - if (p->checkDicSize == 0) - { - UInt32 rem = p->prop.dicSize - p->processedPos; - if (limit - p->dicPos > rem) - limit2 = p->dicPos + rem; - } - - RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - - if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) - p->checkDicSize = p->prop.dicSize; - - LzmaDec_WriteRem(p, limit); - } - while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } - if (p->remainLen > kMatchSpecLenStart) - p->remainLen = kMatchSpecLenStart; + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - return 0; + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + p->remainLen = kMatchSpecLenStart; + + return 0; } typedef enum { - DUMMY_ERROR, /* unexpected end of input stream */ - DUMMY_LIT, - DUMMY_MATCH, - DUMMY_REP + DUMMY_ERROR, + /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP } ELzmaDummy; -static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec* p, const Byte* buf, SizeT inSize) { - UInt32 range = p->range; - UInt32 code = p->code; - const Byte *bufLimit = buf + inSize; - const CLzmaProb *probs = p->probs; - unsigned state = p->state; - ELzmaDummy res; + UInt32 range = p->range; + UInt32 code = p->code; + const Byte* bufLimit = buf + inSize; + const CLzmaProb* probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; - { - const CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + { + const CLzmaProb* prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); - prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK - /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ - prob = probs + Literal; - if (p->checkDicSize != 0 || p->processedPos != 0) - prob += ((UInt32)LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); - if (state < kNumLitStates) - { - unsigned symbol = 1; - do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); - } - else - { - unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; - unsigned offs = 0x100; - unsigned symbol = 1; - do - { - unsigned bit; - const CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) - } - while (symbol < 0x100); - } - res = DUMMY_LIT; - } - else - { - unsigned len; - UPDATE_1_CHECK; + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } + while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + const CLzmaProb* probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; - prob = probs + IsRep + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - state = 0; - prob = probs + LenCoder; - res = DUMMY_MATCH; - } - else - { - UPDATE_1_CHECK; - res = DUMMY_REP; - prob = probs + IsRepG0 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - NORMALIZE_CHECK; - return DUMMY_REP; - } - else - { - UPDATE_1_CHECK; - } - } - else - { - UPDATE_1_CHECK; - prob = probs + IsRepG1 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - } - else - { - UPDATE_1_CHECK; - prob = probs + IsRepG2 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK; - } - else - { - UPDATE_1_CHECK; - } - } - } - state = kNumStates; - prob = probs + RepLenCoder; - } - { - unsigned limit, offset; - const CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK; - probLen = prob + LenLow + (posState << kLenNumLowBits); - offset = 0; - limit = 1 << kLenNumLowBits; - } - else - { - UPDATE_1_CHECK; - probLen = prob + LenChoice2; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK; - probLen = prob + LenMid + (posState << kLenNumMidBits); - offset = kLenNumLowSymbols; - limit = 1 << kLenNumMidBits; - } - else - { - UPDATE_1_CHECK; - probLen = prob + LenHigh; - offset = kLenNumLowSymbols + kLenNumMidSymbols; - limit = 1 << kLenNumHighBits; - } - } - TREE_DECODE_CHECK(probLen, limit, len); - len += offset; - } + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + const CLzmaProb* probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } - if (state < 4) - { - unsigned posSlot; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << - kNumPosSlotBits); - TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); - if (posSlot >= kStartPosModelIndex) - { - unsigned numDirectBits = ((posSlot >> 1) - 1); + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + unsigned numDirectBits = ((posSlot >> 1) - 1); - /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ - if (posSlot < kEndPosModelIndex) - { - prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE_CHECK - range >>= 1; - code -= range & (((code - range) >> 31) - 1); - /* if (code >= range) code -= range; */ - } - while (--numDirectBits != 0); - prob = probs + Align; - numDirectBits = kNumAlignBits; - } - { - unsigned i = 1; - do - { - GET_BIT_CHECK(prob + i, i); - } - while (--numDirectBits != 0); - } - } - } - } - } - NORMALIZE_CHECK; - return res; + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; } -void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +void LzmaDec_InitDicAndState(CLzmaDec* p, Bool initDic, Bool initState) { - p->needFlush = 1; - p->remainLen = 0; - p->tempBufSize = 0; + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; - if (initDic) - { - p->processedPos = 0; - p->checkDicSize = 0; - p->needInitState = 1; - } - if (initState) - p->needInitState = 1; + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; } -void LzmaDec_Init(CLzmaDec *p) +void LzmaDec_Init(CLzmaDec* p) { - p->dicPos = 0; - LzmaDec_InitDicAndState(p, True, True); + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); } -static void LzmaDec_InitStateReal(CLzmaDec *p) +static void LzmaDec_InitStateReal(CLzmaDec* p) { - SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); - SizeT i; - CLzmaProb *probs = p->probs; - for (i = 0; i < numProbs; i++) - probs[i] = kBitModelTotal >> 1; - p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; - p->state = 0; - p->needInitState = 0; + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; + CLzmaProb* probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; } -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, - ELzmaFinishMode finishMode, ELzmaStatus *status) +SRes LzmaDec_DecodeToDic(CLzmaDec* p, SizeT dicLimit, const Byte* src, SizeT* srcLen, + ELzmaFinishMode finishMode, ELzmaStatus* status) { - SizeT inSize = *srcLen; - (*srcLen) = 0; - LzmaDec_WriteRem(p, dicLimit); - - *status = LZMA_STATUS_NOT_SPECIFIED; + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); - while (p->remainLen != kMatchSpecLenStart) - { - int checkEndMarkNow; + *status = LZMA_STATUS_NOT_SPECIFIED; - if (p->needFlush) - { - for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) - p->tempBuf[p->tempBufSize++] = *src++; - if (p->tempBufSize < RC_INIT_SIZE) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (p->tempBuf[0] != 0) - return SZ_ERROR_DATA; - p->code = - ((UInt32)p->tempBuf[1] << 24) - | ((UInt32)p->tempBuf[2] << 16) - | ((UInt32)p->tempBuf[3] << 8) - | ((UInt32)p->tempBuf[4]); - p->range = 0xFFFFFFFF; - p->needFlush = 0; - p->tempBufSize = 0; - } + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; - checkEndMarkNow = 0; - if (p->dicPos >= dicLimit) - { - if (p->remainLen == 0 && p->code == 0) - { - *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; - return SZ_OK; - } - if (finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } - if (p->remainLen != 0) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - checkEndMarkNow = 1; - } + if (p->needFlush) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; + p->tempBufSize = 0; + } - if (p->needInitState) - LzmaDec_InitStateReal(p); - - if (p->tempBufSize == 0) - { - SizeT processed; - const Byte *bufLimit; - if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - int dummyRes = LzmaDec_TryDummy(p, src, inSize); - if (dummyRes == DUMMY_ERROR) - { - memcpy(p->tempBuf, src, inSize); - p->tempBufSize = (unsigned)inSize; - (*srcLen) += inSize; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - bufLimit = src; - } - else - bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; - p->buf = src; - if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) - return SZ_ERROR_DATA; - processed = (SizeT)(p->buf - src); - (*srcLen) += processed; - src += processed; - inSize -= processed; - } - else - { - unsigned rem = p->tempBufSize, lookAhead = 0; - while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) - p->tempBuf[rem++] = src[lookAhead++]; - p->tempBufSize = rem; - if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); - if (dummyRes == DUMMY_ERROR) - { - (*srcLen) += lookAhead; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (checkEndMarkNow && dummyRes != DUMMY_MATCH) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_ERROR_DATA; - } - } - p->buf = p->tempBuf; - if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) - return SZ_ERROR_DATA; - - { - unsigned kkk = (unsigned)(p->buf - p->tempBuf); - if (rem < kkk) - return SZ_ERROR_FAIL; /* some internal error */ - rem -= kkk; - if (lookAhead < rem) - return SZ_ERROR_FAIL; /* some internal error */ - lookAhead -= rem; - } - (*srcLen) += lookAhead; - src += lookAhead; - inSize -= lookAhead; - p->tempBufSize = 0; - } - } - if (p->code == 0) - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte* bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + + { + unsigned kkk = (unsigned)(p->buf - p->tempBuf); + if (rem < kkk) + return SZ_ERROR_FAIL; /* some internal error */ + rem -= kkk; + if (lookAhead < rem) + return SZ_ERROR_FAIL; /* some internal error */ + lookAhead -= rem; + } + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; } -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +SRes LzmaDec_DecodeToBuf(CLzmaDec* p, Byte* dest, SizeT* destLen, const Byte* src, SizeT* srcLen, + ELzmaFinishMode finishMode, ELzmaStatus* status) { - SizeT outSize = *destLen; - SizeT inSize = *srcLen; - *srcLen = *destLen = 0; - for (;;) - { - SizeT inSizeCur = inSize, outSizeCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - if (p->dicPos == p->dicBufSize) - p->dicPos = 0; - dicPos = p->dicPos; - if (outSize > p->dicBufSize - dicPos) - { - outSizeCur = p->dicBufSize; - curFinishMode = LZMA_FINISH_ANY; - } - else - { - outSizeCur = dicPos + outSize; - curFinishMode = finishMode; - } + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } - res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); - src += inSizeCur; - inSize -= inSizeCur; - *srcLen += inSizeCur; - outSizeCur = p->dicPos - dicPos; - memcpy(dest, p->dic + dicPos, outSizeCur); - dest += outSizeCur; - outSize -= outSizeCur; - *destLen += outSizeCur; - if (res != 0) - return res; - if (outSizeCur == 0 || outSize == 0) - return SZ_OK; - } + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } } -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +void LzmaDec_FreeProbs(CLzmaDec* p, ISzAlloc* alloc) { - alloc->Free(alloc, p->probs); - p->probs = NULL; + alloc->Free(alloc, p->probs); + p->probs = NULL; } -static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +static void LzmaDec_FreeDict(CLzmaDec* p, ISzAlloc* alloc) { - alloc->Free(alloc, p->dic); - p->dic = NULL; + alloc->Free(alloc, p->dic); + p->dic = NULL; } -void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +void LzmaDec_Free(CLzmaDec* p, ISzAlloc* alloc) { - LzmaDec_FreeProbs(p, alloc); - LzmaDec_FreeDict(p, alloc); + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); } -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +SRes LzmaProps_Decode(CLzmaProps* p, const Byte* data, unsigned size) { - UInt32 dicSize; - Byte d; - - if (size < LZMA_PROPS_SIZE) - return SZ_ERROR_UNSUPPORTED; - else - dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); - - if (dicSize < LZMA_DIC_MIN) - dicSize = LZMA_DIC_MIN; - p->dicSize = dicSize; + UInt32 dicSize; + Byte d; - d = data[0]; - if (d >= (9 * 5 * 5)) - return SZ_ERROR_UNSUPPORTED; + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); - p->lc = d % 9; - d /= 9; - p->pb = d / 5; - p->lp = d % 5; + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; - return SZ_OK; + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; } -static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +static SRes LzmaDec_AllocateProbs2(CLzmaDec* p, const CLzmaProps* propNew, ISzAlloc* alloc) { - UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (!p->probs || numProbs != p->numProbs) - { - LzmaDec_FreeProbs(p, alloc); - p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); - p->numProbs = numProbs; - if (!p->probs) - return SZ_ERROR_MEM; - } - return SZ_OK; + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (!p->probs || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb*)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (!p->probs) + return SZ_ERROR_MEM; + } + return SZ_OK; } -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +SRes LzmaDec_AllocateProbs(CLzmaDec* p, const Byte* props, unsigned propsSize, ISzAlloc* alloc) { - CLzmaProps propNew; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - p->prop = propNew; - return SZ_OK; + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; } -SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +SRes LzmaDec_Allocate(CLzmaDec* p, const Byte* props, unsigned propsSize, ISzAlloc* alloc) { - CLzmaProps propNew; - SizeT dicBufSize; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - { - UInt32 dictSize = propNew.dicSize; - SizeT mask = ((UInt32)1 << 12) - 1; - if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; - else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; - dicBufSize = ((SizeT)dictSize + mask) & ~mask; - if (dicBufSize < dictSize) - dicBufSize = dictSize; - } + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } - if (!p->dic || dicBufSize != p->dicBufSize) - { - LzmaDec_FreeDict(p, alloc); - p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); - if (!p->dic) - { - LzmaDec_FreeProbs(p, alloc); - return SZ_ERROR_MEM; - } - } - p->dicBufSize = dicBufSize; - p->prop = propNew; - return SZ_OK; + if (!p->dic || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte*)alloc->Alloc(alloc, dicBufSize); + if (!p->dic) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; } -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc) +SRes LzmaDecode(Byte* dest, SizeT* destLen, const Byte* src, SizeT* srcLen, + const Byte* propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus* status, ISzAlloc* alloc) { - CLzmaDec p; - SRes res; - SizeT outSize = *destLen, inSize = *srcLen; - *destLen = *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - if (inSize < RC_INIT_SIZE) - return SZ_ERROR_INPUT_EOF; - LzmaDec_Construct(&p); - RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); - p.dic = dest; - p.dicBufSize = outSize; - LzmaDec_Init(&p); - *srcLen = inSize; - res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); - *destLen = p.dicPos; - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - LzmaDec_FreeProbs(&p, alloc); - return res; + CLzmaDec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + LzmaDec_Construct(&p); + RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); + p.dic = dest; + p.dicBufSize = outSize; + LzmaDec_Init(&p); + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + LzmaDec_FreeProbs(&p, alloc); + return res; } diff --git a/SevenZip/LzmaDec.h b/SevenZip/LzmaDec.h index cc44dae..23e999c 100644 --- a/SevenZip/LzmaDec.h +++ b/SevenZip/LzmaDec.h @@ -25,8 +25,8 @@ EXTERN_C_BEGIN typedef struct _CLzmaProps { - unsigned lc, lp, pb; - UInt32 dicSize; + unsigned lc, lp, pb; + UInt32 dicSize; } CLzmaProps; /* LzmaProps_Decode - decodes properties @@ -35,7 +35,7 @@ Returns: SZ_ERROR_UNSUPPORTED - Unsupported properties */ -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); +SRes LzmaProps_Decode(CLzmaProps* p, const Byte* data, unsigned size); /* ---------- LZMA Decoder state ---------- */ @@ -47,28 +47,28 @@ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); typedef struct { - CLzmaProps prop; - CLzmaProb *probs; - Byte *dic; - const Byte *buf; - UInt32 range, code; - SizeT dicPos; - SizeT dicBufSize; - UInt32 processedPos; - UInt32 checkDicSize; - unsigned state; - UInt32 reps[4]; - unsigned remainLen; - int needFlush; - int needInitState; - UInt32 numProbs; - unsigned tempBufSize; - Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; + CLzmaProps prop; + CLzmaProb* probs; + Byte* dic; + const Byte* buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; } CLzmaDec; #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } -void LzmaDec_Init(CLzmaDec *p); +void LzmaDec_Init(CLzmaDec* p); /* There are two types of LZMA streams: 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. @@ -76,8 +76,9 @@ void LzmaDec_Init(CLzmaDec *p); typedef enum { - LZMA_FINISH_ANY, /* finish at any point */ - LZMA_FINISH_END /* block must be finished at the end */ + LZMA_FINISH_ANY, + /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ } ELzmaFinishMode; /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! @@ -97,11 +98,15 @@ typedef enum typedef enum { - LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ - LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ - LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ + LZMA_STATUS_NOT_SPECIFIED, + /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, + /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, + /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, + /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ } ELzmaStatus; /* ELzmaStatus is used only as output value for function call */ @@ -128,12 +133,12 @@ LzmaDec_Allocate* can return: SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties */ - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); -SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); -void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); +SRes LzmaDec_AllocateProbs(CLzmaDec* p, const Byte* props, unsigned propsSize, ISzAlloc* alloc); +void LzmaDec_FreeProbs(CLzmaDec* p, ISzAlloc* alloc); + +SRes LzmaDec_Allocate(CLzmaDec* state, const Byte* prop, unsigned propsSize, ISzAlloc* alloc); +void LzmaDec_Free(CLzmaDec* state, ISzAlloc* alloc); /* ---------- Dictionary Interface ---------- */ @@ -176,8 +181,8 @@ Returns: SZ_ERROR_DATA - Data error */ -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +SRes LzmaDec_DecodeToDic(CLzmaDec* p, SizeT dicLimit, + const Byte* src, SizeT* srcLen, ELzmaFinishMode finishMode, ELzmaStatus* status); /* ---------- Buffer Interface ---------- */ @@ -193,8 +198,8 @@ finishMode: LZMA_FINISH_END - Stream must be finished after (*destLen). */ -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +SRes LzmaDec_DecodeToBuf(CLzmaDec* p, Byte* dest, SizeT* destLen, + const Byte* src, SizeT* srcLen, ELzmaFinishMode finishMode, ELzmaStatus* status); /* ---------- One Call Interface ---------- */ @@ -218,9 +223,9 @@ Returns: SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); +SRes LzmaDecode(Byte* dest, SizeT* destLen, const Byte* src, SizeT* srcLen, + const Byte* propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus* status, ISzAlloc* alloc); EXTERN_C_END diff --git a/SevenZip/Ppmd.h b/SevenZip/Ppmd.h index 5655b26..d99bb6d 100644 --- a/SevenZip/Ppmd.h +++ b/SevenZip/Ppmd.h @@ -34,9 +34,9 @@ EXTERN_C_BEGIN /* SEE-contexts for PPM-contexts with masked symbols */ typedef struct { - UInt16 Summ; /* Freq */ - Byte Shift; /* Speed of Freq change; low Shift is for fast change */ - Byte Count; /* Count to next change of Shift */ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ } CPpmd_See; #define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ @@ -44,42 +44,42 @@ typedef struct typedef struct { - Byte Symbol; - Byte Freq; - UInt16 SuccessorLow; - UInt16 SuccessorHigh; + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; } CPpmd_State; #pragma pack(pop) typedef - #ifdef PPMD_32BIT +#ifdef PPMD_32BIT CPpmd_State * - #else - UInt32 - #endif - CPpmd_State_Ref; +#else +UInt32 +#endif +CPpmd_State_Ref; typedef - #ifdef PPMD_32BIT +#ifdef PPMD_32BIT void * - #else - UInt32 - #endif - CPpmd_Void_Ref; +#else +UInt32 +#endif +CPpmd_Void_Ref; typedef - #ifdef PPMD_32BIT +#ifdef PPMD_32BIT Byte * - #else - UInt32 - #endif - CPpmd_Byte_Ref; +#else +UInt32 +#endif +CPpmd_Byte_Ref; #define PPMD_SetAllBitsIn256Bytes(p) \ { unsigned z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }} EXTERN_C_END - + #endif diff --git a/SevenZip/Ppmd7.c b/SevenZip/Ppmd7.c index eda8eb7..c4631d6 100644 --- a/SevenZip/Ppmd7.c +++ b/SevenZip/Ppmd7.c @@ -8,8 +8,8 @@ This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #include "Ppmd7.h" -const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; +const Byte PPMD7_kExpEscape[16] = {25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2}; +static const UInt16 kInitBinEsc[] = {0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; #define MAX_FREQ 124 #define UNIT_SIZE 12 @@ -21,7 +21,7 @@ static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x #ifdef PPMD_32BIT #define REF(ptr) (ptr) #else - #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) #endif #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) @@ -31,680 +31,683 @@ static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x #define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) #define SUFFIX(ctx) CTX((ctx)->Suffix) -typedef CPpmd7_Context * CTX_PTR; +typedef CPpmd7_Context* CTX_PTR; struct CPpmd7_Node_; typedef - #ifdef PPMD_32BIT +#ifdef PPMD_32BIT struct CPpmd7_Node_ * - #else - UInt32 - #endif - CPpmd7_Node_Ref; +#else +UInt32 +#endif +CPpmd7_Node_Ref; typedef struct CPpmd7_Node_ { - UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ - UInt16 NU; - CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ - CPpmd7_Node_Ref Prev; + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; } CPpmd7_Node; #ifdef PPMD_32BIT #define NODE(ptr) (ptr) #else - #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) #endif -void Ppmd7_Construct(CPpmd7 *p) +void Ppmd7_Construct(CPpmd7* p) { - unsigned i, k, m; + unsigned i, k, m; - p->Base = 0; + p->Base = 0; - for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) - { - unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); - do { p->Units2Indx[k++] = (Byte)i; } while (--step); - p->Indx2Units[i] = (Byte)k; - } + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } + while (--step); + p->Indx2Units[i] = (Byte)k; + } - p->NS2BSIndx[0] = (0 << 1); - p->NS2BSIndx[1] = (1 << 1); - memset(p->NS2BSIndx + 2, (2 << 1), 9); - memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); - for (i = 0; i < 3; i++) - p->NS2Indx[i] = (Byte)i; - for (m = i, k = 1; i < 256; i++) - { - p->NS2Indx[i] = (Byte)m; - if (--k == 0) - k = (++m) - 2; - } + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } - memset(p->HB2Flag, 0, 0x40); - memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); } -void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) +void Ppmd7_Free(CPpmd7* p, ISzAlloc* alloc) { - alloc->Free(alloc, p->Base); - p->Size = 0; - p->Base = 0; + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; } -Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) +Bool Ppmd7_Alloc(CPpmd7* p, UInt32 size, ISzAlloc* alloc) { - if (p->Base == 0 || p->Size != size) - { - Ppmd7_Free(p, alloc); - p->AlignOffset = - #ifdef PPMD_32BIT + if (p->Base == 0 || p->Size != size) + { + Ppmd7_Free(p, alloc); + p->AlignOffset = +#ifdef PPMD_32BIT (4 - size) & 3; - #else - 4 - (size & 3); - #endif - if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size - #ifndef PPMD_32BIT - + UNIT_SIZE - #endif - )) == 0) - return False; - p->Size = size; - } - return True; +#else + 4 - (size & 3); +#endif + if ((p->Base = (Byte*)alloc->Alloc(alloc, p->AlignOffset + size +#ifndef PPMD_32BIT + + UNIT_SIZE +#endif + )) == 0) + return False; + p->Size = size; + } + return True; } -static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +static void InsertNode(CPpmd7* p, void* node, unsigned indx) { - *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; - p->FreeList[indx] = REF(node); + *((CPpmd_Void_Ref*)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); } -static void *RemoveNode(CPpmd7 *p, unsigned indx) +static void* RemoveNode(CPpmd7* p, unsigned indx) { - CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); - p->FreeList[indx] = *node; - return node; + CPpmd_Void_Ref* node = (CPpmd_Void_Ref*)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; } -static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +static void SplitBlock(CPpmd7* p, void* ptr, unsigned oldIndx, unsigned newIndx) { - unsigned i, nu = I2U(oldIndx) - I2U(newIndx); - ptr = (Byte *)ptr + U2B(I2U(newIndx)); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); - } - InsertNode(p, ptr, i); + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte*)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte*)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); } -static void GlueFreeBlocks(CPpmd7 *p) +static void GlueFreeBlocks(CPpmd7* p) { - #ifdef PPMD_32BIT +#ifdef PPMD_32BIT CPpmd7_Node headItem; CPpmd7_Node_Ref head = &headItem; - #else - CPpmd7_Node_Ref head = p->AlignOffset + p->Size; - #endif - - CPpmd7_Node_Ref n = head; - unsigned i; +#else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; +#endif - p->GlueCount = 255; + CPpmd7_Node_Ref n = head; + unsigned i; - /* create doubly-linked list of free blocks */ - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - UInt16 nu = I2U(i); - CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; - p->FreeList[i] = 0; - while (next != 0) - { - CPpmd7_Node *node = NODE(next); - node->Next = n; - n = NODE(n)->Prev = next; - next = *(const CPpmd7_Node_Ref *)node; - node->Stamp = 0; - node->NU = (UInt16)nu; - } - } - NODE(head)->Stamp = 1; - NODE(head)->Next = n; - NODE(n)->Prev = head; - if (p->LoUnit != p->HiUnit) - ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; - - /* Glue free blocks */ - while (n != head) - { - CPpmd7_Node *node = NODE(n); - UInt32 nu = (UInt32)node->NU; - for (;;) - { - CPpmd7_Node *node2 = NODE(n) + nu; - nu += node2->NU; - if (node2->Stamp != 0 || nu >= 0x10000) - break; - NODE(node2->Prev)->Next = node2->Next; - NODE(node2->Next)->Prev = node2->Prev; - node->NU = (UInt16)nu; - } - n = node->Next; - } - - /* Fill lists of free blocks */ - for (n = NODE(head)->Next; n != head;) - { - CPpmd7_Node *node = NODE(n); - unsigned nu; - CPpmd7_Node_Ref next = node->Next; - for (nu = node->NU; nu > 128; nu -= 128, node += 128) - InsertNode(p, node, PPMD_NUM_INDEXES - 1); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - InsertNode(p, node + k, nu - k - 1); - } - InsertNode(p, node, i); - n = next; - } + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node* node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref*)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node*)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node* node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node* node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node* node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } } -static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +static void* AllocUnitsRare(CPpmd7* p, unsigned indx) { - unsigned i; - void *retVal; - if (p->GlueCount == 0) - { - GlueFreeBlocks(p); - if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - } - i = indx; - do - { - if (++i == PPMD_NUM_INDEXES) - { - UInt32 numBytes = U2B(I2U(indx)); - p->GlueCount--; - return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); - } - } - while (p->FreeList[i] == 0); - retVal = RemoveNode(p, i); - SplitBlock(p, retVal, i, indx); - return retVal; + unsigned i; + void* retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; } -static void *AllocUnits(CPpmd7 *p, unsigned indx) +static void* AllocUnits(CPpmd7* p, unsigned indx) { - UInt32 numBytes; - if (p->FreeList[indx] != 0) - return RemoveNode(p, indx); - numBytes = U2B(I2U(indx)); - if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) - { - void *retVal = p->LoUnit; - p->LoUnit += numBytes; - return retVal; - } - return AllocUnitsRare(p, indx); + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void* retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); } #define MyMem12Cpy(dest, src, num) \ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } -static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +static void* ShrinkUnits(CPpmd7* p, void* oldPtr, unsigned oldNU, unsigned newNU) { - unsigned i0 = U2I(oldNU); - unsigned i1 = U2I(newNU); - if (i0 == i1) - return oldPtr; - if (p->FreeList[i1] != 0) - { - void *ptr = RemoveNode(p, i1); - MyMem12Cpy(ptr, oldPtr, newNU); - InsertNode(p, oldPtr, i0); - return ptr; - } - SplitBlock(p, oldPtr, i0, i1); - return oldPtr; + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void* ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; } #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) -static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +static void SetSuccessor(CPpmd_State* p, CPpmd_Void_Ref v) { - (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); - (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); } -static void RestartModel(CPpmd7 *p) +static void RestartModel(CPpmd7* p) { - unsigned i, k, m; + unsigned i, k, m; - memset(p->FreeList, 0, sizeof(p->FreeList)); - p->Text = p->Base + p->AlignOffset; - p->HiUnit = p->Text + p->Size; - p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; - p->GlueCount = 0; + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; - p->OrderFall = p->MaxOrder; - p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; - p->PrevSuccess = 0; + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; - p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ - p->MinContext->Suffix = 0; - p->MinContext->NumStats = 256; - p->MinContext->SummFreq = 256 + 1; - p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ - p->LoUnit += U2B(256 / 2); - p->MinContext->Stats = REF(p->FoundState); - for (i = 0; i < 256; i++) - { - CPpmd_State *s = &p->FoundState[i]; - s->Symbol = (Byte)i; - s->Freq = 1; - SetSuccessor(s, 0); - } + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State*)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State* s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } - for (i = 0; i < 128; i++) - for (k = 0; k < 8; k++) - { - UInt16 *dest = p->BinSumm[i] + k; - UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); - for (m = 0; m < 64; m += 8) - dest[m] = val; - } - - for (i = 0; i < 25; i++) - for (k = 0; k < 16; k++) - { - CPpmd_See *s = &p->See[i][k]; - s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); - s->Count = 4; - } + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16* dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See* s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } } -void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +void Ppmd7_Init(CPpmd7* p, unsigned maxOrder) { - p->MaxOrder = maxOrder; - RestartModel(p); - p->DummySee.Shift = PPMD_PERIOD_BITS; - p->DummySee.Summ = 0; /* unused */ - p->DummySee.Count = 64; /* unused */ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ } -static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) +static CTX_PTR CreateSuccessors(CPpmd7* p, Bool skip) { - CPpmd_State upState; - CTX_PTR c = p->MinContext; - CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); - CPpmd_State *ps[PPMD7_MAX_ORDER]; - unsigned numPs = 0; - - if (!skip) - ps[numPs++] = p->FoundState; - - while (c->Suffix) - { - CPpmd_Void_Ref successor; - CPpmd_State *s; - c = SUFFIX(c); - if (c->NumStats != 1) - { - for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); - } - else - s = ONE_STATE(c); - successor = SUCCESSOR(s); - if (successor != upBranch) - { - c = CTX(successor); - if (numPs == 0) - return c; - break; - } - ps[numPs++] = s; - } - - upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); - SetSuccessor(&upState, upBranch + 1); - - if (c->NumStats == 1) - upState.Freq = ONE_STATE(c)->Freq; - else - { - UInt32 cf, s0; - CPpmd_State *s; - for (s = STATS(c); s->Symbol != upState.Symbol; s++); - cf = s->Freq - 1; - s0 = c->SummFreq - c->NumStats - cf; - upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); - } + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State* ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; - do - { - /* Create Child */ - CTX_PTR c1; /* = AllocContext(p); */ - if (p->HiUnit != p->LoUnit) - c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); - else if (p->FreeList[0] != 0) - c1 = (CTX_PTR)RemoveNode(p, 0); - else - { - c1 = (CTX_PTR)AllocUnitsRare(p, 0); - if (!c1) - return NULL; - } - c1->NumStats = 1; - *ONE_STATE(c1) = upState; - c1->Suffix = REF(c); - SetSuccessor(ps[--numPs], REF(c1)); - c = c1; - } - while (numPs != 0); - - return c; + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State* s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte*)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State* s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; } -static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +static void SwapStates(CPpmd_State* t1, CPpmd_State* t2) { - CPpmd_State tmp = *t1; - *t1 = *t2; - *t2 = tmp; + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; } -static void UpdateModel(CPpmd7 *p) +static void UpdateModel(CPpmd7* p) { - CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); - CTX_PTR c; - unsigned s0, ns; - - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) - { - c = SUFFIX(p->MinContext); - - if (c->NumStats == 1) - { - CPpmd_State *s = ONE_STATE(c); - if (s->Freq < 32) - s->Freq++; - } - else - { - CPpmd_State *s = STATS(c); - if (s->Symbol != p->FoundState->Symbol) - { - do { s++; } while (s->Symbol != p->FoundState->Symbol); - if (s[0].Freq >= s[-1].Freq) - { - SwapStates(&s[0], &s[-1]); - s--; - } - } - if (s->Freq < MAX_FREQ - 9) - { - s->Freq += 2; - c->SummFreq += 2; - } - } - } + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; - if (p->OrderFall == 0) - { - p->MinContext = p->MaxContext = CreateSuccessors(p, True); - if (p->MinContext == 0) - { - RestartModel(p); - return; - } - SetSuccessor(p->FoundState, REF(p->MinContext)); - return; - } - - *p->Text++ = p->FoundState->Symbol; - successor = REF(p->Text); - if (p->Text >= p->UnitsStart) - { - RestartModel(p); - return; - } - - if (fSuccessor) - { - if (fSuccessor <= successor) - { - CTX_PTR cs = CreateSuccessors(p, False); - if (cs == NULL) - { - RestartModel(p); - return; - } - fSuccessor = REF(cs); - } - if (--p->OrderFall == 0) - { - successor = fSuccessor; - p->Text -= (p->MaxContext != p->MinContext); - } - } - else - { - SetSuccessor(p->FoundState, successor); - fSuccessor = REF(p->MinContext); - } - - s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); - - for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) - { - unsigned ns1; - UInt32 cf, sf; - if ((ns1 = c->NumStats) != 1) - { - if ((ns1 & 1) == 0) - { - /* Expand for one UNIT */ - unsigned oldNU = ns1 >> 1; - unsigned i = U2I(oldNU); - if (i != U2I(oldNU + 1)) - { - void *ptr = AllocUnits(p, i + 1); - void *oldPtr; - if (!ptr) - { - RestartModel(p); - return; - } - oldPtr = STATS(c); - MyMem12Cpy(ptr, oldPtr, oldNU); - InsertNode(p, oldPtr, i); - c->Stats = STATS_REF(ptr); - } - } - c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); - } - else - { - CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); - if (!s) - { - RestartModel(p); - return; - } - *s = *ONE_STATE(c); - c->Stats = REF(s); - if (s->Freq < MAX_FREQ / 4 - 1) - s->Freq <<= 1; - else - s->Freq = MAX_FREQ - 4; - c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); - } - cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); - sf = (UInt32)s0 + c->SummFreq; - if (cf < 6 * sf) - { - cf = 1 + (cf > sf) + (cf >= 4 * sf); - c->SummFreq += 3; - } - else - { - cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); - c->SummFreq = (UInt16)(c->SummFreq + cf); - } - { - CPpmd_State *s = STATS(c) + ns1; - SetSuccessor(s, successor); - s->Symbol = p->FoundState->Symbol; - s->Freq = (Byte)cf; - c->NumStats = (UInt16)(ns1 + 1); - } - } - p->MaxContext = p->MinContext = CTX(fSuccessor); -} - -static void Rescale(CPpmd7 *p) -{ - unsigned i, adder, sumFreq, escFreq; - CPpmd_State *stats = STATS(p->MinContext); - CPpmd_State *s = p->FoundState; - { - CPpmd_State tmp = *s; - for (; s != stats; s--) - s[0] = s[-1]; - *s = tmp; - } - escFreq = p->MinContext->SummFreq - s->Freq; - s->Freq += 4; - adder = (p->OrderFall != 0); - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq = s->Freq; - - i = p->MinContext->NumStats - 1; - do - { - escFreq -= (++s)->Freq; - s->Freq = (Byte)((s->Freq + adder) >> 1); - sumFreq += s->Freq; - if (s[0].Freq > s[-1].Freq) - { - CPpmd_State *s1 = s; - CPpmd_State tmp = *s1; - do - s1[0] = s1[-1]; - while (--s1 != stats && tmp.Freq > s1[-1].Freq); - *s1 = tmp; - } - } - while (--i); - - if (s->Freq == 0) - { - unsigned numStats = p->MinContext->NumStats; - unsigned n0, n1; - do { i++; } while ((--s)->Freq == 0); - escFreq += i; - p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); - if (p->MinContext->NumStats == 1) - { - CPpmd_State tmp = *stats; - do - { - tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); - escFreq >>= 1; - } - while (escFreq > 1); - InsertNode(p, stats, U2I(((numStats + 1) >> 1))); - *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; - return; - } - n0 = (numStats + 1) >> 1; - n1 = (p->MinContext->NumStats + 1) >> 1; - if (n0 != n1) - p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); - } - p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); - p->FoundState = STATS(p->MinContext); + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State* s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State* s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } + while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void* ptr = AllocUnits(p, i + 1); + void* oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State* s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State* s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); } -CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +static void Rescale(CPpmd7* p) { - CPpmd_See *see; - unsigned nonMasked = p->MinContext->NumStats - numMasked; - if (p->MinContext->NumStats != 256) - { - see = p->See[(unsigned)p->NS2Indx[nonMasked - 1]] + - (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + - 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + - 4 * (unsigned)(numMasked > nonMasked) + - p->HiBitsFlag; - { - unsigned r = (see->Summ >> see->Shift); - see->Summ = (UInt16)(see->Summ - r); - *escFreq = r + (r == 0); - } - } - else - { - see = &p->DummySee; - *escFreq = 1; - } - return see; + unsigned i, adder, sumFreq, escFreq; + CPpmd_State* stats = STATS(p->MinContext); + CPpmd_State* s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State* s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } + while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); } -static void NextContext(CPpmd7 *p) +CPpmd_See* Ppmd7_MakeEscFreq(CPpmd7* p, unsigned numMasked, UInt32* escFreq) { - CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); - if (p->OrderFall == 0 && (Byte *)c > p->Text) - p->MinContext = p->MaxContext = c; - else - UpdateModel(p); + CPpmd_See* see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[(unsigned)p->NS2Indx[nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (unsigned)(numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; } -void Ppmd7_Update1(CPpmd7 *p) +static void NextContext(CPpmd7* p) { - CPpmd_State *s = p->FoundState; - s->Freq += 4; - p->MinContext->SummFreq += 4; - if (s[0].Freq > s[-1].Freq) - { - SwapStates(&s[0], &s[-1]); - p->FoundState = --s; - if (s->Freq > MAX_FREQ) - Rescale(p); - } - NextContext(p); + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte*)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); } -void Ppmd7_Update1_0(CPpmd7 *p) +void Ppmd7_Update1(CPpmd7* p) { - p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); - p->RunLength += p->PrevSuccess; - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - NextContext(p); + CPpmd_State* s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); } -void Ppmd7_UpdateBin(CPpmd7 *p) +void Ppmd7_Update1_0(CPpmd7* p) { - p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); - p->PrevSuccess = 1; - p->RunLength++; - NextContext(p); + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); } -void Ppmd7_Update2(CPpmd7 *p) +void Ppmd7_UpdateBin(CPpmd7* p) { - p->MinContext->SummFreq += 4; - if ((p->FoundState->Freq += 4) > MAX_FREQ) - Rescale(p); - p->RunLength = p->InitRL; - UpdateModel(p); + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1 : 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7* p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); } diff --git a/SevenZip/Ppmd7.h b/SevenZip/Ppmd7.h index 87eefde..f1675dd 100644 --- a/SevenZip/Ppmd7.h +++ b/SevenZip/Ppmd7.h @@ -22,47 +22,47 @@ EXTERN_C_BEGIN struct CPpmd7_Context_; typedef - #ifdef PPMD_32BIT +#ifdef PPMD_32BIT struct CPpmd7_Context_ * - #else - UInt32 - #endif - CPpmd7_Context_Ref; +#else +UInt32 +#endif +CPpmd7_Context_Ref; typedef struct CPpmd7_Context_ { - UInt16 NumStats; - UInt16 SummFreq; - CPpmd_State_Ref Stats; - CPpmd7_Context_Ref Suffix; + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; } CPpmd7_Context; #define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) typedef struct { - CPpmd7_Context *MinContext, *MaxContext; - CPpmd_State *FoundState; - unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; - Int32 RunLength, InitRL; /* must be 32-bit at least */ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State* FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ - UInt32 Size; - UInt32 GlueCount; - Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; - UInt32 AlignOffset; + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; - Byte Indx2Units[PPMD_NUM_INDEXES]; - Byte Units2Indx[128]; - CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; - Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; - CPpmd_See DummySee, See[25][16]; - UInt16 BinSumm[128][64]; + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; } CPpmd7; -void Ppmd7_Construct(CPpmd7 *p); -Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); -void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); -void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +void Ppmd7_Construct(CPpmd7* p); +Bool Ppmd7_Alloc(CPpmd7* p, UInt32 size, ISzAlloc* alloc); +void Ppmd7_Free(CPpmd7* p, ISzAlloc* alloc); +void Ppmd7_Init(CPpmd7* p, unsigned maxOrder); #define Ppmd7_WasAllocated(p) ((p)->Base != NULL) @@ -75,15 +75,15 @@ extern const Byte PPMD7_kExpEscape[16]; #define Ppmd7_GetContext(p, ptr) (ptr) #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) #else - #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) - #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) - #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) +#define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) +#define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) #endif -void Ppmd7_Update1(CPpmd7 *p); -void Ppmd7_Update1_0(CPpmd7 *p); -void Ppmd7_Update2(CPpmd7 *p); -void Ppmd7_UpdateBin(CPpmd7 *p); +void Ppmd7_Update1(CPpmd7* p); +void Ppmd7_Update1_0(CPpmd7* p); +void Ppmd7_Update2(CPpmd7* p); +void Ppmd7_UpdateBin(CPpmd7* p); #define Ppmd7_GetBinSumm(p) \ &p->BinSumm[(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ @@ -92,49 +92,49 @@ void Ppmd7_UpdateBin(CPpmd7 *p); 2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \ ((p->RunLength >> 26) & 0x20)] -CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); +CPpmd_See* Ppmd7_MakeEscFreq(CPpmd7* p, unsigned numMasked, UInt32* scale); /* ---------- Decode ---------- */ typedef struct { - UInt32 (*GetThreshold)(void *p, UInt32 total); - void (*Decode)(void *p, UInt32 start, UInt32 size); - UInt32 (*DecodeBit)(void *p, UInt32 size0); + UInt32 (*GetThreshold)(void* p, UInt32 total); + void (*Decode)(void* p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(void* p, UInt32 size0); } IPpmd7_RangeDec; typedef struct { - IPpmd7_RangeDec p; - UInt32 Range; - UInt32 Code; - IByteIn *Stream; + IPpmd7_RangeDec p; + UInt32 Range; + UInt32 Code; + IByteIn* Stream; } CPpmd7z_RangeDec; -void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); -Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec* p); +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec* p); #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); +int Ppmd7_DecodeSymbol(CPpmd7* p, IPpmd7_RangeDec* rc); /* ---------- Encode ---------- */ typedef struct { - UInt64 Low; - UInt32 Range; - Byte Cache; - UInt64 CacheSize; - IByteOut *Stream; + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut* Stream; } CPpmd7z_RangeEnc; -void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); -void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc* p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc* p); -void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); +void Ppmd7_EncodeSymbol(CPpmd7* p, CPpmd7z_RangeEnc* rc, int symbol); EXTERN_C_END - + #endif diff --git a/SevenZip/Ppmd7Dec.c b/SevenZip/Ppmd7Dec.c index 04b4b09..23d8430 100644 --- a/SevenZip/Ppmd7Dec.c +++ b/SevenZip/Ppmd7Dec.c @@ -8,182 +8,184 @@ This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #define kTopValue (1 << 24) -Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec* p) { - unsigned i; - p->Code = 0; - p->Range = 0xFFFFFFFF; - if (p->Stream->Read((void *)p->Stream) != 0) - return False; - for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); - return (p->Code < 0xFFFFFFFF); + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (p->Stream->Read((void*)p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream->Read((void*)p->Stream); + return (p->Code < 0xFFFFFFFF); } -static UInt32 Range_GetThreshold(void *pp, UInt32 total) +static UInt32 Range_GetThreshold(void* pp, UInt32 total) { - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - return (p->Code) / (p->Range /= total); + CPpmd7z_RangeDec* p = (CPpmd7z_RangeDec*)pp; + return (p->Code) / (p->Range /= total); } -static void Range_Normalize(CPpmd7z_RangeDec *p) +static void Range_Normalize(CPpmd7z_RangeDec* p) { - if (p->Range < kTopValue) - { - p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); - p->Range <<= 8; - if (p->Range < kTopValue) - { - p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); - p->Range <<= 8; - } - } + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void*)p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void*)p->Stream); + p->Range <<= 8; + } + } } -static void Range_Decode(void *pp, UInt32 start, UInt32 size) +static void Range_Decode(void* pp, UInt32 start, UInt32 size) { - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - p->Code -= start * p->Range; - p->Range *= size; - Range_Normalize(p); + CPpmd7z_RangeDec* p = (CPpmd7z_RangeDec*)pp; + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); } -static UInt32 Range_DecodeBit(void *pp, UInt32 size0) +static UInt32 Range_DecodeBit(void* pp, UInt32 size0) { - CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; - UInt32 newBound = (p->Range >> 14) * size0; - UInt32 symbol; - if (p->Code < newBound) - { - symbol = 0; - p->Range = newBound; - } - else - { - symbol = 1; - p->Code -= newBound; - p->Range -= newBound; - } - Range_Normalize(p); - return symbol; + CPpmd7z_RangeDec* p = (CPpmd7z_RangeDec*)pp; + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; } -void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec* p) { - p->p.GetThreshold = Range_GetThreshold; - p->p.Decode = Range_Decode; - p->p.DecodeBit = Range_DecodeBit; + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode; + p->p.DecodeBit = Range_DecodeBit; } #define MASK(sym) ((signed char *)charMask)[sym] -int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) +int Ppmd7_DecodeSymbol(CPpmd7* p, IPpmd7_RangeDec* rc) { - size_t charMask[256 / sizeof(size_t)]; - if (p->MinContext->NumStats != 1) - { - CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); - unsigned i; - UInt32 count, hiCnt; - if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) - { - Byte symbol; - rc->Decode(rc, 0, s->Freq); - p->FoundState = s; - symbol = s->Symbol; - Ppmd7_Update1_0(p); - return symbol; - } - p->PrevSuccess = 0; - i = p->MinContext->NumStats - 1; - do - { - if ((hiCnt += (++s)->Freq) > count) - { - Byte symbol; - rc->Decode(rc, hiCnt - s->Freq, s->Freq); - p->FoundState = s; - symbol = s->Symbol; - Ppmd7_Update1(p); - return symbol; - } - } - while (--i); - if (count >= p->MinContext->SummFreq) - return -2; - p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; - rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(s->Symbol) = 0; - i = p->MinContext->NumStats - 1; - do { MASK((--s)->Symbol) = 0; } while (--i); - } - else - { - UInt16 *prob = Ppmd7_GetBinSumm(p); - if (rc->DecodeBit(rc, *prob) == 0) - { - Byte symbol; - *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); - symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; - Ppmd7_UpdateBin(p); - return symbol; - } - *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); - p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; - PPMD_SetAllBitsIn256Bytes(charMask); - MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; - p->PrevSuccess = 0; - } - for (;;) - { - CPpmd_State *ps[256], *s; - UInt32 freqSum, count, hiCnt; - CPpmd_See *see; - unsigned i, num, numMasked = p->MinContext->NumStats; - do - { - p->OrderFall++; - if (!p->MinContext->Suffix) - return -1; - p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); - } - while (p->MinContext->NumStats == numMasked); - hiCnt = 0; - s = Ppmd7_GetStats(p, p->MinContext); - i = 0; - num = p->MinContext->NumStats - numMasked; - do - { - int k = (int)(MASK(s->Symbol)); - hiCnt += (s->Freq & k); - ps[i] = s++; - i -= k; - } - while (i != num); - - see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); - freqSum += hiCnt; - count = rc->GetThreshold(rc, freqSum); - - if (count < hiCnt) - { - Byte symbol; - CPpmd_State **pps = ps; - for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); - s = *pps; - rc->Decode(rc, hiCnt - s->Freq, s->Freq); - Ppmd_See_Update(see); - p->FoundState = s; - symbol = s->Symbol; - Ppmd7_Update2(p); - return symbol; - } - if (count >= freqSum) - return -2; - rc->Decode(rc, hiCnt, freqSum - hiCnt); - see->Summ = (UInt16)(see->Summ + freqSum); - do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); - } + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State* s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } + while (--i); + } + else + { + UInt16* prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See* see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State** pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } + while (i != 0); + } } diff --git a/Utilities/ArchiveReader.cpp b/Utilities/ArchiveReader.cpp index e271ef9..2ed6951 100644 --- a/Utilities/ArchiveReader.cpp +++ b/Utilities/ArchiveReader.cpp @@ -12,11 +12,13 @@ ArchiveReader::~ArchiveReader() delete[] _buffer; } -bool ArchiveReader::GetStream(string filename, std::stringstream &stream) +bool ArchiveReader::GetStream(string filename, std::stringstream& stream) { - if(_initialized) { + if (_initialized) + { vector fileData; - if(ExtractFile(filename, fileData)) { + if (ExtractFile(filename, fileData)) + { stream.write((char*)fileData.data(), fileData.size()); return true; } @@ -26,17 +28,22 @@ bool ArchiveReader::GetStream(string filename, std::stringstream &stream) vector ArchiveReader::GetFileList(std::initializer_list extensions) { - if(extensions.size() == 0) { + if (extensions.size() == 0) + { return InternalGetFileList(); } vector filenames; - for(string filename : InternalGetFileList()) { + for (string filename : InternalGetFileList()) + { string lcFilename = filename; std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), ::tolower); - for(string ext : extensions) { - if(lcFilename.size() >= ext.size()) { - if(lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0) { + for (string ext : extensions) + { + if (lcFilename.size() >= ext.size()) + { + if (lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0) + { filenames.push_back(filename); } } @@ -52,7 +59,7 @@ bool ArchiveReader::CheckFile(string filename) return std::find(files.begin(), files.end(), filename) != files.end(); } -bool ArchiveReader::LoadArchive(std::istream &in) +bool ArchiveReader::LoadArchive(std::istream& in) { in.seekg(0, std::ios::end); std::streampos filesize = in.tellg(); @@ -66,14 +73,15 @@ bool ArchiveReader::LoadArchive(std::istream &in) return result; } -bool ArchiveReader::LoadArchive(vector &data) +bool ArchiveReader::LoadArchive(vector& data) { return LoadArchive(data.data(), data.size()); } bool ArchiveReader::LoadArchive(void* buffer, size_t size) { - if(InternalLoadArchive(buffer, size)) { + if (InternalLoadArchive(buffer, size)) + { _initialized = true; return true; } @@ -83,26 +91,31 @@ bool ArchiveReader::LoadArchive(void* buffer, size_t size) bool ArchiveReader::LoadArchive(string filename) { ifstream in(filename, std::ios::binary | std::ios::in); - if(in.good()) { + if (in.good()) + { LoadArchive(in); in.close(); } return false; } -shared_ptr ArchiveReader::GetReader(std::istream &in) +shared_ptr ArchiveReader::GetReader(std::istream& in) { - uint8_t header[2] = { 0,0 }; + uint8_t header[2] = {0, 0}; in.read((char*)header, 2); shared_ptr reader; - if(memcmp(header, "PK", 2) == 0) { + if (memcmp(header, "PK", 2) == 0) + { reader.reset(new ZipReader()); - } else if(memcmp(header, "7z", 2) == 0) { + } + else if (memcmp(header, "7z", 2) == 0) + { reader.reset(new SZReader()); } - if(reader) { + if (reader) + { reader->LoadArchive(in); } return reader; @@ -111,8 +124,9 @@ shared_ptr ArchiveReader::GetReader(std::istream &in) shared_ptr ArchiveReader::GetReader(string filepath) { ifstream in(filepath, std::ios::in | std::ios::binary); - if(in) { + if (in) + { return GetReader(in); } return nullptr; -} \ No newline at end of file +} diff --git a/Utilities/ArchiveReader.h b/Utilities/ArchiveReader.h index a2076c8..790c23f 100644 --- a/Utilities/ArchiveReader.h +++ b/Utilities/ArchiveReader.h @@ -14,15 +14,15 @@ public: bool LoadArchive(void* buffer, size_t size); bool LoadArchive(vector& data); bool LoadArchive(string filename); - bool LoadArchive(std::istream &in); + bool LoadArchive(std::istream& in); - bool GetStream(string filename, std::stringstream &stream); + bool GetStream(string filename, std::stringstream& stream); vector GetFileList(std::initializer_list extensions = {}); bool CheckFile(string filename); - virtual bool ExtractFile(string filename, vector &output) = 0; + virtual bool ExtractFile(string filename, vector& output) = 0; - static shared_ptr GetReader(std::istream &in); + static shared_ptr GetReader(std::istream& in); static shared_ptr GetReader(string filepath); -}; \ No newline at end of file +}; diff --git a/Utilities/AutoResetEvent.cpp b/Utilities/AutoResetEvent.cpp index f04943c..e5b4ee3 100644 --- a/Utilities/AutoResetEvent.cpp +++ b/Utilities/AutoResetEvent.cpp @@ -15,10 +15,13 @@ AutoResetEvent::~AutoResetEvent() void AutoResetEvent::Wait(int timeoutDelay) { std::unique_lock lock(_mutex); - if(timeoutDelay == 0) { + if (timeoutDelay == 0) + { //Wait until signaled _signal.wait(lock, [this] { return _signaled; }); - } else { + } + else + { //Wait until signaled or timeout auto timeoutTime = std::chrono::system_clock::now() + std::chrono::duration(timeoutDelay); _signal.wait_until(lock, timeoutTime, [this] { return _signaled; }); diff --git a/Utilities/AutoResetEvent.h b/Utilities/AutoResetEvent.h index b272f1d..17269d2 100644 --- a/Utilities/AutoResetEvent.h +++ b/Utilities/AutoResetEvent.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "stdafx.h" #include diff --git a/Utilities/AviRecorder.cpp b/Utilities/AviRecorder.cpp index ca0532f..fe39685 100644 --- a/Utilities/AviRecorder.cpp +++ b/Utilities/AviRecorder.cpp @@ -14,19 +14,23 @@ AviRecorder::AviRecorder(VideoCodec codec, uint32_t compressionLevel) AviRecorder::~AviRecorder() { - if(_recording) { + if (_recording) + { StopRecording(); } - if(_frameBuffer) { + if (_frameBuffer) + { delete[] _frameBuffer; _frameBuffer = nullptr; } } -bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) +bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, + uint32_t audioSampleRate, double fps) { - if(!_recording) { + if (!_recording) + { _outputFile = filename; _sampleRate = audioSampleRate; _width = width; @@ -36,15 +40,20 @@ bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t heigh _frameBuffer = new uint8_t[_frameBufferLength]; _aviWriter.reset(new AviWriter()); - if(!_aviWriter->StartWrite(filename, _codec, width, height, bpp, (uint32_t)(_fps * 1000000), audioSampleRate, _compressionLevel)) { + if (!_aviWriter->StartWrite(filename, _codec, width, height, bpp, (uint32_t)(_fps * 1000000), audioSampleRate, + _compressionLevel)) + { _aviWriter.reset(); return false; } - _aviWriterThread = std::thread([=]() { - while(!_stopFlag) { + _aviWriterThread = std::thread([=]() + { + while (!_stopFlag) + { _waitFrame.Wait(); - if(_stopFlag) { + if (_stopFlag) + { break; } @@ -60,7 +69,8 @@ bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t heigh void AviRecorder::StopRecording() { - if(_recording) { + if (_recording) + { _recording = false; _stopFlag = true; @@ -74,10 +84,14 @@ void AviRecorder::StopRecording() void AviRecorder::AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) { - if(_recording) { - if(_width != width || _height != height || _fps != fps) { + if (_recording) + { + if (_width != width || _height != height || _fps != fps) + { StopRecording(); - } else { + } + else + { auto lock = _lock.AcquireSafe(); memcpy(_frameBuffer, frameBuffer, _frameBufferLength); _waitFrame.Signal(); @@ -87,11 +101,15 @@ void AviRecorder::AddFrame(void* frameBuffer, uint32_t width, uint32_t height, d void AviRecorder::AddSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate) { - if(_recording) { - if(_sampleRate != sampleRate) { + if (_recording) + { + if (_sampleRate != sampleRate) + { auto lock = _lock.AcquireSafe(); StopRecording(); - } else { + } + else + { _aviWriter->AddSound(soundBuffer, sampleCount); } } @@ -105,4 +123,4 @@ bool AviRecorder::IsRecording() string AviRecorder::GetOutputFile() { return _outputFile; -} \ No newline at end of file +} diff --git a/Utilities/AviRecorder.h b/Utilities/AviRecorder.h index f79ecd4..396f634 100644 --- a/Utilities/AviRecorder.h +++ b/Utilities/AviRecorder.h @@ -12,14 +12,14 @@ class AviRecorder : public IVideoRecorder { private: std::thread _aviWriterThread; - + unique_ptr _aviWriter; string _outputFile; SimpleLock _lock; AutoResetEvent _waitFrame; - atomic _stopFlag; + atomic _stopFlag; bool _recording; uint8_t* _frameBuffer; uint32_t _frameBufferLength; @@ -36,7 +36,8 @@ public: AviRecorder(VideoCodec codec, uint32_t compressionLevel); virtual ~AviRecorder(); - bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) override; + bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, + double fps) override; void StopRecording() override; void AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) override; @@ -44,4 +45,4 @@ public: bool IsRecording() override; string GetOutputFile() override; -}; \ No newline at end of file +}; diff --git a/Utilities/AviWriter.cpp b/Utilities/AviWriter.cpp index fdd63fc..82f2ee2 100644 --- a/Utilities/AviWriter.cpp +++ b/Utilities/AviWriter.cpp @@ -28,15 +28,15 @@ #include "ZmbvCodec.h" #include "CamstudioCodec.h" -void AviWriter::WriteAviChunk(const char *tag, uint32_t size, void *data, uint32_t flags) +void AviWriter::WriteAviChunk(const char* tag, uint32_t size, void* data, uint32_t flags) { - uint8_t chunk[8] = { (uint8_t)tag[0], (uint8_t)tag[1], (uint8_t)tag[2], (uint8_t)tag[3] }; + uint8_t chunk[8] = {(uint8_t)tag[0], (uint8_t)tag[1], (uint8_t)tag[2], (uint8_t)tag[3]}; host_writed(&chunk[4], size); _file.write((char*)chunk, 8); - - uint32_t writesize = (size + 1)&~1; + + uint32_t writesize = (size + 1) & ~1; _file.write((char*)data, writesize); - + uint32_t pos = _written + 4; _written += writesize + 8; @@ -64,26 +64,33 @@ void AviWriter::host_writed(uint8_t* buffer, uint32_t value) buffer[3] = value >> 24; } -bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel) +bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, + uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel) { _codecType = codec; _file.open(filename, std::ios::out | std::ios::binary); - if(!_file) { - return false; - } - - switch(_codecType) { - default: - case VideoCodec::None: _codec.reset(new RawCodec()); break; - case VideoCodec::ZMBV: _codec.reset(new ZmbvCodec()); break; - case VideoCodec::CSCD: _codec.reset(new CamstudioCodec()); break; - } - - if(!_codec->SetupCompress(width, height, compressionLevel)) { + if (!_file) + { return false; } - _frameBuffer = new uint8_t[width*height*bpp]; + switch (_codecType) + { + default: + case VideoCodec::None: _codec.reset(new RawCodec()); + break; + case VideoCodec::ZMBV: _codec.reset(new ZmbvCodec()); + break; + case VideoCodec::CSCD: _codec.reset(new CamstudioCodec()); + break; + } + + if (!_codec->SetupCompress(width, height, compressionLevel)) + { + return false; + } + + _frameBuffer = new uint8_t[width * height * bpp]; _aviIndex.clear(); _aviIndex.insert(_aviIndex.end(), 8, 0); @@ -95,7 +102,8 @@ bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, ui _audiorate = audioSampleRate; - for(int i = 0; i < AviWriter::AviHeaderSize; i++) { + for (int i = 0; i < AviWriter::AviHeaderSize; i++) + { _file.put(0); } _frames = 0; @@ -116,100 +124,100 @@ void AviWriter::EndWrite() #define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2; #define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4; /* Try and write an avi header */ - AVIOUT4("RIFF"); // Riff header + AVIOUT4("RIFF"); // Riff header AVIOUTd(AviWriter::AviHeaderSize + _written - 8 + (uint32_t)_aviIndex.size()); AVIOUT4("AVI "); - AVIOUT4("LIST"); // List header + AVIOUT4("LIST"); // List header main_list = header_pos; - AVIOUTd(0); // TODO size of list + AVIOUTd(0); // TODO size of list AVIOUT4("hdrl"); AVIOUT4("avih"); - AVIOUTd(56); /* # of bytes to follow */ - AVIOUTd((uint32_t)(1000000 / _fps)); /* Microseconds per frame */ + AVIOUTd(56); /* # of bytes to follow */ + AVIOUTd((uint32_t)(1000000 / _fps)); /* Microseconds per frame */ AVIOUTd(0); - AVIOUTd(0); /* PaddingGranularity (whatever that might be) */ - AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */ - AVIOUTd(_frames); /* TotalFrames */ - AVIOUTd(0); /* InitialFrames */ - AVIOUTd(2); /* Stream count */ - AVIOUTd(0); /* SuggestedBufferSize */ - AVIOUTd(_width); /* Width */ - AVIOUTd(_height); /* Height */ - AVIOUTd(0); /* TimeScale: Unit used to measure time */ - AVIOUTd(0); /* DataRate: Data rate of playback */ - AVIOUTd(0); /* StartTime: Starting time of AVI data */ - AVIOUTd(0); /* DataLength: Size of AVI data chunk */ + AVIOUTd(0); /* PaddingGranularity (whatever that might be) */ + AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */ + AVIOUTd(_frames); /* TotalFrames */ + AVIOUTd(0); /* InitialFrames */ + AVIOUTd(2); /* Stream count */ + AVIOUTd(0); /* SuggestedBufferSize */ + AVIOUTd(_width); /* Width */ + AVIOUTd(_height); /* Height */ + AVIOUTd(0); /* TimeScale: Unit used to measure time */ + AVIOUTd(0); /* DataRate: Data rate of playback */ + AVIOUTd(0); /* StartTime: Starting time of AVI data */ + AVIOUTd(0); /* DataLength: Size of AVI data chunk */ - /* Video stream list */ + /* Video stream list */ AVIOUT4("LIST"); - AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */ + AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */ AVIOUT4("strl"); /* video stream header */ AVIOUT4("strh"); - AVIOUTd(56); /* # of bytes to follow */ - AVIOUT4("vids"); /* Type */ - AVIOUT4(_codec->GetFourCC()); /* Handler */ - AVIOUTd(0); /* Flags */ - AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ - AVIOUTd(0); /* InitialFrames */ - AVIOUTd(1000000); /* Scale */ - AVIOUTd(_fps); /* Rate: Rate/Scale == samples/second */ - AVIOUTd(0); /* Start */ - AVIOUTd(_frames); /* Length */ - AVIOUTd(0); /* SuggestedBufferSize */ - AVIOUTd(~0); /* Quality */ - AVIOUTd(0); /* SampleSize */ - AVIOUTd(0); /* Frame */ - AVIOUTd(0); /* Frame */ - /* The video stream format */ + AVIOUTd(56); /* # of bytes to follow */ + AVIOUT4("vids"); /* Type */ + AVIOUT4(_codec->GetFourCC()); /* Handler */ + AVIOUTd(0); /* Flags */ + AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ + AVIOUTd(0); /* InitialFrames */ + AVIOUTd(1000000); /* Scale */ + AVIOUTd(_fps); /* Rate: Rate/Scale == samples/second */ + AVIOUTd(0); /* Start */ + AVIOUTd(_frames); /* Length */ + AVIOUTd(0); /* SuggestedBufferSize */ + AVIOUTd(~0); /* Quality */ + AVIOUTd(0); /* SampleSize */ + AVIOUTd(0); /* Frame */ + AVIOUTd(0); /* Frame */ + /* The video stream format */ AVIOUT4("strf"); - AVIOUTd(40); /* # of bytes to follow */ - AVIOUTd(40); /* Size */ - AVIOUTd(_width); /* Width */ - AVIOUTd(_height); /* Height */ - // OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ - AVIOUTw(1); //number of planes + AVIOUTd(40); /* # of bytes to follow */ + AVIOUTd(40); /* Size */ + AVIOUTd(_width); /* Width */ + AVIOUTd(_height); /* Height */ + // OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ + AVIOUTw(1); //number of planes AVIOUTw(24); //bits for colors - AVIOUT4(_codec->GetFourCC()); /* Compression */ - AVIOUTd(_width * _height * 4); /* SizeImage (in bytes?) */ - AVIOUTd(0); /* XPelsPerMeter */ - AVIOUTd(0); /* YPelsPerMeter */ - AVIOUTd(0); /* ClrUsed: Number of colors used */ - AVIOUTd(0); /* ClrImportant: Number of colors important */ + AVIOUT4(_codec->GetFourCC()); /* Compression */ + AVIOUTd(_width * _height * 4); /* SizeImage (in bytes?) */ + AVIOUTd(0); /* XPelsPerMeter */ + AVIOUTd(0); /* YPelsPerMeter */ + AVIOUTd(0); /* ClrUsed: Number of colors used */ + AVIOUTd(0); /* ClrImportant: Number of colors important */ - /* Audio stream list */ + /* Audio stream list */ AVIOUT4("LIST"); - AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */ + AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */ AVIOUT4("strl"); /* The audio stream header */ AVIOUT4("strh"); - AVIOUTd(56); /* # of bytes to follow */ + AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("auds"); - AVIOUTd(0); /* Format (Optionally) */ - AVIOUTd(0); /* Flags */ - AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ - AVIOUTd(0); /* InitialFrames */ - AVIOUTd(4); /* Scale */ - AVIOUTd(_audiorate * 4); /* Rate, actual rate is scale/rate */ - AVIOUTd(0); /* Start */ - if(!_audiorate) + AVIOUTd(0); /* Format (Optionally) */ + AVIOUTd(0); /* Flags */ + AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ + AVIOUTd(0); /* InitialFrames */ + AVIOUTd(4); /* Scale */ + AVIOUTd(_audiorate * 4); /* Rate, actual rate is scale/rate */ + AVIOUTd(0); /* Start */ + if (!_audiorate) _audiorate = 1; - AVIOUTd(_audiowritten / 4); /* Length */ - AVIOUTd(0); /* SuggestedBufferSize */ - AVIOUTd(~0); /* Quality */ - AVIOUTd(4); /* SampleSize */ - AVIOUTd(0); /* Frame */ - AVIOUTd(0); /* Frame */ - /* The audio stream format */ + AVIOUTd(_audiowritten / 4); /* Length */ + AVIOUTd(0); /* SuggestedBufferSize */ + AVIOUTd(~0); /* Quality */ + AVIOUTd(4); /* SampleSize */ + AVIOUTd(0); /* Frame */ + AVIOUTd(0); /* Frame */ + /* The audio stream format */ AVIOUT4("strf"); - AVIOUTd(16); /* # of bytes to follow */ - AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */ - AVIOUTw(2); /* Number of channels */ - AVIOUTd(_audiorate); /* SamplesPerSec */ - AVIOUTd(_audiorate * 4); /* AvgBytesPerSec*/ - AVIOUTw(4); /* BlockAlign */ - AVIOUTw(16); /* BitsPerSample */ + AVIOUTd(16); /* # of bytes to follow */ + AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */ + AVIOUTw(2); /* Number of channels */ + AVIOUTd(_audiorate); /* SamplesPerSec */ + AVIOUTd(_audiorate * 4); /* AvgBytesPerSec*/ + AVIOUTw(4); /* BlockAlign */ + AVIOUTw(16); /* BitsPerSample */ int nmain = header_pos - main_list - 4; /* Finish stream list, i.e. put number of bytes in the list to proper pos */ @@ -226,16 +234,17 @@ void AviWriter::EndWrite() /* First add the index table to the end */ memcpy(_aviIndex.data(), "idx1", 4); host_writed(_aviIndex.data() + 4, (uint32_t)_aviIndex.size() - 8); - + _file.write((char*)_aviIndex.data(), _aviIndex.size()); _file.seekp(std::ios::beg); _file.write((char*)avi_header, AviWriter::AviHeaderSize); _file.close(); } -void AviWriter::AddFrame(uint8_t *frameData) +void AviWriter::AddFrame(uint8_t* frameData) { - if(!_file) { + if (!_file) + { return; } @@ -243,17 +252,20 @@ void AviWriter::AddFrame(uint8_t *frameData) uint8_t* compressedData = nullptr; int written = _codec->CompressFrame(isKeyFrame, frameData, &compressedData); - if(written < 0) { + if (written < 0) + { return; } - if(_codecType == VideoCodec::None) { + if (_codecType == VideoCodec::None) + { isKeyFrame = true; } WriteAviChunk(_codecType == VideoCodec::None ? "00db" : "00dc", written, compressedData, isKeyFrame ? 0x10 : 0); _frames++; - if(_audioPos) { + if (_audioPos) + { auto lock = _audioLock.AcquireSafe(); WriteAviChunk("01wb", _audioPos, _audiobuf, 0); _audiowritten += _audioPos; @@ -261,13 +273,14 @@ void AviWriter::AddFrame(uint8_t *frameData) } } -void AviWriter::AddSound(int16_t *data, uint32_t sampleCount) +void AviWriter::AddSound(int16_t* data, uint32_t sampleCount) { - if(!_file) { + if (!_file) + { return; } auto lock = _audioLock.AcquireSafe(); - memcpy(_audiobuf+_audioPos/2, data, sampleCount * 4); + memcpy(_audiobuf + _audioPos / 2, data, sampleCount * 4); _audioPos += sampleCount * 4; -} \ No newline at end of file +} diff --git a/Utilities/AviWriter.h b/Utilities/AviWriter.h index 0af99ca..9cadb3c 100644 --- a/Utilities/AviWriter.h +++ b/Utilities/AviWriter.h @@ -40,18 +40,19 @@ private: uint8_t* _frameBuffer = nullptr; vector _aviIndex; - + SimpleLock _audioLock; private: void host_writew(uint8_t* buffer, uint16_t value); void host_writed(uint8_t* buffer, uint32_t value); - void WriteAviChunk(const char * tag, uint32_t size, void * data, uint32_t flags); + void WriteAviChunk(const char* tag, uint32_t size, void* data, uint32_t flags); public: void AddFrame(uint8_t* frameData); - void AddSound(int16_t * data, uint32_t sampleCount); + void AddSound(int16_t* data, uint32_t sampleCount); - bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel); + bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, + uint32_t audioSampleRate, uint32_t compressionLevel); void EndWrite(); -}; \ No newline at end of file +}; diff --git a/Utilities/Base64.h b/Utilities/Base64.h index eb6c6ec..d9a25af 100644 --- a/Utilities/Base64.h +++ b/Utilities/Base64.h @@ -9,16 +9,19 @@ public: std::string out; int val = 0, valb = -6; - for(uint8_t c : data) { + for (uint8_t c : data) + { val = (val << 8) + c; valb += 8; - while(valb >= 0) { + while (valb >= 0) + { out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]); valb -= 6; } } - if(valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]); - while(out.size() % 4) out.push_back('='); + if (valb > -6) out.push_back( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]); + while (out.size() % 4) out.push_back('='); return out; } @@ -27,14 +30,16 @@ public: vector out; vector T(256, -1); - for(int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; + for (int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; int val = 0, valb = -8; - for(uint8_t c : in) { - if(T[c] == -1) break; + for (uint8_t c : in) + { + if (T[c] == -1) break; val = (val << 6) + T[c]; valb += 6; - if(valb >= 0) { + if (valb >= 0) + { out.push_back(val >> valb); valb -= 8; } diff --git a/Utilities/BaseCodec.h b/Utilities/BaseCodec.h index 6133378..b7e2ebb 100644 --- a/Utilities/BaseCodec.h +++ b/Utilities/BaseCodec.h @@ -5,8 +5,10 @@ class BaseCodec { public: virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) = 0; - virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) = 0; + virtual int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) = 0; virtual const char* GetFourCC() = 0; - virtual ~BaseCodec() { } -}; \ No newline at end of file + virtual ~BaseCodec() + { + } +}; diff --git a/Utilities/BpsPatcher.cpp b/Utilities/BpsPatcher.cpp index f958f19..d1d378a 100644 --- a/Utilities/BpsPatcher.cpp +++ b/Utilities/BpsPatcher.cpp @@ -4,19 +4,22 @@ #include "BpsPatcher.h" #include "CRC32.h" -int64_t BpsPatcher::ReadBase128Number(std::istream &file) +int64_t BpsPatcher::ReadBase128Number(std::istream& file) { int64_t result = 0; int shift = 0; uint8_t buffer; - while(true) { + while (true) + { file.read((char*)&buffer, 1); - if(file.eof()) { + if (file.eof()) + { return -1; } result += (buffer & 0x7F) << shift; shift += 7; - if(buffer & 0x80) { + if (buffer & 0x80) + { break; } result += (int64_t)1 << shift; @@ -25,16 +28,17 @@ int64_t BpsPatcher::ReadBase128Number(std::istream &file) return result; } -bool BpsPatcher::PatchBuffer(string bpsFilepath, vector &input, vector &output) +bool BpsPatcher::PatchBuffer(string bpsFilepath, vector& input, vector& output) { ifstream bpsFile(bpsFilepath, std::ios::in | std::ios::binary); - if(bpsFile) { + if (bpsFile) + { return PatchBuffer(bpsFile, input, output); } return false; } -bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector &input, vector &output) +bool BpsPatcher::PatchBuffer(std::istream& bpsFile, vector& input, vector& output) { bpsFile.seekg(0, std::ios::end); size_t fileSize = (size_t)bpsFile.tellg(); @@ -42,14 +46,16 @@ bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector &input, vect char header[4]; bpsFile.read((char*)&header, 4); - if(memcmp((char*)&header, "BPS1", 4) != 0) { + if (memcmp((char*)&header, "BPS1", 4) != 0) + { //Invalid BPS file return false; } int64_t inputFileSize = ReadBase128Number(bpsFile); int64_t outputFileSize = ReadBase128Number(bpsFile); - if(inputFileSize == -1 || outputFileSize == -1) { + if (inputFileSize == -1 || outputFileSize == -1) + { //Invalid file return false; } @@ -62,66 +68,78 @@ bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector &input, vect uint32_t outputOffset = 0; uint32_t inputRelativeOffset = 0; uint32_t outputRelativeOffset = 0; - while((size_t)bpsFile.tellg() < fileSize - 12) { + while ((size_t)bpsFile.tellg() < fileSize - 12) + { int64_t data = ReadBase128Number(bpsFile); - if(data == -1) { + if (data == -1) + { //Invalid file return false; } uint8_t command = data & 0x03; uint64_t length = (data >> 2) + 1; - switch(command) { - case 0: - //SourceRead - while(length--) { - output[outputOffset] = input[outputOffset]; - outputOffset++; - } - break; + switch (command) + { + case 0: + //SourceRead + while (length--) + { + output[outputOffset] = input[outputOffset]; + outputOffset++; + } + break; - case 1: - //TargetRead - while(length--) { - uint8_t value = 0; - bpsFile.read((char*)&value, 1); + case 1: + //TargetRead + while (length--) + { + uint8_t value = 0; + bpsFile.read((char*)&value, 1); - output[outputOffset++] = value; - } - break; + output[outputOffset++] = value; + } + break; - case 2: { + case 2: + { //SourceCopy int32_t data = (int32_t)ReadBase128Number(bpsFile); inputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1); - while(length--) { + while (length--) + { output[outputOffset++] = input[inputRelativeOffset++]; } break; } - case 3: { + case 3: + { //TargetCopy int32_t data = (int32_t)ReadBase128Number(bpsFile); outputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1); - while(length--) { + while (length--) + { output[outputOffset++] = output[outputRelativeOffset++]; } break; } - } + } } uint8_t inputChecksum[4]; uint8_t outputChecksum[4]; bpsFile.read((char*)inputChecksum, 4); bpsFile.read((char*)outputChecksum, 4); - uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24); - uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24); + uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << + 24); + uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[ + 3] << 24); uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size()); uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size()); - if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) { + if (patchInputCrc != inputCrc || patchOutputCrc != outputCrc) + { return false; } return true; diff --git a/Utilities/BpsPatcher.h b/Utilities/BpsPatcher.h index f10bb13..9648f71 100644 --- a/Utilities/BpsPatcher.h +++ b/Utilities/BpsPatcher.h @@ -5,9 +5,9 @@ class BpsPatcher { private: - static int64_t ReadBase128Number(std::istream &file); + static int64_t ReadBase128Number(std::istream& file); public: - static bool PatchBuffer(std::istream &bpsFile, vector &input, vector &output); - static bool PatchBuffer(string bpsFilepath, vector &input, vector &output); -}; \ No newline at end of file + static bool PatchBuffer(std::istream& bpsFile, vector& input, vector& output); + static bool PatchBuffer(string bpsFilepath, vector& input, vector& output); +}; diff --git a/Utilities/CRC32.cpp b/Utilities/CRC32.cpp index ef1e282..2462924 100644 --- a/Utilities/CRC32.cpp +++ b/Utilities/CRC32.cpp @@ -17,10 +17,10 @@ extern const uint32_t Crc32Lookup[MaxSlice][256]; // define endianess and some integer data types #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__aarch64__) - // Windows always little endian +// Windows always little endian #define __BYTE_ORDER __LITTLE_ENDIAN #else - // defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN +// defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN #if defined(__APPLE__) || defined(HAVE_LIBNX) #include #elif defined (__FreeBSD__) || defined(__DragonFly__) @@ -46,7 +46,8 @@ uint32_t CRC32::GetCRC(string filename) ifstream file(filename, std::ios::in | std::ios::binary); - if(file) { + if (file) + { file.seekg(0, std::ios::end); std::streamoff fileSize = file.tellg(); file.seekg(0, std::ios::beg); @@ -71,9 +72,11 @@ uint32_t CRC32::crc32_16bytes(const void* data, size_t length, uint32_t previous const size_t Unroll = 4; const size_t BytesAtOnce = 16 * Unroll; - while(length >= BytesAtOnce) { - for(size_t unrolling = 0; unrolling < Unroll; unrolling++) { - #if __BYTE_ORDER == __BIG_ENDIAN + while (length >= BytesAtOnce) + { + for (size_t unrolling = 0; unrolling < Unroll; unrolling++) + { +#if __BYTE_ORDER == __BIG_ENDIAN uint32_t one = *current++ ^ swap(crc); uint32_t two = *current++; uint32_t three = *current++; @@ -94,7 +97,7 @@ uint32_t CRC32::crc32_16bytes(const void* data, size_t length, uint32_t previous Crc32Lookup[13][(one >> 8) & 0xFF] ^ Crc32Lookup[14][(one >> 16) & 0xFF] ^ Crc32Lookup[15][(one >> 24) & 0xFF]; - #else +#else uint32_t one = *current++ ^ crc; uint32_t two = *current++; uint32_t three = *current++; @@ -115,7 +118,7 @@ uint32_t CRC32::crc32_16bytes(const void* data, size_t length, uint32_t previous Crc32Lookup[13][(one >> 16) & 0xFF] ^ Crc32Lookup[14][(one >> 8) & 0xFF] ^ Crc32Lookup[15][one & 0xFF]; - #endif +#endif } length -= BytesAtOnce; @@ -123,7 +126,7 @@ uint32_t CRC32::crc32_16bytes(const void* data, size_t length, uint32_t previous const uint8_t* currentChar = (const uint8_t*)current; // remaining 1 to 63 bytes (standard algorithm) - while(length-- != 0) + while (length-- != 0) crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; return ~crc; // same as crc ^ 0xFFFFFFFF @@ -132,559 +135,559 @@ uint32_t CRC32::crc32_16bytes(const void* data, size_t length, uint32_t previous const uint32_t Crc32Lookup[MaxSlice][256] = { { - 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, - 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, - 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, - 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, - 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, - 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, - 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, - 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, - 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, - 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, - 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, - 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, - 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, - 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, - 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, - 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, - 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, - 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, - 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, - 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, - 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, - 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, - 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, - 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, - 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, - 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, - 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, - 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, - 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, - 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, - 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, - 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, - } - ,{ - 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7, - 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF, - 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496, - 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E, - 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265, - 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D, - 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034, - 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C, - 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2, - 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA, - 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93, - 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B, - 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60, - 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768, - 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31, - 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539, - 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C, - 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484, - 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD, - 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5, - 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E, - 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026, - 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F, - 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277, - 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189, - 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81, - 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8, - 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0, - 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B, - 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23, - 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A, - 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72, - }, + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, + }, + { + 0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7, + 0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF, + 0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192, 0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496, + 0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A, 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E, + 0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761, 0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265, + 0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69, 0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D, + 0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034, + 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C, + 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2, + 0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA, + 0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97, 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93, + 0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F, 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B, + 0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864, 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60, + 0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C, 0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768, + 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2, 0x52488DB3, 0x7965DE70, 0x607EEF31, + 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, 0x9A9107BB, 0xB1BC5478, 0xA8A76539, + 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C, + 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484, + 0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9, 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD, + 0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1, 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5, + 0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E, + 0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522, 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026, + 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B, 0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F, + 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4, 0x516BD0F5, 0x7A468336, 0x635DB277, + 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, 0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189, + 0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85, 0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81, + 0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC, 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8, + 0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0, + 0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B, + 0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23, + 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E, 0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A, + 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876, 0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72, + }, - { - 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685, - 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D, - 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5, - 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D, - 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065, - 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD, - 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315, - 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD, - 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45, - 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD, - 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835, - 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D, - 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5, - 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D, - 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5, - 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D, - 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05, - 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD, - 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75, - 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD, - 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5, - 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D, - 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895, - 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D, - 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5, - 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D, - 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5, - 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D, - 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625, - 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D, - 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555, - 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED, - }, + { + 0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685, + 0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D, + 0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5, + 0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91, 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D, + 0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9, 0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065, + 0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901, 0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD, + 0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315, + 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD, + 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45, + 0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD, + 0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835, + 0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151, 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D, + 0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579, 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5, + 0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1, 0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D, + 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C, 0x523AAABB, 0x507C14E2, 0x51BE7ED5, + 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D, + 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, 0xE7FED96B, 0xE5B86732, 0xE47A0D05, + 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD, + 0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9, 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75, + 0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711, 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD, + 0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5, + 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281, 0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D, + 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049, 0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895, + 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774, 0xCD866D43, 0xCFC0D31A, 0xCE02B92D, + 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, 0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5, + 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1, 0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D, + 0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5, + 0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D, + 0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625, + 0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41, 0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D, + 0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89, 0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555, + 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31, 0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED, + }, - { - 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9, - 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056, - 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26, - 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9, - 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787, - 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68, - 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018, - 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7, - 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084, - 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B, - 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B, - 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4, - 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA, - 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755, - 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825, - 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA, - 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82, - 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D, - 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D, - 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2, - 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC, - 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953, - 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623, - 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC, - 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF, - 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50, - 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120, - 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF, - 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981, - 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E, - 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E, - 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1, - } - ,{ - 0x00000000,0x3D6029B0,0x7AC05360,0x47A07AD0,0xF580A6C0,0xC8E08F70,0x8F40F5A0,0xB220DC10, - 0x30704BC1,0x0D106271,0x4AB018A1,0x77D03111,0xC5F0ED01,0xF890C4B1,0xBF30BE61,0x825097D1, - 0x60E09782,0x5D80BE32,0x1A20C4E2,0x2740ED52,0x95603142,0xA80018F2,0xEFA06222,0xD2C04B92, - 0x5090DC43,0x6DF0F5F3,0x2A508F23,0x1730A693,0xA5107A83,0x98705333,0xDFD029E3,0xE2B00053, - 0xC1C12F04,0xFCA106B4,0xBB017C64,0x866155D4,0x344189C4,0x0921A074,0x4E81DAA4,0x73E1F314, - 0xF1B164C5,0xCCD14D75,0x8B7137A5,0xB6111E15,0x0431C205,0x3951EBB5,0x7EF19165,0x4391B8D5, - 0xA121B886,0x9C419136,0xDBE1EBE6,0xE681C256,0x54A11E46,0x69C137F6,0x2E614D26,0x13016496, - 0x9151F347,0xAC31DAF7,0xEB91A027,0xD6F18997,0x64D15587,0x59B17C37,0x1E1106E7,0x23712F57, - 0x58F35849,0x659371F9,0x22330B29,0x1F532299,0xAD73FE89,0x9013D739,0xD7B3ADE9,0xEAD38459, - 0x68831388,0x55E33A38,0x124340E8,0x2F236958,0x9D03B548,0xA0639CF8,0xE7C3E628,0xDAA3CF98, - 0x3813CFCB,0x0573E67B,0x42D39CAB,0x7FB3B51B,0xCD93690B,0xF0F340BB,0xB7533A6B,0x8A3313DB, - 0x0863840A,0x3503ADBA,0x72A3D76A,0x4FC3FEDA,0xFDE322CA,0xC0830B7A,0x872371AA,0xBA43581A, - 0x9932774D,0xA4525EFD,0xE3F2242D,0xDE920D9D,0x6CB2D18D,0x51D2F83D,0x167282ED,0x2B12AB5D, - 0xA9423C8C,0x9422153C,0xD3826FEC,0xEEE2465C,0x5CC29A4C,0x61A2B3FC,0x2602C92C,0x1B62E09C, - 0xF9D2E0CF,0xC4B2C97F,0x8312B3AF,0xBE729A1F,0x0C52460F,0x31326FBF,0x7692156F,0x4BF23CDF, - 0xC9A2AB0E,0xF4C282BE,0xB362F86E,0x8E02D1DE,0x3C220DCE,0x0142247E,0x46E25EAE,0x7B82771E, - 0xB1E6B092,0x8C869922,0xCB26E3F2,0xF646CA42,0x44661652,0x79063FE2,0x3EA64532,0x03C66C82, - 0x8196FB53,0xBCF6D2E3,0xFB56A833,0xC6368183,0x74165D93,0x49767423,0x0ED60EF3,0x33B62743, - 0xD1062710,0xEC660EA0,0xABC67470,0x96A65DC0,0x248681D0,0x19E6A860,0x5E46D2B0,0x6326FB00, - 0xE1766CD1,0xDC164561,0x9BB63FB1,0xA6D61601,0x14F6CA11,0x2996E3A1,0x6E369971,0x5356B0C1, - 0x70279F96,0x4D47B626,0x0AE7CCF6,0x3787E546,0x85A73956,0xB8C710E6,0xFF676A36,0xC2074386, - 0x4057D457,0x7D37FDE7,0x3A978737,0x07F7AE87,0xB5D77297,0x88B75B27,0xCF1721F7,0xF2770847, - 0x10C70814,0x2DA721A4,0x6A075B74,0x576772C4,0xE547AED4,0xD8278764,0x9F87FDB4,0xA2E7D404, - 0x20B743D5,0x1DD76A65,0x5A7710B5,0x67173905,0xD537E515,0xE857CCA5,0xAFF7B675,0x92979FC5, - 0xE915E8DB,0xD475C16B,0x93D5BBBB,0xAEB5920B,0x1C954E1B,0x21F567AB,0x66551D7B,0x5B3534CB, - 0xD965A31A,0xE4058AAA,0xA3A5F07A,0x9EC5D9CA,0x2CE505DA,0x11852C6A,0x562556BA,0x6B457F0A, - 0x89F57F59,0xB49556E9,0xF3352C39,0xCE550589,0x7C75D999,0x4115F029,0x06B58AF9,0x3BD5A349, - 0xB9853498,0x84E51D28,0xC34567F8,0xFE254E48,0x4C059258,0x7165BBE8,0x36C5C138,0x0BA5E888, - 0x28D4C7DF,0x15B4EE6F,0x521494BF,0x6F74BD0F,0xDD54611F,0xE03448AF,0xA794327F,0x9AF41BCF, - 0x18A48C1E,0x25C4A5AE,0x6264DF7E,0x5F04F6CE,0xED242ADE,0xD044036E,0x97E479BE,0xAA84500E, - 0x4834505D,0x755479ED,0x32F4033D,0x0F942A8D,0xBDB4F69D,0x80D4DF2D,0xC774A5FD,0xFA148C4D, - 0x78441B9C,0x4524322C,0x028448FC,0x3FE4614C,0x8DC4BD5C,0xB0A494EC,0xF704EE3C,0xCA64C78C, - }, + { + 0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9, + 0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056, + 0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871, 0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26, + 0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E, 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9, + 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0, 0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787, + 0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F, 0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68, + 0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018, + 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, 0x0241207C, 0x10F48F92, 0xA848E8F7, + 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084, + 0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B, + 0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C, 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B, + 0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3, 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4, + 0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED, 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA, + 0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002, 0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755, + 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB, 0x5CE150AE, 0x4E54FF40, 0xF6E89825, + 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, 0x99557841, 0x8BE0D7AF, 0x335CB0CA, + 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, 0xDA874609, 0xC832E9E7, 0x708E8E82, + 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D, + 0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A, 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D, + 0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2, + 0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB, 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC, + 0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04, 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953, + 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174, 0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623, + 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122, 0xEF189647, 0xFDAD39A9, 0x45115ECC, + 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, 0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF, + 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907, 0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50, + 0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677, 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120, + 0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF, + 0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981, + 0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639, 0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E, + 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949, 0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E, + 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6, 0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1, + }, + { + 0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0, 0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10, + 0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111, 0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1, + 0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52, 0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92, + 0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693, 0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053, + 0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4, 0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314, + 0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15, 0x0431C205, 0x3951EBB5, 0x7EF19165, 0x4391B8D5, + 0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256, 0x54A11E46, 0x69C137F6, 0x2E614D26, 0x13016496, + 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997, 0x64D15587, 0x59B17C37, 0x1E1106E7, 0x23712F57, + 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299, 0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459, + 0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958, 0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98, + 0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B, 0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB, + 0x0863840A, 0x3503ADBA, 0x72A3D76A, 0x4FC3FEDA, 0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A, + 0x9932774D, 0xA4525EFD, 0xE3F2242D, 0xDE920D9D, 0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D, + 0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C, 0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C, + 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F, 0x0C52460F, 0x31326FBF, 0x7692156F, 0x4BF23CDF, + 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE, 0x3C220DCE, 0x0142247E, 0x46E25EAE, 0x7B82771E, + 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42, 0x44661652, 0x79063FE2, 0x3EA64532, 0x03C66C82, + 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183, 0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743, + 0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0, 0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00, + 0xE1766CD1, 0xDC164561, 0x9BB63FB1, 0xA6D61601, 0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1, + 0x70279F96, 0x4D47B626, 0x0AE7CCF6, 0x3787E546, 0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386, + 0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87, 0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847, + 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4, 0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404, + 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905, 0xD537E515, 0xE857CCA5, 0xAFF7B675, 0x92979FC5, + 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B, 0x1C954E1B, 0x21F567AB, 0x66551D7B, 0x5B3534CB, + 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA, 0x2CE505DA, 0x11852C6A, 0x562556BA, 0x6B457F0A, + 0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589, 0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349, + 0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48, 0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888, + 0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F, 0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF, + 0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE, 0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E, + 0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D, 0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D, + 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C, 0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C, + }, - { - 0x00000000,0xCB5CD3A5,0x4DC8A10B,0x869472AE,0x9B914216,0x50CD91B3,0xD659E31D,0x1D0530B8, - 0xEC53826D,0x270F51C8,0xA19B2366,0x6AC7F0C3,0x77C2C07B,0xBC9E13DE,0x3A0A6170,0xF156B2D5, - 0x03D6029B,0xC88AD13E,0x4E1EA390,0x85427035,0x9847408D,0x531B9328,0xD58FE186,0x1ED33223, - 0xEF8580F6,0x24D95353,0xA24D21FD,0x6911F258,0x7414C2E0,0xBF481145,0x39DC63EB,0xF280B04E, - 0x07AC0536,0xCCF0D693,0x4A64A43D,0x81387798,0x9C3D4720,0x57619485,0xD1F5E62B,0x1AA9358E, - 0xEBFF875B,0x20A354FE,0xA6372650,0x6D6BF5F5,0x706EC54D,0xBB3216E8,0x3DA66446,0xF6FAB7E3, - 0x047A07AD,0xCF26D408,0x49B2A6A6,0x82EE7503,0x9FEB45BB,0x54B7961E,0xD223E4B0,0x197F3715, - 0xE82985C0,0x23755665,0xA5E124CB,0x6EBDF76E,0x73B8C7D6,0xB8E41473,0x3E7066DD,0xF52CB578, - 0x0F580A6C,0xC404D9C9,0x4290AB67,0x89CC78C2,0x94C9487A,0x5F959BDF,0xD901E971,0x125D3AD4, - 0xE30B8801,0x28575BA4,0xAEC3290A,0x659FFAAF,0x789ACA17,0xB3C619B2,0x35526B1C,0xFE0EB8B9, - 0x0C8E08F7,0xC7D2DB52,0x4146A9FC,0x8A1A7A59,0x971F4AE1,0x5C439944,0xDAD7EBEA,0x118B384F, - 0xE0DD8A9A,0x2B81593F,0xAD152B91,0x6649F834,0x7B4CC88C,0xB0101B29,0x36846987,0xFDD8BA22, - 0x08F40F5A,0xC3A8DCFF,0x453CAE51,0x8E607DF4,0x93654D4C,0x58399EE9,0xDEADEC47,0x15F13FE2, - 0xE4A78D37,0x2FFB5E92,0xA96F2C3C,0x6233FF99,0x7F36CF21,0xB46A1C84,0x32FE6E2A,0xF9A2BD8F, - 0x0B220DC1,0xC07EDE64,0x46EAACCA,0x8DB67F6F,0x90B34FD7,0x5BEF9C72,0xDD7BEEDC,0x16273D79, - 0xE7718FAC,0x2C2D5C09,0xAAB92EA7,0x61E5FD02,0x7CE0CDBA,0xB7BC1E1F,0x31286CB1,0xFA74BF14, - 0x1EB014D8,0xD5ECC77D,0x5378B5D3,0x98246676,0x852156CE,0x4E7D856B,0xC8E9F7C5,0x03B52460, - 0xF2E396B5,0x39BF4510,0xBF2B37BE,0x7477E41B,0x6972D4A3,0xA22E0706,0x24BA75A8,0xEFE6A60D, - 0x1D661643,0xD63AC5E6,0x50AEB748,0x9BF264ED,0x86F75455,0x4DAB87F0,0xCB3FF55E,0x006326FB, - 0xF135942E,0x3A69478B,0xBCFD3525,0x77A1E680,0x6AA4D638,0xA1F8059D,0x276C7733,0xEC30A496, - 0x191C11EE,0xD240C24B,0x54D4B0E5,0x9F886340,0x828D53F8,0x49D1805D,0xCF45F2F3,0x04192156, - 0xF54F9383,0x3E134026,0xB8873288,0x73DBE12D,0x6EDED195,0xA5820230,0x2316709E,0xE84AA33B, - 0x1ACA1375,0xD196C0D0,0x5702B27E,0x9C5E61DB,0x815B5163,0x4A0782C6,0xCC93F068,0x07CF23CD, - 0xF6999118,0x3DC542BD,0xBB513013,0x700DE3B6,0x6D08D30E,0xA65400AB,0x20C07205,0xEB9CA1A0, - 0x11E81EB4,0xDAB4CD11,0x5C20BFBF,0x977C6C1A,0x8A795CA2,0x41258F07,0xC7B1FDA9,0x0CED2E0C, - 0xFDBB9CD9,0x36E74F7C,0xB0733DD2,0x7B2FEE77,0x662ADECF,0xAD760D6A,0x2BE27FC4,0xE0BEAC61, - 0x123E1C2F,0xD962CF8A,0x5FF6BD24,0x94AA6E81,0x89AF5E39,0x42F38D9C,0xC467FF32,0x0F3B2C97, - 0xFE6D9E42,0x35314DE7,0xB3A53F49,0x78F9ECEC,0x65FCDC54,0xAEA00FF1,0x28347D5F,0xE368AEFA, - 0x16441B82,0xDD18C827,0x5B8CBA89,0x90D0692C,0x8DD55994,0x46898A31,0xC01DF89F,0x0B412B3A, - 0xFA1799EF,0x314B4A4A,0xB7DF38E4,0x7C83EB41,0x6186DBF9,0xAADA085C,0x2C4E7AF2,0xE712A957, - 0x15921919,0xDECECABC,0x585AB812,0x93066BB7,0x8E035B0F,0x455F88AA,0xC3CBFA04,0x089729A1, - 0xF9C19B74,0x329D48D1,0xB4093A7F,0x7F55E9DA,0x6250D962,0xA90C0AC7,0x2F987869,0xE4C4ABCC, - }, + { + 0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE, 0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8, + 0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3, 0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5, + 0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035, 0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223, + 0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258, 0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E, + 0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798, 0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E, + 0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5, 0x706EC54D, 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3, + 0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503, 0x9FEB45BB, 0x54B7961E, 0xD223E4B0, 0x197F3715, + 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E, 0x73B8C7D6, 0xB8E41473, 0x3E7066DD, 0xF52CB578, + 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2, 0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4, + 0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF, 0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9, + 0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59, 0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F, + 0xE0DD8A9A, 0x2B81593F, 0xAD152B91, 0x6649F834, 0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22, + 0x08F40F5A, 0xC3A8DCFF, 0x453CAE51, 0x8E607DF4, 0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2, + 0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99, 0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F, + 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F, 0x90B34FD7, 0x5BEF9C72, 0xDD7BEEDC, 0x16273D79, + 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02, 0x7CE0CDBA, 0xB7BC1E1F, 0x31286CB1, 0xFA74BF14, + 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676, 0x852156CE, 0x4E7D856B, 0xC8E9F7C5, 0x03B52460, + 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B, 0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D, + 0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED, 0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB, + 0xF135942E, 0x3A69478B, 0xBCFD3525, 0x77A1E680, 0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496, + 0x191C11EE, 0xD240C24B, 0x54D4B0E5, 0x9F886340, 0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156, + 0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D, 0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B, + 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB, 0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD, + 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6, 0x6D08D30E, 0xA65400AB, 0x20C07205, 0xEB9CA1A0, + 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A, 0x8A795CA2, 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C, + 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77, 0x662ADECF, 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61, + 0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81, 0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97, + 0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC, 0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA, + 0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C, 0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A, + 0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41, 0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957, + 0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7, 0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1, + 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA, 0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC, + }, - { - 0x00000000,0xA6770BB4,0x979F1129,0x31E81A9D,0xF44F2413,0x52382FA7,0x63D0353A,0xC5A73E8E, - 0x33EF4E67,0x959845D3,0xA4705F4E,0x020754FA,0xC7A06A74,0x61D761C0,0x503F7B5D,0xF64870E9, - 0x67DE9CCE,0xC1A9977A,0xF0418DE7,0x56368653,0x9391B8DD,0x35E6B369,0x040EA9F4,0xA279A240, - 0x5431D2A9,0xF246D91D,0xC3AEC380,0x65D9C834,0xA07EF6BA,0x0609FD0E,0x37E1E793,0x9196EC27, - 0xCFBD399C,0x69CA3228,0x582228B5,0xFE552301,0x3BF21D8F,0x9D85163B,0xAC6D0CA6,0x0A1A0712, - 0xFC5277FB,0x5A257C4F,0x6BCD66D2,0xCDBA6D66,0x081D53E8,0xAE6A585C,0x9F8242C1,0x39F54975, - 0xA863A552,0x0E14AEE6,0x3FFCB47B,0x998BBFCF,0x5C2C8141,0xFA5B8AF5,0xCBB39068,0x6DC49BDC, - 0x9B8CEB35,0x3DFBE081,0x0C13FA1C,0xAA64F1A8,0x6FC3CF26,0xC9B4C492,0xF85CDE0F,0x5E2BD5BB, - 0x440B7579,0xE27C7ECD,0xD3946450,0x75E36FE4,0xB044516A,0x16335ADE,0x27DB4043,0x81AC4BF7, - 0x77E43B1E,0xD19330AA,0xE07B2A37,0x460C2183,0x83AB1F0D,0x25DC14B9,0x14340E24,0xB2430590, - 0x23D5E9B7,0x85A2E203,0xB44AF89E,0x123DF32A,0xD79ACDA4,0x71EDC610,0x4005DC8D,0xE672D739, - 0x103AA7D0,0xB64DAC64,0x87A5B6F9,0x21D2BD4D,0xE47583C3,0x42028877,0x73EA92EA,0xD59D995E, - 0x8BB64CE5,0x2DC14751,0x1C295DCC,0xBA5E5678,0x7FF968F6,0xD98E6342,0xE86679DF,0x4E11726B, - 0xB8590282,0x1E2E0936,0x2FC613AB,0x89B1181F,0x4C162691,0xEA612D25,0xDB8937B8,0x7DFE3C0C, - 0xEC68D02B,0x4A1FDB9F,0x7BF7C102,0xDD80CAB6,0x1827F438,0xBE50FF8C,0x8FB8E511,0x29CFEEA5, - 0xDF879E4C,0x79F095F8,0x48188F65,0xEE6F84D1,0x2BC8BA5F,0x8DBFB1EB,0xBC57AB76,0x1A20A0C2, - 0x8816EAF2,0x2E61E146,0x1F89FBDB,0xB9FEF06F,0x7C59CEE1,0xDA2EC555,0xEBC6DFC8,0x4DB1D47C, - 0xBBF9A495,0x1D8EAF21,0x2C66B5BC,0x8A11BE08,0x4FB68086,0xE9C18B32,0xD82991AF,0x7E5E9A1B, - 0xEFC8763C,0x49BF7D88,0x78576715,0xDE206CA1,0x1B87522F,0xBDF0599B,0x8C184306,0x2A6F48B2, - 0xDC27385B,0x7A5033EF,0x4BB82972,0xEDCF22C6,0x28681C48,0x8E1F17FC,0xBFF70D61,0x198006D5, - 0x47ABD36E,0xE1DCD8DA,0xD034C247,0x7643C9F3,0xB3E4F77D,0x1593FCC9,0x247BE654,0x820CEDE0, - 0x74449D09,0xD23396BD,0xE3DB8C20,0x45AC8794,0x800BB91A,0x267CB2AE,0x1794A833,0xB1E3A387, - 0x20754FA0,0x86024414,0xB7EA5E89,0x119D553D,0xD43A6BB3,0x724D6007,0x43A57A9A,0xE5D2712E, - 0x139A01C7,0xB5ED0A73,0x840510EE,0x22721B5A,0xE7D525D4,0x41A22E60,0x704A34FD,0xD63D3F49, - 0xCC1D9F8B,0x6A6A943F,0x5B828EA2,0xFDF58516,0x3852BB98,0x9E25B02C,0xAFCDAAB1,0x09BAA105, - 0xFFF2D1EC,0x5985DA58,0x686DC0C5,0xCE1ACB71,0x0BBDF5FF,0xADCAFE4B,0x9C22E4D6,0x3A55EF62, - 0xABC30345,0x0DB408F1,0x3C5C126C,0x9A2B19D8,0x5F8C2756,0xF9FB2CE2,0xC813367F,0x6E643DCB, - 0x982C4D22,0x3E5B4696,0x0FB35C0B,0xA9C457BF,0x6C636931,0xCA146285,0xFBFC7818,0x5D8B73AC, - 0x03A0A617,0xA5D7ADA3,0x943FB73E,0x3248BC8A,0xF7EF8204,0x519889B0,0x6070932D,0xC6079899, - 0x304FE870,0x9638E3C4,0xA7D0F959,0x01A7F2ED,0xC400CC63,0x6277C7D7,0x539FDD4A,0xF5E8D6FE, - 0x647E3AD9,0xC209316D,0xF3E12BF0,0x55962044,0x90311ECA,0x3646157E,0x07AE0FE3,0xA1D90457, - 0x579174BE,0xF1E67F0A,0xC00E6597,0x66796E23,0xA3DE50AD,0x05A95B19,0x34414184,0x92364A30, - }, + { + 0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D, 0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E, + 0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA, 0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9, + 0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653, 0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240, + 0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834, 0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27, + 0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301, 0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712, + 0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66, 0x081D53E8, 0xAE6A585C, 0x9F8242C1, 0x39F54975, + 0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF, 0x5C2C8141, 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC, + 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8, 0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F, 0x5E2BD5BB, + 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4, 0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7, + 0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183, 0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590, + 0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A, 0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739, + 0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, 0x21D2BD4D, 0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E, + 0x8BB64CE5, 0x2DC14751, 0x1C295DCC, 0xBA5E5678, 0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B, + 0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F, 0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C, + 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6, 0x1827F438, 0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5, + 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1, 0x2BC8BA5F, 0x8DBFB1EB, 0xBC57AB76, 0x1A20A0C2, + 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F, 0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C, + 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08, 0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B, + 0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1, 0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2, + 0xDC27385B, 0x7A5033EF, 0x4BB82972, 0xEDCF22C6, 0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5, + 0x47ABD36E, 0xE1DCD8DA, 0xD034C247, 0x7643C9F3, 0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0, + 0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794, 0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387, + 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D, 0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E, + 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A, 0xE7D525D4, 0x41A22E60, 0x704A34FD, 0xD63D3F49, + 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516, 0x3852BB98, 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105, + 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71, 0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62, + 0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8, 0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB, + 0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF, 0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC, + 0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A, 0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899, + 0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED, 0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE, + 0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044, 0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457, + 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23, 0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30, + }, - { - 0x00000000,0xCCAA009E,0x4225077D,0x8E8F07E3,0x844A0EFA,0x48E00E64,0xC66F0987,0x0AC50919, - 0xD3E51BB5,0x1F4F1B2B,0x91C01CC8,0x5D6A1C56,0x57AF154F,0x9B0515D1,0x158A1232,0xD92012AC, - 0x7CBB312B,0xB01131B5,0x3E9E3656,0xF23436C8,0xF8F13FD1,0x345B3F4F,0xBAD438AC,0x767E3832, - 0xAF5E2A9E,0x63F42A00,0xED7B2DE3,0x21D12D7D,0x2B142464,0xE7BE24FA,0x69312319,0xA59B2387, - 0xF9766256,0x35DC62C8,0xBB53652B,0x77F965B5,0x7D3C6CAC,0xB1966C32,0x3F196BD1,0xF3B36B4F, - 0x2A9379E3,0xE639797D,0x68B67E9E,0xA41C7E00,0xAED97719,0x62737787,0xECFC7064,0x205670FA, - 0x85CD537D,0x496753E3,0xC7E85400,0x0B42549E,0x01875D87,0xCD2D5D19,0x43A25AFA,0x8F085A64, - 0x562848C8,0x9A824856,0x140D4FB5,0xD8A74F2B,0xD2624632,0x1EC846AC,0x9047414F,0x5CED41D1, - 0x299DC2ED,0xE537C273,0x6BB8C590,0xA712C50E,0xADD7CC17,0x617DCC89,0xEFF2CB6A,0x2358CBF4, - 0xFA78D958,0x36D2D9C6,0xB85DDE25,0x74F7DEBB,0x7E32D7A2,0xB298D73C,0x3C17D0DF,0xF0BDD041, - 0x5526F3C6,0x998CF358,0x1703F4BB,0xDBA9F425,0xD16CFD3C,0x1DC6FDA2,0x9349FA41,0x5FE3FADF, - 0x86C3E873,0x4A69E8ED,0xC4E6EF0E,0x084CEF90,0x0289E689,0xCE23E617,0x40ACE1F4,0x8C06E16A, - 0xD0EBA0BB,0x1C41A025,0x92CEA7C6,0x5E64A758,0x54A1AE41,0x980BAEDF,0x1684A93C,0xDA2EA9A2, - 0x030EBB0E,0xCFA4BB90,0x412BBC73,0x8D81BCED,0x8744B5F4,0x4BEEB56A,0xC561B289,0x09CBB217, - 0xAC509190,0x60FA910E,0xEE7596ED,0x22DF9673,0x281A9F6A,0xE4B09FF4,0x6A3F9817,0xA6959889, - 0x7FB58A25,0xB31F8ABB,0x3D908D58,0xF13A8DC6,0xFBFF84DF,0x37558441,0xB9DA83A2,0x7570833C, - 0x533B85DA,0x9F918544,0x111E82A7,0xDDB48239,0xD7718B20,0x1BDB8BBE,0x95548C5D,0x59FE8CC3, - 0x80DE9E6F,0x4C749EF1,0xC2FB9912,0x0E51998C,0x04949095,0xC83E900B,0x46B197E8,0x8A1B9776, - 0x2F80B4F1,0xE32AB46F,0x6DA5B38C,0xA10FB312,0xABCABA0B,0x6760BA95,0xE9EFBD76,0x2545BDE8, - 0xFC65AF44,0x30CFAFDA,0xBE40A839,0x72EAA8A7,0x782FA1BE,0xB485A120,0x3A0AA6C3,0xF6A0A65D, - 0xAA4DE78C,0x66E7E712,0xE868E0F1,0x24C2E06F,0x2E07E976,0xE2ADE9E8,0x6C22EE0B,0xA088EE95, - 0x79A8FC39,0xB502FCA7,0x3B8DFB44,0xF727FBDA,0xFDE2F2C3,0x3148F25D,0xBFC7F5BE,0x736DF520, - 0xD6F6D6A7,0x1A5CD639,0x94D3D1DA,0x5879D144,0x52BCD85D,0x9E16D8C3,0x1099DF20,0xDC33DFBE, - 0x0513CD12,0xC9B9CD8C,0x4736CA6F,0x8B9CCAF1,0x8159C3E8,0x4DF3C376,0xC37CC495,0x0FD6C40B, - 0x7AA64737,0xB60C47A9,0x3883404A,0xF42940D4,0xFEEC49CD,0x32464953,0xBCC94EB0,0x70634E2E, - 0xA9435C82,0x65E95C1C,0xEB665BFF,0x27CC5B61,0x2D095278,0xE1A352E6,0x6F2C5505,0xA386559B, - 0x061D761C,0xCAB77682,0x44387161,0x889271FF,0x825778E6,0x4EFD7878,0xC0727F9B,0x0CD87F05, - 0xD5F86DA9,0x19526D37,0x97DD6AD4,0x5B776A4A,0x51B26353,0x9D1863CD,0x1397642E,0xDF3D64B0, - 0x83D02561,0x4F7A25FF,0xC1F5221C,0x0D5F2282,0x079A2B9B,0xCB302B05,0x45BF2CE6,0x89152C78, - 0x50353ED4,0x9C9F3E4A,0x121039A9,0xDEBA3937,0xD47F302E,0x18D530B0,0x965A3753,0x5AF037CD, - 0xFF6B144A,0x33C114D4,0xBD4E1337,0x71E413A9,0x7B211AB0,0xB78B1A2E,0x39041DCD,0xF5AE1D53, - 0x2C8E0FFF,0xE0240F61,0x6EAB0882,0xA201081C,0xA8C40105,0x646E019B,0xEAE10678,0x264B06E6, - } - ,{ - 0x00000000,0x177B1443,0x2EF62886,0x398D3CC5,0x5DEC510C,0x4A97454F,0x731A798A,0x64616DC9, - 0xBBD8A218,0xACA3B65B,0x952E8A9E,0x82559EDD,0xE634F314,0xF14FE757,0xC8C2DB92,0xDFB9CFD1, - 0xACC04271,0xBBBB5632,0x82366AF7,0x954D7EB4,0xF12C137D,0xE657073E,0xDFDA3BFB,0xC8A12FB8, - 0x1718E069,0x0063F42A,0x39EEC8EF,0x2E95DCAC,0x4AF4B165,0x5D8FA526,0x640299E3,0x73798DA0, - 0x82F182A3,0x958A96E0,0xAC07AA25,0xBB7CBE66,0xDF1DD3AF,0xC866C7EC,0xF1EBFB29,0xE690EF6A, - 0x392920BB,0x2E5234F8,0x17DF083D,0x00A41C7E,0x64C571B7,0x73BE65F4,0x4A335931,0x5D484D72, - 0x2E31C0D2,0x394AD491,0x00C7E854,0x17BCFC17,0x73DD91DE,0x64A6859D,0x5D2BB958,0x4A50AD1B, - 0x95E962CA,0x82927689,0xBB1F4A4C,0xAC645E0F,0xC80533C6,0xDF7E2785,0xE6F31B40,0xF1880F03, - 0xDE920307,0xC9E91744,0xF0642B81,0xE71F3FC2,0x837E520B,0x94054648,0xAD887A8D,0xBAF36ECE, - 0x654AA11F,0x7231B55C,0x4BBC8999,0x5CC79DDA,0x38A6F013,0x2FDDE450,0x1650D895,0x012BCCD6, - 0x72524176,0x65295535,0x5CA469F0,0x4BDF7DB3,0x2FBE107A,0x38C50439,0x014838FC,0x16332CBF, - 0xC98AE36E,0xDEF1F72D,0xE77CCBE8,0xF007DFAB,0x9466B262,0x831DA621,0xBA909AE4,0xADEB8EA7, - 0x5C6381A4,0x4B1895E7,0x7295A922,0x65EEBD61,0x018FD0A8,0x16F4C4EB,0x2F79F82E,0x3802EC6D, - 0xE7BB23BC,0xF0C037FF,0xC94D0B3A,0xDE361F79,0xBA5772B0,0xAD2C66F3,0x94A15A36,0x83DA4E75, - 0xF0A3C3D5,0xE7D8D796,0xDE55EB53,0xC92EFF10,0xAD4F92D9,0xBA34869A,0x83B9BA5F,0x94C2AE1C, - 0x4B7B61CD,0x5C00758E,0x658D494B,0x72F65D08,0x169730C1,0x01EC2482,0x38611847,0x2F1A0C04, - 0x6655004F,0x712E140C,0x48A328C9,0x5FD83C8A,0x3BB95143,0x2CC24500,0x154F79C5,0x02346D86, - 0xDD8DA257,0xCAF6B614,0xF37B8AD1,0xE4009E92,0x8061F35B,0x971AE718,0xAE97DBDD,0xB9ECCF9E, - 0xCA95423E,0xDDEE567D,0xE4636AB8,0xF3187EFB,0x97791332,0x80020771,0xB98F3BB4,0xAEF42FF7, - 0x714DE026,0x6636F465,0x5FBBC8A0,0x48C0DCE3,0x2CA1B12A,0x3BDAA569,0x025799AC,0x152C8DEF, - 0xE4A482EC,0xF3DF96AF,0xCA52AA6A,0xDD29BE29,0xB948D3E0,0xAE33C7A3,0x97BEFB66,0x80C5EF25, - 0x5F7C20F4,0x480734B7,0x718A0872,0x66F11C31,0x029071F8,0x15EB65BB,0x2C66597E,0x3B1D4D3D, - 0x4864C09D,0x5F1FD4DE,0x6692E81B,0x71E9FC58,0x15889191,0x02F385D2,0x3B7EB917,0x2C05AD54, - 0xF3BC6285,0xE4C776C6,0xDD4A4A03,0xCA315E40,0xAE503389,0xB92B27CA,0x80A61B0F,0x97DD0F4C, - 0xB8C70348,0xAFBC170B,0x96312BCE,0x814A3F8D,0xE52B5244,0xF2504607,0xCBDD7AC2,0xDCA66E81, - 0x031FA150,0x1464B513,0x2DE989D6,0x3A929D95,0x5EF3F05C,0x4988E41F,0x7005D8DA,0x677ECC99, - 0x14074139,0x037C557A,0x3AF169BF,0x2D8A7DFC,0x49EB1035,0x5E900476,0x671D38B3,0x70662CF0, - 0xAFDFE321,0xB8A4F762,0x8129CBA7,0x9652DFE4,0xF233B22D,0xE548A66E,0xDCC59AAB,0xCBBE8EE8, - 0x3A3681EB,0x2D4D95A8,0x14C0A96D,0x03BBBD2E,0x67DAD0E7,0x70A1C4A4,0x492CF861,0x5E57EC22, - 0x81EE23F3,0x969537B0,0xAF180B75,0xB8631F36,0xDC0272FF,0xCB7966BC,0xF2F45A79,0xE58F4E3A, - 0x96F6C39A,0x818DD7D9,0xB800EB1C,0xAF7BFF5F,0xCB1A9296,0xDC6186D5,0xE5ECBA10,0xF297AE53, - 0x2D2E6182,0x3A5575C1,0x03D84904,0x14A35D47,0x70C2308E,0x67B924CD,0x5E341808,0x494F0C4B, - }, + { + 0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3, 0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919, + 0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56, 0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC, + 0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8, 0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832, + 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D, 0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387, + 0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5, 0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F, + 0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00, 0xAED97719, 0x62737787, 0xECFC7064, 0x205670FA, + 0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E, 0x01875D87, 0xCD2D5D19, 0x43A25AFA, 0x8F085A64, + 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B, 0xD2624632, 0x1EC846AC, 0x9047414F, 0x5CED41D1, + 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E, 0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4, + 0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB, 0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041, + 0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425, 0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF, + 0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, 0x084CEF90, 0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A, + 0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6, 0x5E64A758, 0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2, + 0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED, 0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217, + 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673, 0x281A9F6A, 0xE4B09FF4, 0x6A3F9817, 0xA6959889, + 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6, 0xFBFF84DF, 0x37558441, 0xB9DA83A2, 0x7570833C, + 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239, 0xD7718B20, 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3, + 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C, 0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776, + 0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312, 0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8, + 0xFC65AF44, 0x30CFAFDA, 0xBE40A839, 0x72EAA8A7, 0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D, + 0xAA4DE78C, 0x66E7E712, 0xE868E0F1, 0x24C2E06F, 0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95, + 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA, 0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520, + 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144, 0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE, + 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1, 0x8159C3E8, 0x4DF3C376, 0xC37CC495, 0x0FD6C40B, + 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4, 0xFEEC49CD, 0x32464953, 0xBCC94EB0, 0x70634E2E, + 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61, 0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B, + 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF, 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05, + 0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0, + 0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78, + 0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937, 0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD, + 0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9, 0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, + 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C, 0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6, + }, + { + 0x00000000, 0x177B1443, 0x2EF62886, 0x398D3CC5, 0x5DEC510C, 0x4A97454F, 0x731A798A, 0x64616DC9, + 0xBBD8A218, 0xACA3B65B, 0x952E8A9E, 0x82559EDD, 0xE634F314, 0xF14FE757, 0xC8C2DB92, 0xDFB9CFD1, + 0xACC04271, 0xBBBB5632, 0x82366AF7, 0x954D7EB4, 0xF12C137D, 0xE657073E, 0xDFDA3BFB, 0xC8A12FB8, + 0x1718E069, 0x0063F42A, 0x39EEC8EF, 0x2E95DCAC, 0x4AF4B165, 0x5D8FA526, 0x640299E3, 0x73798DA0, + 0x82F182A3, 0x958A96E0, 0xAC07AA25, 0xBB7CBE66, 0xDF1DD3AF, 0xC866C7EC, 0xF1EBFB29, 0xE690EF6A, + 0x392920BB, 0x2E5234F8, 0x17DF083D, 0x00A41C7E, 0x64C571B7, 0x73BE65F4, 0x4A335931, 0x5D484D72, + 0x2E31C0D2, 0x394AD491, 0x00C7E854, 0x17BCFC17, 0x73DD91DE, 0x64A6859D, 0x5D2BB958, 0x4A50AD1B, + 0x95E962CA, 0x82927689, 0xBB1F4A4C, 0xAC645E0F, 0xC80533C6, 0xDF7E2785, 0xE6F31B40, 0xF1880F03, + 0xDE920307, 0xC9E91744, 0xF0642B81, 0xE71F3FC2, 0x837E520B, 0x94054648, 0xAD887A8D, 0xBAF36ECE, + 0x654AA11F, 0x7231B55C, 0x4BBC8999, 0x5CC79DDA, 0x38A6F013, 0x2FDDE450, 0x1650D895, 0x012BCCD6, + 0x72524176, 0x65295535, 0x5CA469F0, 0x4BDF7DB3, 0x2FBE107A, 0x38C50439, 0x014838FC, 0x16332CBF, + 0xC98AE36E, 0xDEF1F72D, 0xE77CCBE8, 0xF007DFAB, 0x9466B262, 0x831DA621, 0xBA909AE4, 0xADEB8EA7, + 0x5C6381A4, 0x4B1895E7, 0x7295A922, 0x65EEBD61, 0x018FD0A8, 0x16F4C4EB, 0x2F79F82E, 0x3802EC6D, + 0xE7BB23BC, 0xF0C037FF, 0xC94D0B3A, 0xDE361F79, 0xBA5772B0, 0xAD2C66F3, 0x94A15A36, 0x83DA4E75, + 0xF0A3C3D5, 0xE7D8D796, 0xDE55EB53, 0xC92EFF10, 0xAD4F92D9, 0xBA34869A, 0x83B9BA5F, 0x94C2AE1C, + 0x4B7B61CD, 0x5C00758E, 0x658D494B, 0x72F65D08, 0x169730C1, 0x01EC2482, 0x38611847, 0x2F1A0C04, + 0x6655004F, 0x712E140C, 0x48A328C9, 0x5FD83C8A, 0x3BB95143, 0x2CC24500, 0x154F79C5, 0x02346D86, + 0xDD8DA257, 0xCAF6B614, 0xF37B8AD1, 0xE4009E92, 0x8061F35B, 0x971AE718, 0xAE97DBDD, 0xB9ECCF9E, + 0xCA95423E, 0xDDEE567D, 0xE4636AB8, 0xF3187EFB, 0x97791332, 0x80020771, 0xB98F3BB4, 0xAEF42FF7, + 0x714DE026, 0x6636F465, 0x5FBBC8A0, 0x48C0DCE3, 0x2CA1B12A, 0x3BDAA569, 0x025799AC, 0x152C8DEF, + 0xE4A482EC, 0xF3DF96AF, 0xCA52AA6A, 0xDD29BE29, 0xB948D3E0, 0xAE33C7A3, 0x97BEFB66, 0x80C5EF25, + 0x5F7C20F4, 0x480734B7, 0x718A0872, 0x66F11C31, 0x029071F8, 0x15EB65BB, 0x2C66597E, 0x3B1D4D3D, + 0x4864C09D, 0x5F1FD4DE, 0x6692E81B, 0x71E9FC58, 0x15889191, 0x02F385D2, 0x3B7EB917, 0x2C05AD54, + 0xF3BC6285, 0xE4C776C6, 0xDD4A4A03, 0xCA315E40, 0xAE503389, 0xB92B27CA, 0x80A61B0F, 0x97DD0F4C, + 0xB8C70348, 0xAFBC170B, 0x96312BCE, 0x814A3F8D, 0xE52B5244, 0xF2504607, 0xCBDD7AC2, 0xDCA66E81, + 0x031FA150, 0x1464B513, 0x2DE989D6, 0x3A929D95, 0x5EF3F05C, 0x4988E41F, 0x7005D8DA, 0x677ECC99, + 0x14074139, 0x037C557A, 0x3AF169BF, 0x2D8A7DFC, 0x49EB1035, 0x5E900476, 0x671D38B3, 0x70662CF0, + 0xAFDFE321, 0xB8A4F762, 0x8129CBA7, 0x9652DFE4, 0xF233B22D, 0xE548A66E, 0xDCC59AAB, 0xCBBE8EE8, + 0x3A3681EB, 0x2D4D95A8, 0x14C0A96D, 0x03BBBD2E, 0x67DAD0E7, 0x70A1C4A4, 0x492CF861, 0x5E57EC22, + 0x81EE23F3, 0x969537B0, 0xAF180B75, 0xB8631F36, 0xDC0272FF, 0xCB7966BC, 0xF2F45A79, 0xE58F4E3A, + 0x96F6C39A, 0x818DD7D9, 0xB800EB1C, 0xAF7BFF5F, 0xCB1A9296, 0xDC6186D5, 0xE5ECBA10, 0xF297AE53, + 0x2D2E6182, 0x3A5575C1, 0x03D84904, 0x14A35D47, 0x70C2308E, 0x67B924CD, 0x5E341808, 0x494F0C4B, + }, - { - 0x00000000,0xEFC26B3E,0x04F5D03D,0xEB37BB03,0x09EBA07A,0xE629CB44,0x0D1E7047,0xE2DC1B79, - 0x13D740F4,0xFC152BCA,0x172290C9,0xF8E0FBF7,0x1A3CE08E,0xF5FE8BB0,0x1EC930B3,0xF10B5B8D, - 0x27AE81E8,0xC86CEAD6,0x235B51D5,0xCC993AEB,0x2E452192,0xC1874AAC,0x2AB0F1AF,0xC5729A91, - 0x3479C11C,0xDBBBAA22,0x308C1121,0xDF4E7A1F,0x3D926166,0xD2500A58,0x3967B15B,0xD6A5DA65, - 0x4F5D03D0,0xA09F68EE,0x4BA8D3ED,0xA46AB8D3,0x46B6A3AA,0xA974C894,0x42437397,0xAD8118A9, - 0x5C8A4324,0xB348281A,0x587F9319,0xB7BDF827,0x5561E35E,0xBAA38860,0x51943363,0xBE56585D, - 0x68F38238,0x8731E906,0x6C065205,0x83C4393B,0x61182242,0x8EDA497C,0x65EDF27F,0x8A2F9941, - 0x7B24C2CC,0x94E6A9F2,0x7FD112F1,0x901379CF,0x72CF62B6,0x9D0D0988,0x763AB28B,0x99F8D9B5, - 0x9EBA07A0,0x71786C9E,0x9A4FD79D,0x758DBCA3,0x9751A7DA,0x7893CCE4,0x93A477E7,0x7C661CD9, - 0x8D6D4754,0x62AF2C6A,0x89989769,0x665AFC57,0x8486E72E,0x6B448C10,0x80733713,0x6FB15C2D, - 0xB9148648,0x56D6ED76,0xBDE15675,0x52233D4B,0xB0FF2632,0x5F3D4D0C,0xB40AF60F,0x5BC89D31, - 0xAAC3C6BC,0x4501AD82,0xAE361681,0x41F47DBF,0xA32866C6,0x4CEA0DF8,0xA7DDB6FB,0x481FDDC5, - 0xD1E70470,0x3E256F4E,0xD512D44D,0x3AD0BF73,0xD80CA40A,0x37CECF34,0xDCF97437,0x333B1F09, - 0xC2304484,0x2DF22FBA,0xC6C594B9,0x2907FF87,0xCBDBE4FE,0x24198FC0,0xCF2E34C3,0x20EC5FFD, - 0xF6498598,0x198BEEA6,0xF2BC55A5,0x1D7E3E9B,0xFFA225E2,0x10604EDC,0xFB57F5DF,0x14959EE1, - 0xE59EC56C,0x0A5CAE52,0xE16B1551,0x0EA97E6F,0xEC756516,0x03B70E28,0xE880B52B,0x0742DE15, - 0xE6050901,0x09C7623F,0xE2F0D93C,0x0D32B202,0xEFEEA97B,0x002CC245,0xEB1B7946,0x04D91278, - 0xF5D249F5,0x1A1022CB,0xF12799C8,0x1EE5F2F6,0xFC39E98F,0x13FB82B1,0xF8CC39B2,0x170E528C, - 0xC1AB88E9,0x2E69E3D7,0xC55E58D4,0x2A9C33EA,0xC8402893,0x278243AD,0xCCB5F8AE,0x23779390, - 0xD27CC81D,0x3DBEA323,0xD6891820,0x394B731E,0xDB976867,0x34550359,0xDF62B85A,0x30A0D364, - 0xA9580AD1,0x469A61EF,0xADADDAEC,0x426FB1D2,0xA0B3AAAB,0x4F71C195,0xA4467A96,0x4B8411A8, - 0xBA8F4A25,0x554D211B,0xBE7A9A18,0x51B8F126,0xB364EA5F,0x5CA68161,0xB7913A62,0x5853515C, - 0x8EF68B39,0x6134E007,0x8A035B04,0x65C1303A,0x871D2B43,0x68DF407D,0x83E8FB7E,0x6C2A9040, - 0x9D21CBCD,0x72E3A0F3,0x99D41BF0,0x761670CE,0x94CA6BB7,0x7B080089,0x903FBB8A,0x7FFDD0B4, - 0x78BF0EA1,0x977D659F,0x7C4ADE9C,0x9388B5A2,0x7154AEDB,0x9E96C5E5,0x75A17EE6,0x9A6315D8, - 0x6B684E55,0x84AA256B,0x6F9D9E68,0x805FF556,0x6283EE2F,0x8D418511,0x66763E12,0x89B4552C, - 0x5F118F49,0xB0D3E477,0x5BE45F74,0xB426344A,0x56FA2F33,0xB938440D,0x520FFF0E,0xBDCD9430, - 0x4CC6CFBD,0xA304A483,0x48331F80,0xA7F174BE,0x452D6FC7,0xAAEF04F9,0x41D8BFFA,0xAE1AD4C4, - 0x37E20D71,0xD820664F,0x3317DD4C,0xDCD5B672,0x3E09AD0B,0xD1CBC635,0x3AFC7D36,0xD53E1608, - 0x24354D85,0xCBF726BB,0x20C09DB8,0xCF02F686,0x2DDEEDFF,0xC21C86C1,0x292B3DC2,0xC6E956FC, - 0x104C8C99,0xFF8EE7A7,0x14B95CA4,0xFB7B379A,0x19A72CE3,0xF66547DD,0x1D52FCDE,0xF29097E0, - 0x039BCC6D,0xEC59A753,0x076E1C50,0xE8AC776E,0x0A706C17,0xE5B20729,0x0E85BC2A,0xE147D714, - }, + { + 0x00000000, 0xEFC26B3E, 0x04F5D03D, 0xEB37BB03, 0x09EBA07A, 0xE629CB44, 0x0D1E7047, 0xE2DC1B79, + 0x13D740F4, 0xFC152BCA, 0x172290C9, 0xF8E0FBF7, 0x1A3CE08E, 0xF5FE8BB0, 0x1EC930B3, 0xF10B5B8D, + 0x27AE81E8, 0xC86CEAD6, 0x235B51D5, 0xCC993AEB, 0x2E452192, 0xC1874AAC, 0x2AB0F1AF, 0xC5729A91, + 0x3479C11C, 0xDBBBAA22, 0x308C1121, 0xDF4E7A1F, 0x3D926166, 0xD2500A58, 0x3967B15B, 0xD6A5DA65, + 0x4F5D03D0, 0xA09F68EE, 0x4BA8D3ED, 0xA46AB8D3, 0x46B6A3AA, 0xA974C894, 0x42437397, 0xAD8118A9, + 0x5C8A4324, 0xB348281A, 0x587F9319, 0xB7BDF827, 0x5561E35E, 0xBAA38860, 0x51943363, 0xBE56585D, + 0x68F38238, 0x8731E906, 0x6C065205, 0x83C4393B, 0x61182242, 0x8EDA497C, 0x65EDF27F, 0x8A2F9941, + 0x7B24C2CC, 0x94E6A9F2, 0x7FD112F1, 0x901379CF, 0x72CF62B6, 0x9D0D0988, 0x763AB28B, 0x99F8D9B5, + 0x9EBA07A0, 0x71786C9E, 0x9A4FD79D, 0x758DBCA3, 0x9751A7DA, 0x7893CCE4, 0x93A477E7, 0x7C661CD9, + 0x8D6D4754, 0x62AF2C6A, 0x89989769, 0x665AFC57, 0x8486E72E, 0x6B448C10, 0x80733713, 0x6FB15C2D, + 0xB9148648, 0x56D6ED76, 0xBDE15675, 0x52233D4B, 0xB0FF2632, 0x5F3D4D0C, 0xB40AF60F, 0x5BC89D31, + 0xAAC3C6BC, 0x4501AD82, 0xAE361681, 0x41F47DBF, 0xA32866C6, 0x4CEA0DF8, 0xA7DDB6FB, 0x481FDDC5, + 0xD1E70470, 0x3E256F4E, 0xD512D44D, 0x3AD0BF73, 0xD80CA40A, 0x37CECF34, 0xDCF97437, 0x333B1F09, + 0xC2304484, 0x2DF22FBA, 0xC6C594B9, 0x2907FF87, 0xCBDBE4FE, 0x24198FC0, 0xCF2E34C3, 0x20EC5FFD, + 0xF6498598, 0x198BEEA6, 0xF2BC55A5, 0x1D7E3E9B, 0xFFA225E2, 0x10604EDC, 0xFB57F5DF, 0x14959EE1, + 0xE59EC56C, 0x0A5CAE52, 0xE16B1551, 0x0EA97E6F, 0xEC756516, 0x03B70E28, 0xE880B52B, 0x0742DE15, + 0xE6050901, 0x09C7623F, 0xE2F0D93C, 0x0D32B202, 0xEFEEA97B, 0x002CC245, 0xEB1B7946, 0x04D91278, + 0xF5D249F5, 0x1A1022CB, 0xF12799C8, 0x1EE5F2F6, 0xFC39E98F, 0x13FB82B1, 0xF8CC39B2, 0x170E528C, + 0xC1AB88E9, 0x2E69E3D7, 0xC55E58D4, 0x2A9C33EA, 0xC8402893, 0x278243AD, 0xCCB5F8AE, 0x23779390, + 0xD27CC81D, 0x3DBEA323, 0xD6891820, 0x394B731E, 0xDB976867, 0x34550359, 0xDF62B85A, 0x30A0D364, + 0xA9580AD1, 0x469A61EF, 0xADADDAEC, 0x426FB1D2, 0xA0B3AAAB, 0x4F71C195, 0xA4467A96, 0x4B8411A8, + 0xBA8F4A25, 0x554D211B, 0xBE7A9A18, 0x51B8F126, 0xB364EA5F, 0x5CA68161, 0xB7913A62, 0x5853515C, + 0x8EF68B39, 0x6134E007, 0x8A035B04, 0x65C1303A, 0x871D2B43, 0x68DF407D, 0x83E8FB7E, 0x6C2A9040, + 0x9D21CBCD, 0x72E3A0F3, 0x99D41BF0, 0x761670CE, 0x94CA6BB7, 0x7B080089, 0x903FBB8A, 0x7FFDD0B4, + 0x78BF0EA1, 0x977D659F, 0x7C4ADE9C, 0x9388B5A2, 0x7154AEDB, 0x9E96C5E5, 0x75A17EE6, 0x9A6315D8, + 0x6B684E55, 0x84AA256B, 0x6F9D9E68, 0x805FF556, 0x6283EE2F, 0x8D418511, 0x66763E12, 0x89B4552C, + 0x5F118F49, 0xB0D3E477, 0x5BE45F74, 0xB426344A, 0x56FA2F33, 0xB938440D, 0x520FFF0E, 0xBDCD9430, + 0x4CC6CFBD, 0xA304A483, 0x48331F80, 0xA7F174BE, 0x452D6FC7, 0xAAEF04F9, 0x41D8BFFA, 0xAE1AD4C4, + 0x37E20D71, 0xD820664F, 0x3317DD4C, 0xDCD5B672, 0x3E09AD0B, 0xD1CBC635, 0x3AFC7D36, 0xD53E1608, + 0x24354D85, 0xCBF726BB, 0x20C09DB8, 0xCF02F686, 0x2DDEEDFF, 0xC21C86C1, 0x292B3DC2, 0xC6E956FC, + 0x104C8C99, 0xFF8EE7A7, 0x14B95CA4, 0xFB7B379A, 0x19A72CE3, 0xF66547DD, 0x1D52FCDE, 0xF29097E0, + 0x039BCC6D, 0xEC59A753, 0x076E1C50, 0xE8AC776E, 0x0A706C17, 0xE5B20729, 0x0E85BC2A, 0xE147D714, + }, - { - 0x00000000,0xC18EDFC0,0x586CB9C1,0x99E26601,0xB0D97382,0x7157AC42,0xE8B5CA43,0x293B1583, - 0xBAC3E145,0x7B4D3E85,0xE2AF5884,0x23218744,0x0A1A92C7,0xCB944D07,0x52762B06,0x93F8F4C6, - 0xAEF6C4CB,0x6F781B0B,0xF69A7D0A,0x3714A2CA,0x1E2FB749,0xDFA16889,0x46430E88,0x87CDD148, - 0x1435258E,0xD5BBFA4E,0x4C599C4F,0x8DD7438F,0xA4EC560C,0x656289CC,0xFC80EFCD,0x3D0E300D, - 0x869C8FD7,0x47125017,0xDEF03616,0x1F7EE9D6,0x3645FC55,0xF7CB2395,0x6E294594,0xAFA79A54, - 0x3C5F6E92,0xFDD1B152,0x6433D753,0xA5BD0893,0x8C861D10,0x4D08C2D0,0xD4EAA4D1,0x15647B11, - 0x286A4B1C,0xE9E494DC,0x7006F2DD,0xB1882D1D,0x98B3389E,0x593DE75E,0xC0DF815F,0x01515E9F, - 0x92A9AA59,0x53277599,0xCAC51398,0x0B4BCC58,0x2270D9DB,0xE3FE061B,0x7A1C601A,0xBB92BFDA, - 0xD64819EF,0x17C6C62F,0x8E24A02E,0x4FAA7FEE,0x66916A6D,0xA71FB5AD,0x3EFDD3AC,0xFF730C6C, - 0x6C8BF8AA,0xAD05276A,0x34E7416B,0xF5699EAB,0xDC528B28,0x1DDC54E8,0x843E32E9,0x45B0ED29, - 0x78BEDD24,0xB93002E4,0x20D264E5,0xE15CBB25,0xC867AEA6,0x09E97166,0x900B1767,0x5185C8A7, - 0xC27D3C61,0x03F3E3A1,0x9A1185A0,0x5B9F5A60,0x72A44FE3,0xB32A9023,0x2AC8F622,0xEB4629E2, - 0x50D49638,0x915A49F8,0x08B82FF9,0xC936F039,0xE00DE5BA,0x21833A7A,0xB8615C7B,0x79EF83BB, - 0xEA17777D,0x2B99A8BD,0xB27BCEBC,0x73F5117C,0x5ACE04FF,0x9B40DB3F,0x02A2BD3E,0xC32C62FE, - 0xFE2252F3,0x3FAC8D33,0xA64EEB32,0x67C034F2,0x4EFB2171,0x8F75FEB1,0x169798B0,0xD7194770, - 0x44E1B3B6,0x856F6C76,0x1C8D0A77,0xDD03D5B7,0xF438C034,0x35B61FF4,0xAC5479F5,0x6DDAA635, - 0x77E1359F,0xB66FEA5F,0x2F8D8C5E,0xEE03539E,0xC738461D,0x06B699DD,0x9F54FFDC,0x5EDA201C, - 0xCD22D4DA,0x0CAC0B1A,0x954E6D1B,0x54C0B2DB,0x7DFBA758,0xBC757898,0x25971E99,0xE419C159, - 0xD917F154,0x18992E94,0x817B4895,0x40F59755,0x69CE82D6,0xA8405D16,0x31A23B17,0xF02CE4D7, - 0x63D41011,0xA25ACFD1,0x3BB8A9D0,0xFA367610,0xD30D6393,0x1283BC53,0x8B61DA52,0x4AEF0592, - 0xF17DBA48,0x30F36588,0xA9110389,0x689FDC49,0x41A4C9CA,0x802A160A,0x19C8700B,0xD846AFCB, - 0x4BBE5B0D,0x8A3084CD,0x13D2E2CC,0xD25C3D0C,0xFB67288F,0x3AE9F74F,0xA30B914E,0x62854E8E, - 0x5F8B7E83,0x9E05A143,0x07E7C742,0xC6691882,0xEF520D01,0x2EDCD2C1,0xB73EB4C0,0x76B06B00, - 0xE5489FC6,0x24C64006,0xBD242607,0x7CAAF9C7,0x5591EC44,0x941F3384,0x0DFD5585,0xCC738A45, - 0xA1A92C70,0x6027F3B0,0xF9C595B1,0x384B4A71,0x11705FF2,0xD0FE8032,0x491CE633,0x889239F3, - 0x1B6ACD35,0xDAE412F5,0x430674F4,0x8288AB34,0xABB3BEB7,0x6A3D6177,0xF3DF0776,0x3251D8B6, - 0x0F5FE8BB,0xCED1377B,0x5733517A,0x96BD8EBA,0xBF869B39,0x7E0844F9,0xE7EA22F8,0x2664FD38, - 0xB59C09FE,0x7412D63E,0xEDF0B03F,0x2C7E6FFF,0x05457A7C,0xC4CBA5BC,0x5D29C3BD,0x9CA71C7D, - 0x2735A3A7,0xE6BB7C67,0x7F591A66,0xBED7C5A6,0x97ECD025,0x56620FE5,0xCF8069E4,0x0E0EB624, - 0x9DF642E2,0x5C789D22,0xC59AFB23,0x041424E3,0x2D2F3160,0xECA1EEA0,0x754388A1,0xB4CD5761, - 0x89C3676C,0x484DB8AC,0xD1AFDEAD,0x1021016D,0x391A14EE,0xF894CB2E,0x6176AD2F,0xA0F872EF, - 0x33008629,0xF28E59E9,0x6B6C3FE8,0xAAE2E028,0x83D9F5AB,0x42572A6B,0xDBB54C6A,0x1A3B93AA, - }, + { + 0x00000000, 0xC18EDFC0, 0x586CB9C1, 0x99E26601, 0xB0D97382, 0x7157AC42, 0xE8B5CA43, 0x293B1583, + 0xBAC3E145, 0x7B4D3E85, 0xE2AF5884, 0x23218744, 0x0A1A92C7, 0xCB944D07, 0x52762B06, 0x93F8F4C6, + 0xAEF6C4CB, 0x6F781B0B, 0xF69A7D0A, 0x3714A2CA, 0x1E2FB749, 0xDFA16889, 0x46430E88, 0x87CDD148, + 0x1435258E, 0xD5BBFA4E, 0x4C599C4F, 0x8DD7438F, 0xA4EC560C, 0x656289CC, 0xFC80EFCD, 0x3D0E300D, + 0x869C8FD7, 0x47125017, 0xDEF03616, 0x1F7EE9D6, 0x3645FC55, 0xF7CB2395, 0x6E294594, 0xAFA79A54, + 0x3C5F6E92, 0xFDD1B152, 0x6433D753, 0xA5BD0893, 0x8C861D10, 0x4D08C2D0, 0xD4EAA4D1, 0x15647B11, + 0x286A4B1C, 0xE9E494DC, 0x7006F2DD, 0xB1882D1D, 0x98B3389E, 0x593DE75E, 0xC0DF815F, 0x01515E9F, + 0x92A9AA59, 0x53277599, 0xCAC51398, 0x0B4BCC58, 0x2270D9DB, 0xE3FE061B, 0x7A1C601A, 0xBB92BFDA, + 0xD64819EF, 0x17C6C62F, 0x8E24A02E, 0x4FAA7FEE, 0x66916A6D, 0xA71FB5AD, 0x3EFDD3AC, 0xFF730C6C, + 0x6C8BF8AA, 0xAD05276A, 0x34E7416B, 0xF5699EAB, 0xDC528B28, 0x1DDC54E8, 0x843E32E9, 0x45B0ED29, + 0x78BEDD24, 0xB93002E4, 0x20D264E5, 0xE15CBB25, 0xC867AEA6, 0x09E97166, 0x900B1767, 0x5185C8A7, + 0xC27D3C61, 0x03F3E3A1, 0x9A1185A0, 0x5B9F5A60, 0x72A44FE3, 0xB32A9023, 0x2AC8F622, 0xEB4629E2, + 0x50D49638, 0x915A49F8, 0x08B82FF9, 0xC936F039, 0xE00DE5BA, 0x21833A7A, 0xB8615C7B, 0x79EF83BB, + 0xEA17777D, 0x2B99A8BD, 0xB27BCEBC, 0x73F5117C, 0x5ACE04FF, 0x9B40DB3F, 0x02A2BD3E, 0xC32C62FE, + 0xFE2252F3, 0x3FAC8D33, 0xA64EEB32, 0x67C034F2, 0x4EFB2171, 0x8F75FEB1, 0x169798B0, 0xD7194770, + 0x44E1B3B6, 0x856F6C76, 0x1C8D0A77, 0xDD03D5B7, 0xF438C034, 0x35B61FF4, 0xAC5479F5, 0x6DDAA635, + 0x77E1359F, 0xB66FEA5F, 0x2F8D8C5E, 0xEE03539E, 0xC738461D, 0x06B699DD, 0x9F54FFDC, 0x5EDA201C, + 0xCD22D4DA, 0x0CAC0B1A, 0x954E6D1B, 0x54C0B2DB, 0x7DFBA758, 0xBC757898, 0x25971E99, 0xE419C159, + 0xD917F154, 0x18992E94, 0x817B4895, 0x40F59755, 0x69CE82D6, 0xA8405D16, 0x31A23B17, 0xF02CE4D7, + 0x63D41011, 0xA25ACFD1, 0x3BB8A9D0, 0xFA367610, 0xD30D6393, 0x1283BC53, 0x8B61DA52, 0x4AEF0592, + 0xF17DBA48, 0x30F36588, 0xA9110389, 0x689FDC49, 0x41A4C9CA, 0x802A160A, 0x19C8700B, 0xD846AFCB, + 0x4BBE5B0D, 0x8A3084CD, 0x13D2E2CC, 0xD25C3D0C, 0xFB67288F, 0x3AE9F74F, 0xA30B914E, 0x62854E8E, + 0x5F8B7E83, 0x9E05A143, 0x07E7C742, 0xC6691882, 0xEF520D01, 0x2EDCD2C1, 0xB73EB4C0, 0x76B06B00, + 0xE5489FC6, 0x24C64006, 0xBD242607, 0x7CAAF9C7, 0x5591EC44, 0x941F3384, 0x0DFD5585, 0xCC738A45, + 0xA1A92C70, 0x6027F3B0, 0xF9C595B1, 0x384B4A71, 0x11705FF2, 0xD0FE8032, 0x491CE633, 0x889239F3, + 0x1B6ACD35, 0xDAE412F5, 0x430674F4, 0x8288AB34, 0xABB3BEB7, 0x6A3D6177, 0xF3DF0776, 0x3251D8B6, + 0x0F5FE8BB, 0xCED1377B, 0x5733517A, 0x96BD8EBA, 0xBF869B39, 0x7E0844F9, 0xE7EA22F8, 0x2664FD38, + 0xB59C09FE, 0x7412D63E, 0xEDF0B03F, 0x2C7E6FFF, 0x05457A7C, 0xC4CBA5BC, 0x5D29C3BD, 0x9CA71C7D, + 0x2735A3A7, 0xE6BB7C67, 0x7F591A66, 0xBED7C5A6, 0x97ECD025, 0x56620FE5, 0xCF8069E4, 0x0E0EB624, + 0x9DF642E2, 0x5C789D22, 0xC59AFB23, 0x041424E3, 0x2D2F3160, 0xECA1EEA0, 0x754388A1, 0xB4CD5761, + 0x89C3676C, 0x484DB8AC, 0xD1AFDEAD, 0x1021016D, 0x391A14EE, 0xF894CB2E, 0x6176AD2F, 0xA0F872EF, + 0x33008629, 0xF28E59E9, 0x6B6C3FE8, 0xAAE2E028, 0x83D9F5AB, 0x42572A6B, 0xDBB54C6A, 0x1A3B93AA, + }, - { - 0x00000000,0x9BA54C6F,0xEC3B9E9F,0x779ED2F0,0x03063B7F,0x98A37710,0xEF3DA5E0,0x7498E98F, - 0x060C76FE,0x9DA93A91,0xEA37E861,0x7192A40E,0x050A4D81,0x9EAF01EE,0xE931D31E,0x72949F71, - 0x0C18EDFC,0x97BDA193,0xE0237363,0x7B863F0C,0x0F1ED683,0x94BB9AEC,0xE325481C,0x78800473, - 0x0A149B02,0x91B1D76D,0xE62F059D,0x7D8A49F2,0x0912A07D,0x92B7EC12,0xE5293EE2,0x7E8C728D, - 0x1831DBF8,0x83949797,0xF40A4567,0x6FAF0908,0x1B37E087,0x8092ACE8,0xF70C7E18,0x6CA93277, - 0x1E3DAD06,0x8598E169,0xF2063399,0x69A37FF6,0x1D3B9679,0x869EDA16,0xF10008E6,0x6AA54489, - 0x14293604,0x8F8C7A6B,0xF812A89B,0x63B7E4F4,0x172F0D7B,0x8C8A4114,0xFB1493E4,0x60B1DF8B, - 0x122540FA,0x89800C95,0xFE1EDE65,0x65BB920A,0x11237B85,0x8A8637EA,0xFD18E51A,0x66BDA975, - 0x3063B7F0,0xABC6FB9F,0xDC58296F,0x47FD6500,0x33658C8F,0xA8C0C0E0,0xDF5E1210,0x44FB5E7F, - 0x366FC10E,0xADCA8D61,0xDA545F91,0x41F113FE,0x3569FA71,0xAECCB61E,0xD95264EE,0x42F72881, - 0x3C7B5A0C,0xA7DE1663,0xD040C493,0x4BE588FC,0x3F7D6173,0xA4D82D1C,0xD346FFEC,0x48E3B383, - 0x3A772CF2,0xA1D2609D,0xD64CB26D,0x4DE9FE02,0x3971178D,0xA2D45BE2,0xD54A8912,0x4EEFC57D, - 0x28526C08,0xB3F72067,0xC469F297,0x5FCCBEF8,0x2B545777,0xB0F11B18,0xC76FC9E8,0x5CCA8587, - 0x2E5E1AF6,0xB5FB5699,0xC2658469,0x59C0C806,0x2D582189,0xB6FD6DE6,0xC163BF16,0x5AC6F379, - 0x244A81F4,0xBFEFCD9B,0xC8711F6B,0x53D45304,0x274CBA8B,0xBCE9F6E4,0xCB772414,0x50D2687B, - 0x2246F70A,0xB9E3BB65,0xCE7D6995,0x55D825FA,0x2140CC75,0xBAE5801A,0xCD7B52EA,0x56DE1E85, - 0x60C76FE0,0xFB62238F,0x8CFCF17F,0x1759BD10,0x63C1549F,0xF86418F0,0x8FFACA00,0x145F866F, - 0x66CB191E,0xFD6E5571,0x8AF08781,0x1155CBEE,0x65CD2261,0xFE686E0E,0x89F6BCFE,0x1253F091, - 0x6CDF821C,0xF77ACE73,0x80E41C83,0x1B4150EC,0x6FD9B963,0xF47CF50C,0x83E227FC,0x18476B93, - 0x6AD3F4E2,0xF176B88D,0x86E86A7D,0x1D4D2612,0x69D5CF9D,0xF27083F2,0x85EE5102,0x1E4B1D6D, - 0x78F6B418,0xE353F877,0x94CD2A87,0x0F6866E8,0x7BF08F67,0xE055C308,0x97CB11F8,0x0C6E5D97, - 0x7EFAC2E6,0xE55F8E89,0x92C15C79,0x09641016,0x7DFCF999,0xE659B5F6,0x91C76706,0x0A622B69, - 0x74EE59E4,0xEF4B158B,0x98D5C77B,0x03708B14,0x77E8629B,0xEC4D2EF4,0x9BD3FC04,0x0076B06B, - 0x72E22F1A,0xE9476375,0x9ED9B185,0x057CFDEA,0x71E41465,0xEA41580A,0x9DDF8AFA,0x067AC695, - 0x50A4D810,0xCB01947F,0xBC9F468F,0x273A0AE0,0x53A2E36F,0xC807AF00,0xBF997DF0,0x243C319F, - 0x56A8AEEE,0xCD0DE281,0xBA933071,0x21367C1E,0x55AE9591,0xCE0BD9FE,0xB9950B0E,0x22304761, - 0x5CBC35EC,0xC7197983,0xB087AB73,0x2B22E71C,0x5FBA0E93,0xC41F42FC,0xB381900C,0x2824DC63, - 0x5AB04312,0xC1150F7D,0xB68BDD8D,0x2D2E91E2,0x59B6786D,0xC2133402,0xB58DE6F2,0x2E28AA9D, - 0x489503E8,0xD3304F87,0xA4AE9D77,0x3F0BD118,0x4B933897,0xD03674F8,0xA7A8A608,0x3C0DEA67, - 0x4E997516,0xD53C3979,0xA2A2EB89,0x3907A7E6,0x4D9F4E69,0xD63A0206,0xA1A4D0F6,0x3A019C99, - 0x448DEE14,0xDF28A27B,0xA8B6708B,0x33133CE4,0x478BD56B,0xDC2E9904,0xABB04BF4,0x3015079B, - 0x428198EA,0xD924D485,0xAEBA0675,0x351F4A1A,0x4187A395,0xDA22EFFA,0xADBC3D0A,0x36197165, - }, + { + 0x00000000, 0x9BA54C6F, 0xEC3B9E9F, 0x779ED2F0, 0x03063B7F, 0x98A37710, 0xEF3DA5E0, 0x7498E98F, + 0x060C76FE, 0x9DA93A91, 0xEA37E861, 0x7192A40E, 0x050A4D81, 0x9EAF01EE, 0xE931D31E, 0x72949F71, + 0x0C18EDFC, 0x97BDA193, 0xE0237363, 0x7B863F0C, 0x0F1ED683, 0x94BB9AEC, 0xE325481C, 0x78800473, + 0x0A149B02, 0x91B1D76D, 0xE62F059D, 0x7D8A49F2, 0x0912A07D, 0x92B7EC12, 0xE5293EE2, 0x7E8C728D, + 0x1831DBF8, 0x83949797, 0xF40A4567, 0x6FAF0908, 0x1B37E087, 0x8092ACE8, 0xF70C7E18, 0x6CA93277, + 0x1E3DAD06, 0x8598E169, 0xF2063399, 0x69A37FF6, 0x1D3B9679, 0x869EDA16, 0xF10008E6, 0x6AA54489, + 0x14293604, 0x8F8C7A6B, 0xF812A89B, 0x63B7E4F4, 0x172F0D7B, 0x8C8A4114, 0xFB1493E4, 0x60B1DF8B, + 0x122540FA, 0x89800C95, 0xFE1EDE65, 0x65BB920A, 0x11237B85, 0x8A8637EA, 0xFD18E51A, 0x66BDA975, + 0x3063B7F0, 0xABC6FB9F, 0xDC58296F, 0x47FD6500, 0x33658C8F, 0xA8C0C0E0, 0xDF5E1210, 0x44FB5E7F, + 0x366FC10E, 0xADCA8D61, 0xDA545F91, 0x41F113FE, 0x3569FA71, 0xAECCB61E, 0xD95264EE, 0x42F72881, + 0x3C7B5A0C, 0xA7DE1663, 0xD040C493, 0x4BE588FC, 0x3F7D6173, 0xA4D82D1C, 0xD346FFEC, 0x48E3B383, + 0x3A772CF2, 0xA1D2609D, 0xD64CB26D, 0x4DE9FE02, 0x3971178D, 0xA2D45BE2, 0xD54A8912, 0x4EEFC57D, + 0x28526C08, 0xB3F72067, 0xC469F297, 0x5FCCBEF8, 0x2B545777, 0xB0F11B18, 0xC76FC9E8, 0x5CCA8587, + 0x2E5E1AF6, 0xB5FB5699, 0xC2658469, 0x59C0C806, 0x2D582189, 0xB6FD6DE6, 0xC163BF16, 0x5AC6F379, + 0x244A81F4, 0xBFEFCD9B, 0xC8711F6B, 0x53D45304, 0x274CBA8B, 0xBCE9F6E4, 0xCB772414, 0x50D2687B, + 0x2246F70A, 0xB9E3BB65, 0xCE7D6995, 0x55D825FA, 0x2140CC75, 0xBAE5801A, 0xCD7B52EA, 0x56DE1E85, + 0x60C76FE0, 0xFB62238F, 0x8CFCF17F, 0x1759BD10, 0x63C1549F, 0xF86418F0, 0x8FFACA00, 0x145F866F, + 0x66CB191E, 0xFD6E5571, 0x8AF08781, 0x1155CBEE, 0x65CD2261, 0xFE686E0E, 0x89F6BCFE, 0x1253F091, + 0x6CDF821C, 0xF77ACE73, 0x80E41C83, 0x1B4150EC, 0x6FD9B963, 0xF47CF50C, 0x83E227FC, 0x18476B93, + 0x6AD3F4E2, 0xF176B88D, 0x86E86A7D, 0x1D4D2612, 0x69D5CF9D, 0xF27083F2, 0x85EE5102, 0x1E4B1D6D, + 0x78F6B418, 0xE353F877, 0x94CD2A87, 0x0F6866E8, 0x7BF08F67, 0xE055C308, 0x97CB11F8, 0x0C6E5D97, + 0x7EFAC2E6, 0xE55F8E89, 0x92C15C79, 0x09641016, 0x7DFCF999, 0xE659B5F6, 0x91C76706, 0x0A622B69, + 0x74EE59E4, 0xEF4B158B, 0x98D5C77B, 0x03708B14, 0x77E8629B, 0xEC4D2EF4, 0x9BD3FC04, 0x0076B06B, + 0x72E22F1A, 0xE9476375, 0x9ED9B185, 0x057CFDEA, 0x71E41465, 0xEA41580A, 0x9DDF8AFA, 0x067AC695, + 0x50A4D810, 0xCB01947F, 0xBC9F468F, 0x273A0AE0, 0x53A2E36F, 0xC807AF00, 0xBF997DF0, 0x243C319F, + 0x56A8AEEE, 0xCD0DE281, 0xBA933071, 0x21367C1E, 0x55AE9591, 0xCE0BD9FE, 0xB9950B0E, 0x22304761, + 0x5CBC35EC, 0xC7197983, 0xB087AB73, 0x2B22E71C, 0x5FBA0E93, 0xC41F42FC, 0xB381900C, 0x2824DC63, + 0x5AB04312, 0xC1150F7D, 0xB68BDD8D, 0x2D2E91E2, 0x59B6786D, 0xC2133402, 0xB58DE6F2, 0x2E28AA9D, + 0x489503E8, 0xD3304F87, 0xA4AE9D77, 0x3F0BD118, 0x4B933897, 0xD03674F8, 0xA7A8A608, 0x3C0DEA67, + 0x4E997516, 0xD53C3979, 0xA2A2EB89, 0x3907A7E6, 0x4D9F4E69, 0xD63A0206, 0xA1A4D0F6, 0x3A019C99, + 0x448DEE14, 0xDF28A27B, 0xA8B6708B, 0x33133CE4, 0x478BD56B, 0xDC2E9904, 0xABB04BF4, 0x3015079B, + 0x428198EA, 0xD924D485, 0xAEBA0675, 0x351F4A1A, 0x4187A395, 0xDA22EFFA, 0xADBC3D0A, 0x36197165, + }, - { - 0x00000000,0xDD96D985,0x605CB54B,0xBDCA6CCE,0xC0B96A96,0x1D2FB313,0xA0E5DFDD,0x7D730658, - 0x5A03D36D,0x87950AE8,0x3A5F6626,0xE7C9BFA3,0x9ABAB9FB,0x472C607E,0xFAE60CB0,0x2770D535, - 0xB407A6DA,0x69917F5F,0xD45B1391,0x09CDCA14,0x74BECC4C,0xA92815C9,0x14E27907,0xC974A082, - 0xEE0475B7,0x3392AC32,0x8E58C0FC,0x53CE1979,0x2EBD1F21,0xF32BC6A4,0x4EE1AA6A,0x937773EF, - 0xB37E4BF5,0x6EE89270,0xD322FEBE,0x0EB4273B,0x73C72163,0xAE51F8E6,0x139B9428,0xCE0D4DAD, - 0xE97D9898,0x34EB411D,0x89212DD3,0x54B7F456,0x29C4F20E,0xF4522B8B,0x49984745,0x940E9EC0, - 0x0779ED2F,0xDAEF34AA,0x67255864,0xBAB381E1,0xC7C087B9,0x1A565E3C,0xA79C32F2,0x7A0AEB77, - 0x5D7A3E42,0x80ECE7C7,0x3D268B09,0xE0B0528C,0x9DC354D4,0x40558D51,0xFD9FE19F,0x2009381A, - 0xBD8D91AB,0x601B482E,0xDDD124E0,0x0047FD65,0x7D34FB3D,0xA0A222B8,0x1D684E76,0xC0FE97F3, - 0xE78E42C6,0x3A189B43,0x87D2F78D,0x5A442E08,0x27372850,0xFAA1F1D5,0x476B9D1B,0x9AFD449E, - 0x098A3771,0xD41CEEF4,0x69D6823A,0xB4405BBF,0xC9335DE7,0x14A58462,0xA96FE8AC,0x74F93129, - 0x5389E41C,0x8E1F3D99,0x33D55157,0xEE4388D2,0x93308E8A,0x4EA6570F,0xF36C3BC1,0x2EFAE244, - 0x0EF3DA5E,0xD36503DB,0x6EAF6F15,0xB339B690,0xCE4AB0C8,0x13DC694D,0xAE160583,0x7380DC06, - 0x54F00933,0x8966D0B6,0x34ACBC78,0xE93A65FD,0x944963A5,0x49DFBA20,0xF415D6EE,0x29830F6B, - 0xBAF47C84,0x6762A501,0xDAA8C9CF,0x073E104A,0x7A4D1612,0xA7DBCF97,0x1A11A359,0xC7877ADC, - 0xE0F7AFE9,0x3D61766C,0x80AB1AA2,0x5D3DC327,0x204EC57F,0xFDD81CFA,0x40127034,0x9D84A9B1, - 0xA06A2517,0x7DFCFC92,0xC036905C,0x1DA049D9,0x60D34F81,0xBD459604,0x008FFACA,0xDD19234F, - 0xFA69F67A,0x27FF2FFF,0x9A354331,0x47A39AB4,0x3AD09CEC,0xE7464569,0x5A8C29A7,0x871AF022, - 0x146D83CD,0xC9FB5A48,0x74313686,0xA9A7EF03,0xD4D4E95B,0x094230DE,0xB4885C10,0x691E8595, - 0x4E6E50A0,0x93F88925,0x2E32E5EB,0xF3A43C6E,0x8ED73A36,0x5341E3B3,0xEE8B8F7D,0x331D56F8, - 0x13146EE2,0xCE82B767,0x7348DBA9,0xAEDE022C,0xD3AD0474,0x0E3BDDF1,0xB3F1B13F,0x6E6768BA, - 0x4917BD8F,0x9481640A,0x294B08C4,0xF4DDD141,0x89AED719,0x54380E9C,0xE9F26252,0x3464BBD7, - 0xA713C838,0x7A8511BD,0xC74F7D73,0x1AD9A4F6,0x67AAA2AE,0xBA3C7B2B,0x07F617E5,0xDA60CE60, - 0xFD101B55,0x2086C2D0,0x9D4CAE1E,0x40DA779B,0x3DA971C3,0xE03FA846,0x5DF5C488,0x80631D0D, - 0x1DE7B4BC,0xC0716D39,0x7DBB01F7,0xA02DD872,0xDD5EDE2A,0x00C807AF,0xBD026B61,0x6094B2E4, - 0x47E467D1,0x9A72BE54,0x27B8D29A,0xFA2E0B1F,0x875D0D47,0x5ACBD4C2,0xE701B80C,0x3A976189, - 0xA9E01266,0x7476CBE3,0xC9BCA72D,0x142A7EA8,0x695978F0,0xB4CFA175,0x0905CDBB,0xD493143E, - 0xF3E3C10B,0x2E75188E,0x93BF7440,0x4E29ADC5,0x335AAB9D,0xEECC7218,0x53061ED6,0x8E90C753, - 0xAE99FF49,0x730F26CC,0xCEC54A02,0x13539387,0x6E2095DF,0xB3B64C5A,0x0E7C2094,0xD3EAF911, - 0xF49A2C24,0x290CF5A1,0x94C6996F,0x495040EA,0x342346B2,0xE9B59F37,0x547FF3F9,0x89E92A7C, - 0x1A9E5993,0xC7088016,0x7AC2ECD8,0xA754355D,0xDA273305,0x07B1EA80,0xBA7B864E,0x67ED5FCB, - 0x409D8AFE,0x9D0B537B,0x20C13FB5,0xFD57E630,0x8024E068,0x5DB239ED,0xE0785523,0x3DEE8CA6, - }, + { + 0x00000000, 0xDD96D985, 0x605CB54B, 0xBDCA6CCE, 0xC0B96A96, 0x1D2FB313, 0xA0E5DFDD, 0x7D730658, + 0x5A03D36D, 0x87950AE8, 0x3A5F6626, 0xE7C9BFA3, 0x9ABAB9FB, 0x472C607E, 0xFAE60CB0, 0x2770D535, + 0xB407A6DA, 0x69917F5F, 0xD45B1391, 0x09CDCA14, 0x74BECC4C, 0xA92815C9, 0x14E27907, 0xC974A082, + 0xEE0475B7, 0x3392AC32, 0x8E58C0FC, 0x53CE1979, 0x2EBD1F21, 0xF32BC6A4, 0x4EE1AA6A, 0x937773EF, + 0xB37E4BF5, 0x6EE89270, 0xD322FEBE, 0x0EB4273B, 0x73C72163, 0xAE51F8E6, 0x139B9428, 0xCE0D4DAD, + 0xE97D9898, 0x34EB411D, 0x89212DD3, 0x54B7F456, 0x29C4F20E, 0xF4522B8B, 0x49984745, 0x940E9EC0, + 0x0779ED2F, 0xDAEF34AA, 0x67255864, 0xBAB381E1, 0xC7C087B9, 0x1A565E3C, 0xA79C32F2, 0x7A0AEB77, + 0x5D7A3E42, 0x80ECE7C7, 0x3D268B09, 0xE0B0528C, 0x9DC354D4, 0x40558D51, 0xFD9FE19F, 0x2009381A, + 0xBD8D91AB, 0x601B482E, 0xDDD124E0, 0x0047FD65, 0x7D34FB3D, 0xA0A222B8, 0x1D684E76, 0xC0FE97F3, + 0xE78E42C6, 0x3A189B43, 0x87D2F78D, 0x5A442E08, 0x27372850, 0xFAA1F1D5, 0x476B9D1B, 0x9AFD449E, + 0x098A3771, 0xD41CEEF4, 0x69D6823A, 0xB4405BBF, 0xC9335DE7, 0x14A58462, 0xA96FE8AC, 0x74F93129, + 0x5389E41C, 0x8E1F3D99, 0x33D55157, 0xEE4388D2, 0x93308E8A, 0x4EA6570F, 0xF36C3BC1, 0x2EFAE244, + 0x0EF3DA5E, 0xD36503DB, 0x6EAF6F15, 0xB339B690, 0xCE4AB0C8, 0x13DC694D, 0xAE160583, 0x7380DC06, + 0x54F00933, 0x8966D0B6, 0x34ACBC78, 0xE93A65FD, 0x944963A5, 0x49DFBA20, 0xF415D6EE, 0x29830F6B, + 0xBAF47C84, 0x6762A501, 0xDAA8C9CF, 0x073E104A, 0x7A4D1612, 0xA7DBCF97, 0x1A11A359, 0xC7877ADC, + 0xE0F7AFE9, 0x3D61766C, 0x80AB1AA2, 0x5D3DC327, 0x204EC57F, 0xFDD81CFA, 0x40127034, 0x9D84A9B1, + 0xA06A2517, 0x7DFCFC92, 0xC036905C, 0x1DA049D9, 0x60D34F81, 0xBD459604, 0x008FFACA, 0xDD19234F, + 0xFA69F67A, 0x27FF2FFF, 0x9A354331, 0x47A39AB4, 0x3AD09CEC, 0xE7464569, 0x5A8C29A7, 0x871AF022, + 0x146D83CD, 0xC9FB5A48, 0x74313686, 0xA9A7EF03, 0xD4D4E95B, 0x094230DE, 0xB4885C10, 0x691E8595, + 0x4E6E50A0, 0x93F88925, 0x2E32E5EB, 0xF3A43C6E, 0x8ED73A36, 0x5341E3B3, 0xEE8B8F7D, 0x331D56F8, + 0x13146EE2, 0xCE82B767, 0x7348DBA9, 0xAEDE022C, 0xD3AD0474, 0x0E3BDDF1, 0xB3F1B13F, 0x6E6768BA, + 0x4917BD8F, 0x9481640A, 0x294B08C4, 0xF4DDD141, 0x89AED719, 0x54380E9C, 0xE9F26252, 0x3464BBD7, + 0xA713C838, 0x7A8511BD, 0xC74F7D73, 0x1AD9A4F6, 0x67AAA2AE, 0xBA3C7B2B, 0x07F617E5, 0xDA60CE60, + 0xFD101B55, 0x2086C2D0, 0x9D4CAE1E, 0x40DA779B, 0x3DA971C3, 0xE03FA846, 0x5DF5C488, 0x80631D0D, + 0x1DE7B4BC, 0xC0716D39, 0x7DBB01F7, 0xA02DD872, 0xDD5EDE2A, 0x00C807AF, 0xBD026B61, 0x6094B2E4, + 0x47E467D1, 0x9A72BE54, 0x27B8D29A, 0xFA2E0B1F, 0x875D0D47, 0x5ACBD4C2, 0xE701B80C, 0x3A976189, + 0xA9E01266, 0x7476CBE3, 0xC9BCA72D, 0x142A7EA8, 0x695978F0, 0xB4CFA175, 0x0905CDBB, 0xD493143E, + 0xF3E3C10B, 0x2E75188E, 0x93BF7440, 0x4E29ADC5, 0x335AAB9D, 0xEECC7218, 0x53061ED6, 0x8E90C753, + 0xAE99FF49, 0x730F26CC, 0xCEC54A02, 0x13539387, 0x6E2095DF, 0xB3B64C5A, 0x0E7C2094, 0xD3EAF911, + 0xF49A2C24, 0x290CF5A1, 0x94C6996F, 0x495040EA, 0x342346B2, 0xE9B59F37, 0x547FF3F9, 0x89E92A7C, + 0x1A9E5993, 0xC7088016, 0x7AC2ECD8, 0xA754355D, 0xDA273305, 0x07B1EA80, 0xBA7B864E, 0x67ED5FCB, + 0x409D8AFE, 0x9D0B537B, 0x20C13FB5, 0xFD57E630, 0x8024E068, 0x5DB239ED, 0xE0785523, 0x3DEE8CA6, + }, - { - 0x00000000,0x9D0FE176,0xE16EC4AD,0x7C6125DB,0x19AC8F1B,0x84A36E6D,0xF8C24BB6,0x65CDAAC0, - 0x33591E36,0xAE56FF40,0xD237DA9B,0x4F383BED,0x2AF5912D,0xB7FA705B,0xCB9B5580,0x5694B4F6, - 0x66B23C6C,0xFBBDDD1A,0x87DCF8C1,0x1AD319B7,0x7F1EB377,0xE2115201,0x9E7077DA,0x037F96AC, - 0x55EB225A,0xC8E4C32C,0xB485E6F7,0x298A0781,0x4C47AD41,0xD1484C37,0xAD2969EC,0x3026889A, - 0xCD6478D8,0x506B99AE,0x2C0ABC75,0xB1055D03,0xD4C8F7C3,0x49C716B5,0x35A6336E,0xA8A9D218, - 0xFE3D66EE,0x63328798,0x1F53A243,0x825C4335,0xE791E9F5,0x7A9E0883,0x06FF2D58,0x9BF0CC2E, - 0xABD644B4,0x36D9A5C2,0x4AB88019,0xD7B7616F,0xB27ACBAF,0x2F752AD9,0x53140F02,0xCE1BEE74, - 0x988F5A82,0x0580BBF4,0x79E19E2F,0xE4EE7F59,0x8123D599,0x1C2C34EF,0x604D1134,0xFD42F042, - 0x41B9F7F1,0xDCB61687,0xA0D7335C,0x3DD8D22A,0x581578EA,0xC51A999C,0xB97BBC47,0x24745D31, - 0x72E0E9C7,0xEFEF08B1,0x938E2D6A,0x0E81CC1C,0x6B4C66DC,0xF64387AA,0x8A22A271,0x172D4307, - 0x270BCB9D,0xBA042AEB,0xC6650F30,0x5B6AEE46,0x3EA74486,0xA3A8A5F0,0xDFC9802B,0x42C6615D, - 0x1452D5AB,0x895D34DD,0xF53C1106,0x6833F070,0x0DFE5AB0,0x90F1BBC6,0xEC909E1D,0x719F7F6B, - 0x8CDD8F29,0x11D26E5F,0x6DB34B84,0xF0BCAAF2,0x95710032,0x087EE144,0x741FC49F,0xE91025E9, - 0xBF84911F,0x228B7069,0x5EEA55B2,0xC3E5B4C4,0xA6281E04,0x3B27FF72,0x4746DAA9,0xDA493BDF, - 0xEA6FB345,0x77605233,0x0B0177E8,0x960E969E,0xF3C33C5E,0x6ECCDD28,0x12ADF8F3,0x8FA21985, - 0xD936AD73,0x44394C05,0x385869DE,0xA55788A8,0xC09A2268,0x5D95C31E,0x21F4E6C5,0xBCFB07B3, - 0x8373EFE2,0x1E7C0E94,0x621D2B4F,0xFF12CA39,0x9ADF60F9,0x07D0818F,0x7BB1A454,0xE6BE4522, - 0xB02AF1D4,0x2D2510A2,0x51443579,0xCC4BD40F,0xA9867ECF,0x34899FB9,0x48E8BA62,0xD5E75B14, - 0xE5C1D38E,0x78CE32F8,0x04AF1723,0x99A0F655,0xFC6D5C95,0x6162BDE3,0x1D039838,0x800C794E, - 0xD698CDB8,0x4B972CCE,0x37F60915,0xAAF9E863,0xCF3442A3,0x523BA3D5,0x2E5A860E,0xB3556778, - 0x4E17973A,0xD318764C,0xAF795397,0x3276B2E1,0x57BB1821,0xCAB4F957,0xB6D5DC8C,0x2BDA3DFA, - 0x7D4E890C,0xE041687A,0x9C204DA1,0x012FACD7,0x64E20617,0xF9EDE761,0x858CC2BA,0x188323CC, - 0x28A5AB56,0xB5AA4A20,0xC9CB6FFB,0x54C48E8D,0x3109244D,0xAC06C53B,0xD067E0E0,0x4D680196, - 0x1BFCB560,0x86F35416,0xFA9271CD,0x679D90BB,0x02503A7B,0x9F5FDB0D,0xE33EFED6,0x7E311FA0, - 0xC2CA1813,0x5FC5F965,0x23A4DCBE,0xBEAB3DC8,0xDB669708,0x4669767E,0x3A0853A5,0xA707B2D3, - 0xF1930625,0x6C9CE753,0x10FDC288,0x8DF223FE,0xE83F893E,0x75306848,0x09514D93,0x945EACE5, - 0xA478247F,0x3977C509,0x4516E0D2,0xD81901A4,0xBDD4AB64,0x20DB4A12,0x5CBA6FC9,0xC1B58EBF, - 0x97213A49,0x0A2EDB3F,0x764FFEE4,0xEB401F92,0x8E8DB552,0x13825424,0x6FE371FF,0xF2EC9089, - 0x0FAE60CB,0x92A181BD,0xEEC0A466,0x73CF4510,0x1602EFD0,0x8B0D0EA6,0xF76C2B7D,0x6A63CA0B, - 0x3CF77EFD,0xA1F89F8B,0xDD99BA50,0x40965B26,0x255BF1E6,0xB8541090,0xC435354B,0x593AD43D, - 0x691C5CA7,0xF413BDD1,0x8872980A,0x157D797C,0x70B0D3BC,0xEDBF32CA,0x91DE1711,0x0CD1F667, - 0x5A454291,0xC74AA3E7,0xBB2B863C,0x2624674A,0x43E9CD8A,0xDEE62CFC,0xA2870927,0x3F88E851, - }, + { + 0x00000000, 0x9D0FE176, 0xE16EC4AD, 0x7C6125DB, 0x19AC8F1B, 0x84A36E6D, 0xF8C24BB6, 0x65CDAAC0, + 0x33591E36, 0xAE56FF40, 0xD237DA9B, 0x4F383BED, 0x2AF5912D, 0xB7FA705B, 0xCB9B5580, 0x5694B4F6, + 0x66B23C6C, 0xFBBDDD1A, 0x87DCF8C1, 0x1AD319B7, 0x7F1EB377, 0xE2115201, 0x9E7077DA, 0x037F96AC, + 0x55EB225A, 0xC8E4C32C, 0xB485E6F7, 0x298A0781, 0x4C47AD41, 0xD1484C37, 0xAD2969EC, 0x3026889A, + 0xCD6478D8, 0x506B99AE, 0x2C0ABC75, 0xB1055D03, 0xD4C8F7C3, 0x49C716B5, 0x35A6336E, 0xA8A9D218, + 0xFE3D66EE, 0x63328798, 0x1F53A243, 0x825C4335, 0xE791E9F5, 0x7A9E0883, 0x06FF2D58, 0x9BF0CC2E, + 0xABD644B4, 0x36D9A5C2, 0x4AB88019, 0xD7B7616F, 0xB27ACBAF, 0x2F752AD9, 0x53140F02, 0xCE1BEE74, + 0x988F5A82, 0x0580BBF4, 0x79E19E2F, 0xE4EE7F59, 0x8123D599, 0x1C2C34EF, 0x604D1134, 0xFD42F042, + 0x41B9F7F1, 0xDCB61687, 0xA0D7335C, 0x3DD8D22A, 0x581578EA, 0xC51A999C, 0xB97BBC47, 0x24745D31, + 0x72E0E9C7, 0xEFEF08B1, 0x938E2D6A, 0x0E81CC1C, 0x6B4C66DC, 0xF64387AA, 0x8A22A271, 0x172D4307, + 0x270BCB9D, 0xBA042AEB, 0xC6650F30, 0x5B6AEE46, 0x3EA74486, 0xA3A8A5F0, 0xDFC9802B, 0x42C6615D, + 0x1452D5AB, 0x895D34DD, 0xF53C1106, 0x6833F070, 0x0DFE5AB0, 0x90F1BBC6, 0xEC909E1D, 0x719F7F6B, + 0x8CDD8F29, 0x11D26E5F, 0x6DB34B84, 0xF0BCAAF2, 0x95710032, 0x087EE144, 0x741FC49F, 0xE91025E9, + 0xBF84911F, 0x228B7069, 0x5EEA55B2, 0xC3E5B4C4, 0xA6281E04, 0x3B27FF72, 0x4746DAA9, 0xDA493BDF, + 0xEA6FB345, 0x77605233, 0x0B0177E8, 0x960E969E, 0xF3C33C5E, 0x6ECCDD28, 0x12ADF8F3, 0x8FA21985, + 0xD936AD73, 0x44394C05, 0x385869DE, 0xA55788A8, 0xC09A2268, 0x5D95C31E, 0x21F4E6C5, 0xBCFB07B3, + 0x8373EFE2, 0x1E7C0E94, 0x621D2B4F, 0xFF12CA39, 0x9ADF60F9, 0x07D0818F, 0x7BB1A454, 0xE6BE4522, + 0xB02AF1D4, 0x2D2510A2, 0x51443579, 0xCC4BD40F, 0xA9867ECF, 0x34899FB9, 0x48E8BA62, 0xD5E75B14, + 0xE5C1D38E, 0x78CE32F8, 0x04AF1723, 0x99A0F655, 0xFC6D5C95, 0x6162BDE3, 0x1D039838, 0x800C794E, + 0xD698CDB8, 0x4B972CCE, 0x37F60915, 0xAAF9E863, 0xCF3442A3, 0x523BA3D5, 0x2E5A860E, 0xB3556778, + 0x4E17973A, 0xD318764C, 0xAF795397, 0x3276B2E1, 0x57BB1821, 0xCAB4F957, 0xB6D5DC8C, 0x2BDA3DFA, + 0x7D4E890C, 0xE041687A, 0x9C204DA1, 0x012FACD7, 0x64E20617, 0xF9EDE761, 0x858CC2BA, 0x188323CC, + 0x28A5AB56, 0xB5AA4A20, 0xC9CB6FFB, 0x54C48E8D, 0x3109244D, 0xAC06C53B, 0xD067E0E0, 0x4D680196, + 0x1BFCB560, 0x86F35416, 0xFA9271CD, 0x679D90BB, 0x02503A7B, 0x9F5FDB0D, 0xE33EFED6, 0x7E311FA0, + 0xC2CA1813, 0x5FC5F965, 0x23A4DCBE, 0xBEAB3DC8, 0xDB669708, 0x4669767E, 0x3A0853A5, 0xA707B2D3, + 0xF1930625, 0x6C9CE753, 0x10FDC288, 0x8DF223FE, 0xE83F893E, 0x75306848, 0x09514D93, 0x945EACE5, + 0xA478247F, 0x3977C509, 0x4516E0D2, 0xD81901A4, 0xBDD4AB64, 0x20DB4A12, 0x5CBA6FC9, 0xC1B58EBF, + 0x97213A49, 0x0A2EDB3F, 0x764FFEE4, 0xEB401F92, 0x8E8DB552, 0x13825424, 0x6FE371FF, 0xF2EC9089, + 0x0FAE60CB, 0x92A181BD, 0xEEC0A466, 0x73CF4510, 0x1602EFD0, 0x8B0D0EA6, 0xF76C2B7D, 0x6A63CA0B, + 0x3CF77EFD, 0xA1F89F8B, 0xDD99BA50, 0x40965B26, 0x255BF1E6, 0xB8541090, 0xC435354B, 0x593AD43D, + 0x691C5CA7, 0xF413BDD1, 0x8872980A, 0x157D797C, 0x70B0D3BC, 0xEDBF32CA, 0x91DE1711, 0x0CD1F667, + 0x5A454291, 0xC74AA3E7, 0xBB2B863C, 0x2624674A, 0x43E9CD8A, 0xDEE62CFC, 0xA2870927, 0x3F88E851, + }, - { - 0x00000000,0xB9FBDBE8,0xA886B191,0x117D6A79,0x8A7C6563,0x3387BE8B,0x22FAD4F2,0x9B010F1A, - 0xCF89CC87,0x7672176F,0x670F7D16,0xDEF4A6FE,0x45F5A9E4,0xFC0E720C,0xED731875,0x5488C39D, - 0x44629F4F,0xFD9944A7,0xECE42EDE,0x551FF536,0xCE1EFA2C,0x77E521C4,0x66984BBD,0xDF639055, - 0x8BEB53C8,0x32108820,0x236DE259,0x9A9639B1,0x019736AB,0xB86CED43,0xA911873A,0x10EA5CD2, - 0x88C53E9E,0x313EE576,0x20438F0F,0x99B854E7,0x02B95BFD,0xBB428015,0xAA3FEA6C,0x13C43184, - 0x474CF219,0xFEB729F1,0xEFCA4388,0x56319860,0xCD30977A,0x74CB4C92,0x65B626EB,0xDC4DFD03, - 0xCCA7A1D1,0x755C7A39,0x64211040,0xDDDACBA8,0x46DBC4B2,0xFF201F5A,0xEE5D7523,0x57A6AECB, - 0x032E6D56,0xBAD5B6BE,0xABA8DCC7,0x1253072F,0x89520835,0x30A9D3DD,0x21D4B9A4,0x982F624C, - 0xCAFB7B7D,0x7300A095,0x627DCAEC,0xDB861104,0x40871E1E,0xF97CC5F6,0xE801AF8F,0x51FA7467, - 0x0572B7FA,0xBC896C12,0xADF4066B,0x140FDD83,0x8F0ED299,0x36F50971,0x27886308,0x9E73B8E0, - 0x8E99E432,0x37623FDA,0x261F55A3,0x9FE48E4B,0x04E58151,0xBD1E5AB9,0xAC6330C0,0x1598EB28, - 0x411028B5,0xF8EBF35D,0xE9969924,0x506D42CC,0xCB6C4DD6,0x7297963E,0x63EAFC47,0xDA1127AF, - 0x423E45E3,0xFBC59E0B,0xEAB8F472,0x53432F9A,0xC8422080,0x71B9FB68,0x60C49111,0xD93F4AF9, - 0x8DB78964,0x344C528C,0x253138F5,0x9CCAE31D,0x07CBEC07,0xBE3037EF,0xAF4D5D96,0x16B6867E, - 0x065CDAAC,0xBFA70144,0xAEDA6B3D,0x1721B0D5,0x8C20BFCF,0x35DB6427,0x24A60E5E,0x9D5DD5B6, - 0xC9D5162B,0x702ECDC3,0x6153A7BA,0xD8A87C52,0x43A97348,0xFA52A8A0,0xEB2FC2D9,0x52D41931, - 0x4E87F0BB,0xF77C2B53,0xE601412A,0x5FFA9AC2,0xC4FB95D8,0x7D004E30,0x6C7D2449,0xD586FFA1, - 0x810E3C3C,0x38F5E7D4,0x29888DAD,0x90735645,0x0B72595F,0xB28982B7,0xA3F4E8CE,0x1A0F3326, - 0x0AE56FF4,0xB31EB41C,0xA263DE65,0x1B98058D,0x80990A97,0x3962D17F,0x281FBB06,0x91E460EE, - 0xC56CA373,0x7C97789B,0x6DEA12E2,0xD411C90A,0x4F10C610,0xF6EB1DF8,0xE7967781,0x5E6DAC69, - 0xC642CE25,0x7FB915CD,0x6EC47FB4,0xD73FA45C,0x4C3EAB46,0xF5C570AE,0xE4B81AD7,0x5D43C13F, - 0x09CB02A2,0xB030D94A,0xA14DB333,0x18B668DB,0x83B767C1,0x3A4CBC29,0x2B31D650,0x92CA0DB8, - 0x8220516A,0x3BDB8A82,0x2AA6E0FB,0x935D3B13,0x085C3409,0xB1A7EFE1,0xA0DA8598,0x19215E70, - 0x4DA99DED,0xF4524605,0xE52F2C7C,0x5CD4F794,0xC7D5F88E,0x7E2E2366,0x6F53491F,0xD6A892F7, - 0x847C8BC6,0x3D87502E,0x2CFA3A57,0x9501E1BF,0x0E00EEA5,0xB7FB354D,0xA6865F34,0x1F7D84DC, - 0x4BF54741,0xF20E9CA9,0xE373F6D0,0x5A882D38,0xC1892222,0x7872F9CA,0x690F93B3,0xD0F4485B, - 0xC01E1489,0x79E5CF61,0x6898A518,0xD1637EF0,0x4A6271EA,0xF399AA02,0xE2E4C07B,0x5B1F1B93, - 0x0F97D80E,0xB66C03E6,0xA711699F,0x1EEAB277,0x85EBBD6D,0x3C106685,0x2D6D0CFC,0x9496D714, - 0x0CB9B558,0xB5426EB0,0xA43F04C9,0x1DC4DF21,0x86C5D03B,0x3F3E0BD3,0x2E4361AA,0x97B8BA42, - 0xC33079DF,0x7ACBA237,0x6BB6C84E,0xD24D13A6,0x494C1CBC,0xF0B7C754,0xE1CAAD2D,0x583176C5, - 0x48DB2A17,0xF120F1FF,0xE05D9B86,0x59A6406E,0xC2A74F74,0x7B5C949C,0x6A21FEE5,0xD3DA250D, - 0x8752E690,0x3EA93D78,0x2FD45701,0x962F8CE9,0x0D2E83F3,0xB4D5581B,0xA5A83262,0x1C53E98A, - }, + { + 0x00000000, 0xB9FBDBE8, 0xA886B191, 0x117D6A79, 0x8A7C6563, 0x3387BE8B, 0x22FAD4F2, 0x9B010F1A, + 0xCF89CC87, 0x7672176F, 0x670F7D16, 0xDEF4A6FE, 0x45F5A9E4, 0xFC0E720C, 0xED731875, 0x5488C39D, + 0x44629F4F, 0xFD9944A7, 0xECE42EDE, 0x551FF536, 0xCE1EFA2C, 0x77E521C4, 0x66984BBD, 0xDF639055, + 0x8BEB53C8, 0x32108820, 0x236DE259, 0x9A9639B1, 0x019736AB, 0xB86CED43, 0xA911873A, 0x10EA5CD2, + 0x88C53E9E, 0x313EE576, 0x20438F0F, 0x99B854E7, 0x02B95BFD, 0xBB428015, 0xAA3FEA6C, 0x13C43184, + 0x474CF219, 0xFEB729F1, 0xEFCA4388, 0x56319860, 0xCD30977A, 0x74CB4C92, 0x65B626EB, 0xDC4DFD03, + 0xCCA7A1D1, 0x755C7A39, 0x64211040, 0xDDDACBA8, 0x46DBC4B2, 0xFF201F5A, 0xEE5D7523, 0x57A6AECB, + 0x032E6D56, 0xBAD5B6BE, 0xABA8DCC7, 0x1253072F, 0x89520835, 0x30A9D3DD, 0x21D4B9A4, 0x982F624C, + 0xCAFB7B7D, 0x7300A095, 0x627DCAEC, 0xDB861104, 0x40871E1E, 0xF97CC5F6, 0xE801AF8F, 0x51FA7467, + 0x0572B7FA, 0xBC896C12, 0xADF4066B, 0x140FDD83, 0x8F0ED299, 0x36F50971, 0x27886308, 0x9E73B8E0, + 0x8E99E432, 0x37623FDA, 0x261F55A3, 0x9FE48E4B, 0x04E58151, 0xBD1E5AB9, 0xAC6330C0, 0x1598EB28, + 0x411028B5, 0xF8EBF35D, 0xE9969924, 0x506D42CC, 0xCB6C4DD6, 0x7297963E, 0x63EAFC47, 0xDA1127AF, + 0x423E45E3, 0xFBC59E0B, 0xEAB8F472, 0x53432F9A, 0xC8422080, 0x71B9FB68, 0x60C49111, 0xD93F4AF9, + 0x8DB78964, 0x344C528C, 0x253138F5, 0x9CCAE31D, 0x07CBEC07, 0xBE3037EF, 0xAF4D5D96, 0x16B6867E, + 0x065CDAAC, 0xBFA70144, 0xAEDA6B3D, 0x1721B0D5, 0x8C20BFCF, 0x35DB6427, 0x24A60E5E, 0x9D5DD5B6, + 0xC9D5162B, 0x702ECDC3, 0x6153A7BA, 0xD8A87C52, 0x43A97348, 0xFA52A8A0, 0xEB2FC2D9, 0x52D41931, + 0x4E87F0BB, 0xF77C2B53, 0xE601412A, 0x5FFA9AC2, 0xC4FB95D8, 0x7D004E30, 0x6C7D2449, 0xD586FFA1, + 0x810E3C3C, 0x38F5E7D4, 0x29888DAD, 0x90735645, 0x0B72595F, 0xB28982B7, 0xA3F4E8CE, 0x1A0F3326, + 0x0AE56FF4, 0xB31EB41C, 0xA263DE65, 0x1B98058D, 0x80990A97, 0x3962D17F, 0x281FBB06, 0x91E460EE, + 0xC56CA373, 0x7C97789B, 0x6DEA12E2, 0xD411C90A, 0x4F10C610, 0xF6EB1DF8, 0xE7967781, 0x5E6DAC69, + 0xC642CE25, 0x7FB915CD, 0x6EC47FB4, 0xD73FA45C, 0x4C3EAB46, 0xF5C570AE, 0xE4B81AD7, 0x5D43C13F, + 0x09CB02A2, 0xB030D94A, 0xA14DB333, 0x18B668DB, 0x83B767C1, 0x3A4CBC29, 0x2B31D650, 0x92CA0DB8, + 0x8220516A, 0x3BDB8A82, 0x2AA6E0FB, 0x935D3B13, 0x085C3409, 0xB1A7EFE1, 0xA0DA8598, 0x19215E70, + 0x4DA99DED, 0xF4524605, 0xE52F2C7C, 0x5CD4F794, 0xC7D5F88E, 0x7E2E2366, 0x6F53491F, 0xD6A892F7, + 0x847C8BC6, 0x3D87502E, 0x2CFA3A57, 0x9501E1BF, 0x0E00EEA5, 0xB7FB354D, 0xA6865F34, 0x1F7D84DC, + 0x4BF54741, 0xF20E9CA9, 0xE373F6D0, 0x5A882D38, 0xC1892222, 0x7872F9CA, 0x690F93B3, 0xD0F4485B, + 0xC01E1489, 0x79E5CF61, 0x6898A518, 0xD1637EF0, 0x4A6271EA, 0xF399AA02, 0xE2E4C07B, 0x5B1F1B93, + 0x0F97D80E, 0xB66C03E6, 0xA711699F, 0x1EEAB277, 0x85EBBD6D, 0x3C106685, 0x2D6D0CFC, 0x9496D714, + 0x0CB9B558, 0xB5426EB0, 0xA43F04C9, 0x1DC4DF21, 0x86C5D03B, 0x3F3E0BD3, 0x2E4361AA, 0x97B8BA42, + 0xC33079DF, 0x7ACBA237, 0x6BB6C84E, 0xD24D13A6, 0x494C1CBC, 0xF0B7C754, 0xE1CAAD2D, 0x583176C5, + 0x48DB2A17, 0xF120F1FF, 0xE05D9B86, 0x59A6406E, 0xC2A74F74, 0x7B5C949C, 0x6A21FEE5, 0xD3DA250D, + 0x8752E690, 0x3EA93D78, 0x2FD45701, 0x962F8CE9, 0x0D2E83F3, 0xB4D5581B, 0xA5A83262, 0x1C53E98A, + }, - { - 0x00000000,0xAE689191,0x87A02563,0x29C8B4F2,0xD4314C87,0x7A59DD16,0x539169E4,0xFDF9F875, - 0x73139F4F,0xDD7B0EDE,0xF4B3BA2C,0x5ADB2BBD,0xA722D3C8,0x094A4259,0x2082F6AB,0x8EEA673A, - 0xE6273E9E,0x484FAF0F,0x61871BFD,0xCFEF8A6C,0x32167219,0x9C7EE388,0xB5B6577A,0x1BDEC6EB, - 0x9534A1D1,0x3B5C3040,0x129484B2,0xBCFC1523,0x4105ED56,0xEF6D7CC7,0xC6A5C835,0x68CD59A4, - 0x173F7B7D,0xB957EAEC,0x909F5E1E,0x3EF7CF8F,0xC30E37FA,0x6D66A66B,0x44AE1299,0xEAC68308, - 0x642CE432,0xCA4475A3,0xE38CC151,0x4DE450C0,0xB01DA8B5,0x1E753924,0x37BD8DD6,0x99D51C47, - 0xF11845E3,0x5F70D472,0x76B86080,0xD8D0F111,0x25290964,0x8B4198F5,0xA2892C07,0x0CE1BD96, - 0x820BDAAC,0x2C634B3D,0x05ABFFCF,0xABC36E5E,0x563A962B,0xF85207BA,0xD19AB348,0x7FF222D9, - 0x2E7EF6FA,0x8016676B,0xA9DED399,0x07B64208,0xFA4FBA7D,0x54272BEC,0x7DEF9F1E,0xD3870E8F, - 0x5D6D69B5,0xF305F824,0xDACD4CD6,0x74A5DD47,0x895C2532,0x2734B4A3,0x0EFC0051,0xA09491C0, - 0xC859C864,0x663159F5,0x4FF9ED07,0xE1917C96,0x1C6884E3,0xB2001572,0x9BC8A180,0x35A03011, - 0xBB4A572B,0x1522C6BA,0x3CEA7248,0x9282E3D9,0x6F7B1BAC,0xC1138A3D,0xE8DB3ECF,0x46B3AF5E, - 0x39418D87,0x97291C16,0xBEE1A8E4,0x10893975,0xED70C100,0x43185091,0x6AD0E463,0xC4B875F2, - 0x4A5212C8,0xE43A8359,0xCDF237AB,0x639AA63A,0x9E635E4F,0x300BCFDE,0x19C37B2C,0xB7ABEABD, - 0xDF66B319,0x710E2288,0x58C6967A,0xF6AE07EB,0x0B57FF9E,0xA53F6E0F,0x8CF7DAFD,0x229F4B6C, - 0xAC752C56,0x021DBDC7,0x2BD50935,0x85BD98A4,0x784460D1,0xD62CF140,0xFFE445B2,0x518CD423, - 0x5CFDEDF4,0xF2957C65,0xDB5DC897,0x75355906,0x88CCA173,0x26A430E2,0x0F6C8410,0xA1041581, - 0x2FEE72BB,0x8186E32A,0xA84E57D8,0x0626C649,0xFBDF3E3C,0x55B7AFAD,0x7C7F1B5F,0xD2178ACE, - 0xBADAD36A,0x14B242FB,0x3D7AF609,0x93126798,0x6EEB9FED,0xC0830E7C,0xE94BBA8E,0x47232B1F, - 0xC9C94C25,0x67A1DDB4,0x4E696946,0xE001F8D7,0x1DF800A2,0xB3909133,0x9A5825C1,0x3430B450, - 0x4BC29689,0xE5AA0718,0xCC62B3EA,0x620A227B,0x9FF3DA0E,0x319B4B9F,0x1853FF6D,0xB63B6EFC, - 0x38D109C6,0x96B99857,0xBF712CA5,0x1119BD34,0xECE04541,0x4288D4D0,0x6B406022,0xC528F1B3, - 0xADE5A817,0x038D3986,0x2A458D74,0x842D1CE5,0x79D4E490,0xD7BC7501,0xFE74C1F3,0x501C5062, - 0xDEF63758,0x709EA6C9,0x5956123B,0xF73E83AA,0x0AC77BDF,0xA4AFEA4E,0x8D675EBC,0x230FCF2D, - 0x72831B0E,0xDCEB8A9F,0xF5233E6D,0x5B4BAFFC,0xA6B25789,0x08DAC618,0x211272EA,0x8F7AE37B, - 0x01908441,0xAFF815D0,0x8630A122,0x285830B3,0xD5A1C8C6,0x7BC95957,0x5201EDA5,0xFC697C34, - 0x94A42590,0x3ACCB401,0x130400F3,0xBD6C9162,0x40956917,0xEEFDF886,0xC7354C74,0x695DDDE5, - 0xE7B7BADF,0x49DF2B4E,0x60179FBC,0xCE7F0E2D,0x3386F658,0x9DEE67C9,0xB426D33B,0x1A4E42AA, - 0x65BC6073,0xCBD4F1E2,0xE21C4510,0x4C74D481,0xB18D2CF4,0x1FE5BD65,0x362D0997,0x98459806, - 0x16AFFF3C,0xB8C76EAD,0x910FDA5F,0x3F674BCE,0xC29EB3BB,0x6CF6222A,0x453E96D8,0xEB560749, - 0x839B5EED,0x2DF3CF7C,0x043B7B8E,0xAA53EA1F,0x57AA126A,0xF9C283FB,0xD00A3709,0x7E62A698, - 0xF088C1A2,0x5EE05033,0x7728E4C1,0xD9407550,0x24B98D25,0x8AD11CB4,0xA319A846,0x0D7139D7, - } + { + 0x00000000, 0xAE689191, 0x87A02563, 0x29C8B4F2, 0xD4314C87, 0x7A59DD16, 0x539169E4, 0xFDF9F875, + 0x73139F4F, 0xDD7B0EDE, 0xF4B3BA2C, 0x5ADB2BBD, 0xA722D3C8, 0x094A4259, 0x2082F6AB, 0x8EEA673A, + 0xE6273E9E, 0x484FAF0F, 0x61871BFD, 0xCFEF8A6C, 0x32167219, 0x9C7EE388, 0xB5B6577A, 0x1BDEC6EB, + 0x9534A1D1, 0x3B5C3040, 0x129484B2, 0xBCFC1523, 0x4105ED56, 0xEF6D7CC7, 0xC6A5C835, 0x68CD59A4, + 0x173F7B7D, 0xB957EAEC, 0x909F5E1E, 0x3EF7CF8F, 0xC30E37FA, 0x6D66A66B, 0x44AE1299, 0xEAC68308, + 0x642CE432, 0xCA4475A3, 0xE38CC151, 0x4DE450C0, 0xB01DA8B5, 0x1E753924, 0x37BD8DD6, 0x99D51C47, + 0xF11845E3, 0x5F70D472, 0x76B86080, 0xD8D0F111, 0x25290964, 0x8B4198F5, 0xA2892C07, 0x0CE1BD96, + 0x820BDAAC, 0x2C634B3D, 0x05ABFFCF, 0xABC36E5E, 0x563A962B, 0xF85207BA, 0xD19AB348, 0x7FF222D9, + 0x2E7EF6FA, 0x8016676B, 0xA9DED399, 0x07B64208, 0xFA4FBA7D, 0x54272BEC, 0x7DEF9F1E, 0xD3870E8F, + 0x5D6D69B5, 0xF305F824, 0xDACD4CD6, 0x74A5DD47, 0x895C2532, 0x2734B4A3, 0x0EFC0051, 0xA09491C0, + 0xC859C864, 0x663159F5, 0x4FF9ED07, 0xE1917C96, 0x1C6884E3, 0xB2001572, 0x9BC8A180, 0x35A03011, + 0xBB4A572B, 0x1522C6BA, 0x3CEA7248, 0x9282E3D9, 0x6F7B1BAC, 0xC1138A3D, 0xE8DB3ECF, 0x46B3AF5E, + 0x39418D87, 0x97291C16, 0xBEE1A8E4, 0x10893975, 0xED70C100, 0x43185091, 0x6AD0E463, 0xC4B875F2, + 0x4A5212C8, 0xE43A8359, 0xCDF237AB, 0x639AA63A, 0x9E635E4F, 0x300BCFDE, 0x19C37B2C, 0xB7ABEABD, + 0xDF66B319, 0x710E2288, 0x58C6967A, 0xF6AE07EB, 0x0B57FF9E, 0xA53F6E0F, 0x8CF7DAFD, 0x229F4B6C, + 0xAC752C56, 0x021DBDC7, 0x2BD50935, 0x85BD98A4, 0x784460D1, 0xD62CF140, 0xFFE445B2, 0x518CD423, + 0x5CFDEDF4, 0xF2957C65, 0xDB5DC897, 0x75355906, 0x88CCA173, 0x26A430E2, 0x0F6C8410, 0xA1041581, + 0x2FEE72BB, 0x8186E32A, 0xA84E57D8, 0x0626C649, 0xFBDF3E3C, 0x55B7AFAD, 0x7C7F1B5F, 0xD2178ACE, + 0xBADAD36A, 0x14B242FB, 0x3D7AF609, 0x93126798, 0x6EEB9FED, 0xC0830E7C, 0xE94BBA8E, 0x47232B1F, + 0xC9C94C25, 0x67A1DDB4, 0x4E696946, 0xE001F8D7, 0x1DF800A2, 0xB3909133, 0x9A5825C1, 0x3430B450, + 0x4BC29689, 0xE5AA0718, 0xCC62B3EA, 0x620A227B, 0x9FF3DA0E, 0x319B4B9F, 0x1853FF6D, 0xB63B6EFC, + 0x38D109C6, 0x96B99857, 0xBF712CA5, 0x1119BD34, 0xECE04541, 0x4288D4D0, 0x6B406022, 0xC528F1B3, + 0xADE5A817, 0x038D3986, 0x2A458D74, 0x842D1CE5, 0x79D4E490, 0xD7BC7501, 0xFE74C1F3, 0x501C5062, + 0xDEF63758, 0x709EA6C9, 0x5956123B, 0xF73E83AA, 0x0AC77BDF, 0xA4AFEA4E, 0x8D675EBC, 0x230FCF2D, + 0x72831B0E, 0xDCEB8A9F, 0xF5233E6D, 0x5B4BAFFC, 0xA6B25789, 0x08DAC618, 0x211272EA, 0x8F7AE37B, + 0x01908441, 0xAFF815D0, 0x8630A122, 0x285830B3, 0xD5A1C8C6, 0x7BC95957, 0x5201EDA5, 0xFC697C34, + 0x94A42590, 0x3ACCB401, 0x130400F3, 0xBD6C9162, 0x40956917, 0xEEFDF886, 0xC7354C74, 0x695DDDE5, + 0xE7B7BADF, 0x49DF2B4E, 0x60179FBC, 0xCE7F0E2D, 0x3386F658, 0x9DEE67C9, 0xB426D33B, 0x1A4E42AA, + 0x65BC6073, 0xCBD4F1E2, 0xE21C4510, 0x4C74D481, 0xB18D2CF4, 0x1FE5BD65, 0x362D0997, 0x98459806, + 0x16AFFF3C, 0xB8C76EAD, 0x910FDA5F, 0x3F674BCE, 0xC29EB3BB, 0x6CF6222A, 0x453E96D8, 0xEB560749, + 0x839B5EED, 0x2DF3CF7C, 0x043B7B8E, 0xAA53EA1F, 0x57AA126A, 0xF9C283FB, 0xD00A3709, 0x7E62A698, + 0xF088C1A2, 0x5EE05033, 0x7728E4C1, 0xD9407550, 0x24B98D25, 0x8AD11CB4, 0xA319A846, 0x0D7139D7, + } }; diff --git a/Utilities/CRC32.h b/Utilities/CRC32.h index a3bc813..fe7622e 100644 --- a/Utilities/CRC32.h +++ b/Utilities/CRC32.h @@ -9,4 +9,4 @@ private: public: static uint32_t GetCRC(uint8_t* buffer, std::streamoff length); static uint32_t GetCRC(string filename); -}; \ No newline at end of file +}; diff --git a/Utilities/CamstudioCodec.cpp b/Utilities/CamstudioCodec.cpp index 2ea313e..240dd61 100644 --- a/Utilities/CamstudioCodec.cpp +++ b/Utilities/CamstudioCodec.cpp @@ -19,25 +19,28 @@ bool CamstudioCodec::SetupCompress(int width, int height, uint32_t compressionLe _compressionLevel = compressionLevel; _orgWidth = width; - if(width % 4 != 0) { + if (width % 4 != 0) + { _rowStride = ((int)((width * 24 + 31) / 32 * 4)); - } else { - _rowStride = width*3; + } + else + { + _rowStride = width * 3; } _height = height; - _prevFrame = new uint8_t[_rowStride*_height]; //24-bit RGB - _currentFrame = new uint8_t[_rowStride*_height]; //24-bit RGB - _buffer = new uint8_t[_rowStride*_height]; //24-bit RGB + _prevFrame = new uint8_t[_rowStride * _height]; //24-bit RGB + _currentFrame = new uint8_t[_rowStride * _height]; //24-bit RGB + _buffer = new uint8_t[_rowStride * _height]; //24-bit RGB - _compressBufferLength = compressBound(_rowStride*_height) + 2; + _compressBufferLength = compressBound(_rowStride * _height) + 2; _compressBuffer = new uint8_t[_compressBufferLength]; - + memset(_prevFrame, 0, _rowStride * _height); memset(_currentFrame, 0, _rowStride * _height); memset(_buffer, 0, _rowStride * _height); memset(_compressBuffer, 0, _compressBufferLength); - + deflateInit(&_compressor, compressionLevel); return true; @@ -45,7 +48,8 @@ bool CamstudioCodec::SetupCompress(int width, int height, uint32_t compressionLe void CamstudioCodec::LoadRow(uint8_t* inPointer, uint8_t* outPointer) { - for(int x = 0; x < _orgWidth; x++) { + for (int x = 0; x < _orgWidth; x++) + { outPointer[0] = inPointer[0]; outPointer[1] = inPointer[1]; outPointer[2] = inPointer[2]; @@ -54,7 +58,7 @@ void CamstudioCodec::LoadRow(uint8_t* inPointer, uint8_t* outPointer) } } -int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) +int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) { deflateReset(&_compressor); @@ -65,25 +69,30 @@ int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** _compressBuffer[1] = 8; //8-bit per color uint8_t* rowBuffer = _currentFrame; - for(int y = 0; y < _height; y++) { + for (int y = 0; y < _height; y++) + { LoadRow(frameData + (_height - y - 1) * _orgWidth * 4, rowBuffer); rowBuffer += _rowStride; } - if(isKeyFrame) { + if (isKeyFrame) + { _compressor.next_in = _currentFrame; - } else { - for(int i = 0, len = _rowStride * _height; i < len; i++) { + } + else + { + for (int i = 0, len = _rowStride * _height; i < len; i++) + { _buffer[i] = _currentFrame[i] - _prevFrame[i]; } _compressor.next_in = _buffer; } - memcpy(_prevFrame, _currentFrame, _rowStride*_height); - + memcpy(_prevFrame, _currentFrame, _rowStride * _height); + _compressor.avail_in = _height * _rowStride; deflate(&_compressor, MZ_FINISH); - + *compressedData = _compressBuffer; return _compressor.total_out + 2; } @@ -91,4 +100,4 @@ int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** const char* CamstudioCodec::GetFourCC() { return "CSCD"; -} \ No newline at end of file +} diff --git a/Utilities/CamstudioCodec.h b/Utilities/CamstudioCodec.h index 4e5eede..0e108bc 100644 --- a/Utilities/CamstudioCodec.h +++ b/Utilities/CamstudioCodec.h @@ -25,6 +25,6 @@ public: virtual ~CamstudioCodec(); virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override; - virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override; + virtual int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) override; virtual const char* GetFourCC() override; -}; \ No newline at end of file +}; diff --git a/Utilities/Equalizer.cpp b/Utilities/Equalizer.cpp index 7189816..c965724 100644 --- a/Utilities/Equalizer.cpp +++ b/Utilities/Equalizer.cpp @@ -2,13 +2,14 @@ #include "Equalizer.h" #include "orfanidis_eq.h" -void Equalizer::ApplyEqualizer(uint32_t sampleCount, int16_t *samples) +void Equalizer::ApplyEqualizer(uint32_t sampleCount, int16_t* samples) { double outL, outR; - for(uint32_t i = 0; i < sampleCount; i++) { + for (uint32_t i = 0; i < sampleCount; i++) + { double inL = samples[i * 2]; double inR = samples[i * 2 + 1]; - + _equalizerLeft->sbs_process(&inL, &outL); _equalizerRight->sbs_process(&inR, &outR); @@ -19,13 +20,18 @@ void Equalizer::ApplyEqualizer(uint32_t sampleCount, int16_t *samples) void Equalizer::UpdateEqualizers(vector bandGains, uint32_t sampleRate) { - if(_prevSampleRate != sampleRate || memcmp(bandGains.data(), _prevEqualizerGains.data(), bandGains.size() * sizeof(double)) != 0) { - vector bands = { 40, 56, 80, 113, 160, 225, 320, 450, 600, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 10000, 12500, 13000 }; + if (_prevSampleRate != sampleRate || memcmp(bandGains.data(), _prevEqualizerGains.data(), + bandGains.size() * sizeof(double)) != 0) + { + vector bands = { + 40, 56, 80, 113, 160, 225, 320, 450, 600, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 10000, 12500, 13000 + }; bands.insert(bands.begin(), bands[0] - (bands[1] - bands[0])); bands.insert(bands.end(), bands[bands.size() - 1] + (bands[bands.size() - 1] - bands[bands.size() - 2])); _eqFrequencyGrid.reset(new orfanidis_eq::freq_grid()); - for(size_t i = 1; i < bands.size() - 1; i++) { + for (size_t i = 1; i < bands.size() - 1; i++) + { _eqFrequencyGrid->add_band((bands[i] + bands[i - 1]) / 2, bands[i], (bands[i + 1] + bands[i]) / 2); } @@ -34,7 +40,8 @@ void Equalizer::UpdateEqualizers(vector bandGains, uint32_t sampleRate) _equalizerLeft->set_sample_rate(sampleRate); _equalizerRight->set_sample_rate(sampleRate); - for(unsigned int i = 0; i < _eqFrequencyGrid->get_number_of_bands(); i++) { + for (unsigned int i = 0; i < _eqFrequencyGrid->get_number_of_bands(); i++) + { _equalizerLeft->change_band_gain_db(i, bandGains[i]); _equalizerRight->change_band_gain_db(i, bandGains[i]); } diff --git a/Utilities/Equalizer.h b/Utilities/Equalizer.h index a354d36..83ebfa5 100644 --- a/Utilities/Equalizer.h +++ b/Utilities/Equalizer.h @@ -13,6 +13,6 @@ private: vector _prevEqualizerGains; public: - void ApplyEqualizer(uint32_t sampleCount, int16_t *samples); + void ApplyEqualizer(uint32_t sampleCount, int16_t* samples); void UpdateEqualizers(vector bandGains, uint32_t sampleRate); -}; \ No newline at end of file +}; diff --git a/Utilities/FastString.h b/Utilities/FastString.h index 2e329f7..b3368fa 100644 --- a/Utilities/FastString.h +++ b/Utilities/FastString.h @@ -8,29 +8,38 @@ private: uint16_t _pos = 0; bool _lowerCase = false; - void WriteAll() {} + void WriteAll() + { + } public: FastString(bool lowerCase = false) { _lowerCase = lowerCase; } FastString(const char* str, int size) { Write(str, size); } - FastString(string &str) { Write(str); } + FastString(string& str) { Write(str); } void Write(char c) { - if(_lowerCase) { + if (_lowerCase) + { _buffer[_pos++] = ::tolower(c); - } else { + } + else + { _buffer[_pos++] = c; } } void Write(const char* str, int size) { - if(_lowerCase) { - for(int i = 0; i < size; i++) { + if (_lowerCase) + { + for (int i = 0; i < size; i++) + { _buffer[_pos + i] = ::tolower(str[i]); } - } else { + } + else + { memcpy(_buffer + _pos, str, size); } _pos += size; @@ -38,7 +47,8 @@ public: void Delimiter(const char* str) { - if(_pos > 0) { + if (_pos > 0) + { Write(str, (uint16_t)strlen(str)); } } @@ -48,19 +58,23 @@ public: Write(str, (uint16_t)strlen(str)); } - void Write(string &str, bool preserveCase = false) + void Write(string& str, bool preserveCase = false) { - if(_lowerCase && !preserveCase) { - for(size_t i = 0; i < str.size(); i++) { + if (_lowerCase && !preserveCase) + { + for (size_t i = 0; i < str.size(); i++) + { _buffer[_pos + i] = ::tolower(str[i]); } - } else { + } + else + { memcpy(_buffer + _pos, str.c_str(), str.size()); } _pos += (uint16_t)str.size(); } - void Write(FastString &str) + void Write(FastString& str) { memcpy(_buffer + _pos, str._buffer, str._pos); _pos += str._pos; @@ -77,8 +91,8 @@ public: return _pos; } - template - void WriteAll(T first, Args... args) + template + void WriteAll(T first, Args ... args) { Write(first); WriteAll(args...); diff --git a/Utilities/FolderUtilities.cpp b/Utilities/FolderUtilities.cpp index aba5cf8..53d2a57 100644 --- a/Utilities/FolderUtilities.cpp +++ b/Utilities/FolderUtilities.cpp @@ -2,8 +2,8 @@ #ifndef LIBRETRO #if __has_include() - #include - namespace fs = std::filesystem; +#include +namespace fs = std::filesystem; #elif __has_include() #include namespace fs = std::experimental::filesystem; @@ -30,7 +30,8 @@ void FolderUtilities::SetHomeFolder(string homeFolder) string FolderUtilities::GetHomeFolder() { - if(_homeFolder.size() == 0) { + if (_homeFolder.size() == 0) + { throw std::runtime_error("Home folder not specified"); } return _homeFolder; @@ -42,15 +43,18 @@ void FolderUtilities::AddKnownGameFolder(string gameFolder) string lowerCaseFolder = gameFolder; std::transform(lowerCaseFolder.begin(), lowerCaseFolder.end(), lowerCaseFolder.begin(), ::tolower); - for(string folder : _gameFolders) { + for (string folder : _gameFolders) + { std::transform(folder.begin(), folder.end(), folder.begin(), ::tolower); - if(folder.compare(lowerCaseFolder) == 0) { + if (folder.compare(lowerCaseFolder) == 0) + { alreadyExists = true; break; } } - if(!alreadyExists) { + if (!alreadyExists) + { _gameFolders.push_back(gameFolder); } } @@ -60,7 +64,8 @@ vector FolderUtilities::GetKnownGameFolders() return _gameFolders; } -void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder, string firmwareFolder) +void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder, + string firmwareFolder) { _saveFolderOverride = saveFolder; _saveStateFolderOverride = saveStateFolder; @@ -71,9 +76,12 @@ void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFold string FolderUtilities::GetSaveFolder() { string folder; - if(_saveFolderOverride.empty()) { + if (_saveFolderOverride.empty()) + { folder = CombinePath(GetHomeFolder(), "Saves"); - } else { + } + else + { folder = _saveFolderOverride; } CreateFolder(folder); @@ -83,9 +91,12 @@ string FolderUtilities::GetSaveFolder() string FolderUtilities::GetFirmwareFolder() { string folder; - if(_firmwareFolderOverride.empty()) { + if (_firmwareFolderOverride.empty()) + { folder = CombinePath(GetHomeFolder(), "Firmware"); - } else { + } + else + { folder = _firmwareFolderOverride; } CreateFolder(folder); @@ -109,9 +120,12 @@ string FolderUtilities::GetDebuggerFolder() string FolderUtilities::GetSaveStateFolder() { string folder; - if(_saveStateFolderOverride.empty()) { + if (_saveStateFolderOverride.empty()) + { folder = CombinePath(GetHomeFolder(), "SaveStates"); - } else { + } + else + { folder = _saveStateFolderOverride; } CreateFolder(folder); @@ -121,9 +135,12 @@ string FolderUtilities::GetSaveStateFolder() string FolderUtilities::GetScreenshotFolder() { string folder; - if(_screenshotFolderOverride.empty()) { + if (_screenshotFolderOverride.empty()) + { folder = CombinePath(GetHomeFolder(), "Screenshots"); - } else { + } + else + { folder = _screenshotFolderOverride; } CreateFolder(folder); @@ -140,7 +157,8 @@ string FolderUtilities::GetRecentGamesFolder() string FolderUtilities::GetExtension(string filename) { size_t position = filename.find_last_of('.'); - if(position != string::npos) { + if (position != string::npos) + { string ext = filename.substr(position, filename.size() - position); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); return ext; @@ -160,16 +178,22 @@ vector FolderUtilities::GetFolders(string rootFolder) vector folders; std::error_code errorCode; - if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) { + if (!fs::is_directory(fs::u8path(rootFolder), errorCode)) + { return folders; - } + } - for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) { - if(i.depth() > 1) { + for (fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) + { + if (i.depth() > 1) + { //Prevent excessive recursion i.disable_recursion_pending(); - } else { - if(fs::is_directory(i->path(), errorCode)) { + } + else + { + if (fs::is_directory(i->path(), errorCode)) + { folders.push_back(i->path().u8string()); } } @@ -178,34 +202,46 @@ vector FolderUtilities::GetFolders(string rootFolder) return folders; } -vector FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set extensions, bool recursive) +vector FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set extensions, + bool recursive) { vector files; - vector folders = { { rootFolder } }; + vector folders = {{rootFolder}}; std::error_code errorCode; - if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) { + if (!fs::is_directory(fs::u8path(rootFolder), errorCode)) + { return files; } - if(recursive) { - for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) { - if(i.depth() > 1) { + if (recursive) + { + for (fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) + { + if (i.depth() > 1) + { //Prevent excessive recursion i.disable_recursion_pending(); - } else { + } + else + { string extension = i->path().extension().u8string(); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if(extensions.empty() || extensions.find(extension) != extensions.end()) { + if (extensions.empty() || extensions.find(extension) != extensions.end()) + { files.push_back(i->path().u8string()); } } } - } else { - for(fs::directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) { + } + else + { + for (fs::directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) + { string extension = i->path().extension().u8string(); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if(extensions.empty() || extensions.find(extension) != extensions.end()) { + if (extensions.empty() || extensions.find(extension) != extensions.end()) + { files.push_back(i->path().u8string()); } } @@ -217,7 +253,8 @@ vector FolderUtilities::GetFilesInFolder(string rootFolder, std::unorder string FolderUtilities::GetFilename(string filepath, bool includeExtension) { fs::path filename = fs::u8path(filepath).filename(); - if(!includeExtension) { + if (!includeExtension) + { filename.replace_extension(""); } return filename.u8string(); @@ -231,9 +268,12 @@ string FolderUtilities::GetFolderName(string filepath) string FolderUtilities::CombinePath(string folder, string filename) { //Windows supports forward slashes for paths, too. And fs::u8path is abnormally slow. - if(folder[folder.length() - 1] != '/') { + if (folder[folder.length() - 1] != '/') + { return folder + "/" + filename; - } else { + } + else + { return folder + filename; } } @@ -244,7 +284,7 @@ string FolderUtilities::CombinePath(string folder, string filename) #ifdef _WIN32 static const char* PATHSEPARATOR = "\\"; -#else +#else static const char* PATHSEPARATOR = "/"; #endif @@ -286,4 +326,4 @@ string FolderUtilities::CombinePath(string folder, string filename) return folder + filename; } -#endif \ No newline at end of file +#endif diff --git a/Utilities/FolderUtilities.h b/Utilities/FolderUtilities.h index 2fa9505..3b658b9 100644 --- a/Utilities/FolderUtilities.h +++ b/Utilities/FolderUtilities.h @@ -17,7 +17,8 @@ public: static void SetHomeFolder(string homeFolder); static string GetHomeFolder(); - static void SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder, string firmwareFolder); + static void SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder, + string firmwareFolder); static void AddKnownGameFolder(string gameFolder); static vector GetKnownGameFolders(); @@ -40,4 +41,4 @@ public: static void CreateFolder(string folder); static string CombinePath(string folder, string filename); -}; \ No newline at end of file +}; diff --git a/Utilities/GifRecorder.cpp b/Utilities/GifRecorder.cpp index a1978e2..f831eb3 100644 --- a/Utilities/GifRecorder.cpp +++ b/Utilities/GifRecorder.cpp @@ -12,7 +12,8 @@ GifRecorder::~GifRecorder() StopRecording(); } -bool GifRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) +bool GifRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, + uint32_t audioSampleRate, double fps) { _outputFile = filename; _recording = GifBegin(_gif.get(), filename.c_str(), width, height, 2, 8, false); @@ -22,7 +23,8 @@ bool GifRecorder::StartRecording(string filename, uint32_t width, uint32_t heigh void GifRecorder::StopRecording() { - if(_recording) { + if (_recording) + { GifEnd(_gif.get()); } } @@ -30,8 +32,9 @@ void GifRecorder::StopRecording() void GifRecorder::AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) { _frameCounter++; - - if(fps < 55 || (_frameCounter % 6) != 0) { + + if (fps < 55 || (_frameCounter % 6) != 0) + { //At 60 FPS, skip 1 of every 6 frames (max FPS for GIFs is 50fps) GifWriteFrame(_gif.get(), (uint8_t*)frameBuffer, width, height, 2, 8, false); } @@ -49,4 +52,4 @@ bool GifRecorder::IsRecording() string GifRecorder::GetOutputFile() { return _outputFile; -} \ No newline at end of file +} diff --git a/Utilities/GifRecorder.h b/Utilities/GifRecorder.h index 4fbecab..5ede201 100644 --- a/Utilities/GifRecorder.h +++ b/Utilities/GifRecorder.h @@ -16,10 +16,11 @@ public: GifRecorder(); virtual ~GifRecorder(); - bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) override; + bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, + double fps) override; void StopRecording() override; void AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) override; void AddSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate) override; bool IsRecording() override; string GetOutputFile() override; -}; \ No newline at end of file +}; diff --git a/Utilities/HQX/common.h b/Utilities/HQX/common.h index dbd6c33..7ec2785 100644 --- a/Utilities/HQX/common.h +++ b/Utilities/HQX/common.h @@ -43,100 +43,103 @@ extern uint32_t RGBtoYUV[16777216]; static inline uint32_t rgb_to_yuv(uint32_t c) { - // Mask against MASK_RGB to discard the alpha channel - return RGBtoYUV[MASK_RGB & c]; + // Mask against MASK_RGB to discard the alpha channel + return RGBtoYUV[MASK_RGB & c]; } /* Test if there is difference in color */ -static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2) { - return (( std::abs((int)((yuv1 & Ymask) - (yuv2 & Ymask))) > trY ) || - ( std::abs((int)((yuv1 & Umask) - (yuv2 & Umask))) > trU ) || - ( std::abs((int)((yuv1 & Vmask) - (yuv2 & Vmask))) > trV ) ); +static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2) +{ + return ((std::abs((int)((yuv1 & Ymask) - (yuv2 & Ymask))) > trY) || + (std::abs((int)((yuv1 & Umask) - (yuv2 & Umask))) > trU) || + (std::abs((int)((yuv1 & Vmask) - (yuv2 & Vmask))) > trV)); } static inline int Diff(uint32_t c1, uint32_t c2) { - return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2)); + return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2)); } /* Interpolate functions */ static inline uint32_t Interpolate_2(uint32_t c1, int w1, uint32_t c2, int w2, int s) { - if (c1 == c2) { - return c1; - } - return - (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24-s)) & MASK_ALPHA) + - ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) + - ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13); + if (c1 == c2) + { + return c1; + } + return + (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24 - s)) & MASK_ALPHA) + + ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) + + ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13); } static inline uint32_t Interpolate_3(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s) { - return - (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24-s)) & MASK_ALPHA) + - ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) + - ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13); + return + (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24 - s)) + & MASK_ALPHA) + + ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) + + ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13); } static inline uint32_t Interp1(uint32_t c1, uint32_t c2) { - //(c1*3+c2) >> 2; - return Interpolate_2(c1, 3, c2, 1, 2); + //(c1*3+c2) >> 2; + return Interpolate_2(c1, 3, c2, 1, 2); } static inline uint32_t Interp2(uint32_t c1, uint32_t c2, uint32_t c3) { - //(c1*2+c2+c3) >> 2; - return Interpolate_3(c1, 2, c2, 1, c3, 1, 2); + //(c1*2+c2+c3) >> 2; + return Interpolate_3(c1, 2, c2, 1, c3, 1, 2); } static inline uint32_t Interp3(uint32_t c1, uint32_t c2) { - //(c1*7+c2)/8; - return Interpolate_2(c1, 7, c2, 1, 3); + //(c1*7+c2)/8; + return Interpolate_2(c1, 7, c2, 1, 3); } static inline uint32_t Interp4(uint32_t c1, uint32_t c2, uint32_t c3) { - //(c1*2+(c2+c3)*7)/16; - return Interpolate_3(c1, 2, c2, 7, c3, 7, 4); + //(c1*2+(c2+c3)*7)/16; + return Interpolate_3(c1, 2, c2, 7, c3, 7, 4); } static inline uint32_t Interp5(uint32_t c1, uint32_t c2) { - //(c1+c2) >> 1; - return Interpolate_2(c1, 1, c2, 1, 1); + //(c1+c2) >> 1; + return Interpolate_2(c1, 1, c2, 1, 1); } static inline uint32_t Interp6(uint32_t c1, uint32_t c2, uint32_t c3) { - //(c1*5+c2*2+c3)/8; - return Interpolate_3(c1, 5, c2, 2, c3, 1, 3); + //(c1*5+c2*2+c3)/8; + return Interpolate_3(c1, 5, c2, 2, c3, 1, 3); } static inline uint32_t Interp7(uint32_t c1, uint32_t c2, uint32_t c3) { - //(c1*6+c2+c3)/8; - return Interpolate_3(c1, 6, c2, 1, c3, 1, 3); + //(c1*6+c2+c3)/8; + return Interpolate_3(c1, 6, c2, 1, c3, 1, 3); } static inline uint32_t Interp8(uint32_t c1, uint32_t c2) { - //(c1*5+c2*3)/8; - return Interpolate_2(c1, 5, c2, 3, 3); + //(c1*5+c2*3)/8; + return Interpolate_2(c1, 5, c2, 3, 3); } static inline uint32_t Interp9(uint32_t c1, uint32_t c2, uint32_t c3) { - //(c1*2+(c2+c3)*3)/8; - return Interpolate_3(c1, 2, c2, 3, c3, 3, 3); + //(c1*2+(c2+c3)*3)/8; + return Interpolate_3(c1, 2, c2, 3, c3, 3, 3); } static inline uint32_t Interp10(uint32_t c1, uint32_t c2, uint32_t c3) { - //(c1*14+c2+c3)/16; - return Interpolate_3(c1, 14, c2, 1, c3, 1, 4); + //(c1*14+c2+c3)/16; + return Interpolate_3(c1, 14, c2, 1, c3, 1, 4); } #endif diff --git a/Utilities/HQX/hq2x.cpp b/Utilities/HQX/hq2x.cpp index 0aa7fff..6e1c77d 100644 --- a/Utilities/HQX/hq2x.cpp +++ b/Utilities/HQX/hq2x.cpp @@ -72,2739 +72,2741 @@ #define PIXEL11_90 *(dp+dpL+1) = Interp9(w[5], w[6], w[8]); #define PIXEL11_100 *(dp+dpL+1) = Interp10(w[5], w[6], w[8]); -void HQX_CALLCONV hq2x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres ) +void HQX_CALLCONV hq2x_32_rb(uint32_t* sp, uint32_t srb, uint32_t* dp, uint32_t drb, int Xres, int Yres) { - int i, j, k; - int prevline, nextline; - uint32_t w[10]; - int dpL = (drb >> 2); - int spL = (srb >> 2); - uint8_t *sRowP = (uint8_t *) sp; - uint8_t *dRowP = (uint8_t *) dp; - uint32_t yuv1, yuv2; + int i, j, k; + int prevline, nextline; + uint32_t w[10]; + int dpL = (drb >> 2); + int spL = (srb >> 2); + uint8_t* sRowP = (uint8_t*)sp; + uint8_t* dRowP = (uint8_t*)dp; + uint32_t yuv1, yuv2; - // +----+----+----+ - // | | | | - // | w1 | w2 | w3 | - // +----+----+----+ - // | | | | - // | w4 | w5 | w6 | - // +----+----+----+ - // | | | | - // | w7 | w8 | w9 | - // +----+----+----+ + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ - for (j=0; j0) prevline = -spL; else prevline = 0; - if (j 0) prevline = -spL; + else prevline = 0; + if (j < Yres - 1) nextline = spL; + else nextline = 0; - for (i=0; i0) - { - w[1] = *(sp + prevline - 1); - w[4] = *(sp - 1); - w[7] = *(sp + nextline - 1); - } - else - { - w[1] = w[2]; - w[4] = w[5]; - w[7] = w[8]; - } + if (i > 0) + { + w[1] = *(sp + prevline - 1); + w[4] = *(sp - 1); + w[7] = *(sp + nextline - 1); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } - if (i> 2); - int spL = (srb >> 2); - uint8_t *sRowP = (uint8_t *) sp; - uint8_t *dRowP = (uint8_t *) dp; - uint32_t yuv1, yuv2; + int i, j, k; + int prevline, nextline; + uint32_t w[10]; + int dpL = (drb >> 2); + int spL = (srb >> 2); + uint8_t* sRowP = (uint8_t*)sp; + uint8_t* dRowP = (uint8_t*)dp; + uint32_t yuv1, yuv2; - // +----+----+----+ - // | | | | - // | w1 | w2 | w3 | - // +----+----+----+ - // | | | | - // | w4 | w5 | w6 | - // +----+----+----+ - // | | | | - // | w7 | w8 | w9 | - // +----+----+----+ + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ - for (j=0; j0) prevline = -spL; else prevline = 0; - if (j 0) prevline = -spL; + else prevline = 0; + if (j < Yres - 1) nextline = spL; + else nextline = 0; - for (i=0; i0) - { - w[1] = *(sp + prevline - 1); - w[4] = *(sp - 1); - w[7] = *(sp + nextline - 1); - } - else - { - w[1] = w[2]; - w[4] = w[5]; - w[7] = w[8]; - } + if (i > 0) + { + w[1] = *(sp + prevline - 1); + w[4] = *(sp - 1); + w[7] = *(sp + nextline - 1); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } - if (i> 2); - int spL = (srb >> 2); - uint8_t *sRowP = (uint8_t *) sp; - uint8_t *dRowP = (uint8_t *) dp; - uint32_t yuv1, yuv2; + int i, j, k; + int prevline, nextline; + uint32_t w[10]; + int dpL = (drb >> 2); + int spL = (srb >> 2); + uint8_t* sRowP = (uint8_t*)sp; + uint8_t* dRowP = (uint8_t*)dp; + uint32_t yuv1, yuv2; - // +----+----+----+ - // | | | | - // | w1 | w2 | w3 | - // +----+----+----+ - // | | | | - // | w4 | w5 | w6 | - // +----+----+----+ - // | | | | - // | w7 | w8 | w9 | - // +----+----+----+ + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ - for (j=0; j0) prevline = -spL; else prevline = 0; - if (j 0) prevline = -spL; + else prevline = 0; + if (j < Yres - 1) nextline = spL; + else nextline = 0; - for (i=0; i0) - { - w[1] = *(sp + prevline - 1); - w[4] = *(sp - 1); - w[7] = *(sp + nextline - 1); - } - else - { - w[1] = w[2]; - w[4] = w[5]; - w[7] = w[8]; - } + if (i > 0) + { + w[1] = *(sp + prevline - 1); + w[4] = *(sp - 1); + w[7] = *(sp + nextline - 1); + } + else + { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } - if (i #if defined( __GNUC__ ) - #ifdef __MINGW32__ +#ifdef __MINGW32__ #define HQX_CALLCONV __stdcall - #else - #define HQX_CALLCONV - #endif #else - #define HQX_CALLCONV + #define HQX_CALLCONV +#endif +#else +#define HQX_CALLCONV #endif #if defined(_WIN32) - #ifdef DLL_EXPORT +#ifdef DLL_EXPORT #define HQX_API __declspec(dllexport) - #else - #define HQX_API __declspec(dllimport) - #endif +#else +#define HQX_API __declspec(dllimport) +#endif #else #define HQX_API #endif void HQX_CALLCONV hqxInit(void); -void HQX_CALLCONV hqx(uint32_t scale, uint32_t * src, uint32_t * dest, int width, int height); +void HQX_CALLCONV hqx(uint32_t scale, uint32_t* src, uint32_t* dest, int width, int height); -void HQX_CALLCONV hq2x_32( uint32_t * src, uint32_t * dest, int width, int height ); -void HQX_CALLCONV hq3x_32( uint32_t * src, uint32_t * dest, int width, int height ); -void HQX_CALLCONV hq4x_32( uint32_t * src, uint32_t * dest, int width, int height ); +void HQX_CALLCONV hq2x_32(uint32_t* src, uint32_t* dest, int width, int height); +void HQX_CALLCONV hq3x_32(uint32_t* src, uint32_t* dest, int width, int height); +void HQX_CALLCONV hq4x_32(uint32_t* src, uint32_t* dest, int width, int height); -void HQX_CALLCONV hq2x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); -void HQX_CALLCONV hq3x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); -void HQX_CALLCONV hq4x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); +void HQX_CALLCONV hq2x_32_rb(uint32_t* src, uint32_t src_rowBytes, uint32_t* dest, uint32_t dest_rowBytes, int width, + int height); +void HQX_CALLCONV hq3x_32_rb(uint32_t* src, uint32_t src_rowBytes, uint32_t* dest, uint32_t dest_rowBytes, int width, + int height); +void HQX_CALLCONV hq4x_32_rb(uint32_t* src, uint32_t src_rowBytes, uint32_t* dest, uint32_t dest_rowBytes, int width, + int height); #endif diff --git a/Utilities/HQX/init.cpp b/Utilities/HQX/init.cpp index be9de48..65e8046 100644 --- a/Utilities/HQX/init.cpp +++ b/Utilities/HQX/init.cpp @@ -20,29 +20,34 @@ #include #include "hqx.h" -uint32_t RGBtoYUV[16777216]; -uint32_t YUV1, YUV2; +uint32_t RGBtoYUV[16777216]; +uint32_t YUV1, YUV2; void HQX_CALLCONV hqxInit(void) { - /* Initalize RGB to YUV lookup table */ - uint32_t c, r, g, b, y, u, v; - for (c = 0; c < 16777215; c++) { - r = (c & 0xFF0000) >> 16; - g = (c & 0x00FF00) >> 8; - b = c & 0x0000FF; - y = (uint32_t)(0.299*r + 0.587*g + 0.114*b); - u = (uint32_t)(-0.169*r - 0.331*g + 0.5*b) + 128; - v = (uint32_t)(0.5*r - 0.419*g - 0.081*b) + 128; - RGBtoYUV[c] = (y << 16) + (u << 8) + v; - } + /* Initalize RGB to YUV lookup table */ + uint32_t c, r, g, b, y, u, v; + for (c = 0; c < 16777215; c++) + { + r = (c & 0xFF0000) >> 16; + g = (c & 0x00FF00) >> 8; + b = c & 0x0000FF; + y = (uint32_t)(0.299 * r + 0.587 * g + 0.114 * b); + u = (uint32_t)(-0.169 * r - 0.331 * g + 0.5 * b) + 128; + v = (uint32_t)(0.5 * r - 0.419 * g - 0.081 * b) + 128; + RGBtoYUV[c] = (y << 16) + (u << 8) + v; + } } -void HQX_CALLCONV hqx(uint32_t scale, uint32_t * src, uint32_t * dest, int width, int height) +void HQX_CALLCONV hqx(uint32_t scale, uint32_t* src, uint32_t* dest, int width, int height) { - switch(scale) { - case 2: hq2x_32(src, dest, width, height); break; - case 3: hq3x_32(src, dest, width, height); break; - case 4: hq4x_32(src, dest, width, height); break; + switch (scale) + { + case 2: hq2x_32(src, dest, width, height); + break; + case 3: hq3x_32(src, dest, width, height); + break; + case 4: hq4x_32(src, dest, width, height); + break; } -} \ No newline at end of file +} diff --git a/Utilities/HermiteResampler.cpp b/Utilities/HermiteResampler.cpp index db1d2d3..e703721 100644 --- a/Utilities/HermiteResampler.cpp +++ b/Utilities/HermiteResampler.cpp @@ -36,7 +36,8 @@ void HermiteResampler::PushSample(double prevValues[4], int16_t sample) void HermiteResampler::Reset() { - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { _prevLeft[i] = 0.0; _prevRight[i] = 0.0; } @@ -50,15 +51,18 @@ void HermiteResampler::SetSampleRates(double srcRate, double dstRate) uint32_t HermiteResampler::Resample(int16_t* in, uint32_t inSampleCount, int16_t* out) { - if(_rateRatio == 1.0) { + if (_rateRatio == 1.0) + { memcpy(out, in, inSampleCount * 2 * sizeof(int16_t)); return inSampleCount; } uint32_t outPos = 0; - for(uint32_t i = 0; i < inSampleCount * 2; i += 2) { - while(_fraction <= 1.0) { + for (uint32_t i = 0; i < inSampleCount * 2; i += 2) + { + while (_fraction <= 1.0) + { //Generate interpolated samples until we have enough samples for the current source sample out[outPos] = HermiteInterpolate(_prevLeft, _fraction); out[outPos + 1] = HermiteInterpolate(_prevRight, _fraction); diff --git a/Utilities/HermiteResampler.h b/Utilities/HermiteResampler.h index 5755951..94b6cf1 100644 --- a/Utilities/HermiteResampler.h +++ b/Utilities/HermiteResampler.h @@ -17,4 +17,4 @@ public: void SetSampleRates(double srcRate, double dstRate); uint32_t Resample(int16_t* in, uint32_t inSampleCount, int16_t* out); -}; \ No newline at end of file +}; diff --git a/Utilities/HexUtilities.cpp b/Utilities/HexUtilities.cpp index e370eec..a0d64a8 100644 --- a/Utilities/HexUtilities.cpp +++ b/Utilities/HexUtilities.cpp @@ -1,26 +1,8 @@ #include "stdafx.h" #include "HexUtilities.h" -const vector HexUtilities::_hexCache = { { - "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", - "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", - "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", - "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", - "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", - "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", - "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", - "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", - "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", - "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", - "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", - "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", - "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", - "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", - "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", - "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" -} }; - -constexpr const char* _hexCharCache[256] = { +const vector HexUtilities::_hexCache = { + { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", @@ -37,19 +19,45 @@ constexpr const char* _hexCharCache[256] = { "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" + } +}; + +constexpr const char* _hexCharCache[256] = { + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", + "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", + "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", + "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", + "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", + "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", + "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", + "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", + "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", + "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" }; int HexUtilities::FromHex(string hex) { int value = 0; - for(size_t i = 0, len = hex.size(); i < len; i++) { + for (size_t i = 0, len = hex.size(); i < len; i++) + { value <<= 4; - if(hex[i] >= '0' && hex[i] <= '9') { + if (hex[i] >= '0' && hex[i] <= '9') + { value |= hex[i] - '0'; - } else if(hex[i] >= 'A' && hex[i] <= 'F') { + } + else if (hex[i] >= 'A' && hex[i] <= 'F') + { value |= hex[i] - 'A' + 10; - } else if(hex[i] >= 'a' && hex[i] <= 'f') { + } + else if (hex[i] >= 'a' && hex[i] <= 'f') + { value |= hex[i] - 'a' + 10; } } @@ -83,23 +91,32 @@ string HexUtilities::ToHex24(int32_t value) string HexUtilities::ToHex(uint32_t value, bool fullSize) { - if(fullSize || value > 0xFFFFFF) { - return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF]; - } else if(value <= 0xFF) { + if (fullSize || value > 0xFFFFFF) + { + return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value + & 0xFF]; + } + else if (value <= 0xFF) + { return ToHex((uint8_t)value); - } else if(value <= 0xFFFF) { + } + else if (value <= 0xFFFF) + { return ToHex((uint16_t)value); - } else { + } + else + { return _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF]; } } -string HexUtilities::ToHex(vector &data) +string HexUtilities::ToHex(vector& data) { string result; result.reserve(data.size() * 2); - for(uint8_t value : data) { + for (uint8_t value : data) + { result += HexUtilities::ToHex(value); } return result; -} \ No newline at end of file +} diff --git a/Utilities/HexUtilities.h b/Utilities/HexUtilities.h index 606b55a..87690ef 100644 --- a/Utilities/HexUtilities.h +++ b/Utilities/HexUtilities.h @@ -13,7 +13,7 @@ public: static string ToHex(uint32_t value, bool fullSize = false); static string ToHex(int32_t value, bool fullSize = false); static string ToHex24(int32_t value); - static string ToHex(vector &data); + static string ToHex(vector& data); static int FromHex(string hex); -}; \ No newline at end of file +}; diff --git a/Utilities/ISerializable.h b/Utilities/ISerializable.h index 7d8138e..0727845 100644 --- a/Utilities/ISerializable.h +++ b/Utilities/ISerializable.h @@ -5,6 +5,5 @@ class Serializer; class ISerializable { public: - virtual void Serialize(Serializer &s) = 0; + virtual void Serialize(Serializer& s) = 0; }; - diff --git a/Utilities/IVideoRecorder.h b/Utilities/IVideoRecorder.h index 0d5ccd4..73a2d24 100644 --- a/Utilities/IVideoRecorder.h +++ b/Utilities/IVideoRecorder.h @@ -4,7 +4,8 @@ class IVideoRecorder { public: - virtual bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) = 0; + virtual bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, + double fps) = 0; virtual void StopRecording() = 0; virtual void AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) = 0; @@ -12,4 +13,4 @@ public: virtual bool IsRecording() = 0; virtual string GetOutputFile() = 0; -}; \ No newline at end of file +}; diff --git a/Utilities/IpsPatcher.cpp b/Utilities/IpsPatcher.cpp index c7a4279..d975d50 100644 --- a/Utilities/IpsPatcher.cpp +++ b/Utilities/IpsPatcher.cpp @@ -15,26 +15,32 @@ public: uint16_t RepeatCount = 0; uint8_t Value = 0; - bool ReadRecord(std::istream &ipsFile) + bool ReadRecord(std::istream& ipsFile) { uint8_t buffer[3]; ipsFile.read((char*)buffer, 3); - if(memcmp(buffer, "EOF", 3) == 0) { + if (memcmp(buffer, "EOF", 3) == 0) + { //EOF reached return false; - } else { + } + else + { Address = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16); ipsFile.read((char*)buffer, 2); Length = buffer[1] | (buffer[0] << 8); - if(Length == 0) { + if (Length == 0) + { //RLE record ipsFile.read((char*)buffer, 3); RepeatCount = buffer[1] | (buffer[0] << 8); Value = buffer[2]; - } else { + } + else + { Replacement.resize(Length); ipsFile.read((char*)Replacement.data(), Length); } @@ -42,7 +48,7 @@ public: } } - void WriteRecord(vector &output) + void WriteRecord(vector& output) { output.push_back((Address >> 16) & 0xFF); output.push_back((Address >> 8) & 0xFF); @@ -51,37 +57,42 @@ public: output.push_back((Length >> 8) & 0xFF); output.push_back(Length & 0xFF); - if(Length == 0) { + if (Length == 0) + { output.push_back((RepeatCount >> 8) & 0xFF); output.push_back(RepeatCount & 0xFF); output.push_back(Value); - } else { + } + else + { output.insert(output.end(), Replacement.data(), Replacement.data() + Replacement.size()); } } }; -bool IpsPatcher::PatchBuffer(string ipsFilepath, vector &input, vector &output) +bool IpsPatcher::PatchBuffer(string ipsFilepath, vector& input, vector& output) { ifstream ipsFile(ipsFilepath, std::ios::in | std::ios::binary); - if(ipsFile) { + if (ipsFile) + { return PatchBuffer(ipsFile, input, output); } return false; } -bool IpsPatcher::PatchBuffer(vector &ipsData, vector &input, vector &output) +bool IpsPatcher::PatchBuffer(vector& ipsData, vector& input, vector& output) { std::stringstream ss; ss.write((char*)ipsData.data(), ipsData.size()); return PatchBuffer(ss, input, output); } -bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector &input, vector &output) +bool IpsPatcher::PatchBuffer(std::istream& ipsFile, vector& input, vector& output) { char header[5]; ipsFile.read((char*)&header, 5); - if(memcmp((char*)&header, "PATCH", 5) != 0) { + if (memcmp((char*)&header, "PATCH", 5) != 0) + { //Invalid ips file return false; } @@ -89,18 +100,24 @@ bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector &input, vect vector records; int32_t truncateOffset = -1; size_t maxOutputSize = input.size(); - while(!ipsFile.eof()) { + while (!ipsFile.eof()) + { IpsRecord record; - if(record.ReadRecord(ipsFile)) { - if(record.Address + record.Length + record.RepeatCount > maxOutputSize) { + if (record.ReadRecord(ipsFile)) + { + if (record.Address + record.Length + record.RepeatCount > maxOutputSize) + { maxOutputSize = record.Address + record.Length + record.RepeatCount; } records.push_back(record); - } else { + } + else + { //EOF, try to read truncate offset record if it exists uint8_t buffer[3]; ipsFile.read((char*)buffer, 3); - if(!ipsFile.eof()) { + if (!ipsFile.eof()) + { truncateOffset = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16); } break; @@ -110,15 +127,20 @@ bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector &input, vect output.resize(maxOutputSize); std::copy(input.begin(), input.end(), output.begin()); - for(IpsRecord record : records) { - if(record.Length == 0) { - std::fill(&output[record.Address], &output[record.Address]+record.RepeatCount, record.Value); - } else { - std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin()+record.Address); + for (IpsRecord record : records) + { + if (record.Length == 0) + { + std::fill(&output[record.Address], &output[record.Address] + record.RepeatCount, record.Value); + } + else + { + std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin() + record.Address); } } - if(truncateOffset != -1 && (int32_t)output.size() > truncateOffset) { + if (truncateOffset != -1 && (int32_t)output.size() > truncateOffset) + { output.resize(truncateOffset); } @@ -128,31 +150,41 @@ bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector &input, vect vector IpsPatcher::CreatePatch(vector originalData, vector newData) { vector patchFile; - if(originalData.size() != newData.size()) { + if (originalData.size() != newData.size()) + { return patchFile; } - uint8_t header[5] = { 'P', 'A', 'T', 'C', 'H' }; + uint8_t header[5] = {'P', 'A', 'T', 'C', 'H'}; patchFile.insert(patchFile.end(), header, header + sizeof(header)); size_t i = 0, len = originalData.size(); - while(i < len) { - while(i < len && originalData[i] == newData[i]) { + while (i < len) + { + while (i < len && originalData[i] == newData[i]) + { i++; } - if(i < len) { + if (i < len) + { IpsRecord patchRecord; uint8_t rleByte = newData[i]; uint8_t rleCount = 0; bool createRleRecord = false; patchRecord.Address = (uint32_t)i; patchRecord.Length = 0; - while(i < len && patchRecord.Length < 65535 && originalData[i] != newData[i]) { - if(newData[i] == rleByte) { + while (i < len && patchRecord.Length < 65535 && originalData[i] != newData[i]) + { + if (newData[i] == rleByte) + { rleCount++; - } else if(createRleRecord) { + } + else if (createRleRecord) + { break; - } else { + } + else + { rleByte = newData[i]; rleCount = 1; } @@ -160,31 +192,39 @@ vector IpsPatcher::CreatePatch(vector originalData, vector 3) || rleCount > 13) { + if ((patchRecord.Length == rleCount && rleCount > 3) || rleCount > 13) + { //Making a RLE entry would probably save space, so write the current entry and create a RLE entry after it - if(patchRecord.Length == rleCount) { + if (patchRecord.Length == rleCount) + { //Same character since the start of this entry, make the RLE entry now createRleRecord = true; - } else { + } + else + { patchRecord.Length -= rleCount; i -= rleCount; break; } } } - if(createRleRecord) { + if (createRleRecord) + { patchRecord.Length = 0; patchRecord.RepeatCount = rleCount; patchRecord.Value = rleByte; - } else { - patchRecord.Replacement = vector(&newData[patchRecord.Address], &newData[patchRecord.Address + patchRecord.Length]); + } + else + { + patchRecord.Replacement = vector(&newData[patchRecord.Address], + &newData[patchRecord.Address + patchRecord.Length]); } patchRecord.WriteRecord(patchFile); } } - uint8_t endOfFile[3] = { 'E', 'O', 'F' }; + uint8_t endOfFile[3] = {'E', 'O', 'F'}; patchFile.insert(patchFile.end(), endOfFile, endOfFile + sizeof(endOfFile)); return patchFile; -} \ No newline at end of file +} diff --git a/Utilities/IpsPatcher.h b/Utilities/IpsPatcher.h index d88081a..4781833 100644 --- a/Utilities/IpsPatcher.h +++ b/Utilities/IpsPatcher.h @@ -5,8 +5,8 @@ class IpsPatcher { public: - static bool PatchBuffer(string ipsFilepath, vector &input, vector &output); + static bool PatchBuffer(string ipsFilepath, vector& input, vector& output); static bool PatchBuffer(vector& ipsData, vector& input, vector& output); - static bool PatchBuffer(std::istream &ipsFile, vector &input, vector &output); + static bool PatchBuffer(std::istream& ipsFile, vector& input, vector& output); static vector CreatePatch(vector originalData, vector newData); -}; \ No newline at end of file +}; diff --git a/Utilities/KreedSaiEagle/2xSai.cpp b/Utilities/KreedSaiEagle/2xSai.cpp index d35e055..b64459b 100644 --- a/Utilities/KreedSaiEagle/2xSai.cpp +++ b/Utilities/KreedSaiEagle/2xSai.cpp @@ -40,8 +40,7 @@ typename_t colorL = *(in + nextline + nextcolumn2); \ typename_t colorM = *(in + nextline2 - prevcolumn); \ typename_t colorN = *(in + nextline2 + 0); \ - typename_t colorO = *(in + nextline2 + nextcolumn); \ - + typename_t colorO = *(in + nextline2 + nextcolumn); #ifndef twoxsai_function #define twoxsai_function(result_cb, interpolate_cb, interpolate2_cb) \ if (colorA == colorD && colorB != colorC) \ @@ -130,20 +129,23 @@ out += 2 #endif -void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride) +void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst, + unsigned dst_stride) { - unsigned finish; + unsigned finish; int y = 0; int x = 0; - for(; height; height--) { - uint32_t *in = (uint32_t*)src; - uint32_t *out = (uint32_t*)dst; + for (; height; height--) + { + uint32_t* in = (uint32_t*)src; + uint32_t* out = (uint32_t*)dst; int prevline = (y > 0 ? src_stride : 0); int nextline = (height > 1 ? src_stride : 0); int nextline2 = (height > 2 ? src_stride * 2 : nextline); - for(finish = width; finish; finish -= 1) { + for (finish = width; finish; finish -= 1) + { int prevcolumn = (x > 0 ? 1 : 0); int nextcolumn = (finish > 1 ? 1 : 0); int nextcolumn2 = (finish > 2 ? 2 : nextcolumn); diff --git a/Utilities/KreedSaiEagle/SaiEagle.h b/Utilities/KreedSaiEagle/SaiEagle.h index 129f6b1..5502977 100644 --- a/Utilities/KreedSaiEagle/SaiEagle.h +++ b/Utilities/KreedSaiEagle/SaiEagle.h @@ -1,7 +1,9 @@ #pragma once #include "../stdafx.h" -extern void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride); -extern void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride); -extern void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride); - +extern void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, + uint32_t* dst, unsigned dst_stride); +extern void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst, + unsigned dst_stride); +extern void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, + uint32_t* dst, unsigned dst_stride); diff --git a/Utilities/KreedSaiEagle/Super2xSai.cpp b/Utilities/KreedSaiEagle/Super2xSai.cpp index ee9d7b2..7ea81b8 100644 --- a/Utilities/KreedSaiEagle/Super2xSai.cpp +++ b/Utilities/KreedSaiEagle/Super2xSai.cpp @@ -108,20 +108,23 @@ out += 2 #endif -void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride) +void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst, + unsigned dst_stride) { unsigned finish; int y = 0; int x = 0; - for(; height; height--) { - uint32_t *in = (uint32_t*)src; - uint32_t *out = (uint32_t*)dst; + for (; height; height--) + { + uint32_t* in = (uint32_t*)src; + uint32_t* out = (uint32_t*)dst; int prevline = (y > 0 ? src_stride : 0); int nextline = (height > 1 ? src_stride : 0); int nextline2 = (height > 2 ? src_stride * 2 : nextline); - for(finish = width; finish; finish -= 1) { + for (finish = width; finish; finish -= 1) + { int prevcolumn = (x > 0 ? 1 : 0); int nextcolumn = (finish > 1 ? 1 : 0); int nextcolumn2 = (finish > 2 ? 2 : nextcolumn); @@ -133,7 +136,8 @@ void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *sr // A1 A2 //-------------------------------------- - supertwoxsai_function(supertwoxsai_result, supertwoxsai_interpolate_xrgb8888, supertwoxsai_interpolate2_xrgb8888); + supertwoxsai_function(supertwoxsai_result, supertwoxsai_interpolate_xrgb8888, + supertwoxsai_interpolate2_xrgb8888); x++; } @@ -142,4 +146,4 @@ void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *sr y++; x = 0; } -} \ No newline at end of file +} diff --git a/Utilities/KreedSaiEagle/SuperEagle.cpp b/Utilities/KreedSaiEagle/SuperEagle.cpp index 11c15d7..c9d8fdf 100644 --- a/Utilities/KreedSaiEagle/SuperEagle.cpp +++ b/Utilities/KreedSaiEagle/SuperEagle.cpp @@ -125,20 +125,23 @@ out += 2 #endif -void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride) +void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst, + unsigned dst_stride) { - unsigned finish; + unsigned finish; int y = 0; int x = 0; - for(; height; height--) { - uint32_t *in = (uint32_t*)src; - uint32_t *out = (uint32_t*)dst; + for (; height; height--) + { + uint32_t* in = (uint32_t*)src; + uint32_t* out = (uint32_t*)dst; int prevline = (y > 0 ? src_stride : 0); int nextline = (height > 1 ? src_stride : 0); int nextline2 = (height > 2 ? src_stride * 2 : nextline); - for(finish = width; finish; finish -= 1) { + for (finish = width; finish; finish -= 1) + { int prevcolumn = (x > 0 ? 1 : 0); int nextcolumn = (finish > 1 ? 1 : 0); int nextcolumn2 = (finish > 2 ? 2 : nextcolumn); @@ -153,4 +156,4 @@ void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, y++; x = 0; } -} \ No newline at end of file +} diff --git a/Utilities/LowPassFilter.h b/Utilities/LowPassFilter.h index 4550ecb..f8b7938 100644 --- a/Utilities/LowPassFilter.h +++ b/Utilities/LowPassFilter.h @@ -7,31 +7,36 @@ class LowPassFilter { private: uint8_t _prevSampleCounter = 0; - int16_t _prevSamplesLeft[10] = { 0,0,0,0,0,0,0,0,0,0 }; - int16_t _prevSamplesRight[10] = { 0,0,0,0,0,0,0,0,0,0 }; + int16_t _prevSamplesLeft[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int16_t _prevSamplesRight[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - void UpdateSample(int16_t *buffer, size_t index, int strength, double volume, int16_t *_prevSamples) + void UpdateSample(int16_t* buffer, size_t index, int strength, double volume, int16_t* _prevSamples) { - if(strength > 0) { + if (strength > 0) + { int32_t sum = std::accumulate(_prevSamples, _prevSamples + strength, 0); buffer[index] = (int16_t)((sum + buffer[index]) / (strength + 1) * volume); _prevSamples[_prevSampleCounter] = buffer[index]; - } else { + } + else + { buffer[index] = (int16_t)(buffer[index] * volume); } } public: - void ApplyFilter(int16_t *buffer, size_t sampleCount, int strength, double volume = 1.0f) + void ApplyFilter(int16_t* buffer, size_t sampleCount, int strength, double volume = 1.0f) { assert(strength <= 10); - for(size_t i = 0; i < sampleCount*2; i+=2) { + for (size_t i = 0; i < sampleCount * 2; i += 2) + { UpdateSample(buffer, i, strength, volume, _prevSamplesLeft); - UpdateSample(buffer, i+1, strength, volume, _prevSamplesRight); - if(strength > 0) { + UpdateSample(buffer, i + 1, strength, volume, _prevSamplesRight); + if (strength > 0) + { _prevSampleCounter = (_prevSampleCounter + 1) % strength; } } } -}; \ No newline at end of file +}; diff --git a/Utilities/PNGHelper.cpp b/Utilities/PNGHelper.cpp index 75fb41d..45cb870 100644 --- a/Utilities/PNGHelper.cpp +++ b/Utilities/PNGHelper.cpp @@ -3,24 +3,30 @@ #include "PNGHelper.h" #include "miniz.h" -bool PNGHelper::WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel) +bool PNGHelper::WritePNG(std::stringstream& stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, + uint32_t bitsPerPixel) { size_t pngSize = 0; //ARGB -> BGR uint32_t size = xSize * ySize * bitsPerPixel / 8 / 4; vector convertedData(size * 3, 0); - for(uint32_t i = 0; i < size; i++) { + for (uint32_t i = 0; i < size; i++) + { convertedData[i * 3] = (buffer[i] & 0xFF0000) >> 16; convertedData[i * 3 + 1] = (buffer[i] & 0xFF00) >> 8; convertedData[i * 3 + 2] = (buffer[i] & 0xFF); } - void* pngData = tdefl_write_image_to_png_file_in_memory_ex(convertedData.data(), xSize, ySize, 3, &pngSize, MZ_DEFAULT_LEVEL, MZ_FALSE); - if(!pngData) { + void* pngData = tdefl_write_image_to_png_file_in_memory_ex(convertedData.data(), xSize, ySize, 3, &pngSize, + MZ_DEFAULT_LEVEL, MZ_FALSE); + if (!pngData) + { std::cout << "tdefl_write_image_to_png_file_in_memory_ex() failed!" << std::endl; return false; - } else { + } + else + { stream.write((char*)pngData, pngSize); mz_free(pngData); return true; @@ -30,9 +36,11 @@ bool PNGHelper::WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t x bool PNGHelper::WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel) { std::stringstream stream; - if(WritePNG(stream, buffer, xSize, ySize, bitsPerPixel)) { + if (WritePNG(stream, buffer, xSize, ySize, bitsPerPixel)) + { ofstream file(filename, std::ios::out | std::ios::binary); - if(file.good()) { + if (file.good()) + { file << stream.rdbuf(); } file.close(); @@ -41,7 +49,7 @@ bool PNGHelper::WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint return false; } -bool PNGHelper::ReadPNG(vector input, vector &output, uint32_t &pngWidth, uint32_t &pngHeight) +bool PNGHelper::ReadPNG(vector input, vector& output, uint32_t& pngWidth, uint32_t& pngHeight) { unsigned long width = 0; unsigned long height = 0; @@ -49,28 +57,34 @@ bool PNGHelper::ReadPNG(vector input, vector &output, uint32_t pngWidth = 0; pngHeight = 0; - if(DecodePNG(output, width, height, input.data(), input.size()) == 0) { - uint32_t *pngDataPtr = (uint32_t*)output.data(); - for(size_t i = 0, len = output.size() / 4; i < len; i++) { + if (DecodePNG(output, width, height, input.data(), input.size()) == 0) + { + uint32_t* pngDataPtr = (uint32_t*)output.data(); + for (size_t i = 0, len = output.size() / 4; i < len; i++) + { //ABGR to ARGB - pngDataPtr[i] = (pngDataPtr[i] & 0xFF00FF00) | ((pngDataPtr[i] & 0xFF0000) >> 16) | ((pngDataPtr[i] & 0xFF) << 16); + pngDataPtr[i] = (pngDataPtr[i] & 0xFF00FF00) | ((pngDataPtr[i] & 0xFF0000) >> 16) | ((pngDataPtr[i] & 0xFF) << + 16); } pngWidth = width; pngHeight = height; return true; - } else { + } + else + { return false; } -} +} -bool PNGHelper::ReadPNG(string filename, vector &pngData, uint32_t &pngWidth, uint32_t &pngHeight) +bool PNGHelper::ReadPNG(string filename, vector& pngData, uint32_t& pngWidth, uint32_t& pngHeight) { pngWidth = 0; pngHeight = 0; ifstream pngFile(filename, std::ios::in | std::ios::binary); - if(pngFile) { + if (pngFile) + { pngFile.seekg(0, std::ios::end); size_t fileSize = (size_t)pngFile.tellg(); pngFile.seekg(0, std::ios::beg); @@ -104,512 +118,846 @@ convert_to_rgba32: optional parameter, true by default. works for trusted PNG files. Use LodePNG instead of picoPNG if you need this information. return: 0 if success, not 0 if some error occured. */ -int PNGHelper::DecodePNG(vector& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32) +int PNGHelper::DecodePNG(vector& out_image, unsigned long& image_width, unsigned long& image_height, + const unsigned char* in_png, size_t in_size, bool convert_to_rgba32) { - // picoPNG version 20101224 - // Copyright (c) 2005-2010 Lode Vandevenne - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - // picoPNG is a PNG decoder in one C++ function of around 500 lines. Use picoPNG for - // programs that need only 1 .cpp file. Since it's a single function, it's very limited, - // it can convert a PNG to raw pixel data either converted to 32-bit RGBA color or - // with no color conversion at all. For anything more complex, another tiny library - // is available: LodePNG (lodepng.c(pp)), which is a single source and header file. - // Apologies for the compact code style, it's to make this tiny. - - static const unsigned long LENBASE[29] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}; - static const unsigned long LENEXTRA[29] = {0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; - static const unsigned long DISTBASE[30] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; - static const unsigned long DISTEXTRA[30] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; - static const unsigned long CLCL[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; //code length code lengths - struct Zlib //nested functions for zlib decompression - { - static unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; bitp++; return result;} - static unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits) - { - unsigned long result = 0; - for(size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i; - return result; - } - struct HuffmanTree - { - int makeFromLengths(const std::vector& bitlen, unsigned long maxbitlen) - { //make tree given the lengths - unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0; - std::vector tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0); - for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++; //count number of instances of each code length - for(unsigned long bits = 1; bits <= maxbitlen; bits++) nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1; - for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++; //generate all the codes - tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet - for(unsigned long n = 0; n < numcodes; n++) //the codes - for(unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code - { - unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1; - if(treepos > numcodes - 2) return 55; - if(tree2d[2 * treepos + bit] == 32767) //not yet filled in - { - if(i + 1 == bitlen[n]) { tree2d[2 * treepos + bit] = n; treepos = 0; } //last bit - else { tree2d[2 * treepos + bit] = ++nodefilled + numcodes; treepos = nodefilled; } //addresses are encoded as values > numcodes - } - else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value - } - return 0; - } - int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const - { //Decodes a symbol from the tree - unsigned long numcodes = (unsigned long)tree2d.size() / 2; - if(treepos >= numcodes) return 11; //error: you appeared outside the codetree - result = tree2d[2 * treepos + bit]; - decoded = (result < numcodes); - treepos = decoded ? 0 : result - numcodes; - return 0; - } - std::vector tree2d; //2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree. - }; - struct Inflator - { - int error; - void inflate(std::vector& out, const std::vector& in, size_t inpos = 0) - { - size_t bp = 0, pos = 0; //bit pointer and byte pointer - error = 0; - unsigned long BFINAL = 0; - while(!BFINAL && !error) - { - if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory - BFINAL = readBitFromStream(bp, &in[inpos]); - unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]); - if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE - else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size()); - else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE); - } - if(!error) out.resize(pos); //Only now we know the true size of out, resize it to that - } - void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) //get the tree of a deflated block with fixed tree - { - std::vector bitlen(288, 8), bitlenD(32, 5);; - for(size_t i = 144; i <= 255; i++) bitlen[i] = 9; - for(size_t i = 256; i <= 279; i++) bitlen[i] = 7; - tree.makeFromLengths(bitlen, 15); - treeD.makeFromLengths(bitlenD, 15); - } - HuffmanTree codetree, codetreeD, codelengthcodetree; //the code tree for Huffman codes, dist codes, and code length codes - unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength) - { //decode a single symbol from given list of bits with given code tree. return value is the symbol - bool decoded; unsigned long ct; - for(size_t treepos = 0;;) - { - if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode - error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in)); if(error) return 0; //stop, an error happened - if(decoded) return ct; - } - } - void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, size_t& bp, size_t inlength) - { //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree - std::vector bitlen(288, 0), bitlenD(32, 0); - if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory - size_t HLIT = readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257 - size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1 - size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4 - std::vector codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree - for(size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0; - error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return; - size_t i = 0, replength; - while(i < HLIT + HDIST) - { - unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return; - if(code <= 15) { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code - else if(code == 16) //repeat previous - { - if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory - replength = 3 + readBitsFromStream(bp, in, 2); - unsigned long value; //set value to the previous code - if((i - 1) < HLIT) value = bitlen[i - 1]; - else value = bitlenD[i - HLIT - 1]; - for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths - { - if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes - if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value; - } - } - else if(code == 17) //repeat "0" 3-10 times - { - if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory - replength = 3 + readBitsFromStream(bp, in, 3); - for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths - { - if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes - if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0; - } - } - else if(code == 18) //repeat "0" 11-138 times - { - if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory - replength = 11 + readBitsFromStream(bp, in, 7); - for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths - { - if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes - if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0; - } - } - else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen. - } - if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0 - error = tree.makeFromLengths(bitlen, 15); if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done - error = treeD.makeFromLengths(bitlenD, 15); if(error) return; - } - void inflateHuffmanBlock(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype) - { - if(btype == 1) { generateFixedTrees(codetree, codetreeD); } - else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; } - for(;;) - { - unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return; - if(code == 256) return; //end code - else if(code <= 255) //literal symbol - { - if(pos >= out.size()) out.resize((pos + 1) * 2); //reserve more room - out[pos++] = (unsigned char)(code); - } - else if(code >= 257 && code <= 285) //length code - { - size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257]; - if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory - length += readBitsFromStream(bp, in, numextrabits); - unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return; - if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used) - unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD]; - if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory - dist += readBitsFromStream(bp, in, numextrabitsD); - size_t start = pos, back = start - dist; //backwards - if(pos + length >= out.size()) out.resize((pos + length) * 2); //reserve more room - for(size_t i = 0; i < length; i++) { out[pos++] = out[back++]; if(back >= start) back = start - dist; } - } - } - } - void inflateNoCompression(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength) - { - while((bp & 0x7) != 0) bp++; //go to first boundary of byte - size_t p = bp / 8; - if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory - unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4; - if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN - if(pos + LEN >= out.size()) out.resize(pos + LEN); - if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer - for(unsigned long n = 0; n < LEN; n++) out[pos++] = in[p++]; //read LEN bytes of literal data - bp = p * 8; - } - }; - int decompress(std::vector& out, const std::vector& in) //returns error value - { - Inflator inflator; - if(in.size() < 2) { return 53; } //error, size of zlib data too small - if((in[0] * 256 + in[1]) % 31 != 0) { return 24; } //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way - unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1; - if(CM != 8 || CINFO > 7) { return 25; } //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec - if(FDICT != 0) { return 26; } //error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary." - inflator.inflate(out, in, 2); - return inflator.error; //note: adler32 checksum was skipped and ignored - } - }; - struct PNG //nested functions for PNG decoding - { - struct Info - { - unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, key_g, key_b; - bool key_defined; //is a transparent color key given? - std::vector palette; - } info; - int error; - void decode(std::vector& out, const unsigned char* in, size_t size, bool convert_to_rgba32) - { - error = 0; - if(size == 0 || in == 0) { error = 48; return; } //the given data is empty - readPngHeader(&in[0], size); if(error) return; - size_t pos = 33; //first byte of the first chunk after the header - std::vector idat; //the data from idat chunks - bool IEND = false; - info.key_defined = false; - while(!IEND) //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer - { - if(pos + 8 >= size) { error = 30; return; } //error: size of the in buffer too small to contain next chunk - size_t chunkLength = read32bitInt(&in[pos]); pos += 4; - if(chunkLength > 2147483647) { error = 63; return; } - if(pos + chunkLength >= size) { error = 35; return; } //error: size of the in buffer too small to contain next chunk - if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') //IDAT chunk, containing compressed image data - { - idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]); - pos += (4 + chunkLength); - } - else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') { pos += 4; IEND = true; } - else if(in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') //palette chunk (PLTE) - { - pos += 4; //go after the 4 letters - info.palette.resize(4 * (chunkLength / 3)); - if(info.palette.size() > (4 * 256)) { error = 38; return; } //error: palette too big - for(size_t i = 0; i < info.palette.size(); i += 4) - { - for(size_t j = 0; j < 3; j++) info.palette[i + j] = in[pos++]; //RGB - info.palette[i + 3] = 255; //alpha - } - } - else if(in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') //palette transparency chunk (tRNS) - { - pos += 4; //go after the 4 letters - if(info.colorType == 3) - { - if(4 * chunkLength > info.palette.size()) { error = 39; return; } //error: more alpha values given than there are palette entries - for(size_t i = 0; i < chunkLength; i++) info.palette[4 * i + 3] = in[pos++]; - } - else if(info.colorType == 0) - { - if(chunkLength != 2) { error = 40; return; } //error: this chunk must be 2 bytes for greyscale image - info.key_defined = 1; info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2; - } - else if(info.colorType == 2) - { - if(chunkLength != 6) { error = 41; return; } //error: this chunk must be 6 bytes for RGB image - info.key_defined = 1; - info.key_r = 256 * in[pos] + in[pos + 1]; pos += 2; - info.key_g = 256 * in[pos] + in[pos + 1]; pos += 2; - info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2; - } - else { error = 42; return; } //error: tRNS chunk not allowed for other color models - } - else //it's not an implemented chunk type, so ignore it: skip over the data - { - if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0) - pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk - } - pos += 4; //step over CRC (which is ignored) - } - unsigned long bpp = getBpp(info); - std::vector scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); //now the out buffer will be filled - Zlib zlib; //decompress with the Zlib decompressor - error = zlib.decompress(scanlines, idat); if(error) return; //stop if the zlib decompressor returned an error - size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8; - out.resize(outlength); //time to fill the out buffer - unsigned char* out_ = outlength ? &out[0] : 0; //use a regular pointer to the std::vector for faster code if compiled without optimization - if(info.interlaceMethod == 0) //no interlace, just filter - { - size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; //length in bytes of a scanline, excluding the filtertype byte - if(bpp >= 8) //byte per byte - for(unsigned long y = 0; y < info.height; y++) - { - unsigned long filterType = scanlines[linestart]; - const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth]; - unFilterScanline(&out_[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return; - linestart += (1 + linelength); //go to start of next scanline - } - else //less than 8 bits per pixel, so fill it up bit per bit - { - std::vector templine((info.width * bpp + 7) >> 3); //only used if bpp < 8 - for(size_t y = 0, obp = 0; y < info.height; y++) - { - unsigned long filterType = scanlines[linestart]; - const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth]; - unFilterScanline(&templine[0], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return; - for(size_t bp = 0; bp < info.width * bpp;) setBitOfReversedStream(obp, out_, readBitFromReversedStream(bp, &templine[0])); - linestart += (1 + linelength); //go to start of next scanline - } - } - } - else //interlaceMethod is 1 (Adam7) - { - size_t passw[7] = { (info.width + 7) / 8, (info.width + 3) / 8, (info.width + 3) / 4, (info.width + 1) / 4, (info.width + 1) / 2, (info.width + 0) / 2, (info.width + 0) / 1 }; - size_t passh[7] = { (info.height + 7) / 8, (info.height + 7) / 8, (info.height + 3) / 8, (info.height + 3) / 4, (info.height + 1) / 4, (info.height + 1) / 2, (info.height + 0) / 2 }; - size_t passstart[7] = {0}; - size_t pattern[28] = {0,4,0,2,0,1,0,0,0,4,0,2,0,1,8,8,4,4,2,2,1,8,8,8,4,4,2,2}; //values for the adam7 passes - for(int i = 0; i < 6; i++) passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8); - std::vector scanlineo((info.width * bpp + 7) / 8), scanlinen((info.width * bpp + 7) / 8); //"old" and "new" scanline - for(int i = 0; i < 7; i++) - adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], &scanlines[passstart[i]], info.width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21], passw[i], passh[i], bpp); - } - if(convert_to_rgba32 && (info.colorType != 6 || info.bitDepth != 8)) //conversion needed - { - std::vector data = out; - error = convert(out, &data[0], info, info.width, info.height); - } - } - void readPngHeader(const unsigned char* in, size_t inlength) //read the information from the header and store it in the Info - { - if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header - if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature - if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; } //error: it doesn't start with a IHDR chunk! - info.width = read32bitInt(&in[16]); info.height = read32bitInt(&in[20]); - info.bitDepth = in[24]; info.colorType = in[25]; - info.compressionMethod = in[26]; if(in[26] != 0) { error = 32; return; } //error: only compression method 0 is allowed in the specification - info.filterMethod = in[27]; if(in[27] != 0) { error = 33; return; } //error: only filter method 0 is allowed in the specification - info.interlaceMethod = in[28]; if(in[28] > 1) { error = 34; return; } //error: only interlace methods 0 and 1 exist in the specification - error = checkColorValidity(info.colorType, info.bitDepth); - } - void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned long filterType, size_t length) - { - switch(filterType) - { - case 0: for(size_t i = 0; i < length; i++) recon[i] = scanline[i]; break; - case 1: - for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; - break; - case 2: - if(precon) for(size_t i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; - else for(size_t i = 0; i < length; i++) recon[i] = scanline[i]; - break; - case 3: - if(precon) - { - for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; - for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); - } - else - { - for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; - } - break; - case 4: - if(precon) - { - for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + paethPredictor(0, precon[i], 0); - for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]); - } - else - { - for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0); - } - break; - default: error = 36; return; //error: unexisting filter type given - } - } - void adam7Pass(unsigned char* out, unsigned char* linen, unsigned char* lineo, const unsigned char* in, unsigned long w, size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh, unsigned long bpp) - { //filter and reposition the pixels into the output when the image is Adam7 interlaced. This function can only do it after the full image is already decoded. The out buffer must have the correct allocated memory size already. - if(passw == 0) return; - size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8); - for(unsigned long y = 0; y < passh; y++) - { - unsigned char filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo; - unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType, (w * bpp + 7) / 8); if(error) return; - if(bpp >= 8) for(size_t i = 0; i < passw; i++) for(size_t b = 0; b < bytewidth; b++) //b = current byte of this pixel - out[bytewidth * w * (passtop + spacey * y) + bytewidth * (passleft + spacex * i) + b] = linen[bytewidth * i + b]; - else for(size_t i = 0; i < passw; i++) - { - size_t obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i), bp = i * bpp; - for(size_t b = 0; b < bpp; b++) setBitOfReversedStream(obp, out, readBitFromReversedStream(bp, &linen[0])); - } - unsigned char* temp = linen; linen = lineo; lineo = temp; //swap the two buffer pointers "line old" and "line new" - } - } - static unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; bitp++; return result;} - static unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits) - { - unsigned long result = 0; - for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i); - return result; - } - void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit) { bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); bitp++; } - unsigned long read32bitInt(const unsigned char* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; } - int checkColorValidity(unsigned long colorType, unsigned long bd) //return type is a LodePNG error code - { - if((colorType == 2 || colorType == 4 || colorType == 6)) { if(!(bd == 8 || bd == 16)) return 37; else return 0; } - else if(colorType == 0) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; else return 0; } - else if(colorType == 3) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; else return 0; } - else return 31; //unexisting color type - } - unsigned long getBpp(const Info& info) - { - if(info.colorType == 2) return (3 * info.bitDepth); - else if(info.colorType >= 4) return (info.colorType - 2) * info.bitDepth; - else return info.bitDepth; - } - int convert(std::vector& out, const unsigned char* in, Info& infoIn, unsigned long w, unsigned long h) - { //converts from any color type to 32-bit. return value = LodePNG error code - size_t numpixels = w * h, bp = 0; - out.resize(numpixels * 4); - unsigned char* out_ = out.empty() ? 0 : &out[0]; //faster if compiled without optimization - if(infoIn.bitDepth == 8 && infoIn.colorType == 0) //greyscale - for(size_t i = 0; i < numpixels; i++) - { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i]; - out_[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255; - } - else if(infoIn.bitDepth == 8 && infoIn.colorType == 2) //RGB color - for(size_t i = 0; i < numpixels; i++) - { - for(size_t c = 0; c < 3; c++) out_[4 * i + c] = in[3 * i + c]; - out_[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn.key_g && in[3 * i + 2] == infoIn.key_b) ? 0 : 255; - } - else if(infoIn.bitDepth == 8 && infoIn.colorType == 3) //indexed color (palette) - for(size_t i = 0; i < numpixels; i++) - { - if(4U * in[i] >= infoIn.palette.size()) return 46; - for(size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * in[i] + c]; //get rgb colors from the palette - } - else if(infoIn.bitDepth == 8 && infoIn.colorType == 4) //greyscale with alpha - for(size_t i = 0; i < numpixels; i++) - { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i + 0]; - out_[4 * i + 3] = in[2 * i + 1]; - } - else if(infoIn.bitDepth == 8 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out_[4 * i + c] = in[4 * i + c]; //RGB with alpha - else if(infoIn.bitDepth == 16 && infoIn.colorType == 0) //greyscale - for(size_t i = 0; i < numpixels; i++) - { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i]; - out_[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255; - } - else if(infoIn.bitDepth == 16 && infoIn.colorType == 2) //RGB color - for(size_t i = 0; i < numpixels; i++) - { - for(size_t c = 0; c < 3; c++) out_[4 * i + c] = in[6 * i + 2 * c]; - out_[4 * i + 3] = (infoIn.key_defined && 256U*in[6*i+0]+in[6*i+1] == infoIn.key_r && 256U*in[6*i+2]+in[6*i+3] == infoIn.key_g && 256U*in[6*i+4]+in[6*i+5] == infoIn.key_b) ? 0 : 255; - } - else if(infoIn.bitDepth == 16 && infoIn.colorType == 4) //greyscale with alpha - for(size_t i = 0; i < numpixels; i++) - { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[4 * i]; //most significant byte - out_[4 * i + 3] = in[4 * i + 2]; - } - else if(infoIn.bitDepth == 16 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out_[4 * i + c] = in[8 * i + 2 * c]; //RGB with alpha - else if(infoIn.bitDepth < 8 && infoIn.colorType == 0) //greyscale - for(size_t i = 0; i < numpixels; i++) - { - unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn.bitDepth) - 1); //scale value from 0 to 255 - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = (unsigned char)(value); - out_[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U << infoIn.bitDepth) - 1U)) ? 0 : 255; - } - else if(infoIn.bitDepth < 8 && infoIn.colorType == 3) //palette - for(size_t i = 0; i < numpixels; i++) - { - unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth); - if(4 * value >= infoIn.palette.size()) return 47; - for(size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * value + c]; //get rgb colors from the palette - } - return 0; - } - unsigned char paethPredictor(short a, short b, short c) //Paeth predicter, used by PNG filter type 4 - { - short p = a + b - c, pa = p > a ? (p - a) : (a - p), pb = p > b ? (p - b) : (b - p), pc = p > c ? (p - c) : (c - p); - return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b : c); - } - }; - PNG decoder = { }; decoder.decode(out_image, in_png, in_size, convert_to_rgba32); - image_width = decoder.info.width; image_height = decoder.info.height; - return decoder.error; -} \ No newline at end of file + // picoPNG version 20101224 + // Copyright (c) 2005-2010 Lode Vandevenne + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // picoPNG is a PNG decoder in one C++ function of around 500 lines. Use picoPNG for + // programs that need only 1 .cpp file. Since it's a single function, it's very limited, + // it can convert a PNG to raw pixel data either converted to 32-bit RGBA color or + // with no color conversion at all. For anything more complex, another tiny library + // is available: LodePNG (lodepng.c(pp)), which is a single source and header file. + // Apologies for the compact code style, it's to make this tiny. + + static const unsigned long LENBASE[29] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 + }; + static const unsigned long LENEXTRA[29] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 + }; + static const unsigned long DISTBASE[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + static const unsigned long DISTEXTRA[30] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 + }; + static const unsigned long CLCL[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + //code length code lengths + struct Zlib //nested functions for zlib decompression + { + static unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits) + { + unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; + bitp++; + return result; + } + + static unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits) + { + unsigned long result = 0; + for (size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i; + return result; + } + + struct HuffmanTree + { + int makeFromLengths(const std::vector& bitlen, unsigned long maxbitlen) + { + //make tree given the lengths + unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0; + std::vector tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0); + for (unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++; + //count number of instances of each code length + for (unsigned long bits = 1; bits <= maxbitlen; bits++) nextcode[bits] = (nextcode[bits - 1] + blcount[bits + - 1]) << 1; + for (unsigned long n = 0; n < numcodes; n++) if (bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++; + //generate all the codes + tree2d.clear(); + tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet + for (unsigned long n = 0; n < numcodes; n++) //the codes + for (unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code + { + unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1; + if (treepos > numcodes - 2) return 55; + if (tree2d[2 * treepos + bit] == 32767) //not yet filled in + { + if (i + 1 == bitlen[n]) + { + tree2d[2 * treepos + bit] = n; + treepos = 0; + } //last bit + else + { + tree2d[2 * treepos + bit] = ++nodefilled + numcodes; + treepos = nodefilled; + } //addresses are encoded as values > numcodes + } + else treepos = tree2d[2 * treepos + bit] - numcodes; + //subtract numcodes from address to get address value + } + return 0; + } + + int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const + { + //Decodes a symbol from the tree + unsigned long numcodes = (unsigned long)tree2d.size() / 2; + if (treepos >= numcodes) return 11; //error: you appeared outside the codetree + result = tree2d[2 * treepos + bit]; + decoded = (result < numcodes); + treepos = decoded ? 0 : result - numcodes; + return 0; + } + + std::vector tree2d; + //2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree. + }; + + struct Inflator + { + int error; + + void inflate(std::vector& out, const std::vector& in, size_t inpos = 0) + { + size_t bp = 0, pos = 0; //bit pointer and byte pointer + error = 0; + unsigned long BFINAL = 0; + while (!BFINAL && !error) + { + if (bp >> 3 >= in.size()) + { + error = 52; + return; + } //error, bit pointer will jump past memory + BFINAL = readBitFromStream(bp, &in[inpos]); + unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); + BTYPE += 2 * readBitFromStream(bp, &in[inpos]); + if (BTYPE == 3) + { + error = 20; + return; + } //error: invalid BTYPE + else if (BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size()); + else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE); + } + if (!error) out.resize(pos); //Only now we know the true size of out, resize it to that + } + + void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) + //get the tree of a deflated block with fixed tree + { + std::vector bitlen(288, 8), bitlenD(32, 5);; + for (size_t i = 144; i <= 255; i++) bitlen[i] = 9; + for (size_t i = 256; i <= 279; i++) bitlen[i] = 7; + tree.makeFromLengths(bitlen, 15); + treeD.makeFromLengths(bitlenD, 15); + } + + HuffmanTree codetree, codetreeD, codelengthcodetree; + //the code tree for Huffman codes, dist codes, and code length codes + unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, + size_t inlength) + { + //decode a single symbol from given list of bits with given code tree. return value is the symbol + bool decoded; + unsigned long ct; + for (size_t treepos = 0;;) + { + if ((bp & 0x07) == 0 && (bp >> 3) > inlength) + { + error = 10; + return 0; + } //error: end reached without endcode + error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in)); + if (error) return 0; //stop, an error happened + if (decoded) return ct; + } + } + + void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, size_t& bp, + size_t inlength) + { + //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree + std::vector bitlen(288, 0), bitlenD(32, 0); + if (bp >> 3 >= inlength - 2) + { + error = 49; + return; + } //the bit pointer is or will go past the memory + size_t HLIT = readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257 + size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1 + size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4 + std::vector codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree + for (size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0; + error = codelengthcodetree.makeFromLengths(codelengthcode, 7); + if (error) return; + size_t i = 0, replength; + while (i < HLIT + HDIST) + { + unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); + if (error) return; + if (code <= 15) + { + if (i < HLIT) bitlen[i++] = code; + else bitlenD[i++ - HLIT] = code; + } //a length code + else if (code == 16) //repeat previous + { + if (bp >> 3 >= inlength) + { + error = 50; + return; + } //error, bit pointer jumps past memory + replength = 3 + readBitsFromStream(bp, in, 2); + unsigned long value; //set value to the previous code + if ((i - 1) < HLIT) value = bitlen[i - 1]; + else value = bitlenD[i - HLIT - 1]; + for (size_t n = 0; n < replength; n++) //repeat this value in the next lengths + { + if (i >= HLIT + HDIST) + { + error = 13; + return; + } //error: i is larger than the amount of codes + if (i < HLIT) bitlen[i++] = value; + else bitlenD[i++ - HLIT] = value; + } + } + else if (code == 17) //repeat "0" 3-10 times + { + if (bp >> 3 >= inlength) + { + error = 50; + return; + } //error, bit pointer jumps past memory + replength = 3 + readBitsFromStream(bp, in, 3); + for (size_t n = 0; n < replength; n++) //repeat this value in the next lengths + { + if (i >= HLIT + HDIST) + { + error = 14; + return; + } //error: i is larger than the amount of codes + if (i < HLIT) bitlen[i++] = 0; + else bitlenD[i++ - HLIT] = 0; + } + } + else if (code == 18) //repeat "0" 11-138 times + { + if (bp >> 3 >= inlength) + { + error = 50; + return; + } //error, bit pointer jumps past memory + replength = 11 + readBitsFromStream(bp, in, 7); + for (size_t n = 0; n < replength; n++) //repeat this value in the next lengths + { + if (i >= HLIT + HDIST) + { + error = 15; + return; + } //error: i is larger than the amount of codes + if (i < HLIT) bitlen[i++] = 0; + else bitlenD[i++ - HLIT] = 0; + } + } + else + { + error = 16; + return; + } //error: somehow an unexisting code appeared. This can never happen. + } + if (bitlen[256] == 0) + { + error = 64; + return; + } //the length of the end code 256 must be larger than 0 + error = tree.makeFromLengths(bitlen, 15); + if (error) return; + //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done + error = treeD.makeFromLengths(bitlenD, 15); + if (error) return; + } + + void inflateHuffmanBlock(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, + size_t inlength, unsigned long btype) + { + if (btype == 1) { generateFixedTrees(codetree, codetreeD); } + else if (btype == 2) + { + getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); + if (error) return; + } + for (;;) + { + unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); + if (error) return; + if (code == 256) return; //end code + else if (code <= 255) //literal symbol + { + if (pos >= out.size()) out.resize((pos + 1) * 2); //reserve more room + out[pos++] = (unsigned char)(code); + } + else if (code >= 257 && code <= 285) //length code + { + size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257]; + if ((bp >> 3) >= inlength) + { + error = 51; + return; + } //error, bit pointer will jump past memory + length += readBitsFromStream(bp, in, numextrabits); + unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); + if (error) return; + if (codeD > 29) + { + error = 18; + return; + } //error: invalid dist code (30-31 are never used) + unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD]; + if ((bp >> 3) >= inlength) + { + error = 51; + return; + } //error, bit pointer will jump past memory + dist += readBitsFromStream(bp, in, numextrabitsD); + size_t start = pos, back = start - dist; //backwards + if (pos + length >= out.size()) out.resize((pos + length) * 2); //reserve more room + for (size_t i = 0; i < length; i++) + { + out[pos++] = out[back++]; + if (back >= start) back = start - dist; + } + } + } + } + + void inflateNoCompression(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, + size_t inlength) + { + while ((bp & 0x7) != 0) bp++; //go to first boundary of byte + size_t p = bp / 8; + if (p >= inlength - 4) + { + error = 52; + return; + } //error, bit pointer will jump past memory + unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; + p += 4; + if (LEN + NLEN != 65535) + { + error = 21; + return; + } //error: NLEN is not one's complement of LEN + if (pos + LEN >= out.size()) out.resize(pos + LEN); + if (p + LEN > inlength) + { + error = 23; + return; + } //error: reading outside of in buffer + for (unsigned long n = 0; n < LEN; n++) out[pos++] = in[p++]; //read LEN bytes of literal data + bp = p * 8; + } + }; + + int decompress(std::vector& out, const std::vector& in) //returns error value + { + Inflator inflator; + if (in.size() < 2) { return 53; } //error, size of zlib data too small + if ((in[0] * 256 + in[1]) % 31 != 0) { return 24; } + //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way + unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1; + if (CM != 8 || CINFO > 7) { return 25; } + //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec + if (FDICT != 0) { return 26; } + //error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary." + inflator.inflate(out, in, 2); + return inflator.error; //note: adler32 checksum was skipped and ignored + } + }; + struct PNG //nested functions for PNG decoding + { + struct Info + { + unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, + key_g, key_b; + bool key_defined; //is a transparent color key given? + std::vector palette; + } info; + + int error; + + void decode(std::vector& out, const unsigned char* in, size_t size, bool convert_to_rgba32) + { + error = 0; + if (size == 0 || in == 0) + { + error = 48; + return; + } //the given data is empty + readPngHeader(&in[0], size); + if (error) return; + size_t pos = 33; //first byte of the first chunk after the header + std::vector idat; //the data from idat chunks + bool IEND = false; + info.key_defined = false; + while (!IEND) + //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer + { + if (pos + 8 >= size) + { + error = 30; + return; + } //error: size of the in buffer too small to contain next chunk + size_t chunkLength = read32bitInt(&in[pos]); + pos += 4; + if (chunkLength > 2147483647) + { + error = 63; + return; + } + if (pos + chunkLength >= size) + { + error = 35; + return; + } //error: size of the in buffer too small to contain next chunk + if (in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') + //IDAT chunk, containing compressed image data + { + idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]); + pos += (4 + chunkLength); + } + else if (in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') + { + pos += 4; + IEND = true; + } + else if (in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') + //palette chunk (PLTE) + { + pos += 4; //go after the 4 letters + info.palette.resize(4 * (chunkLength / 3)); + if (info.palette.size() > (4 * 256)) + { + error = 38; + return; + } //error: palette too big + for (size_t i = 0; i < info.palette.size(); i += 4) + { + for (size_t j = 0; j < 3; j++) info.palette[i + j] = in[pos++]; //RGB + info.palette[i + 3] = 255; //alpha + } + } + else if (in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') + //palette transparency chunk (tRNS) + { + pos += 4; //go after the 4 letters + if (info.colorType == 3) + { + if (4 * chunkLength > info.palette.size()) + { + error = 39; + return; + } //error: more alpha values given than there are palette entries + for (size_t i = 0; i < chunkLength; i++) info.palette[4 * i + 3] = in[pos++]; + } + else if (info.colorType == 0) + { + if (chunkLength != 2) + { + error = 40; + return; + } //error: this chunk must be 2 bytes for greyscale image + info.key_defined = 1; + info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1]; + pos += 2; + } + else if (info.colorType == 2) + { + if (chunkLength != 6) + { + error = 41; + return; + } //error: this chunk must be 6 bytes for RGB image + info.key_defined = 1; + info.key_r = 256 * in[pos] + in[pos + 1]; + pos += 2; + info.key_g = 256 * in[pos] + in[pos + 1]; + pos += 2; + info.key_b = 256 * in[pos] + in[pos + 1]; + pos += 2; + } + else + { + error = 42; + return; + } //error: tRNS chunk not allowed for other color models + } + else //it's not an implemented chunk type, so ignore it: skip over the data + { + if (!(in[pos + 0] & 32)) + { + error = 69; + return; + } //error: unknown critical chunk (5th bit of first byte of chunk type is 0) + pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk + } + pos += 4; //step over CRC (which is ignored) + } + unsigned long bpp = getBpp(info); + std::vector scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); + //now the out buffer will be filled + Zlib zlib; //decompress with the Zlib decompressor + error = zlib.decompress(scanlines, idat); + if (error) return; //stop if the zlib decompressor returned an error + size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8; + out.resize(outlength); //time to fill the out buffer + unsigned char* out_ = outlength ? &out[0] : 0; + //use a regular pointer to the std::vector for faster code if compiled without optimization + if (info.interlaceMethod == 0) //no interlace, just filter + { + size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; + //length in bytes of a scanline, excluding the filtertype byte + if (bpp >= 8) //byte per byte + for (unsigned long y = 0; y < info.height; y++) + { + unsigned long filterType = scanlines[linestart]; + const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth]; + unFilterScanline(&out_[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, + linelength); + if (error) return; + linestart += (1 + linelength); //go to start of next scanline + } + else //less than 8 bits per pixel, so fill it up bit per bit + { + std::vector templine((info.width * bpp + 7) >> 3); //only used if bpp < 8 + for (size_t y = 0, obp = 0; y < info.height; y++) + { + unsigned long filterType = scanlines[linestart]; + const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth]; + unFilterScanline(&templine[0], &scanlines[linestart + 1], prevline, bytewidth, filterType, + linelength); + if (error) return; + for (size_t bp = 0; bp < info.width * bpp;) setBitOfReversedStream( + obp, out_, readBitFromReversedStream(bp, &templine[0])); + linestart += (1 + linelength); //go to start of next scanline + } + } + } + else //interlaceMethod is 1 (Adam7) + { + size_t passw[7] = { + (info.width + 7) / 8, (info.width + 3) / 8, (info.width + 3) / 4, (info.width + 1) / 4, + (info.width + 1) / 2, (info.width + 0) / 2, (info.width + 0) / 1 + }; + size_t passh[7] = { + (info.height + 7) / 8, (info.height + 7) / 8, (info.height + 3) / 8, (info.height + 3) / 4, + (info.height + 1) / 4, (info.height + 1) / 2, (info.height + 0) / 2 + }; + size_t passstart[7] = {0}; + size_t pattern[28] = { + 0, 4, 0, 2, 0, 1, 0, 0, 0, 4, 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, 1, 8, 8, 8, 4, 4, 2, 2 + }; //values for the adam7 passes + for (int i = 0; i < 6; i++) passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * + bpp + 7) / 8); + std::vector scanlineo((info.width * bpp + 7) / 8), scanlinen((info.width * bpp + 7) / 8); + //"old" and "new" scanline + for (int i = 0; i < 7; i++) + adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], &scanlines[passstart[i]], info.width, pattern[i], + pattern[i + 7], pattern[i + 14], pattern[i + 21], passw[i], passh[i], bpp); + } + if (convert_to_rgba32 && (info.colorType != 6 || info.bitDepth != 8)) //conversion needed + { + std::vector data = out; + error = convert(out, &data[0], info, info.width, info.height); + } + } + + void readPngHeader(const unsigned char* in, size_t inlength) + //read the information from the header and store it in the Info + { + if (inlength < 29) + { + error = 27; + return; + } //error: the data length is smaller than the length of the header + if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || + in[7] != 10) + { + error = 28; + return; + } //no PNG signature + if (in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') + { + error = 29; + return; + } //error: it doesn't start with a IHDR chunk! + info.width = read32bitInt(&in[16]); + info.height = read32bitInt(&in[20]); + info.bitDepth = in[24]; + info.colorType = in[25]; + info.compressionMethod = in[26]; + if (in[26] != 0) + { + error = 32; + return; + } //error: only compression method 0 is allowed in the specification + info.filterMethod = in[27]; + if (in[27] != 0) + { + error = 33; + return; + } //error: only filter method 0 is allowed in the specification + info.interlaceMethod = in[28]; + if (in[28] > 1) + { + error = 34; + return; + } //error: only interlace methods 0 and 1 exist in the specification + error = checkColorValidity(info.colorType, info.bitDepth); + } + + void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned long filterType, size_t length) + { + switch (filterType) + { + case 0: for (size_t i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 1: + for (size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for (size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if (precon) for (size_t i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + else for (size_t i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 3: + if (precon) + { + for (size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; + for (size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) + / 2); + } + else + { + for (size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for (size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if (precon) + { + for (size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + paethPredictor(0, precon[i], 0); + for (size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor( + recon[i - bytewidth], precon[i], precon[i - bytewidth]); + } + else + { + for (size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for (size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor( + recon[i - bytewidth], 0, 0); + } + break; + default: error = 36; + return; //error: unexisting filter type given + } + } + + void adam7Pass(unsigned char* out, unsigned char* linen, unsigned char* lineo, const unsigned char* in, + unsigned long w, size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, + size_t passh, unsigned long bpp) + { + //filter and reposition the pixels into the output when the image is Adam7 interlaced. This function can only do it after the full image is already decoded. The out buffer must have the correct allocated memory size already. + if (passw == 0) return; + size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8); + for (unsigned long y = 0; y < passh; y++) + { + unsigned char filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo; + unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType, (w * bpp + 7) / 8); + if (error) return; + if (bpp >= 8) + for (size_t i = 0; i < passw; i++) + for (size_t b = 0; b < bytewidth; b++) //b = current byte of this pixel + out[bytewidth * w * (passtop + spacey * y) + bytewidth * (passleft + spacex * i) + b] = linen[ + bytewidth * i + b]; + else + for (size_t i = 0; i < passw; i++) + { + size_t obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i), bp = i * bpp; + for (size_t b = 0; b < bpp; b++) setBitOfReversedStream( + obp, out, readBitFromReversedStream(bp, &linen[0])); + } + unsigned char* temp = linen; + linen = lineo; + lineo = temp; //swap the two buffer pointers "line old" and "line new" + } + } + + static unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits) + { + unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; + bitp++; + return result; + } + + static unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits) + { + unsigned long result = 0; + for (size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i); + return result; + } + + void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit) + { + bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); + bitp++; + } + + unsigned long read32bitInt(const unsigned char* buffer) + { + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + } + + int checkColorValidity(unsigned long colorType, unsigned long bd) //return type is a LodePNG error code + { + if ((colorType == 2 || colorType == 4 || colorType == 6)) + { + if (!(bd == 8 || bd == 16)) return 37; + else return 0; + } + else if (colorType == 0) + { + if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; + else return 0; + } + else if (colorType == 3) + { + if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8)) return 37; + else return 0; + } + else return 31; //unexisting color type + } + + unsigned long getBpp(const Info& info) + { + if (info.colorType == 2) return (3 * info.bitDepth); + else if (info.colorType >= 4) return (info.colorType - 2) * info.bitDepth; + else return info.bitDepth; + } + + int convert(std::vector& out, const unsigned char* in, Info& infoIn, unsigned long w, + unsigned long h) + { + //converts from any color type to 32-bit. return value = LodePNG error code + size_t numpixels = w * h, bp = 0; + out.resize(numpixels * 4); + unsigned char* out_ = out.empty() ? 0 : &out[0]; //faster if compiled without optimization + if (infoIn.bitDepth == 8 && infoIn.colorType == 0) //greyscale + for (size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i]; + out_[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255; + } + else if (infoIn.bitDepth == 8 && infoIn.colorType == 2) //RGB color + for (size_t i = 0; i < numpixels; i++) + { + for (size_t c = 0; c < 3; c++) out_[4 * i + c] = in[3 * i + c]; + out_[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn. + key_g && in[3 * i + 2] == infoIn.key_b) + ? 0 + : 255; + } + else if (infoIn.bitDepth == 8 && infoIn.colorType == 3) //indexed color (palette) + for (size_t i = 0; i < numpixels; i++) + { + if (4U * in[i] >= infoIn.palette.size()) return 46; + for (size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * in[i] + c]; + //get rgb colors from the palette + } + else if (infoIn.bitDepth == 8 && infoIn.colorType == 4) //greyscale with alpha + for (size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i + 0]; + out_[4 * i + 3] = in[2 * i + 1]; + } + else if (infoIn.bitDepth == 8 && infoIn.colorType == 6) for (size_t i = 0; i < numpixels; i++) for ( + size_t c = 0; c < 4; c++) out_[4 * i + c] = in[4 * i + c]; //RGB with alpha + else if (infoIn.bitDepth == 16 && infoIn.colorType == 0) //greyscale + for (size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i]; + out_[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255; + } + else if (infoIn.bitDepth == 16 && infoIn.colorType == 2) //RGB color + for (size_t i = 0; i < numpixels; i++) + { + for (size_t c = 0; c < 3; c++) out_[4 * i + c] = in[6 * i + 2 * c]; + out_[4 * i + 3] = (infoIn.key_defined && 256U * in[6 * i + 0] + in[6 * i + 1] == infoIn.key_r && 256U * + in[6 * i + 2] + in[6 * i + 3] == infoIn.key_g && 256U * in[6 * i + 4] + in[6 * i + 5 + ] == infoIn.key_b) + ? 0 + : 255; + } + else if (infoIn.bitDepth == 16 && infoIn.colorType == 4) //greyscale with alpha + for (size_t i = 0; i < numpixels; i++) + { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[4 * i]; //most significant byte + out_[4 * i + 3] = in[4 * i + 2]; + } + else if (infoIn.bitDepth == 16 && infoIn.colorType == 6) for (size_t i = 0; i < numpixels; i++) for ( + size_t c = 0; c < 4; c++) out_[4 * i + c] = in[8 * i + 2 * c]; //RGB with alpha + else if (infoIn.bitDepth < 8 && infoIn.colorType == 0) //greyscale + for (size_t i = 0; i < numpixels; i++) + { + unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn. + bitDepth) - 1); //scale value from 0 to 255 + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = (unsigned char)(value); + out_[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U + << infoIn.bitDepth) - 1U)) + ? 0 + : 255; + } + else if (infoIn.bitDepth < 8 && infoIn.colorType == 3) //palette + for (size_t i = 0; i < numpixels; i++) + { + unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth); + if (4 * value >= infoIn.palette.size()) return 47; + for (size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * value + c]; + //get rgb colors from the palette + } + return 0; + } + + unsigned char paethPredictor(short a, short b, short c) //Paeth predicter, used by PNG filter type 4 + { + short p = a + b - c, pa = p > a ? (p - a) : (a - p), pb = p > b ? (p - b) : (b - p), pc = + p > c ? (p - c) : (c - p); + return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b : c); + } + }; + PNG decoder = {}; + decoder.decode(out_image, in_png, in_size, convert_to_rgba32); + image_width = decoder.info.width; + image_height = decoder.info.height; + return decoder.error; +} diff --git a/Utilities/PNGHelper.h b/Utilities/PNGHelper.h index 531a709..96d936f 100644 --- a/Utilities/PNGHelper.h +++ b/Utilities/PNGHelper.h @@ -4,11 +4,13 @@ class PNGHelper { private: - static int DecodePNG(vector& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true); + static int DecodePNG(vector& out_image, unsigned long& image_width, unsigned long& image_height, + const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true); public: - static bool WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32); + static bool WritePNG(std::stringstream& stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, + uint32_t bitsPerPixel = 32); static bool WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32); - static bool ReadPNG(string filename, vector &pngData, uint32_t &pngWidth, uint32_t &pngHeight); - static bool ReadPNG(vector input, vector &output, uint32_t &pngWidth, uint32_t &pngHeight); -}; \ No newline at end of file + static bool ReadPNG(string filename, vector& pngData, uint32_t& pngWidth, uint32_t& pngHeight); + static bool ReadPNG(vector input, vector& output, uint32_t& pngWidth, uint32_t& pngHeight); +}; diff --git a/Utilities/PlatformUtilities.cpp b/Utilities/PlatformUtilities.cpp index d129c07..bef9e4d 100644 --- a/Utilities/PlatformUtilities.cpp +++ b/Utilities/PlatformUtilities.cpp @@ -11,35 +11,37 @@ void PlatformUtilities::DisableScreensaver() { //Prevent screensaver/etc from starting while using the emulator //DirectInput devices apparently do not always count as user input - #if !defined(LIBRETRO) && defined(_WIN32) +#if !defined(LIBRETRO) && defined(_WIN32) SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_CONTINUOUS); - #endif +#endif } void PlatformUtilities::EnableScreensaver() { - #if !defined(LIBRETRO) && defined(_WIN32) +#if !defined(LIBRETRO) && defined(_WIN32) SetThreadExecutionState(ES_CONTINUOUS); - #endif +#endif } void PlatformUtilities::EnableHighResolutionTimer() { #if !defined(LIBRETRO) && defined(_WIN32) //Request a 1ms timer resolution on Windows while a game is running - if(!_highResTimerEnabled) { + if (!_highResTimerEnabled) + { timeBeginPeriod(1); _highResTimerEnabled = true; } - #endif +#endif } void PlatformUtilities::RestoreTimerResolution() { - #if !defined(LIBRETRO) && defined(_WIN32) - if(_highResTimerEnabled) { +#if !defined(LIBRETRO) && defined(_WIN32) + if (_highResTimerEnabled) + { timeEndPeriod(1); _highResTimerEnabled = false; } - #endif -} \ No newline at end of file +#endif +} diff --git a/Utilities/PlatformUtilities.h b/Utilities/PlatformUtilities.h index e5a0fd1..774ee1f 100644 --- a/Utilities/PlatformUtilities.h +++ b/Utilities/PlatformUtilities.h @@ -12,4 +12,4 @@ public: static void EnableHighResolutionTimer(); static void RestoreTimerResolution(); -}; \ No newline at end of file +}; diff --git a/Utilities/RawCodec.h b/Utilities/RawCodec.h index ea32899..5fa64c5 100644 --- a/Utilities/RawCodec.h +++ b/Utilities/RawCodec.h @@ -24,15 +24,17 @@ public: return true; } - virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override + virtual int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) override { *compressedData = _buffer; //Convert raw frame to BMP/DIB format (row order is reversed) uint8_t* buffer = _buffer; frameData += (_height - 1) * _width * 4; - for(int y = 0; y < _height; y++) { - for(int x = 0; x < _width; x++) { + for (int y = 0; y < _height; y++) + { + for (int x = 0; x < _width; x++) + { buffer[0] = frameData[0]; buffer[1] = frameData[1]; buffer[2] = frameData[2]; @@ -48,4 +50,4 @@ public: { return "\0\0\0\0"; } -}; \ No newline at end of file +}; diff --git a/Utilities/SZReader.cpp b/Utilities/SZReader.cpp index 71daade..1e28d4d 100644 --- a/Utilities/SZReader.cpp +++ b/Utilities/SZReader.cpp @@ -16,13 +16,14 @@ SZReader::~SZReader() bool SZReader::InternalLoadArchive(void* buffer, size_t size) { - if(_initialized) { + if (_initialized) + { SzArEx_Free(&_archive, &_allocImp); _initialized = false; } - ISzAlloc allocImp{ SzAlloc, SzFree }; - ISzAlloc allocTempImp{ SzAllocTemp, SzFreeTemp }; + ISzAlloc allocImp{SzAlloc, SzFree}; + ISzAlloc allocTempImp{SzAllocTemp, SzFreeTemp}; MemBufferInit(&_memBufferStream, &_lookStream, buffer, size); CrcGenerateTable(); @@ -31,30 +32,36 @@ bool SZReader::InternalLoadArchive(void* buffer, size_t size) return !SzArEx_Open(&_archive, &_lookStream.s, &allocImp, &allocTempImp); } -bool SZReader::ExtractFile(string filename, vector &output) +bool SZReader::ExtractFile(string filename, vector& output) { bool result = false; - if(_initialized) { - char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000); + if (_initialized) + { + char16_t* utf16Filename = (char16_t*)SzAlloc(nullptr, 2000); uint32_t blockIndex = 0xFFFFFFFF; - uint8_t *outBuffer = 0; + uint8_t* outBuffer = 0; size_t outBufferSize = 0; - for(uint32_t i = 0; i < _archive.NumFiles; i++) { + for (uint32_t i = 0; i < _archive.NumFiles; i++) + { size_t offset = 0; size_t outSizeProcessed = 0; unsigned isDir = SzArEx_IsDir(&_archive, i); - if(isDir) { + if (isDir) + { continue; } SzArEx_GetFileNameUtf16(&_archive, i, (uint16_t*)utf16Filename); string entryName = utf8::utf8::encode(std::u16string(utf16Filename)); - if(filename == entryName) { - WRes res = SzArEx_Extract(&_archive, &_lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &_allocImp, &_allocTempImp); - if(res == SZ_OK) { - output = vector(outBuffer+offset, outBuffer+offset+outSizeProcessed); + if (filename == entryName) + { + WRes res = SzArEx_Extract(&_archive, &_lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, + &outSizeProcessed, &_allocImp, &_allocTempImp); + if (res == SZ_OK) + { + output = vector(outBuffer + offset, outBuffer + offset + outSizeProcessed); result = true; } IAlloc_Free(&_allocImp, outBuffer); @@ -70,12 +77,15 @@ bool SZReader::ExtractFile(string filename, vector &output) vector SZReader::InternalGetFileList() { vector filenames; - char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000); + char16_t* utf16Filename = (char16_t*)SzAlloc(nullptr, 2000); - if(_initialized) { - for(uint32_t i = 0; i < _archive.NumFiles; i++) { + if (_initialized) + { + for (uint32_t i = 0; i < _archive.NumFiles; i++) + { unsigned isDir = SzArEx_IsDir(&_archive, i); - if(isDir) { + if (isDir) + { continue; } @@ -87,4 +97,4 @@ vector SZReader::InternalGetFileList() SzFree(nullptr, utf16Filename); return filenames; -} \ No newline at end of file +} diff --git a/Utilities/SZReader.h b/Utilities/SZReader.h index 9c3634f..91bb825 100644 --- a/Utilities/SZReader.h +++ b/Utilities/SZReader.h @@ -13,8 +13,8 @@ private: CMemBufferInStream _memBufferStream; CLookToRead _lookStream; CSzArEx _archive; - ISzAlloc _allocImp{ SzAlloc, SzFree }; - ISzAlloc _allocTempImp{ SzAllocTemp, SzFreeTemp }; + ISzAlloc _allocImp{SzAlloc, SzFree}; + ISzAlloc _allocTempImp{SzAllocTemp, SzFreeTemp}; protected: bool InternalLoadArchive(void* buffer, size_t size); @@ -24,5 +24,5 @@ public: SZReader(); virtual ~SZReader(); - bool ExtractFile(string filename, vector &output); -}; \ No newline at end of file + bool ExtractFile(string filename, vector& output); +}; diff --git a/Utilities/Scale2x/scale2x.cpp b/Utilities/Scale2x/scale2x.cpp index 43f31b1..94989de 100644 --- a/Utilities/Scale2x/scale2x.cpp +++ b/Utilities/Scale2x/scale2x.cpp @@ -44,15 +44,19 @@ */ /* #define USE_SCALE_RANDOMWRITE */ -static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, + const scale2x_uint8* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -63,11 +67,15 @@ static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -80,24 +88,33 @@ static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[0] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } } -static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, + const scale2x_uint8* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0]; - dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -108,11 +125,19 @@ static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; - dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; + dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -125,24 +150,33 @@ static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } } -static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, + const scale2x_uint16* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -153,11 +187,15 @@ static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -170,24 +208,33 @@ static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[0] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } } -static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, + const scale2x_uint16* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0]; - dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -198,11 +245,19 @@ static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; - dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; + dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -215,24 +270,33 @@ static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } } -static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, + const scale2x_uint32* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -243,11 +307,15 @@ static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -260,24 +328,33 @@ static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; dst[1] = src1[0] == src0[0] ? src0[0] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } } -static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, + const scale2x_uint32* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0]; - dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -288,11 +365,19 @@ static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; - dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; + dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -305,10 +390,15 @@ static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; } @@ -329,7 +419,8 @@ static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint * \param dst0 First destination row, double length in pixels. * \param dst1 Second destination row, double length in pixels. */ -void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, + const scale2x_uint8* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_8_def_whole(dst0, dst1, src0, src1, src2, count); @@ -350,7 +441,8 @@ void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8 * \param dst0 First destination row, double length in pixels. * \param dst1 Second destination row, double length in pixels. */ -void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, + const scale2x_uint16* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_16_def_whole(dst0, dst1, src0, src1, src2, count); @@ -371,7 +463,8 @@ void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_ui * \param dst0 First destination row, double length in pixels. * \param dst1 Second destination row, double length in pixels. */ -void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, + const scale2x_uint32* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_32_def_whole(dst0, dst1, src0, src1, src2, count); @@ -385,7 +478,8 @@ void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_ui * Scale by a factor of 2x3 a row of pixels of 8 bits. * \note Like scale2x_8_def(); */ -void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, + const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_8_def_whole(dst0, dst2, src0, src1, src2, count); @@ -401,7 +495,8 @@ void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst * Scale by a factor of 2x3 a row of pixels of 16 bits. * \note Like scale2x_16_def(); */ -void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, + const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_16_def_whole(dst0, dst2, src0, src1, src2, count); @@ -417,7 +512,8 @@ void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* * Scale by a factor of 2x3 a row of pixels of 32 bits. * \note Like scale2x_32_def(); */ -void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, + const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_32_def_whole(dst0, dst2, src0, src1, src2, count); @@ -433,7 +529,8 @@ void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* * Scale by a factor of 2x4 a row of pixels of 8 bits. * \note Like scale2x_8_def(); */ -void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) +void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, + const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_8_def_whole(dst0, dst3, src0, src1, src2, count); @@ -451,7 +548,8 @@ void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst * Scale by a factor of 2x4 a row of pixels of 16 bits. * \note Like scale2x_16_def(); */ -void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) +void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, + const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_16_def_whole(dst0, dst3, src0, src1, src2, count); @@ -469,7 +567,8 @@ void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* * Scale by a factor of 2x4 a row of pixels of 32 bits. * \note Like scale2x_32_def(); */ -void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) +void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, + const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale2x_32_def_whole(dst0, dst3, src0, src1, src2, count); diff --git a/Utilities/Scale2x/scale2x.h b/Utilities/Scale2x/scale2x.h index e1431c4..5801469 100644 --- a/Utilities/Scale2x/scale2x.h +++ b/Utilities/Scale2x/scale2x.h @@ -21,17 +21,27 @@ typedef unsigned char scale2x_uint8; typedef unsigned short scale2x_uint16; typedef unsigned scale2x_uint32; -void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); -void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); -void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); +void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, + const scale2x_uint8* src2, unsigned count); +void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, + const scale2x_uint16* src2, unsigned count); +void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, + const scale2x_uint32* src2, unsigned count); -void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); -void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); -void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); +void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, + const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, + const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); +void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, + const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); -void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); -void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count); -void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count); +void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, + const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count); +void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, + const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, + unsigned count); +void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, + const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, + unsigned count); #endif - diff --git a/Utilities/Scale2x/scale3x.cpp b/Utilities/Scale2x/scale3x.cpp index 8bfe328..11d7bae 100644 --- a/Utilities/Scale2x/scale3x.cpp +++ b/Utilities/Scale2x/scale3x.cpp @@ -44,16 +44,22 @@ */ /* #define USE_SCALE_RANDOMWRITE */ -static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) +static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, + const scale3x_uint8* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0]; - dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) + ? src0[0] + : src1[0]; dst[2] = src1[1] == src0[0] ? src1[1] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -65,12 +71,18 @@ static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; - dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) + ? src0[0] + : src1[0]; dst[2] = src1[1] == src0[0] ? src1[1] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -84,27 +96,40 @@ static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; - dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) + ? src0[0] + : src1[0]; dst[2] = src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; } } -static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) +static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, + const scale3x_uint8* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { - dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + if (src0[0] != src2[0] && src1[0] != src1[1]) + { + dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) + ? src1[0] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -116,12 +141,20 @@ static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -135,27 +168,40 @@ static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; - } else { + dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) + ? src1[0] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; } } -static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) +static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, + const scale3x_uint16* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0]; - dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) + ? src0[0] + : src1[0]; dst[2] = src1[1] == src0[0] ? src1[1] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -167,12 +213,18 @@ static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; - dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) + ? src0[0] + : src1[0]; dst[2] = src1[1] == src0[0] ? src1[1] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -186,27 +238,40 @@ static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; - dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) + ? src0[0] + : src1[0]; dst[2] = src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; } } -static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) +static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, + const scale3x_uint16* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { - dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + if (src0[0] != src2[0] && src1[0] != src1[1]) + { + dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) + ? src1[0] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -218,12 +283,20 @@ static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -237,27 +310,40 @@ static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; - } else { + dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) + ? src1[0] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; } } -static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) +static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, + const scale3x_uint32* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { + if (src0[0] != src2[0] && src1[0] != src1[1]) + { dst[0] = src1[0]; - dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) + ? src0[0] + : src1[0]; dst[2] = src1[1] == src0[0] ? src1[1] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -269,12 +355,18 @@ static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; - dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) + ? src0[0] + : src1[0]; dst[2] = src1[1] == src0[0] ? src1[1] : src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -288,27 +380,40 @@ static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; - dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) + ? src0[0] + : src1[0]; dst[2] = src1[0]; - } else { + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; } } -static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) +static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, + const scale3x_uint32* src2, unsigned count) { assert(count >= 2); /* first pixel */ - if (src0[0] != src2[0] && src1[0] != src1[1]) { - dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + if (src0[0] != src2[0] && src1[0] != src1[1]) + { + dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) + ? src1[0] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -320,12 +425,20 @@ static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint /* central pixels */ count -= 2; - while (count) { - if (src0[0] != src2[0] && src1[-1] != src1[1]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + while (count) + { + if (src0[0] != src2[0] && src1[-1] != src1[1]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; - } else { + dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) + ? src1[1] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -339,11 +452,18 @@ static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint } /* last pixel */ - if (src0[0] != src2[0] && src1[-1] != src1[0]) { - dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + if (src0[0] != src2[0] && src1[-1] != src1[0]) + { + dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) + ? src1[-1] + : src1[0]; dst[1] = src1[0]; - dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; - } else { + dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) + ? src1[0] + : src1[0]; + } + else + { dst[0] = src1[0]; dst[1] = src1[0]; dst[2] = src1[0]; @@ -364,7 +484,8 @@ static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint * \param dst1 Second destination row, triple length in pixels. * \param dst2 Third destination row, triple length in pixels. */ -void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) +void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, + const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale3x_8_def_whole(dst0, dst1, dst2, src0, src1, src2, count); @@ -387,7 +508,8 @@ void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2 * \param dst1 Second destination row, triple length in pixels. * \param dst2 Third destination row, triple length in pixels. */ -void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) +void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, + const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, count); @@ -410,7 +532,8 @@ void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* * \param dst1 Second destination row, triple length in pixels. * \param dst2 Third destination row, triple length in pixels. */ -void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) +void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, + const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) { #ifdef USE_SCALE_RANDOMWRITE scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, count); @@ -420,4 +543,3 @@ void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* scale3x_32_def_border(dst2, src2, src1, src0, count); #endif } - diff --git a/Utilities/Scale2x/scale3x.h b/Utilities/Scale2x/scale3x.h index 895752a..d4e8972 100644 --- a/Utilities/Scale2x/scale3x.h +++ b/Utilities/Scale2x/scale3x.h @@ -21,9 +21,11 @@ typedef unsigned char scale3x_uint8; typedef unsigned short scale3x_uint16; typedef unsigned scale3x_uint32; -void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count); -void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count); -void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count); +void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, + const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count); +void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, + const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count); +void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, + const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count); #endif - diff --git a/Utilities/Scale2x/scalebit.cpp b/Utilities/Scale2x/scalebit.cpp index d4ab4c3..f19f82e 100644 --- a/Utilities/Scale2x/scalebit.cpp +++ b/Utilities/Scale2x/scalebit.cpp @@ -49,55 +49,83 @@ /** * Apply the Scale2x effect on a group of rows. Used internally. */ -static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) +static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, + unsigned pixel, unsigned pixel_per_row) { - switch (pixel) { - case 1 : scale2x_8_def(SSDST(8,0), SSDST(8,1), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; - case 2 : scale2x_16_def(SSDST(16,0), SSDST(16,1), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; - case 4 : scale2x_32_def(SSDST(32,0), SSDST(32,1), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; + switch (pixel) + { + case 1: scale2x_8_def(SSDST(8, 0), SSDST(8, 1), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), pixel_per_row); + break; + case 2: scale2x_16_def(SSDST(16, 0), SSDST(16, 1), SSSRC(16, 0), SSSRC(16, 1), SSSRC(16, 2), pixel_per_row); + break; + case 4: scale2x_32_def(SSDST(32, 0), SSDST(32, 1), SSSRC(32, 0), SSSRC(32, 1), SSSRC(32, 2), pixel_per_row); + break; } } /** * Apply the Scale2x3 effect on a group of rows. Used internally. */ -static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) +static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, + const void* src2, unsigned pixel, unsigned pixel_per_row) { - switch (pixel) { - case 1 : scale2x3_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; - case 2 : scale2x3_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; - case 4 : scale2x3_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; + switch (pixel) + { + case 1: scale2x3_8_def(SSDST(8, 0), SSDST(8, 1), SSDST(8, 2), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), pixel_per_row); + break; + case 2: scale2x3_16_def(SSDST(16, 0), SSDST(16, 1), SSDST(16, 2), SSSRC(16, 0), SSSRC(16, 1), SSSRC(16, 2), + pixel_per_row); + break; + case 4: scale2x3_32_def(SSDST(32, 0), SSDST(32, 1), SSDST(32, 2), SSSRC(32, 0), SSSRC(32, 1), SSSRC(32, 2), + pixel_per_row); + break; } } /** * Apply the Scale2x4 effect on a group of rows. Used internally. */ -static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) +static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, + const void* src2, unsigned pixel, unsigned pixel_per_row) { - switch (pixel) { - case 1 : scale2x4_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSDST(8,3), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; - case 2 : scale2x4_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSDST(16,3), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; - case 4 : scale2x4_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSDST(32,3), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; + switch (pixel) + { + case 1: scale2x4_8_def(SSDST(8, 0), SSDST(8, 1), SSDST(8, 2), SSDST(8, 3), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), + pixel_per_row); + break; + case 2: scale2x4_16_def(SSDST(16, 0), SSDST(16, 1), SSDST(16, 2), SSDST(16, 3), SSSRC(16, 0), SSSRC(16, 1), + SSSRC(16, 2), pixel_per_row); + break; + case 4: scale2x4_32_def(SSDST(32, 0), SSDST(32, 1), SSDST(32, 2), SSDST(32, 3), SSSRC(32, 0), SSSRC(32, 1), + SSSRC(32, 2), pixel_per_row); + break; } } /** * Apply the Scale3x effect on a group of rows. Used internally. */ -static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) +static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, + const void* src2, unsigned pixel, unsigned pixel_per_row) { - switch (pixel) { - case 1 : scale3x_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break; - case 2 : scale3x_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break; - case 4 : scale3x_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break; + switch (pixel) + { + case 1: scale3x_8_def(SSDST(8, 0), SSDST(8, 1), SSDST(8, 2), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), pixel_per_row); + break; + case 2: scale3x_16_def(SSDST(16, 0), SSDST(16, 1), SSDST(16, 2), SSSRC(16, 0), SSSRC(16, 1), SSSRC(16, 2), + pixel_per_row); + break; + case 4: scale3x_32_def(SSDST(32, 0), SSDST(32, 1), SSDST(32, 2), SSSRC(32, 0), SSSRC(32, 1), SSSRC(32, 2), + pixel_per_row); + break; } } /** * Apply the Scale4x effect on a group of rows. Used internally. */ -static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row) +static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, + const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row) { stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row); stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row); @@ -121,7 +149,8 @@ static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height) { unsigned char* dst = (unsigned char*)void_dst; const unsigned char* src = (const unsigned char*)void_src; @@ -136,7 +165,8 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un dst = SCDST(2); count -= 2; - while (count) { + while (count) + { stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); dst = SCDST(2); @@ -162,7 +192,8 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height) { unsigned char* dst = (unsigned char*)void_dst; const unsigned char* src = (const unsigned char*)void_src; @@ -177,7 +208,8 @@ static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, u dst = SCDST(3); count -= 2; - while (count) { + while (count) + { stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); dst = SCDST(3); @@ -203,7 +235,8 @@ static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, u * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height) { unsigned char* dst = (unsigned char*)void_dst; const unsigned char* src = (const unsigned char*)void_src; @@ -218,7 +251,8 @@ static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, u dst = SCDST(4); count -= 2; - while (count) { + while (count) + { stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); dst = SCDST(4); @@ -244,7 +278,8 @@ static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, u * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height) { unsigned char* dst = (unsigned char*)void_dst; const unsigned char* src = (const unsigned char*)void_src; @@ -259,7 +294,8 @@ static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, un dst = SCDST(3); count -= 2; - while (count) { + while (count) + { stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width); dst = SCDST(3); @@ -292,7 +328,8 @@ static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, un * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, + unsigned src_slice, unsigned pixel, unsigned width, unsigned height) { unsigned char* dst = (unsigned char*)void_dst; const unsigned char* src = (const unsigned char*)void_src; @@ -323,7 +360,8 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi dst = SCDST(4); count -= 4; - while (count) { + while (count) + { unsigned char* tmp; stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width); @@ -368,7 +406,8 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height) { unsigned mid_slice; void* mid; @@ -410,18 +449,19 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned if (pixel != 1 && pixel != 2 && pixel != 4) return -1; - switch (scale) { - case 202 : - case 203 : - case 204 : - case 2 : - case 303 : - case 3 : + switch (scale) + { + case 202: + case 203: + case 204: + case 2: + case 303: + case 3: if (height < 2) return -1; break; - case 404 : - case 4 : + case 404: + case 4: if (height < 4) return -1; break; @@ -447,27 +487,28 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned * \param width Horizontal size in pixels of the source bitmap. * \param height Vertical size in pixels of the source bitmap. */ -void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) +void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height) { - switch (scale) { - case 202 : - case 2 : + switch (scale) + { + case 202: + case 2: scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height); break; - case 203 : + case 203: scale2x3(void_dst, dst_slice, void_src, src_slice, pixel, width, height); break; - case 204 : + case 204: scale2x4(void_dst, dst_slice, void_src, src_slice, pixel, width, height); break; - case 303 : - case 3 : + case 303: + case 3: scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height); break; - case 404 : - case 4 : + case 404: + case 4: scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height); break; } } - diff --git a/Utilities/Scale2x/scalebit.h b/Utilities/Scale2x/scalebit.h index 29dd5f5..bf1b0a2 100644 --- a/Utilities/Scale2x/scalebit.h +++ b/Utilities/Scale2x/scalebit.h @@ -27,7 +27,7 @@ #define __SCALEBIT_H int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height); -void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height); +void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, + unsigned width, unsigned height); #endif - diff --git a/Utilities/Serializer.cpp b/Utilities/Serializer.cpp index 0a20fe3..478e4a5 100644 --- a/Utilities/Serializer.cpp +++ b/Utilities/Serializer.cpp @@ -14,7 +14,7 @@ Serializer::Serializer(uint32_t version) _saving = true; } -Serializer::Serializer(istream &file, uint32_t version, bool compressed) +Serializer::Serializer(istream& file, uint32_t version, bool compressed) { _version = version; @@ -22,7 +22,8 @@ Serializer::Serializer(istream &file, uint32_t version, bool compressed) _block->Position = 0; _saving = false; - if(compressed) { + if (compressed) + { uint32_t decompressedSize; file.read((char*)&decompressedSize, sizeof(decompressedSize)); @@ -36,7 +37,9 @@ Serializer::Serializer(istream &file, uint32_t version, bool compressed) unsigned long decompSize = decompressedSize; uncompress(_block->Data.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size()); - } else { + } + else + { file.seekg(0, std::ios::end); uint32_t size = (uint32_t)file.tellg(); file.seekg(0, std::ios::beg); @@ -50,14 +53,16 @@ void Serializer::EnsureCapacity(uint32_t typeSize) { //Make sure the current block/stream is large enough to fit the next write uint32_t oldSize = (uint32_t)_block->Data.size(); - if(oldSize == 0) { + if (oldSize == 0) + { oldSize = typeSize * 2; } uint32_t sizeRequired = _block->Position + typeSize; - + uint32_t newSize = oldSize; - while(newSize < sizeRequired) { + while (newSize < sizeRequired) + { newSize *= 2; } @@ -73,10 +78,13 @@ void Serializer::StreamStartBlock() unique_ptr block(new BlockData()); block->Position = 0; - if(!_saving) { - VectorInfo vectorInfo = { &block->Data }; + if (!_saving) + { + VectorInfo vectorInfo = {&block->Data}; InternalStream(vectorInfo); - } else { + } + else + { block->Data = vector(0x100); } @@ -86,7 +94,8 @@ void Serializer::StreamStartBlock() void Serializer::StreamEndBlock() { - if(_blocks.empty()) { + if (_blocks.empty()) + { throw std::runtime_error("Invalid call to end block"); } @@ -95,20 +104,25 @@ void Serializer::StreamEndBlock() _block = std::move(_blocks.back()); _blocks.pop_back(); - if(_saving) { - ArrayInfo arrayInfo { block->Data.data(), block->Position }; + if (_saving) + { + ArrayInfo arrayInfo{block->Data.data(), block->Position}; InternalStream(arrayInfo); } } void Serializer::Save(ostream& file, int compressionLevel) { - if(compressionLevel == 0) { + if (compressionLevel == 0) + { file.write((char*)_block->Data.data(), _block->Position); - } else { + } + else + { unsigned long compressedSize = compressBound((unsigned long)_block->Position); uint8_t* compressedData = new uint8_t[compressedSize]; - compress2(compressedData, &compressedSize, (unsigned char*)_block->Data.data(), (unsigned long)_block->Position, compressionLevel); + compress2(compressedData, &compressedSize, (unsigned char*)_block->Data.data(), (unsigned long)_block->Position, + compressionLevel); uint32_t size = (uint32_t)compressedSize; file.write((char*)&_block->Position, sizeof(uint32_t)); @@ -131,27 +145,31 @@ void Serializer::SkipBlock(istream* file) file->seekg(blockSize, std::ios::cur); } -void Serializer::Stream(ISerializable &obj) +void Serializer::Stream(ISerializable& obj) { StreamStartBlock(); obj.Serialize(*this); StreamEndBlock(); } -void Serializer::Stream(ISerializable *obj) + +void Serializer::Stream(ISerializable* obj) { StreamStartBlock(); obj->Serialize(*this); StreamEndBlock(); } -void Serializer::InternalStream(string &str) +void Serializer::InternalStream(string& str) { - if(_saving) { + if (_saving) + { vector stringData; stringData.resize(str.size()); memcpy(stringData.data(), str.data(), str.size()); StreamVector(stringData); - } else { + } + else + { vector stringData; StreamVector(stringData); str = string(stringData.begin(), stringData.end()); diff --git a/Utilities/Serializer.h b/Utilities/Serializer.h index 07cd518..10145b9 100644 --- a/Utilities/Serializer.h +++ b/Utilities/Serializer.h @@ -5,20 +5,20 @@ class Serializer; class ISerializable; -template +template struct ArrayInfo { T* Array; uint32_t ElementCount; }; -template +template struct VectorInfo { vector* Vector; }; -template +template struct ValueInfo { T* Value; @@ -34,7 +34,7 @@ struct BlockData class Serializer { private: - vector> _blocks; + vector> _blocks; unique_ptr _block; uint32_t _version = 0; @@ -43,69 +43,86 @@ private: private: void EnsureCapacity(uint32_t typeSize); - template void StreamElement(T &value, T defaultValue = T()); - - template void InternalStream(ArrayInfo &info); - template void InternalStream(VectorInfo &info); - template void InternalStream(ValueInfo &info); - template void InternalStream(T &value); - void InternalStream(string &str); + template + void StreamElement(T& value, T defaultValue = T()); + + template + void InternalStream(ArrayInfo& info); + template + void InternalStream(VectorInfo& info); + template + void InternalStream(ValueInfo& info); + template + void InternalStream(T& value); + void InternalStream(string& str); void RecursiveStream(); - template void RecursiveStream(T &value, T2&... args); + template + void RecursiveStream(T& value, T2&... args); void StreamStartBlock(); void StreamEndBlock(); public: Serializer(uint32_t version); - Serializer(istream &file, uint32_t version, bool compressed = true); + Serializer(istream& file, uint32_t version, bool compressed = true); uint32_t GetVersion() { return _version; } bool IsSaving() { return _saving; } - template void Stream(T&... args); - template void StreamArray(T *array, uint32_t size); - template void StreamVector(vector &list); + template + void Stream(T&... args); + template + void StreamArray(T* array, uint32_t size); + template + void StreamVector(vector& list); - void Save(ostream &file, int compressionLevel = 1); + void Save(ostream& file, int compressionLevel = 1); - void Stream(ISerializable &obj); - void Stream(ISerializable *obj); + void Stream(ISerializable& obj); + void Stream(ISerializable* obj); void WriteEmptyBlock(ostream* file); void SkipBlock(istream* file); }; -template -void Serializer::StreamElement(T &value, T defaultValue) +template +void Serializer::StreamElement(T& value, T defaultValue) { - if(_saving) { + if (_saving) + { uint8_t* bytes = (uint8_t*)&value; int typeSize = sizeof(T); EnsureCapacity(typeSize); - for(int i = 0; i < typeSize; i++) { + for (int i = 0; i < typeSize; i++) + { _block->Data[_block->Position++] = bytes[i]; } - } else { - if(_block->Position + sizeof(T) <= _block->Data.size()) { + } + else + { + if (_block->Position + sizeof(T) <= _block->Data.size()) + { memcpy(&value, _block->Data.data() + _block->Position, sizeof(T)); _block->Position += sizeof(T); - } else { + } + else + { value = defaultValue; _block->Position = (uint32_t)_block->Data.size(); } } } -template -void Serializer::InternalStream(ArrayInfo &info) +template +void Serializer::InternalStream(ArrayInfo& info) { uint32_t count = info.ElementCount; StreamElement(count); - if(!_saving) { + if (!_saving) + { //Reset array to 0 before loading from file memset(info.Array, 0, info.ElementCount * sizeof(T)); } @@ -113,58 +130,64 @@ void Serializer::InternalStream(ArrayInfo &info) //Load the number of elements requested, or the maximum possible (based on what is present in the save state) EnsureCapacity(info.ElementCount * sizeof(T)); - if(_saving) { + if (_saving) + { memcpy(_block->Data.data() + _block->Position, info.Array, info.ElementCount * sizeof(T)); - } else { + } + else + { memcpy(info.Array, _block->Data.data() + _block->Position, info.ElementCount * sizeof(T)); } _block->Position += info.ElementCount * sizeof(T); } -template -void Serializer::InternalStream(VectorInfo &info) +template +void Serializer::InternalStream(VectorInfo& info) { - vector *vector = info.Vector; + vector* vector = info.Vector; uint32_t count = (uint32_t)vector->size(); StreamElement(count); - if(!_saving) { - if(count > 0xFFFFFF) { + if (!_saving) + { + if (count > 0xFFFFFF) + { throw std::runtime_error("Invalid save state"); } vector->resize(count); - memset(vector->data(), 0, sizeof(T)*count); + memset(vector->data(), 0, sizeof(T) * count); } //Load the number of elements requested T* pointer = vector->data(); - for(uint32_t i = 0; i < count; i++) { + for (uint32_t i = 0; i < count; i++) + { StreamElement(*pointer); pointer++; } } -template -void Serializer::InternalStream(ValueInfo &info) +template +void Serializer::InternalStream(ValueInfo& info) { StreamElement(*info.Value, info.DefaultValue); } -template -void Serializer::InternalStream(T &value) +template +void Serializer::InternalStream(T& value) { StreamElement(value); } -template -void Serializer::RecursiveStream(T &value, T2&... args) +template +void Serializer::RecursiveStream(T& value, T2&... args) { InternalStream(value); RecursiveStream(args...); } -template +template void Serializer::Stream(T&... args) { StreamStartBlock(); @@ -172,8 +195,8 @@ void Serializer::Stream(T&... args) StreamEndBlock(); } -template -void Serializer::StreamArray(T *array, uint32_t size) +template +void Serializer::StreamArray(T* array, uint32_t size) { ArrayInfo info; info.Array = array; @@ -181,10 +204,10 @@ void Serializer::StreamArray(T *array, uint32_t size) InternalStream(info); } -template -void Serializer::StreamVector(vector &list) +template +void Serializer::StreamVector(vector& list) { VectorInfo info; info.Vector = &list; InternalStream(info); -} \ No newline at end of file +} diff --git a/Utilities/SimpleLock.cpp b/Utilities/SimpleLock.cpp index b3f6946..c87abb5 100644 --- a/Utilities/SimpleLock.cpp +++ b/Utilities/SimpleLock.cpp @@ -22,11 +22,14 @@ LockHandler SimpleLock::AcquireSafe() void SimpleLock::Acquire() { - if(_lockCount == 0 || _holderThreadID != _threadID) { - while(_lock.test_and_set()); + if (_lockCount == 0 || _holderThreadID != _threadID) + { + while (_lock.test_and_set()); _holderThreadID = _threadID; _lockCount = 1; - } else { + } + else + { //Same thread can acquire the same lock multiple times _lockCount++; } @@ -46,19 +49,23 @@ void SimpleLock::WaitForRelease() void SimpleLock::Release() { - if(_lockCount > 0 && _holderThreadID == _threadID) { + if (_lockCount > 0 && _holderThreadID == _threadID) + { _lockCount--; - if(_lockCount == 0) { + if (_lockCount == 0) + { _holderThreadID = std::thread::id(); _lock.clear(); } - } else { + } + else + { assert(false); } } -LockHandler::LockHandler(SimpleLock *lock) +LockHandler::LockHandler(SimpleLock* lock) { _lock = lock; _lock->Acquire(); @@ -67,4 +74,4 @@ LockHandler::LockHandler(SimpleLock *lock) LockHandler::~LockHandler() { _lock->Release(); -} \ No newline at end of file +} diff --git a/Utilities/SimpleLock.h b/Utilities/SimpleLock.h index 630a3ab..6ecf7d5 100644 --- a/Utilities/SimpleLock.h +++ b/Utilities/SimpleLock.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "stdafx.h" #include @@ -7,9 +7,9 @@ class SimpleLock; class LockHandler { private: - SimpleLock *_lock; + SimpleLock* _lock; public: - LockHandler(SimpleLock *lock); + LockHandler(SimpleLock* lock); ~LockHandler(); }; @@ -33,4 +33,3 @@ public: void WaitForRelease(); void Release(); }; - diff --git a/Utilities/Socket.cpp b/Utilities/Socket.cpp index 4b3bb50..1e94322 100644 --- a/Utilities/Socket.cpp +++ b/Utilities/Socket.cpp @@ -8,11 +8,11 @@ using namespace std; #ifdef _WIN32 - #pragma comment(lib,"ws2_32.lib") //Winsock Library - #define WIN32_LEAN_AND_MEAN - #include - #include - #include +#pragma comment(lib,"ws2_32.lib") //Winsock Library +#define WIN32_LEAN_AND_MEAN +#include +#include +#include #else #include #include @@ -38,51 +38,61 @@ using namespace std; Socket::Socket() { - #ifdef _WIN32 - WSADATA wsaDat; - if(WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0) { - std::cout << "WSAStartup failed." << std::endl; - SetConnectionErrorFlag(); - return; - } - _cleanupWSA = true; - #endif +#ifdef _WIN32 + WSADATA wsaDat; + if (WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0) + { + std::cout << "WSAStartup failed." << std::endl; + SetConnectionErrorFlag(); + return; + } + _cleanupWSA = true; +#endif _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if(_socket == INVALID_SOCKET) { + if (_socket == INVALID_SOCKET) + { std::cout << "Socket creation failed." << std::endl; SetConnectionErrorFlag(); - } else { + } + else + { SetSocketOptions(); } } -Socket::Socket(uintptr_t socket) +Socket::Socket(uintptr_t socket) { _socket = socket; - if(socket == INVALID_SOCKET) { + if (socket == INVALID_SOCKET) + { SetConnectionErrorFlag(); - } else { + } + else + { SetSocketOptions(); } } Socket::~Socket() { - if(_UPnPPort != -1) { + if (_UPnPPort != -1) + { UPnPPortMapper::RemoveNATPortMapping(_UPnPPort, IPProtocol::TCP); } - if(_socket != INVALID_SOCKET) { + if (_socket != INVALID_SOCKET) + { Close(); } - #ifdef _WIN32 - if(_cleanupWSA) { - WSACleanup(); - } - #endif +#ifdef _WIN32 + if (_cleanupWSA) + { + WSACleanup(); + } +#endif } void Socket::SetSocketOptions() @@ -90,7 +100,7 @@ void Socket::SetSocketOptions() //Non-blocking mode u_long iMode = 1; ioctlsocket(_socket, FIONBIO, &iMode); - + //Set send/recv buffers to 256k int bufferSize = 0x40000; setsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (char*)&bufferSize, sizeof(int)); @@ -98,7 +108,7 @@ void Socket::SetSocketOptions() //Disable nagle's algorithm to improve latency u_long value = 1; - setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(value)); + setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(value)); } void Socket::SetConnectionErrorFlag() @@ -126,11 +136,13 @@ void Socket::Bind(uint16_t port) serverInf.sin_addr.s_addr = INADDR_ANY; serverInf.sin_port = htons(port); - if(UPnPPortMapper::AddNATPortMapping(port, port, IPProtocol::TCP)) { + if (UPnPPortMapper::AddNATPortMapping(port, port, IPProtocol::TCP)) + { _UPnPPort = port; } - if(::bind(_socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR) { + if (::bind(_socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR) + { std::cout << "Unable to bind socket." << std::endl; SetConnectionErrorFlag(); } @@ -145,12 +157,15 @@ bool Socket::Connect(const char* hostname, uint16_t port) hint.ai_family = AF_INET; hint.ai_protocol = IPPROTO_TCP; hint.ai_socktype = SOCK_STREAM; - addrinfo *addrInfo; + addrinfo* addrInfo; - if(getaddrinfo(hostname, std::to_string(port).c_str(), &hint, &addrInfo) != 0) { + if (getaddrinfo(hostname, std::to_string(port).c_str(), &hint, &addrInfo) != 0) + { std::cout << "Failed to resolve hostname." << std::endl; SetConnectionErrorFlag(); - } else { + } + else + { //Set socket in non-blocking mode u_long iMode = 1; ioctlsocket(_socket, FIONBIO, &iMode); @@ -159,13 +174,13 @@ bool Socket::Connect(const char* hostname, uint16_t port) connect(_socket, addrInfo->ai_addr, (int)addrInfo->ai_addrlen); fd_set writeSockets; - #ifdef _WIN32 - writeSockets.fd_count = 1; - writeSockets.fd_array[0] = _socket; - #else +#ifdef _WIN32 + writeSockets.fd_count = 1; + writeSockets.fd_array[0] = _socket; +#else FD_ZERO(&writeSockets); FD_SET(_socket, &writeSockets); - #endif +#endif //Timeout after 3 seconds TIMEVAL timeout; @@ -173,18 +188,22 @@ bool Socket::Connect(const char* hostname, uint16_t port) timeout.tv_usec = 0; // check if the socket is ready - int returnVal = select((int)_socket+1, nullptr, &writeSockets, nullptr, &timeout); - if(returnVal > 0) { + int returnVal = select((int)_socket + 1, nullptr, &writeSockets, nullptr, &timeout); + if (returnVal > 0) + { result = true; - } else { + } + else + { //Could not connect - if(returnVal == SOCKET_ERROR) { + if (returnVal == SOCKET_ERROR) + { //int nError = WSAGetLastError(); //std::cout << "select failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl; } SetConnectionErrorFlag(); } - + freeaddrinfo(addrInfo); } @@ -193,7 +212,8 @@ bool Socket::Connect(const char* hostname, uint16_t port) void Socket::Listen(int backlog) { - if(listen(_socket, backlog) == SOCKET_ERROR) { + if (listen(_socket, backlog) == SOCKET_ERROR) + { std::cout << "listen failed." << std::endl; SetConnectionErrorFlag(); } @@ -210,53 +230,68 @@ bool WouldBlock(int nError) return nError == WSAEWOULDBLOCK || nError == EAGAIN; } -int Socket::Send(char *buf, int len, int flags) +int Socket::Send(char* buf, int len, int flags) { int retryCount = 15; int nError = 0; int returnVal; - do { + do + { //Loop until everything has been sent (shouldn't loop at all in the vast majority of cases) returnVal = send(_socket, buf, len, flags); - if(returnVal > 0) { + if (returnVal > 0) + { //Sent partial data, adjust pointer & length buf += returnVal; len -= returnVal; - } else if(returnVal == SOCKET_ERROR) { + } + else if (returnVal == SOCKET_ERROR) + { nError = WSAGetLastError(); - if(nError != 0) { - if(!WouldBlock(nError)) { + if (nError != 0) + { + if (!WouldBlock(nError)) + { SetConnectionErrorFlag(); - } else { + } + else + { retryCount--; - if(retryCount == 0) { + if (retryCount == 0) + { //Connection seems dead, close it. std::cout << "Unable to send data, closing socket." << std::endl; Close(); return 0; } - + std::this_thread::sleep_for(std::chrono::duration(10)); } } } - } while(WouldBlock(nError) && len > 0); - + } + while (WouldBlock(nError) && len > 0); + return returnVal; } -int Socket::Recv(char *buf, int len, int flags) +int Socket::Recv(char* buf, int len, int flags) { int returnVal = recv(_socket, buf, len, flags); - - if(returnVal == SOCKET_ERROR) { + + if (returnVal == SOCKET_ERROR) + { int nError = WSAGetLastError(); - if(nError && !WouldBlock(nError)) { - std::cout << "recv failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl; + if (nError && !WouldBlock(nError)) + { + std::cout << "recv failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << + std::endl; SetConnectionErrorFlag(); } - } else if(returnVal == 0) { + } + else if (returnVal == 0) + { //Socket closed std::cout << "Socket closed by peer." << std::endl; Close(); diff --git a/Utilities/Socket.h b/Utilities/Socket.h index 841491a..9b930fb 100644 --- a/Utilities/Socket.h +++ b/Utilities/Socket.h @@ -6,10 +6,10 @@ class Socket { private: #ifndef LIBRETRO - #ifdef _WIN32 +#ifdef _WIN32 bool _cleanupWSA = false; - #endif - +#endif + uintptr_t _socket = ~0; bool _connectionError = false; int32_t _UPnPPort = -1; @@ -31,8 +31,8 @@ public: void Listen(int backlog); shared_ptr Accept(); - int Send(char *buf, int len, int flags); - void BufferedSend(char *buf, int len); + int Send(char* buf, int len, int flags); + void BufferedSend(char* buf, int len); void SendBuffer(); - int Recv(char *buf, int len, int flags); + int Recv(char* buf, int len, int flags); }; diff --git a/Utilities/StringUtilities.h b/Utilities/StringUtilities.h index 22658be..6257aa0 100644 --- a/Utilities/StringUtilities.h +++ b/Utilities/StringUtilities.h @@ -9,7 +9,8 @@ public: vector result; size_t index = 0; size_t lastIndex = 0; - while((index = input.find(delimiter, index)) != string::npos) { + while ((index = input.find(delimiter, index)) != string::npos) + { result.push_back(input.substr(lastIndex, index - lastIndex)); index++; lastIndex = index; diff --git a/Utilities/Timer.cpp b/Utilities/Timer.cpp index a26c653..b2f5162 100644 --- a/Utilities/Timer.cpp +++ b/Utilities/Timer.cpp @@ -6,7 +6,7 @@ using namespace std::chrono; -Timer::Timer() +Timer::Timer() { Reset(); } @@ -25,9 +25,11 @@ double Timer::GetElapsedMS() void Timer::WaitUntil(double targetMillisecond) { - if(targetMillisecond > 0) { + if (targetMillisecond > 0) + { double elapsedTime = GetElapsedMS(); - if(targetMillisecond - elapsedTime > 1) { + if (targetMillisecond - elapsedTime > 1) + { std::this_thread::sleep_for(std::chrono::duration((int)(targetMillisecond - elapsedTime))); } } diff --git a/Utilities/Timer.h b/Utilities/Timer.h index 743ac7f..d679ddc 100644 --- a/Utilities/Timer.h +++ b/Utilities/Timer.h @@ -5,12 +5,12 @@ using namespace std::chrono; class Timer { - private: - high_resolution_clock::time_point _start; +private: + high_resolution_clock::time_point _start; public: - Timer(); - void Reset(); - double GetElapsedMS(); - void WaitUntil(double targetMillisecond); -}; \ No newline at end of file + Timer(); + void Reset(); + double GetElapsedMS(); + void WaitUntil(double targetMillisecond); +}; diff --git a/Utilities/UPnPPortMapper.cpp b/Utilities/UPnPPortMapper.cpp index 2b5bc8e..4af4dd7 100644 --- a/Utilities/UPnPPortMapper.cpp +++ b/Utilities/UPnPPortMapper.cpp @@ -6,58 +6,72 @@ #include #include -bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalPort, IPProtocol protocol) +bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalPort, IPProtocol protocol) { bool result = false; - + CoInitializeEx(nullptr, COINIT_MULTITHREADED); - IUPnPNAT *nat = nullptr; + IUPnPNAT* nat = nullptr; HRESULT hResult = CoCreateInstance(__uuidof(UPnPNAT), nullptr, CLSCTX_ALL, __uuidof(IUPnPNAT), (void**)&nat); BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP"); - if(SUCCEEDED(hResult) && nat) { - IStaticPortMappingCollection *spmc = nullptr; + if (SUCCEEDED(hResult) && nat) + { + IStaticPortMappingCollection* spmc = nullptr; hResult = nat->get_StaticPortMappingCollection(&spmc); - if(SUCCEEDED(hResult) && spmc) { - IStaticPortMapping *spm = nullptr; + if (SUCCEEDED(hResult) && spmc) + { + IStaticPortMapping* spm = nullptr; hResult = spmc->get_Item(externalPort, proto, &spm); - if(spm != nullptr) { + if (spm != nullptr) + { //An identical mapping already exists, remove it - if(RemoveNATPortMapping(externalPort, protocol)) { + if (RemoveNATPortMapping(externalPort, protocol)) + { std::cout << "Removed existing UPnP mapping." << std::endl; spm->Release(); spm = nullptr; } } - if(!SUCCEEDED(hResult) || spm == nullptr) { + if (!SUCCEEDED(hResult) || spm == nullptr) + { std::cout << "Attempting to automatically forward port via UPnP..." << std::endl; vector localIPs = GetLocalIPs(); BSTR desc = SysAllocString(L"Mesen NetPlay"); spm = nullptr; - for(size_t i = 0, len = localIPs.size(); i < len; i++) { + for (size_t i = 0, len = localIPs.size(); i < len; i++) + { BSTR clientStr = SysAllocString(localIPs[i].c_str()); hResult = spmc->Add(externalPort, proto, internalPort, clientStr, true, desc, &spm); SysFreeString(clientStr); SysFreeString(desc); - if(SUCCEEDED(hResult) && spm) { + if (SUCCEEDED(hResult) && spm) + { //Successfully added a new port mapping - std::cout << std::dec << "Forwarded port " << externalPort << " to IP " << utf8::utf8::encode(localIPs[i]) << std::endl; + std::cout << std::dec << "Forwarded port " << externalPort << " to IP " << + utf8::utf8::encode(localIPs[i]) << std::endl; result = true; - } else { - std::cout << "Unable to add UPnP port mapping. IP: " << utf8::utf8::encode(localIPs[i]) << " HRESULT: 0x" << std::hex << hResult << std::endl; + } + else + { + std::cout << "Unable to add UPnP port mapping. IP: " << utf8::utf8::encode(localIPs[i]) << + " HRESULT: 0x" << std::hex << hResult << std::endl; } - if(spm) { + if (spm) + { spm->Release(); } } - } else { + } + else + { std::cout << "Unable to add UPnP port mapping." << std::endl; } spmc->Release(); @@ -66,16 +80,16 @@ bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalP } SysFreeString(proto); - + CoUninitialize(); return result; } -bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol) +bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol) { - IUPnPNAT *nat = nullptr; - IStaticPortMappingCollection *spmc; + IUPnPNAT* nat = nullptr; + IStaticPortMappingCollection* spmc; bool result = false; CoInitializeEx(nullptr, COINIT_MULTITHREADED); @@ -84,9 +98,11 @@ bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol prot BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP"); - if(SUCCEEDED(hResult) && nat) { + if (SUCCEEDED(hResult) && nat) + { hResult = nat->get_StaticPortMappingCollection(&spmc); - if(SUCCEEDED(hResult) && spmc) { + if (SUCCEEDED(hResult) && spmc) + { spmc->Remove(externalPort, proto); spmc->Release(); result = true; @@ -104,8 +120,8 @@ bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol prot vector UPnPPortMapper::GetLocalIPs() { vector localIPs; - ADDRINFOW *result = nullptr; - ADDRINFOW *current = nullptr; + ADDRINFOW* result = nullptr; + ADDRINFOW* current = nullptr; ADDRINFOW hints; ZeroMemory(&hints, sizeof(hints)); @@ -117,14 +133,18 @@ vector UPnPPortMapper::GetLocalIPs() DWORD hostSize = 255; GetComputerName(hostName, &hostSize); - if(GetAddrInfoW(hostName, nullptr, &hints, &result) == 0) { + if (GetAddrInfoW(hostName, nullptr, &hints, &result) == 0) + { current = result; - while(current != nullptr) { + while (current != nullptr) + { wchar_t ipAddr[255]; DWORD ipSize = 255; - if(WSAAddressToString(current->ai_addr, (DWORD)current->ai_addrlen, nullptr, ipAddr, &ipSize) == 0) { - if(std::find(localIPs.begin(), localIPs.end(), ipAddr) == localIPs.end()) { + if (WSAAddressToString(current->ai_addr, (DWORD)current->ai_addrlen, nullptr, ipAddr, &ipSize) == 0) + { + if (std::find(localIPs.begin(), localIPs.end(), ipAddr) == localIPs.end()) + { localIPs.push_back(ipAddr); } } @@ -153,4 +173,4 @@ vector UPnPPortMapper::GetLocalIPs() return vector(); } -#endif \ No newline at end of file +#endif diff --git a/Utilities/UPnPPortMapper.h b/Utilities/UPnPPortMapper.h index 82f1301..17109ec 100644 --- a/Utilities/UPnPPortMapper.h +++ b/Utilities/UPnPPortMapper.h @@ -18,4 +18,4 @@ private: public: static bool AddNATPortMapping(uint16_t internalPort, uint16_t externalPort, IPProtocol protocol); static bool RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol); -}; \ No newline at end of file +}; diff --git a/Utilities/UTF8Util.cpp b/Utilities/UTF8Util.cpp index 0a99fea..11c54b3 100644 --- a/Utilities/UTF8Util.cpp +++ b/Utilities/UTF8Util.cpp @@ -3,29 +3,29 @@ #include #include -namespace utf8 +namespace utf8 { - std::wstring utf8::decode(const std::string &str) + std::wstring utf8::decode(const std::string& str) { std::wstring_convert> conv; return conv.from_bytes(str); } - std::string utf8::encode(const std::wstring &wstr) + std::string utf8::encode(const std::wstring& wstr) { std::wstring_convert> conv; - return conv.to_bytes(wstr); + return conv.to_bytes(wstr); } - std::string utf8::encode(const std::u16string &wstr) + std::string utf8::encode(const std::u16string& wstr) { - #ifdef _MSC_VER - std::wstring_convert, int16_t> conv; - auto p = reinterpret_cast(wstr.data()); - return conv.to_bytes(p, p + wstr.size()); - #else +#ifdef _MSC_VER + std::wstring_convert, int16_t> conv; + auto p = reinterpret_cast(wstr.data()); + return conv.to_bytes(p, p + wstr.size()); +#else std::wstring_convert, char16_t> conv; return conv.to_bytes(wstr); - #endif - } -} \ No newline at end of file +#endif + } +} diff --git a/Utilities/UTF8Util.h b/Utilities/UTF8Util.h index c60c966..3925cee 100644 --- a/Utilities/UTF8Util.h +++ b/Utilities/UTF8Util.h @@ -2,33 +2,54 @@ #include -namespace utf8 { +namespace utf8 +{ class utf8 { public: - static std::wstring decode(const std::string &str); - static std::string encode(const std::wstring &wstr); - static std::string encode(const std::u16string &wstr); + static std::wstring decode(const std::string& str); + static std::string encode(const std::wstring& wstr); + static std::string encode(const std::u16string& wstr); }; - + #if defined(_WIN32) && !defined(LIBRETRO) class ifstream : public std::ifstream { public: - ifstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) : std::ifstream(utf8::decode(_Str), _Mode, _Prot) { } - ifstream() : std::ifstream() { } - void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) { std::ifstream::open(utf8::decode(_Str), _Mode, _Prot); } + ifstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, + int _Prot = (int)ios_base::_Openprot) : std::ifstream(utf8::decode(_Str), _Mode, _Prot) + { + } + + ifstream() : std::ifstream() + { + } + + void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) + { + std::ifstream::open(utf8::decode(_Str), _Mode, _Prot); + } }; class ofstream : public std::ofstream { public: - ofstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) : std::ofstream(utf8::decode(_Str), _Mode, _Prot) { } - ofstream() : std::ofstream() { } - void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) { std::ofstream::open(utf8::decode(_Str), _Mode, _Prot); } + ofstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, + int _Prot = (int)ios_base::_Openprot) : std::ofstream(utf8::decode(_Str), _Mode, _Prot) + { + } + + ofstream() : std::ofstream() + { + } + + void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) + { + std::ofstream::open(utf8::decode(_Str), _Mode, _Prot); + } }; #else using std::ifstream; using std::ofstream; #endif -} \ No newline at end of file +} diff --git a/Utilities/UpsPatcher.cpp b/Utilities/UpsPatcher.cpp index 1c3a72b..c02f412 100644 --- a/Utilities/UpsPatcher.cpp +++ b/Utilities/UpsPatcher.cpp @@ -4,19 +4,22 @@ #include "UpsPatcher.h" #include "CRC32.h" -int64_t UpsPatcher::ReadBase128Number(std::istream &file) +int64_t UpsPatcher::ReadBase128Number(std::istream& file) { int64_t result = 0; int shift = 0; uint8_t buffer; - while(true) { + while (true) + { file.read((char*)&buffer, 1); - if(file.eof()) { + if (file.eof()) + { return -1; } result += (buffer & 0x7F) << shift; shift += 7; - if(buffer & 0x80) { + if (buffer & 0x80) + { break; } result += (int64_t)1 << shift; @@ -25,16 +28,17 @@ int64_t UpsPatcher::ReadBase128Number(std::istream &file) return result; } -bool UpsPatcher::PatchBuffer(string upsFilepath, vector &input, vector &output) +bool UpsPatcher::PatchBuffer(string upsFilepath, vector& input, vector& output) { ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary); - if(upsFile) { + if (upsFile) + { return PatchBuffer(upsFile, input, output); } return false; } -bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector &input, vector &output) +bool UpsPatcher::PatchBuffer(std::istream& upsFile, vector& input, vector& output) { upsFile.seekg(0, std::ios::end); size_t fileSize = (size_t)upsFile.tellg(); @@ -42,14 +46,16 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector &input, vect char header[4]; upsFile.read((char*)&header, 4); - if(memcmp((char*)&header, "UPS1", 4) != 0) { + if (memcmp((char*)&header, "UPS1", 4) != 0) + { //Invalid UPS file return false; } int64_t inputFileSize = ReadBase128Number(upsFile); int64_t outputFileSize = ReadBase128Number(upsFile); - if(inputFileSize == -1 || outputFileSize == -1) { + if (inputFileSize == -1 || outputFileSize == -1) + { //Invalid file return false; } @@ -58,19 +64,23 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector &input, vect std::copy(input.begin(), input.end(), output.begin()); uint32_t pos = 0; - while((size_t)upsFile.tellg() < fileSize - 12) { + while ((size_t)upsFile.tellg() < fileSize - 12) + { int32_t offset = (int32_t)ReadBase128Number(upsFile); - if(offset == -1) { + if (offset == -1) + { //Invalid file return false; } pos += offset; - while(true) { + while (true) + { uint8_t xorValue = 0; upsFile.read((char*)&xorValue, 1); - if((size_t)upsFile.tellg() > fileSize - 12) { + if ((size_t)upsFile.tellg() > fileSize - 12) + { //Invalid file return false; } @@ -78,7 +88,8 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector &input, vect output[pos] ^= xorValue; pos++; - if(!xorValue) { + if (!xorValue) + { break; } } @@ -88,12 +99,15 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector &input, vect uint8_t outputChecksum[4]; upsFile.read((char*)inputChecksum, 4); upsFile.read((char*)outputChecksum, 4); - uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24); - uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24); + uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << + 24); + uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[ + 3] << 24); uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size()); uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size()); - if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) { + if (patchInputCrc != inputCrc || patchOutputCrc != outputCrc) + { return false; } return true; diff --git a/Utilities/UpsPatcher.h b/Utilities/UpsPatcher.h index bf75b1e..7a3c2c2 100644 --- a/Utilities/UpsPatcher.h +++ b/Utilities/UpsPatcher.h @@ -5,9 +5,9 @@ class UpsPatcher { private: - static int64_t ReadBase128Number(std::istream &file); + static int64_t ReadBase128Number(std::istream& file); public: - static bool PatchBuffer(std::istream &upsFile, vector &input, vector &output); - static bool PatchBuffer(string upsFilepath, vector &input, vector &output); -}; \ No newline at end of file + static bool PatchBuffer(std::istream& upsFile, vector& input, vector& output); + static bool PatchBuffer(string upsFilepath, vector& input, vector& output); +}; diff --git a/Utilities/VirtualFile.cpp b/Utilities/VirtualFile.cpp index 3144e42..d41a3ef 100644 --- a/Utilities/VirtualFile.cpp +++ b/Utilities/VirtualFile.cpp @@ -10,7 +10,7 @@ #include "../Utilities/IpsPatcher.h" #include "../Utilities/UpsPatcher.h" -const std::initializer_list VirtualFile::RomExtensions = { ".sfc", ".smc", ".swc", ".fig", ".bs", ".gb", ".gbc" }; +const std::initializer_list VirtualFile::RomExtensions = {".sfc", ".smc", ".swc", ".fig", ".bs", ".gb", ".gbc"}; VirtualFile::VirtualFile() { @@ -26,12 +26,18 @@ VirtualFile::VirtualFile(const string& file) { vector tokens = StringUtilities::Split(file, '\x1'); _path = tokens[0]; - if(tokens.size() > 1) { + if (tokens.size() > 1) + { _innerFile = tokens[1]; - if(tokens.size() > 2) { - try { + if (tokens.size() > 2) + { + try + { _innerFileIndex = std::stoi(tokens[2]); - } catch(std::exception&) {} + } + catch (std::exception&) + { + } } } } @@ -52,14 +58,22 @@ VirtualFile::VirtualFile(std::istream& input, string filePath) VirtualFile::operator std::string() const { - if(_innerFile.empty()) { + if (_innerFile.empty()) + { return _path; - } else if(_path.empty()) { + } + else if (_path.empty()) + { throw std::runtime_error("Cannot convert to string"); - } else { - if(_innerFileIndex >= 0) { + } + else + { + if (_innerFileIndex >= 0) + { return _path + "\x1" + _innerFile + "\x1" + std::to_string(_innerFileIndex); - } else { + } + else + { return _path + "\x1" + _innerFile; } } @@ -77,22 +91,32 @@ void VirtualFile::FromStream(std::istream& input, vector& output) void VirtualFile::LoadFile() { - if(_data.size() == 0) { - if(!_innerFile.empty()) { + if (_data.size() == 0) + { + if (!_innerFile.empty()) + { shared_ptr reader = ArchiveReader::GetReader(_path); - if(reader) { - if(_innerFileIndex >= 0) { + if (reader) + { + if (_innerFileIndex >= 0) + { vector filelist = reader->GetFileList(VirtualFile::RomExtensions); - if((int32_t)filelist.size() > _innerFileIndex) { + if ((int32_t)filelist.size() > _innerFileIndex) + { reader->ExtractFile(filelist[_innerFileIndex], _data); } - } else { + } + else + { reader->ExtractFile(_innerFile, _data); } } - } else { + } + else + { ifstream input(_path, std::ios::in | std::ios::binary); - if(input.good()) { + if (input.good()) + { FromStream(input, _data); } } @@ -101,25 +125,35 @@ void VirtualFile::LoadFile() bool VirtualFile::IsValid() { - if(_data.size() > 0) { + if (_data.size() > 0) + { return true; } - if(!_innerFile.empty()) { + if (!_innerFile.empty()) + { shared_ptr reader = ArchiveReader::GetReader(_path); - if(reader) { + if (reader) + { vector filelist = reader->GetFileList(); - if(_innerFileIndex >= 0) { - if((int32_t)filelist.size() > _innerFileIndex) { + if (_innerFileIndex >= 0) + { + if ((int32_t)filelist.size() > _innerFileIndex) + { return true; } - } else { + } + else + { return std::find(filelist.begin(), filelist.end(), _innerFile) != filelist.end(); } } - } else { + } + else + { ifstream input(_path, std::ios::in | std::ios::binary); - if(input) { + if (input) + { return true; } } @@ -156,7 +190,8 @@ size_t VirtualFile::GetSize() bool VirtualFile::ReadFile(vector& out) { LoadFile(); - if(_data.size() > 0) { + if (_data.size() > 0) + { out.resize(_data.size(), 0); std::copy(_data.begin(), _data.end(), out.begin()); return true; @@ -167,7 +202,8 @@ bool VirtualFile::ReadFile(vector& out) bool VirtualFile::ReadFile(std::stringstream& out) { LoadFile(); - if(_data.size() > 0) { + if (_data.size() > 0) + { out.write((char*)_data.data(), _data.size()); return true; } @@ -177,7 +213,8 @@ bool VirtualFile::ReadFile(std::stringstream& out) bool VirtualFile::ReadFile(uint8_t* out, uint32_t expectedSize) { LoadFile(); - if(_data.size() == expectedSize) { + if (_data.size() == expectedSize) + { memcpy(out, _data.data(), _data.size()); return true; } @@ -188,25 +225,33 @@ bool VirtualFile::ApplyPatch(VirtualFile& patch) { //Apply patch file bool result = false; - if(IsValid() && patch.IsValid()) { + if (IsValid() && patch.IsValid()) + { patch.LoadFile(); LoadFile(); - if(patch._data.size() >= 5) { + if (patch._data.size() >= 5) + { vector patchedData; std::stringstream ss; patch.ReadFile(ss); - if(memcmp(patch._data.data(), "PATCH", 5) == 0) { + if (memcmp(patch._data.data(), "PATCH", 5) == 0) + { result = IpsPatcher::PatchBuffer(ss, _data, patchedData); - } else if(memcmp(patch._data.data(), "UPS1", 4) == 0) { + } + else if (memcmp(patch._data.data(), "UPS1", 4) == 0) + { result = UpsPatcher::PatchBuffer(ss, _data, patchedData); - } else if(memcmp(patch._data.data(), "BPS1", 4) == 0) { + } + else if (memcmp(patch._data.data(), "BPS1", 4) == 0) + { result = BpsPatcher::PatchBuffer(ss, _data, patchedData); } - if(result) { + if (result) + { _data = patchedData; } } } return result; -} \ No newline at end of file +} diff --git a/Utilities/VirtualFile.h b/Utilities/VirtualFile.h index 6e59c09..e2a232e 100644 --- a/Utilities/VirtualFile.h +++ b/Utilities/VirtualFile.h @@ -10,7 +10,7 @@ private: int32_t _innerFileIndex = -1; vector _data; - void FromStream(std::istream &input, vector &output); + void FromStream(std::istream& input, vector& output); void LoadFile(); @@ -18,13 +18,13 @@ public: static const std::initializer_list RomExtensions; VirtualFile(); - VirtualFile(const string &archivePath, const string innerFile); - VirtualFile(const string &file); - VirtualFile(const void *buffer, size_t bufferSize, string fileName = "noname"); - VirtualFile(std::istream &input, string filePath); + VirtualFile(const string& archivePath, const string innerFile); + VirtualFile(const string& file); + VirtualFile(const void* buffer, size_t bufferSize, string fileName = "noname"); + VirtualFile(std::istream& input, string filePath); operator std::string() const; - + bool IsValid(); string GetFilePath(); string GetFolderPath(); @@ -33,9 +33,9 @@ public: size_t GetSize(); - bool ReadFile(vector &out); - bool ReadFile(std::stringstream &out); + bool ReadFile(vector& out); + bool ReadFile(std::stringstream& out); bool ReadFile(uint8_t* out, uint32_t expectedSize); - bool ApplyPatch(VirtualFile &patch); -}; \ No newline at end of file + bool ApplyPatch(VirtualFile& patch); +}; diff --git a/Utilities/ZipReader.cpp b/Utilities/ZipReader.cpp index 9023eb1..a0bde83 100644 --- a/Utilities/ZipReader.cpp +++ b/Utilities/ZipReader.cpp @@ -10,14 +10,16 @@ ZipReader::ZipReader() ZipReader::~ZipReader() { - if(_initialized) { + if (_initialized) + { mz_zip_reader_end(&_zipArchive); } } bool ZipReader::InternalLoadArchive(void* buffer, size_t size) { - if(_initialized) { + if (_initialized) + { mz_zip_reader_end(&_zipArchive); memset(&_zipArchive, 0, sizeof(mz_zip_archive)); _initialized = false; @@ -29,10 +31,13 @@ bool ZipReader::InternalLoadArchive(void* buffer, size_t size) vector ZipReader::InternalGetFileList() { vector fileList; - if(_initialized) { - for(int i = 0, len = (int)mz_zip_reader_get_num_files(&_zipArchive); i < len; i++) { + if (_initialized) + { + for (int i = 0, len = (int)mz_zip_reader_get_num_files(&_zipArchive); i < len; i++) + { mz_zip_archive_file_stat file_stat; - if(!mz_zip_reader_file_stat(&_zipArchive, i, &file_stat)) { + if (!mz_zip_reader_file_stat(&_zipArchive, i, &file_stat)) + { std::cout << "mz_zip_reader_file_stat() failed!" << std::endl; } @@ -42,12 +47,14 @@ vector ZipReader::InternalGetFileList() return fileList; } -bool ZipReader::ExtractFile(string filename, vector &output) +bool ZipReader::ExtractFile(string filename, vector& output) { - if(_initialized) { + if (_initialized) + { size_t uncompSize; - void *p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0); - if(!p) { + void* p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0); + if (!p) + { #ifdef _DEBUG std::cout << "mz_zip_reader_extract_file_to_heap() failed!" << std::endl; #endif @@ -63,4 +70,4 @@ bool ZipReader::ExtractFile(string filename, vector &output) } return false; -} \ No newline at end of file +} diff --git a/Utilities/ZipReader.h b/Utilities/ZipReader.h index 4d4573e..61e817e 100644 --- a/Utilities/ZipReader.h +++ b/Utilities/ZipReader.h @@ -16,5 +16,5 @@ public: ZipReader(); virtual ~ZipReader(); - bool ExtractFile(string filename, vector &output); -}; \ No newline at end of file + bool ExtractFile(string filename, vector& output); +}; diff --git a/Utilities/ZipWriter.cpp b/Utilities/ZipWriter.cpp index 37ef6b9..966c568 100644 --- a/Utilities/ZipWriter.cpp +++ b/Utilities/ZipWriter.cpp @@ -29,19 +29,21 @@ bool ZipWriter::Save() void ZipWriter::AddFile(string filepath, string zipFilename) { - if(!mz_zip_writer_add_file(&_zipArchive, zipFilename.c_str(), filepath.c_str(), "", 0, MZ_BEST_COMPRESSION)) { + if (!mz_zip_writer_add_file(&_zipArchive, zipFilename.c_str(), filepath.c_str(), "", 0, MZ_BEST_COMPRESSION)) + { std::cout << "mz_zip_writer_add_file() failed!" << std::endl; } } -void ZipWriter::AddFile(vector &fileData, string zipFilename) +void ZipWriter::AddFile(vector& fileData, string zipFilename) { - if(!mz_zip_writer_add_mem(&_zipArchive, zipFilename.c_str(), fileData.data(), fileData.size(), MZ_BEST_COMPRESSION)) { + if (!mz_zip_writer_add_mem(&_zipArchive, zipFilename.c_str(), fileData.data(), fileData.size(), MZ_BEST_COMPRESSION)) + { std::cout << "mz_zip_writer_add_file() failed!" << std::endl; } } -void ZipWriter::AddFile(std::stringstream &filestream, string zipFilename) +void ZipWriter::AddFile(std::stringstream& filestream, string zipFilename) { filestream.seekg(0, std::ios::end); size_t bufferSize = (size_t)filestream.tellg(); diff --git a/Utilities/ZipWriter.h b/Utilities/ZipWriter.h index 45b111c..3d8af5b 100644 --- a/Utilities/ZipWriter.h +++ b/Utilities/ZipWriter.h @@ -16,6 +16,6 @@ public: bool Save(); void AddFile(string filepath, string zipFilename); - void AddFile(vector &fileData, string zipFilename); - void AddFile(std::stringstream &filestream, string zipFilename); -}; \ No newline at end of file + void AddFile(vector& fileData, string zipFilename); + void AddFile(std::stringstream& filestream, string zipFilename); +}; diff --git a/Utilities/ZmbvCodec.cpp b/Utilities/ZmbvCodec.cpp index f6fadca..4fb07bc 100644 --- a/Utilities/ZmbvCodec.cpp +++ b/Utilities/ZmbvCodec.cpp @@ -39,24 +39,32 @@ #define Mask_KeyFrame 0x01 #define Mask_DeltaPalette 0x02 -int ZmbvCodec::NeededSize( int _width, int _height, zmbv_format_t _format) { +int ZmbvCodec::NeededSize(int _width, int _height, zmbv_format_t _format) +{ int f; - switch (_format) { - case ZMBV_FORMAT_8BPP:f = 1;break; - case ZMBV_FORMAT_15BPP:f = 2;break; - case ZMBV_FORMAT_16BPP:f = 2;break; - case ZMBV_FORMAT_32BPP:f = 4;break; + switch (_format) + { + case ZMBV_FORMAT_8BPP: f = 1; + break; + case ZMBV_FORMAT_15BPP: f = 2; + break; + case ZMBV_FORMAT_16BPP: f = 2; + break; + case ZMBV_FORMAT_32BPP: f = 4; + break; default: return -1; } - f = f*_width*_height + 2*(1+(_width/8)) * (1+(_height/8))+1024; - return f + f/1000; + f = f * _width * _height + 2 * (1 + (_width / 8)) * (1 + (_height / 8)) + 1024; + return f + f / 1000; } -bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockheight) { +bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockheight) +{ FreeBuffers(); palsize = 0; - switch (_format) { + switch (_format) + { case ZMBV_FORMAT_8BPP: pixelsize = 1; palsize = 256; @@ -73,50 +81,59 @@ bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockhei default: return false; }; - bufsize = (height+2*MAX_VECTOR)*pitch*pixelsize+2048; + bufsize = (height + 2 * MAX_VECTOR) * pitch * pixelsize + 2048; buf1 = new unsigned char[bufsize]; buf2 = new unsigned char[bufsize]; work = new unsigned char[bufsize]; - int xblocks = (width/blockwidth); + int xblocks = (width / blockwidth); int xleft = width % blockwidth; if (xleft) xblocks++; - int yblocks = (height/blockheight); + int yblocks = (height / blockheight); int yleft = height % blockheight; if (yleft) yblocks++; - blockcount=yblocks*xblocks; - blocks=new FrameBlock[blockcount]; + blockcount = yblocks * xblocks; + blocks = new FrameBlock[blockcount]; - if (!buf1 || !buf2 || !work || !blocks) { + if (!buf1 || !buf2 || !work || !blocks) + { FreeBuffers(); return false; } - int y,x,i; - i=0; - for (y=0;y -INLINE int ZmbvCodec::PossibleBlock(int vx,int vy,FrameBlock * block) { - int ret=0; - P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; - P * pnew=((P*)newframe)+block->start;; - for (int y=0;ydy;y+=4) { - for (int x=0;xdx;x+=4) { - int test=0-((pold[x]-pnew[x])&0x00ffffff); - ret-=(test>>31); +template +INLINE int ZmbvCodec::PossibleBlock(int vx, int vy, FrameBlock* block) +{ + int ret = 0; + P* pold = ((P*)oldframe) + block->start + (vy * pitch) + vx; + P* pnew = ((P*)newframe) + block->start;; + for (int y = 0; y < block->dy; y += 4) + { + for (int x = 0; x < block->dx; x += 4) + { + int test = 0 - ((pold[x] - pnew[x]) & 0x00ffffff); + ret -= (test >> 31); } - pold+=pitch*4; - pnew+=pitch*4; + pold += pitch * 4; + pnew += pitch * 4; } return ret; } -template -INLINE int ZmbvCodec::CompareBlock(int vx,int vy,FrameBlock * block) { - int ret=0; - P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; - P * pnew=((P*)newframe)+block->start;; - for (int y=0;ydy;y++) { - for (int x=0;xdx;x++) { - int test=0-((pold[x]-pnew[x])&0x00ffffff); - ret-=(test>>31); +template +INLINE int ZmbvCodec::CompareBlock(int vx, int vy, FrameBlock* block) +{ + int ret = 0; + P* pold = ((P*)oldframe) + block->start + (vy * pitch) + vx; + P* pnew = ((P*)newframe) + block->start;; + for (int y = 0; y < block->dy; y++) + { + for (int x = 0; x < block->dx; x++) + { + int test = 0 - ((pold[x] - pnew[x]) & 0x00ffffff); + ret -= (test >> 31); } - pold+=pitch; - pnew+=pitch; + pold += pitch; + pnew += pitch; } return ret; } -template -INLINE void ZmbvCodec::AddXorBlock(int vx,int vy,FrameBlock * block) { - P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; - P * pnew=((P*)newframe)+block->start; - for (int y=0;ydy;y++) { - for (int x=0;xdx;x++) { - *((P*)&work[workUsed])=pnew[x] ^ pold[x]; - workUsed+=sizeof(P); +template +INLINE void ZmbvCodec::AddXorBlock(int vx, int vy, FrameBlock* block) +{ + P* pold = ((P*)oldframe) + block->start + (vy * pitch) + vx; + P* pnew = ((P*)newframe) + block->start; + for (int y = 0; y < block->dy; y++) + { + for (int x = 0; x < block->dx; x++) + { + *((P*)&work[workUsed]) = pnew[x] ^ pold[x]; + workUsed += sizeof(P); } - pold+=pitch; - pnew+=pitch; + pold += pitch; + pnew += pitch; } } -template -void ZmbvCodec::AddXorFrame(void) { - signed char * vectors=(signed char*)&work[workUsed]; +template +void ZmbvCodec::AddXorFrame(void) +{ + signed char* vectors = (signed char*)&work[workUsed]; /* Align the following xor data on 4 byte boundary*/ - workUsed=(workUsed + blockcount*2 +3) & ~3; - for (int b=0;b(0,0, block); - int possibles=64; - for (int v=0;v(0, 0, block); + int possibles = 64; + for (int v = 0; v < VectorCount && possibles; v++) + { + if (bestchange < 4) break; int vx = VectorTable[v].x; int vy = VectorTable[v].y; - if (PossibleBlock

(vx, vy, block) < 4) { + if (PossibleBlock

(vx, vy, block) < 4) + { possibles--; - int testchange=CompareBlock

(vx,vy, block); - if (testchange(vx, vy, block); + if (testchange < bestchange) + { + bestchange = testchange; bestvx = vx; bestvy = vy; } } } - vectors[b*2+0]=(bestvx << 1); - vectors[b*2+1]=(bestvy << 1); - if (bestchange) { - vectors[b*2+0]|=1; + vectors[b * 2 + 0] = (bestvx << 1); + vectors[b * 2 + 1] = (bestvy << 1); + if (bestchange) + { + vectors[b * 2 + 0] |= 1; AddXorBlock

(bestvx, bestvy, block); } } } -bool ZmbvCodec::SetupCompress( int _width, int _height, uint32_t compressionLevel ) { +bool ZmbvCodec::SetupCompress(int _width, int _height, uint32_t compressionLevel) +{ width = _width; height = _height; - pitch = _width + 2*MAX_VECTOR; + pitch = _width + 2 * MAX_VECTOR; format = ZMBV_FORMAT_NONE; - if (deflateInit (&zstream, compressionLevel) != Z_OK) + if (deflateInit(&zstream, compressionLevel) != Z_OK) return false; return true; } -bool ZmbvCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char * pal) +bool ZmbvCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char* pal) { int i; - unsigned char *firstByte; + unsigned char* firstByte; - if (_format != format) { - if (!SetupBuffers( _format, 16, 16)) + if (_format != format) + { + if (!SetupBuffers(_format, 16, 16)) return false; - flags|=1; //Force a keyframe + flags |= 1; //Force a keyframe } /* replace oldframe with new frame */ - unsigned char *copyFrame = newframe; + unsigned char* copyFrame = newframe; newframe = oldframe; oldframe = copyFrame; compressInfo.linesDone = 0; compressInfo.writeSize = _bufSize; compressInfo.writeDone = 1; - compressInfo.writeBuf = (unsigned char *)_buf; + compressInfo.writeBuf = (unsigned char*)_buf; /* Set a pointer to the first byte which will contain info about this frame */ firstByte = compressInfo.writeBuf; *firstByte = 0; //Reset the work buffer - workUsed = 0;workPos = 0; - if (flags & 1) { + workUsed = 0; + workPos = 0; + if (flags & 1) + { /* Make a keyframe */ *firstByte |= Mask_KeyFrame; - KeyframeHeader * header = (KeyframeHeader *)(compressInfo.writeBuf + compressInfo.writeDone); + KeyframeHeader* header = (KeyframeHeader*)(compressInfo.writeBuf + compressInfo.writeDone); header->high_version = DBZV_VERSION_HIGH; header->low_version = DBZV_VERSION_LOW; header->compression = COMPRESSION_ZLIB; @@ -268,85 +309,98 @@ bool ZmbvCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char * pa header->blockheight = 16; compressInfo.writeDone += sizeof(KeyframeHeader); /* Copy the new frame directly over */ - if (palsize) { + if (palsize) + { if (pal) memcpy(&palette, pal, sizeof(palette)); - else - memset(&palette,0, sizeof(palette)); + else + memset(&palette, 0, sizeof(palette)); /* keyframes get the full palette */ - for (i=0;i(); - break; - case ZMBV_FORMAT_15BPP: - case ZMBV_FORMAT_16BPP: - AddXorFrame(); - break; + switch (format) + { + case ZMBV_FORMAT_8BPP: + AddXorFrame(); + break; + case ZMBV_FORMAT_15BPP: + case ZMBV_FORMAT_16BPP: + AddXorFrame(); + break; - default: - case ZMBV_FORMAT_32BPP: - AddXorFrame(); - break; + default: + case ZMBV_FORMAT_32BPP: + AddXorFrame(); + break; } } /* Create the actual frame with compression */ - zstream.next_in = (Bytef *)work; + zstream.next_in = (Bytef*)work; zstream.avail_in = workUsed; zstream.total_in = 0; - zstream.next_out = (Bytef *)(compressInfo.writeBuf + compressInfo.writeDone); + zstream.next_out = (Bytef*)(compressInfo.writeBuf + compressInfo.writeDone); zstream.avail_out = compressInfo.writeSize - compressInfo.writeDone; zstream.total_out = 0; - + deflate(&zstream, Z_SYNC_FLUSH); *compressedData = _buf; @@ -368,24 +422,26 @@ void ZmbvCodec::FreeBuffers() _buf = nullptr; } -ZmbvCodec::ZmbvCodec() +ZmbvCodec::ZmbvCodec() { CreateVectorTable(); blocks = nullptr; buf1 = nullptr; buf2 = nullptr; work = nullptr; - memset( &zstream, 0, sizeof(zstream)); + memset(&zstream, 0, sizeof(zstream)); } -int ZmbvCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) +int ZmbvCodec::CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) { - if(!PrepareCompressFrame(isKeyFrame ? 1 : 0, ZMBV_FORMAT_32BPP, nullptr)) { + if (!PrepareCompressFrame(isKeyFrame ? 1 : 0, ZMBV_FORMAT_32BPP, nullptr)) + { return -1; } - for(int i = 0; i < height; i++) { - void * rowPointer = frameData + i*width*4; + for (int i = 0; i < height; i++) + { + void* rowPointer = frameData + i * width * 4; CompressLines(1, &rowPointer); } @@ -395,4 +451,4 @@ int ZmbvCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** comp const char* ZmbvCodec::GetFourCC() { return "ZMBV"; -} \ No newline at end of file +} diff --git a/Utilities/ZmbvCodec.h b/Utilities/ZmbvCodec.h index 5e3c285..f0d56ea 100644 --- a/Utilities/ZmbvCodec.h +++ b/Utilities/ZmbvCodec.h @@ -30,58 +30,65 @@ #define INLINE inline #endif -typedef enum { - ZMBV_FORMAT_NONE = 0x00, - ZMBV_FORMAT_1BPP = 0x01, - ZMBV_FORMAT_2BPP = 0x02, - ZMBV_FORMAT_4BPP = 0x03, - ZMBV_FORMAT_8BPP = 0x04, - ZMBV_FORMAT_15BPP = 0x05, - ZMBV_FORMAT_16BPP = 0x06, - ZMBV_FORMAT_24BPP = 0x07, - ZMBV_FORMAT_32BPP = 0x08 +typedef enum +{ + ZMBV_FORMAT_NONE = 0x00, + ZMBV_FORMAT_1BPP = 0x01, + ZMBV_FORMAT_2BPP = 0x02, + ZMBV_FORMAT_4BPP = 0x03, + ZMBV_FORMAT_8BPP = 0x04, + ZMBV_FORMAT_15BPP = 0x05, + ZMBV_FORMAT_16BPP = 0x06, + ZMBV_FORMAT_24BPP = 0x07, + ZMBV_FORMAT_32BPP = 0x08 } zmbv_format_t; class ZmbvCodec : public BaseCodec { private: - struct FrameBlock { + struct FrameBlock + { int start = 0; - int dx = 0,dy = 0; + int dx = 0, dy = 0; }; - struct CodecVector { - int x = 0,y = 0; + + struct CodecVector + { + int x = 0, y = 0; int slot = 0; }; - struct KeyframeHeader { + + struct KeyframeHeader + { unsigned char high_version = 0; unsigned char low_version = 0; unsigned char compression = 0; unsigned char format = 0; - unsigned char blockwidth = 0,blockheight = 0; + unsigned char blockwidth = 0, blockheight = 0; }; - struct { - int linesDone = 0; - int writeSize = 0; - int writeDone = 0; - unsigned char *writeBuf = nullptr; + struct + { + int linesDone = 0; + int writeSize = 0; + int writeDone = 0; + unsigned char* writeBuf = nullptr; } compressInfo; CodecVector VectorTable[512] = {}; int VectorCount = 0; - unsigned char *oldframe=nullptr, *newframe=nullptr; - unsigned char *buf1=nullptr, *buf2=nullptr, *work=nullptr; + unsigned char *oldframe = nullptr, *newframe = nullptr; + unsigned char *buf1 = nullptr, *buf2 = nullptr, *work = nullptr; int bufsize = 0; - int blockcount = 0; - FrameBlock * blocks = nullptr; + int blockcount = 0; + FrameBlock* blocks = nullptr; int workUsed = 0, workPos = 0; int palsize = 0; - char palette[256*4] = {}; + char palette[256 * 4] = {}; int height = 0, width = 0, pitch = 0; zmbv_format_t format = zmbv_format_t::ZMBV_FORMAT_NONE; int pixelsize = 0; @@ -96,20 +103,24 @@ private: void CreateVectorTable(void); bool SetupBuffers(zmbv_format_t format, int blockwidth, int blockheight); - template void AddXorFrame(void); - template INLINE int PossibleBlock(int vx,int vy,FrameBlock * block); - template INLINE int CompareBlock(int vx,int vy,FrameBlock * block); - template INLINE void AddXorBlock(int vx,int vy,FrameBlock * block); + template + void AddXorFrame(void); + template + INLINE int PossibleBlock(int vx, int vy, FrameBlock* block); + template + INLINE int CompareBlock(int vx, int vy, FrameBlock* block); + template + INLINE void AddXorBlock(int vx, int vy, FrameBlock* block); int NeededSize(int _width, int _height, zmbv_format_t _format); - void CompressLines(int lineCount, void *lineData[]); - bool PrepareCompressFrame(int flags, zmbv_format_t _format, char * pal); + void CompressLines(int lineCount, void* lineData[]); + bool PrepareCompressFrame(int flags, zmbv_format_t _format, char* pal); int FinishCompressFrame(uint8_t** compressedData); public: ZmbvCodec(); bool SetupCompress(int _width, int _height, uint32_t compressionLevel) override; - int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override; + int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) override; const char* GetFourCC() override; }; diff --git a/Utilities/blip_buf.cpp b/Utilities/blip_buf.cpp index ad42438..e8e959c 100644 --- a/Utilities/blip_buf.cpp +++ b/Utilities/blip_buf.cpp @@ -30,8 +30,9 @@ Avoids constants that don't fit in 32 bits. */ enum { pre_shift = 32 }; #elif defined(ULLONG_MAX) - typedef unsigned long long fixed_t; - enum { pre_shift = 32 }; +typedef unsigned long long fixed_t; + +enum { pre_shift = 32 }; #else typedef unsigned fixed_t; @@ -41,17 +42,23 @@ Avoids constants that don't fit in 32 bits. */ enum { time_bits = pre_shift + 20 }; -static fixed_t const time_unit = (fixed_t) 1 << time_bits; +static fixed_t const time_unit = (fixed_t)1 << time_bits; -enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */ +enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */ enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */ -enum { half_width = 8 }; -enum { buf_extra = half_width*2 + end_frame_extra }; -enum { phase_bits = 5 }; +enum { half_width = 8 }; + +enum { buf_extra = half_width * 2 + end_frame_extra }; + +enum { phase_bits = 5 }; + enum { phase_count = 1 << phase_bits }; -enum { delta_bits = 15 }; -enum { delta_unit = 1 << delta_bits }; + +enum { delta_bits = 15 }; + +enum { delta_unit = 1 << delta_bits }; + enum { frac_bits = time_bits - pre_shift }; /* We could eliminate avail and encode whole samples in offset, but that would @@ -80,6 +87,7 @@ typedef int buf_t; ((n) >> (shift)) enum { max_sample = +32767 }; + enum { min_sample = -32768 }; #define CLAMP( n ) \ @@ -88,158 +96,158 @@ enum { min_sample = -32768 }; n = ARITH_SHIFT( n, 16 ) ^ max_sample;\ } -static void check_assumptions( void ) +static void check_assumptions(void) { int n; - - #if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF + +#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF #error "int must be at least 32 bits" - #endif - - assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */ - +#endif + + assert((-3 >> 1) == -2); /* right shift must preserve sign */ + n = max_sample * 2; - CLAMP( n ); - assert( n == max_sample ); - + CLAMP(n); + assert(n == max_sample); + n = min_sample * 2; - CLAMP( n ); - assert( n == min_sample ); - - assert( blip_max_ratio <= time_unit ); - assert( blip_max_frame <= (fixed_t) -1 >> time_bits ); + CLAMP(n); + assert(n == min_sample); + + assert(blip_max_ratio <= time_unit); + assert(blip_max_frame <= (fixed_t) -1 >> time_bits); } -blip_t* blip_new( int size ) +blip_t* blip_new(int size) { blip_t* m; - assert( size >= 0 ); - - m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) ); - if ( m ) + assert(size >= 0); + + m = (blip_t*)malloc(sizeof *m + (size + buf_extra) * sizeof(buf_t)); + if (m) { m->factor = time_unit / blip_max_ratio; - m->size = size; - blip_clear( m ); + m->size = size; + blip_clear(m); check_assumptions(); } return m; } -void blip_delete( blip_t* m ) +void blip_delete(blip_t* m) { - if ( m != NULL ) + if (m != NULL) { /* Clear fields in case user tries to use after freeing */ - memset( m, 0, sizeof *m ); - free( m ); + memset(m, 0, sizeof *m); + free(m); } } -void blip_set_rates( blip_t* m, double clock_rate, double sample_rate ) +void blip_set_rates(blip_t* m, double clock_rate, double sample_rate) { double factor = time_unit * sample_rate / clock_rate; - m->factor = (fixed_t) factor; - + m->factor = (fixed_t)factor; + /* Fails if clock_rate exceeds maximum, relative to sample_rate */ - assert( 0 <= factor - m->factor && factor - m->factor < 1 ); - + assert(0 <= factor - m->factor && factor - m->factor < 1); + /* Avoid requiring math.h. Equivalent to m->factor = (int) ceil( factor ) */ - if ( m->factor < factor ) + if (m->factor < factor) m->factor++; - + /* At this point, factor is most likely rounded up, but could still have been rounded down in the floating-point calculation. */ } -void blip_clear( blip_t* m ) +void blip_clear(blip_t* m) { /* We could set offset to 0, factor/2, or factor-1. 0 is suitable if factor is rounded up. factor-1 is suitable if factor is rounded down. Since we don't know rounding direction, factor/2 accommodates either, with the slight loss of showing an error in half the time. Since for a 64-bit factor this is years, the halving isn't a problem. */ - - m->offset = m->factor / 2; - m->avail = 0; + + m->offset = m->factor / 2; + m->avail = 0; m->integrator = 0; - memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) ); + memset(SAMPLES(m), 0, (m->size + buf_extra) * sizeof(buf_t)); } -int blip_clocks_needed( const blip_t* m, int samples ) +int blip_clocks_needed(const blip_t* m, int samples) { fixed_t needed; - + /* Fails if buffer can't hold that many more samples */ - assert( samples >= 0 && m->avail + samples <= m->size ); - - needed = (fixed_t) samples * time_unit; - if ( needed < m->offset ) + assert(samples >= 0 && m->avail + samples <= m->size); + + needed = (fixed_t)samples * time_unit; + if (needed < m->offset) return 0; - + return (int)((needed - m->offset + m->factor - 1) / m->factor); } -void blip_end_frame( blip_t* m, unsigned t ) +void blip_end_frame(blip_t* m, unsigned t) { fixed_t off = t * m->factor + m->offset; m->avail += off >> time_bits; m->offset = off & (time_unit - 1); - + /* Fails if buffer size was exceeded */ - assert( m->avail <= m->size ); + assert(m->avail <= m->size); } -int blip_samples_avail( const blip_t* m ) +int blip_samples_avail(const blip_t* m) { return m->avail; } -static void remove_samples( blip_t* m, int count ) +static void remove_samples(blip_t* m, int count) { - buf_t* buf = SAMPLES( m ); + buf_t* buf = SAMPLES(m); int remain = m->avail + buf_extra - count; m->avail -= count; - - memmove( &buf [0], &buf [count], remain * sizeof buf [0] ); - memset( &buf [remain], 0, count * sizeof buf [0] ); + + memmove(&buf[0], &buf[count], remain * sizeof buf[0]); + memset(&buf[remain], 0, count * sizeof buf[0]); } -int blip_read_samples( blip_t* m, short out [], int count, int stereo ) +int blip_read_samples(blip_t* m, short out[], int count, int stereo) { - assert( count >= 0 ); - - if ( count > m->avail ) + assert(count >= 0); + + if (count > m->avail) count = m->avail; - - if ( count ) + + if (count) { int const step = stereo ? 2 : 1; - buf_t const* in = SAMPLES( m ); + buf_t const* in = SAMPLES(m); buf_t const* end = in + count; int sum = m->integrator; do { /* Eliminate fraction */ - int s = ARITH_SHIFT( sum, delta_bits ); - + int s = ARITH_SHIFT(sum, delta_bits); + sum += *in++; - - CLAMP( s ); - + + CLAMP(s); + *out = s; out += step; - + /* High-pass filter */ sum -= s << (delta_bits - bass_shift); } - while ( in != end ); + while (in != end); m->integrator = sum; - - remove_samples( m, count ); + + remove_samples(m, count); } - + return count; } @@ -250,41 +258,41 @@ int blip_read_samples( blip_t* m, short out [], int count, int stereo ) */ /* Sinc_Generator( 0.9, 0.55, 4.5 ) */ -static short const bl_step [phase_count + 1] [half_width] = +static short const bl_step[phase_count + 1][half_width] = { -{ 43, -115, 350, -488, 1136, -914, 5861,21022}, -{ 44, -118, 348, -473, 1076, -799, 5274,21001}, -{ 45, -121, 344, -454, 1011, -677, 4706,20936}, -{ 46, -122, 336, -431, 942, -549, 4156,20829}, -{ 47, -123, 327, -404, 868, -418, 3629,20679}, -{ 47, -122, 316, -375, 792, -285, 3124,20488}, -{ 47, -120, 303, -344, 714, -151, 2644,20256}, -{ 46, -117, 289, -310, 634, -17, 2188,19985}, -{ 46, -114, 273, -275, 553, 117, 1758,19675}, -{ 44, -108, 255, -237, 471, 247, 1356,19327}, -{ 43, -103, 237, -199, 390, 373, 981,18944}, -{ 42, -98, 218, -160, 310, 495, 633,18527}, -{ 40, -91, 198, -121, 231, 611, 314,18078}, -{ 38, -84, 178, -81, 153, 722, 22,17599}, -{ 36, -76, 157, -43, 80, 824, -241,17092}, -{ 34, -68, 135, -3, 8, 919, -476,16558}, -{ 32, -61, 115, 34, -60, 1006, -683,16001}, -{ 29, -52, 94, 70, -123, 1083, -862,15422}, -{ 27, -44, 73, 106, -184, 1152,-1015,14824}, -{ 25, -36, 53, 139, -239, 1211,-1142,14210}, -{ 22, -27, 34, 170, -290, 1261,-1244,13582}, -{ 20, -20, 16, 199, -335, 1301,-1322,12942}, -{ 18, -12, -3, 226, -375, 1331,-1376,12293}, -{ 15, -4, -19, 250, -410, 1351,-1408,11638}, -{ 13, 3, -35, 272, -439, 1361,-1419,10979}, -{ 11, 9, -49, 292, -464, 1362,-1410,10319}, -{ 9, 16, -63, 309, -483, 1354,-1383, 9660}, -{ 7, 22, -75, 322, -496, 1337,-1339, 9005}, -{ 6, 26, -85, 333, -504, 1312,-1280, 8355}, -{ 4, 31, -94, 341, -507, 1278,-1205, 7713}, -{ 3, 35, -102, 347, -506, 1238,-1119, 7082}, -{ 1, 40, -110, 350, -499, 1190,-1021, 6464}, -{ 0, 43, -115, 350, -488, 1136, -914, 5861} + {43, -115, 350, -488, 1136, -914, 5861, 21022}, + {44, -118, 348, -473, 1076, -799, 5274, 21001}, + {45, -121, 344, -454, 1011, -677, 4706, 20936}, + {46, -122, 336, -431, 942, -549, 4156, 20829}, + {47, -123, 327, -404, 868, -418, 3629, 20679}, + {47, -122, 316, -375, 792, -285, 3124, 20488}, + {47, -120, 303, -344, 714, -151, 2644, 20256}, + {46, -117, 289, -310, 634, -17, 2188, 19985}, + {46, -114, 273, -275, 553, 117, 1758, 19675}, + {44, -108, 255, -237, 471, 247, 1356, 19327}, + {43, -103, 237, -199, 390, 373, 981, 18944}, + {42, -98, 218, -160, 310, 495, 633, 18527}, + {40, -91, 198, -121, 231, 611, 314, 18078}, + {38, -84, 178, -81, 153, 722, 22, 17599}, + {36, -76, 157, -43, 80, 824, -241, 17092}, + {34, -68, 135, -3, 8, 919, -476, 16558}, + {32, -61, 115, 34, -60, 1006, -683, 16001}, + {29, -52, 94, 70, -123, 1083, -862, 15422}, + {27, -44, 73, 106, -184, 1152, -1015, 14824}, + {25, -36, 53, 139, -239, 1211, -1142, 14210}, + {22, -27, 34, 170, -290, 1261, -1244, 13582}, + {20, -20, 16, 199, -335, 1301, -1322, 12942}, + {18, -12, -3, 226, -375, 1331, -1376, 12293}, + {15, -4, -19, 250, -410, 1351, -1408, 11638}, + {13, 3, -35, 272, -439, 1361, -1419, 10979}, + {11, 9, -49, 292, -464, 1362, -1410, 10319}, + {9, 16, -63, 309, -483, 1354, -1383, 9660}, + {7, 22, -75, 322, -496, 1337, -1339, 9005}, + {6, 26, -85, 333, -504, 1312, -1280, 8355}, + {4, 31, -94, 341, -507, 1278, -1205, 7713}, + {3, 35, -102, 347, -506, 1238, -1119, 7082}, + {1, 40, -110, 350, -499, 1190, -1021, 6464}, + {0, 43, -115, 350, -488, 1136, -914, 5861} }; /* Shifting by pre_shift allows calculation using unsigned int rather than @@ -292,54 +300,54 @@ possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient. And by having pre_shift 32, a 32-bit platform can easily do the shift by simply ignoring the low half. */ -void blip_add_delta( blip_t* m, unsigned time, int delta ) +void blip_add_delta(blip_t* m, unsigned time, int delta) { - unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift); - buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits); - + unsigned fixed = (unsigned)((time * m->factor + m->offset) >> pre_shift); + buf_t* out = SAMPLES(m) + m->avail + (fixed >> frac_bits); + int const phase_shift = frac_bits - phase_bits; int phase = fixed >> phase_shift & (phase_count - 1); - short const* in = bl_step [phase]; - short const* rev = bl_step [phase_count - phase]; - + short const* in = bl_step[phase]; + short const* rev = bl_step[phase_count - phase]; + int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1); int delta2 = (delta * interp) >> delta_bits; delta -= delta2; - + /* Fails if buffer size was exceeded */ - assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] ); - - out [0] += in[0]*delta + in[half_width+0]*delta2; - out [1] += in[1]*delta + in[half_width+1]*delta2; - out [2] += in[2]*delta + in[half_width+2]*delta2; - out [3] += in[3]*delta + in[half_width+3]*delta2; - out [4] += in[4]*delta + in[half_width+4]*delta2; - out [5] += in[5]*delta + in[half_width+5]*delta2; - out [6] += in[6]*delta + in[half_width+6]*delta2; - out [7] += in[7]*delta + in[half_width+7]*delta2; - + assert(out <= &SAMPLES( m ) [m->size + end_frame_extra]); + + out[0] += in[0] * delta + in[half_width + 0] * delta2; + out[1] += in[1] * delta + in[half_width + 1] * delta2; + out[2] += in[2] * delta + in[half_width + 2] * delta2; + out[3] += in[3] * delta + in[half_width + 3] * delta2; + out[4] += in[4] * delta + in[half_width + 4] * delta2; + out[5] += in[5] * delta + in[half_width + 5] * delta2; + out[6] += in[6] * delta + in[half_width + 6] * delta2; + out[7] += in[7] * delta + in[half_width + 7] * delta2; + in = rev; - out [ 8] += in[7]*delta + in[7-half_width]*delta2; - out [ 9] += in[6]*delta + in[6-half_width]*delta2; - out [10] += in[5]*delta + in[5-half_width]*delta2; - out [11] += in[4]*delta + in[4-half_width]*delta2; - out [12] += in[3]*delta + in[3-half_width]*delta2; - out [13] += in[2]*delta + in[2-half_width]*delta2; - out [14] += in[1]*delta + in[1-half_width]*delta2; - out [15] += in[0]*delta + in[0-half_width]*delta2; + out[8] += in[7] * delta + in[7 - half_width] * delta2; + out[9] += in[6] * delta + in[6 - half_width] * delta2; + out[10] += in[5] * delta + in[5 - half_width] * delta2; + out[11] += in[4] * delta + in[4 - half_width] * delta2; + out[12] += in[3] * delta + in[3 - half_width] * delta2; + out[13] += in[2] * delta + in[2 - half_width] * delta2; + out[14] += in[1] * delta + in[1 - half_width] * delta2; + out[15] += in[0] * delta + in[0 - half_width] * delta2; } -void blip_add_delta_fast( blip_t* m, unsigned time, int delta ) +void blip_add_delta_fast(blip_t* m, unsigned time, int delta) { - unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift); - buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits); - + unsigned fixed = (unsigned)((time * m->factor + m->offset) >> pre_shift); + buf_t* out = SAMPLES(m) + m->avail + (fixed >> frac_bits); + int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1); int delta2 = delta * interp; - + /* Fails if buffer size was exceeded */ - assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] ); - - out [7] += delta * delta_unit - delta2; - out [8] += delta2; + assert(out <= &SAMPLES( m ) [m->size + end_frame_extra]); + + out[7] += delta * delta_unit - delta2; + out[8] += delta2; } diff --git a/Utilities/blip_buf.h b/Utilities/blip_buf.h index a50ff96..8983d4b 100644 --- a/Utilities/blip_buf.h +++ b/Utilities/blip_buf.h @@ -5,17 +5,17 @@ Sample buffer that resamples from input clock rate to output sample rate */ /* blip_buf 1.1.0 */ -#ifndef BLIP_BUF_H +#ifndef BLIP_BUF_H #define BLIP_BUF_H #if defined(_MSC_VER) - #define EXPORT __declspec(dllexport) +#define EXPORT __declspec(dllexport) #else #define EXPORT -#endif +#endif #ifdef __cplusplus - extern "C" { +extern "C" { #endif /** First parameter of most functions is blip_t*, or const blip_t* if nothing @@ -25,57 +25,63 @@ typedef struct blip_t blip_t; /** Creates new buffer that can hold at most sample_count samples. Sets rates so that there are blip_max_ratio clocks per sample. Returns pointer to new buffer, or NULL if insufficient memory. */ -EXPORT blip_t* blip_new( int sample_count ); +EXPORT blip_t* blip_new(int sample_count); /** Sets approximate input clock rate and output sample rate. For every clock_rate input clocks, approximately sample_rate samples are generated. */ -EXPORT void blip_set_rates( blip_t*, double clock_rate, double sample_rate ); +EXPORT void blip_set_rates(blip_t*, double clock_rate, double sample_rate); -enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, -clock_rate must not be greater than sample_rate*blip_max_ratio. */ -blip_max_ratio = 1 << 20 }; +enum +{ + /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, + clock_rate must not be greater than sample_rate*blip_max_ratio. */ + blip_max_ratio = 1 << 20 +}; /** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ -EXPORT void blip_clear( blip_t* ); +EXPORT void blip_clear(blip_t*); /** Adds positive/negative delta into buffer at specified clock time. */ -EXPORT void blip_add_delta( blip_t*, unsigned int clock_time, int delta ); +EXPORT void blip_add_delta(blip_t*, unsigned int clock_time, int delta); /** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */ -void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta ); +void blip_add_delta_fast(blip_t*, unsigned int clock_time, int delta); /** Length of time frame, in clocks, needed to make sample_count additional samples available. */ -int blip_clocks_needed( const blip_t*, int sample_count ); +int blip_clocks_needed(const blip_t*, int sample_count); -enum { /** Maximum number of samples that can be generated from one time frame. */ -blip_max_frame = 4000 }; +enum +{ + /** Maximum number of samples that can be generated from one time frame. */ + blip_max_frame = 4000 +}; /** Makes input clocks before clock_duration available for reading as output samples. Also begins new time frame at clock_duration, so that clock time 0 in the new time frame specifies the same clock as clock_duration in the old time frame specified. Deltas can have been added slightly past clock_duration (up to however many clocks there are in two output samples). */ -EXPORT void blip_end_frame( blip_t*, unsigned int clock_duration ); +EXPORT void blip_end_frame(blip_t*, unsigned int clock_duration); /** Number of buffered samples available for reading. */ -int blip_samples_avail( const blip_t* ); +int blip_samples_avail(const blip_t*); /** Reads and removes at most 'count' samples and writes them to 'out'. If 'stereo' is true, writes output to every other element of 'out', allowing easy interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed samples. Returns number of samples actually read. */ -EXPORT int blip_read_samples( blip_t*, short out [], int count, int stereo ); +EXPORT int blip_read_samples(blip_t*, short out[], int count, int stereo); /** Frees buffer. No effect if NULL is passed. */ -EXPORT void blip_delete( blip_t* ); +EXPORT void blip_delete(blip_t*); /* Deprecated */ typedef blip_t blip_buffer_t; #ifdef __cplusplus - } +} #endif #endif diff --git a/Utilities/gif.h b/Utilities/gif.h index 7d9615e..a67d4c4 100644 --- a/Utilities/gif.h +++ b/Utilities/gif.h @@ -63,23 +63,23 @@ const int kGifTransIndex = 0; struct GifPalette { - int bitDepth; + int bitDepth; - uint8_t r[256]; - uint8_t g[256]; - uint8_t b[256]; + uint8_t r[256]; + uint8_t g[256]; + uint8_t b[256]; - // k-d tree over RGB space, organized in heap fashion - // i.e. left child of node i is node i*2, right child is node i*2+1 - // nodes 256-511 are implicitly the leaves, containing a color - uint8_t treeSplitElt[255]; - uint8_t treeSplit[255]; + // k-d tree over RGB space, organized in heap fashion + // i.e. left child of node i is node i*2, right child is node i*2+1 + // nodes 256-511 are implicitly the leaves, containing a color + uint8_t treeSplitElt[255]; + uint8_t treeSplit[255]; }; // max, min, and abs functions -int GifIMax(int l, int r) { return l>r?l:r; } -int GifIMin(int l, int r) { return l r ? l : r; } +int GifIMin(int l, int r) { return l < r ? l : r; } +int GifIAbs(int i) { return i < 0 ? -i : i; } // walks the k-d tree to pick the palette entry for a desired color. // Takes as in/out parameters the current best color and its error - @@ -87,750 +87,763 @@ int GifIAbs(int i) { return i<0?-i:i; } // this is the major hotspot in the code at the moment. void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestInd, int& bestDiff, int treeRoot = 1) { - // base case, reached the bottom of the tree - if(treeRoot > (1<bitDepth)-1) - { - int ind = treeRoot-(1<bitDepth); - if(ind == kGifTransIndex) return; + // base case, reached the bottom of the tree + if (treeRoot > (1 << pPal->bitDepth) - 1) + { + int ind = treeRoot - (1 << pPal->bitDepth); + if (ind == kGifTransIndex) return; - // check whether this color is better than the current winner - int r_err = r - ((int32_t)pPal->r[ind]); - int g_err = g - ((int32_t)pPal->g[ind]); - int b_err = b - ((int32_t)pPal->b[ind]); - int diff = GifIAbs(r_err)+GifIAbs(g_err)+GifIAbs(b_err); + // check whether this color is better than the current winner + int r_err = r - ((int32_t)pPal->r[ind]); + int g_err = g - ((int32_t)pPal->g[ind]); + int b_err = b - ((int32_t)pPal->b[ind]); + int diff = GifIAbs(r_err) + GifIAbs(g_err) + GifIAbs(b_err); - if(diff < bestDiff) - { - bestInd = ind; - bestDiff = diff; - } + if (diff < bestDiff) + { + bestInd = ind; + bestDiff = diff; + } - return; - } + return; + } - // take the appropriate color (r, g, or b) for this node of the k-d tree - int comps[3]; comps[0] = r; comps[1] = g; comps[2] = b; - int splitComp = comps[pPal->treeSplitElt[treeRoot]]; + // take the appropriate color (r, g, or b) for this node of the k-d tree + int comps[3]; + comps[0] = r; + comps[1] = g; + comps[2] = b; + int splitComp = comps[pPal->treeSplitElt[treeRoot]]; - int splitPos = pPal->treeSplit[treeRoot]; - if(splitPos > splitComp) - { - // check the left subtree - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2); - if( bestDiff > splitPos - splitComp ) - { - // cannot prove there's not a better value in the right subtree, check that too - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1); - } - } - else - { - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1); - if( bestDiff > splitComp - splitPos ) - { - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2); - } - } + int splitPos = pPal->treeSplit[treeRoot]; + if (splitPos > splitComp) + { + // check the left subtree + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2); + if (bestDiff > splitPos - splitComp) + { + // cannot prove there's not a better value in the right subtree, check that too + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1); + } + } + else + { + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1); + if (bestDiff > splitComp - splitPos) + { + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2); + } + } } void GifSwapPixels(uint8_t* image, int pixA, int pixB) { - uint8_t rA = image[pixA*4]; - uint8_t gA = image[pixA*4+1]; - uint8_t bA = image[pixA*4+2]; - uint8_t aA = image[pixA*4+3]; + uint8_t rA = image[pixA * 4]; + uint8_t gA = image[pixA * 4 + 1]; + uint8_t bA = image[pixA * 4 + 2]; + uint8_t aA = image[pixA * 4 + 3]; - uint8_t rB = image[pixB*4]; - uint8_t gB = image[pixB*4+1]; - uint8_t bB = image[pixB*4+2]; - uint8_t aB = image[pixA*4+3]; + uint8_t rB = image[pixB * 4]; + uint8_t gB = image[pixB * 4 + 1]; + uint8_t bB = image[pixB * 4 + 2]; + uint8_t aB = image[pixA * 4 + 3]; - image[pixA*4] = rB; - image[pixA*4+1] = gB; - image[pixA*4+2] = bB; - image[pixA*4+3] = aB; + image[pixA * 4] = rB; + image[pixA * 4 + 1] = gB; + image[pixA * 4 + 2] = bB; + image[pixA * 4 + 3] = aB; - image[pixB*4] = rA; - image[pixB*4+1] = gA; - image[pixB*4+2] = bA; - image[pixB*4+3] = aA; + image[pixB * 4] = rA; + image[pixB * 4 + 1] = gA; + image[pixB * 4 + 2] = bA; + image[pixB * 4 + 3] = aA; } // just the partition operation from quicksort int GifPartition(uint8_t* image, const int left, const int right, const int elt, int pivotIndex) { - const int pivotValue = image[(pivotIndex)*4+elt]; - GifSwapPixels(image, pivotIndex, right-1); - int storeIndex = left; - bool split = 0; - for(int ii=left; ii neededCenter) - GifPartitionByMedian(image, left, pivotIndex, com, neededCenter); + // Only "sort" the section of the array that contains the median + if (pivotIndex > neededCenter) + GifPartitionByMedian(image, left, pivotIndex, com, neededCenter); - if(pivotIndex < neededCenter) - GifPartitionByMedian(image, pivotIndex+1, right, com, neededCenter); - } + if (pivotIndex < neededCenter) + GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter); + } } // Builds a palette by creating a balanced k-d tree of all pixels in the image -void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette* pal) +void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, + int treeNode, bool buildForDither, GifPalette* pal) { - if(lastElt <= firstElt || numPixels == 0) - return; + if (lastElt <= firstElt || numPixels == 0) + return; - // base case, bottom of the tree - if(lastElt == firstElt+1) - { - if(buildForDither) - { - // Dithering needs at least one color as dark as anything - // in the image and at least one brightest color - - // otherwise it builds up error and produces strange artifacts - if( firstElt == 1 ) - { - // special case: the darkest color in the image - uint32_t r=255, g=255, b=255; - for(int ii=0; iir[firstElt] = (uint8_t)r; - pal->g[firstElt] = (uint8_t)g; - pal->b[firstElt] = (uint8_t)b; + pal->r[firstElt] = (uint8_t)r; + pal->g[firstElt] = (uint8_t)g; + pal->b[firstElt] = (uint8_t)b; - return; - } + return; + } - if( firstElt == (1 << pal->bitDepth)-1 ) - { - // special case: the lightest color in the image - uint32_t r=0, g=0, b=0; - for(int ii=0; iibitDepth) - 1) + { + // special case: the lightest color in the image + uint32_t r = 0, g = 0, b = 0; + for (int ii = 0; ii < numPixels; ++ii) + { + r = (uint32_t)GifIMax((int32_t)r, image[ii * 4 + 0]); + g = (uint32_t)GifIMax((int32_t)g, image[ii * 4 + 1]); + b = (uint32_t)GifIMax((int32_t)b, image[ii * 4 + 2]); + } - pal->r[firstElt] = (uint8_t)r; - pal->g[firstElt] = (uint8_t)g; - pal->b[firstElt] = (uint8_t)b; + pal->r[firstElt] = (uint8_t)r; + pal->g[firstElt] = (uint8_t)g; + pal->b[firstElt] = (uint8_t)b; - return; - } - } + return; + } + } - // otherwise, take the average of all colors in this subcube - uint64_t r=0, g=0, b=0; - for(int ii=0; iir[firstElt] = (uint8_t)r; - pal->g[firstElt] = (uint8_t)g; - pal->b[firstElt] = (uint8_t)b; + pal->r[firstElt] = (uint8_t)r; + pal->g[firstElt] = (uint8_t)g; + pal->b[firstElt] = (uint8_t)b; - return; - } + return; + } - // Find the axis with the largest range - int minR = 255, maxR = 0; - int minG = 255, maxG = 0; - int minB = 255, maxB = 0; - for(int ii=0; ii maxR) maxR = r; - if(r < minR) minR = r; + if (r > maxR) maxR = r; + if (r < minR) minR = r; - if(g > maxG) maxG = g; - if(g < minG) minG = g; + if (g > maxG) maxG = g; + if (g < minG) minG = g; - if(b > maxB) maxB = b; - if(b < minB) minB = b; - } + if (b > maxB) maxB = b; + if (b < minB) minB = b; + } - int rRange = maxR - minR; - int gRange = maxG - minG; - int bRange = maxB - minB; + int rRange = maxR - minR; + int gRange = maxG - minG; + int bRange = maxB - minB; - // and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it) - int splitCom = 1; - if(bRange > gRange) splitCom = 2; - if(rRange > bRange && rRange > gRange) splitCom = 0; + // and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it) + int splitCom = 1; + if (bRange > gRange) splitCom = 2; + if (rRange > bRange && rRange > gRange) splitCom = 0; - int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt); - int subPixelsB = numPixels-subPixelsA; + int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt); + int subPixelsB = numPixels - subPixelsA; - GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA); + GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA); - pal->treeSplitElt[treeNode] = (uint8_t)splitCom; - pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom]; + pal->treeSplitElt[treeNode] = (uint8_t)splitCom; + pal->treeSplit[treeNode] = image[subPixelsA * 4 + splitCom]; - GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal); - GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2+1, buildForDither, pal); + GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt - splitDist, splitDist / 2, treeNode * 2, + buildForDither, pal); + GifSplitPalette(image + subPixelsA * 4, subPixelsB, splitElt, lastElt, splitElt + splitDist, splitDist / 2, + treeNode * 2 + 1, buildForDither, pal); } // Finds all pixels that have changed from the previous image and // moves them to the fromt of th buffer. // This allows us to build a palette optimized for the colors of the // changed pixels only. -int GifPickChangedPixels( const uint8_t* lastFrame, uint8_t* frame, int numPixels ) +int GifPickChangedPixels(const uint8_t* lastFrame, uint8_t* frame, int numPixels) { - int numChanged = 0; - uint8_t* writeIter = frame; + int numChanged = 0; + uint8_t* writeIter = frame; - for (int ii=0; iibitDepth = bitDepth; + pPal->bitDepth = bitDepth; - // SplitPalette is destructive (it sorts the pixels by color) so - // we must create a copy of the image for it to destroy - size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t)); - uint8_t* destroyableImage = (uint8_t*)GIF_TEMP_MALLOC(imageSize); - memcpy(destroyableImage, nextFrame, imageSize); + // SplitPalette is destructive (it sorts the pixels by color) so + // we must create a copy of the image for it to destroy + size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t)); + uint8_t* destroyableImage = (uint8_t*)GIF_TEMP_MALLOC(imageSize); + memcpy(destroyableImage, nextFrame, imageSize); - int numPixels = (int)(width * height); - if(lastFrame) - numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels); + int numPixels = (int)(width * height); + if (lastFrame) + numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels); - const int lastElt = 1 << bitDepth; - const int splitElt = lastElt/2; - const int splitDist = splitElt/2; + const int lastElt = 1 << bitDepth; + const int splitElt = lastElt / 2; + const int splitDist = splitElt / 2; - GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal); + GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal); - GIF_TEMP_FREE(destroyableImage); + GIF_TEMP_FREE(destroyableImage); - // add the bottom node for the transparency index - int index = 1 << (bitDepth - 1); - pPal->treeSplit[index] = 0; - pPal->treeSplitElt[index] = 0; - - pPal->r[0] = pPal->g[0] = pPal->b[0] = 0; + // add the bottom node for the transparency index + int index = 1 << (bitDepth - 1); + pPal->treeSplit[index] = 0; + pPal->treeSplitElt[index] = 0; + + pPal->r[0] = pPal->g[0] = pPal->b[0] = 0; } // Implements Floyd-Steinberg dithering, writes palette value to alpha -void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal ) +void GifDitherImage(const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, + uint32_t height, GifPalette* pPal) { - int numPixels = (int)(width * height); + int numPixels = (int)(width * height); - // quantPixels initially holds color*256 for all pixels - // The extra 8 bits of precision allow for sub-single-color error values - // to be propagated - int32_t *quantPixels = (int32_t *)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4); + // quantPixels initially holds color*256 for all pixels + // The extra 8 bits of precision allow for sub-single-color error values + // to be propagated + int32_t* quantPixels = (int32_t*)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4); - for( int ii=0; iir[bestInd]) * 256; - int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256; - int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256; + // Write the result to the temp buffer + int32_t r_err = nextPix[0] - int32_t(pPal->r[bestInd]) * 256; + int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256; + int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256; - nextPix[0] = pPal->r[bestInd]; - nextPix[1] = pPal->g[bestInd]; - nextPix[2] = pPal->b[bestInd]; - nextPix[3] = bestInd; + nextPix[0] = pPal->r[bestInd]; + nextPix[1] = pPal->g[bestInd]; + nextPix[2] = pPal->b[bestInd]; + nextPix[3] = bestInd; - // Propagate the error to the four adjacent locations - // that we haven't touched yet - int quantloc_7 = (int)(yy * width + xx + 1); - int quantloc_3 = (int)(yy * width + width + xx - 1); - int quantloc_5 = (int)(yy * width + width + xx); - int quantloc_1 = (int)(yy * width + width + xx + 1); + // Propagate the error to the four adjacent locations + // that we haven't touched yet + int quantloc_7 = (int)(yy * width + xx + 1); + int quantloc_3 = (int)(yy * width + width + xx - 1); + int quantloc_5 = (int)(yy * width + width + xx); + int quantloc_1 = (int)(yy * width + width + xx + 1); - if(quantloc_7 < numPixels) - { - int32_t* pix7 = quantPixels+4*quantloc_7; - pix7[0] += GifIMax( -pix7[0], r_err * 7 / 16 ); - pix7[1] += GifIMax( -pix7[1], g_err * 7 / 16 ); - pix7[2] += GifIMax( -pix7[2], b_err * 7 / 16 ); - } + if (quantloc_7 < numPixels) + { + int32_t* pix7 = quantPixels + 4 * quantloc_7; + pix7[0] += GifIMax(-pix7[0], r_err * 7 / 16); + pix7[1] += GifIMax(-pix7[1], g_err * 7 / 16); + pix7[2] += GifIMax(-pix7[2], b_err * 7 / 16); + } - if(quantloc_3 < numPixels) - { - int32_t* pix3 = quantPixels+4*quantloc_3; - pix3[0] += GifIMax( -pix3[0], r_err * 3 / 16 ); - pix3[1] += GifIMax( -pix3[1], g_err * 3 / 16 ); - pix3[2] += GifIMax( -pix3[2], b_err * 3 / 16 ); - } + if (quantloc_3 < numPixels) + { + int32_t* pix3 = quantPixels + 4 * quantloc_3; + pix3[0] += GifIMax(-pix3[0], r_err * 3 / 16); + pix3[1] += GifIMax(-pix3[1], g_err * 3 / 16); + pix3[2] += GifIMax(-pix3[2], b_err * 3 / 16); + } - if(quantloc_5 < numPixels) - { - int32_t* pix5 = quantPixels+4*quantloc_5; - pix5[0] += GifIMax( -pix5[0], r_err * 5 / 16 ); - pix5[1] += GifIMax( -pix5[1], g_err * 5 / 16 ); - pix5[2] += GifIMax( -pix5[2], b_err * 5 / 16 ); - } + if (quantloc_5 < numPixels) + { + int32_t* pix5 = quantPixels + 4 * quantloc_5; + pix5[0] += GifIMax(-pix5[0], r_err * 5 / 16); + pix5[1] += GifIMax(-pix5[1], g_err * 5 / 16); + pix5[2] += GifIMax(-pix5[2], b_err * 5 / 16); + } - if(quantloc_1 < numPixels) - { - int32_t* pix1 = quantPixels+4*quantloc_1; - pix1[0] += GifIMax( -pix1[0], r_err / 16 ); - pix1[1] += GifIMax( -pix1[1], g_err / 16 ); - pix1[2] += GifIMax( -pix1[2], b_err / 16 ); - } - } - } + if (quantloc_1 < numPixels) + { + int32_t* pix1 = quantPixels + 4 * quantloc_1; + pix1[0] += GifIMax(-pix1[0], r_err / 16); + pix1[1] += GifIMax(-pix1[1], g_err / 16); + pix1[2] += GifIMax(-pix1[2], b_err / 16); + } + } + } - // Copy the palettized result to the output buffer - for( int ii=0; iir[bestInd]; - outFrame[1] = pPal->g[bestInd]; - outFrame[2] = pPal->b[bestInd]; - outFrame[3] = (uint8_t)bestInd; - } + // Write the resulting color to the output buffer + outFrame[0] = pPal->r[bestInd]; + outFrame[1] = pPal->g[bestInd]; + outFrame[2] = pPal->b[bestInd]; + outFrame[3] = (uint8_t)bestInd; + } - if(lastFrame) lastFrame += 4; - outFrame += 4; - nextFrame += 4; - } + if (lastFrame) lastFrame += 4; + outFrame += 4; + nextFrame += 4; + } } // Simple structure to write out the LZW-compressed portion of the image // one bit at a time struct GifBitStatus { - uint8_t bitIndex; // how many bits in the partial byte written so far - uint8_t byte; // current partial byte + uint8_t bitIndex; // how many bits in the partial byte written so far + uint8_t byte; // current partial byte - uint32_t chunkIndex; - uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file + uint32_t chunkIndex; + uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file }; // insert a single bit -void GifWriteBit( GifBitStatus& stat, uint32_t bit ) +void GifWriteBit(GifBitStatus& stat, uint32_t bit) { - bit = bit & 1; - bit = bit << stat.bitIndex; - stat.byte |= bit; + bit = bit & 1; + bit = bit << stat.bitIndex; + stat.byte |= bit; - ++stat.bitIndex; - if( stat.bitIndex > 7 ) - { - // move the newly-finished byte to the chunk buffer - stat.chunk[stat.chunkIndex++] = stat.byte; - // and start a new byte - stat.bitIndex = 0; - stat.byte = 0; - } + ++stat.bitIndex; + if (stat.bitIndex > 7) + { + // move the newly-finished byte to the chunk buffer + stat.chunk[stat.chunkIndex++] = stat.byte; + // and start a new byte + stat.bitIndex = 0; + stat.byte = 0; + } } // write all bytes so far to the file -void GifWriteChunk( FILE* f, GifBitStatus& stat ) +void GifWriteChunk(FILE* f, GifBitStatus& stat) { - fputc((int)stat.chunkIndex, f); - fwrite(stat.chunk, 1, stat.chunkIndex, f); + fputc((int)stat.chunkIndex, f); + fwrite(stat.chunk, 1, stat.chunkIndex, f); - stat.bitIndex = 0; - stat.byte = 0; - stat.chunkIndex = 0; + stat.bitIndex = 0; + stat.byte = 0; + stat.chunkIndex = 0; } -void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length ) +void GifWriteCode(FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length) { - for( uint32_t ii=0; ii> 1; + for (uint32_t ii = 0; ii < length; ++ii) + { + GifWriteBit(stat, code); + code = code >> 1; - if( stat.chunkIndex == 255 ) - { - GifWriteChunk(f, stat); - } - } + if (stat.chunkIndex == 255) + { + GifWriteChunk(f, stat); + } + } } // The LZW dictionary is a 256-ary tree constructed as the file is encoded, // this is one node struct GifLzwNode { - uint16_t m_next[256]; + uint16_t m_next[256]; }; // write a 256-color (8-bit) image palette to the file -void GifWritePalette( const GifPalette* pPal, FILE* f ) +void GifWritePalette(const GifPalette* pPal, FILE* f) { - fputc(0, f); // first color: transparency - fputc(0, f); - fputc(0, f); + fputc(0, f); // first color: transparency + fputc(0, f); + fputc(0, f); - for(int ii=1; ii<(1 << pPal->bitDepth); ++ii) - { - uint32_t r = pPal->r[ii]; - uint32_t g = pPal->g[ii]; - uint32_t b = pPal->b[ii]; + for (int ii = 1; ii < (1 << pPal->bitDepth); ++ii) + { + uint32_t r = pPal->r[ii]; + uint32_t g = pPal->g[ii]; + uint32_t b = pPal->b[ii]; - fputc((int)b, f); - fputc((int)g, f); - fputc((int)r, f); - } + fputc((int)b, f); + fputc((int)g, f); + fputc((int)r, f); + } } // write the image header, LZW-compress and write out the image -void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uint32_t width, uint32_t height, uint32_t delay, GifPalette* pPal) +void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uint32_t width, uint32_t height, + uint32_t delay, GifPalette* pPal) { - // graphics control extension - fputc(0x21, f); - fputc(0xf9, f); - fputc(0x04, f); - fputc(0x05, f); // leave prev frame in place, this frame has transparency - fputc(delay & 0xff, f); - fputc((delay >> 8) & 0xff, f); - fputc(kGifTransIndex, f); // transparent color index - fputc(0, f); + // graphics control extension + fputc(0x21, f); + fputc(0xf9, f); + fputc(0x04, f); + fputc(0x05, f); // leave prev frame in place, this frame has transparency + fputc(delay & 0xff, f); + fputc((delay >> 8) & 0xff, f); + fputc(kGifTransIndex, f); // transparent color index + fputc(0, f); - fputc(0x2c, f); // image descriptor block + fputc(0x2c, f); // image descriptor block - fputc(left & 0xff, f); // corner of image in canvas space - fputc((left >> 8) & 0xff, f); - fputc(top & 0xff, f); - fputc((top >> 8) & 0xff, f); + fputc(left & 0xff, f); // corner of image in canvas space + fputc((left >> 8) & 0xff, f); + fputc(top & 0xff, f); + fputc((top >> 8) & 0xff, f); - fputc(width & 0xff, f); // width and height of image - fputc((width >> 8) & 0xff, f); - fputc(height & 0xff, f); - fputc((height >> 8) & 0xff, f); + fputc(width & 0xff, f); // width and height of image + fputc((width >> 8) & 0xff, f); + fputc(height & 0xff, f); + fputc((height >> 8) & 0xff, f); - //fputc(0, f); // no local color table, no transparency - //fputc(0x80, f); // no local color table, but transparency + //fputc(0, f); // no local color table, no transparency + //fputc(0x80, f); // no local color table, but transparency - fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries - GifWritePalette(pPal, f); + fputc(0x80 + pPal->bitDepth - 1, f); // local color table present, 2 ^ bitDepth entries + GifWritePalette(pPal, f); - const int minCodeSize = pPal->bitDepth; - const uint32_t clearCode = 1 << pPal->bitDepth; + const int minCodeSize = pPal->bitDepth; + const uint32_t clearCode = 1 << pPal->bitDepth; - fputc(minCodeSize, f); // min code size 8 bits + fputc(minCodeSize, f); // min code size 8 bits - GifLzwNode* codetree = (GifLzwNode*)GIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096); + GifLzwNode* codetree = (GifLzwNode*)GIF_TEMP_MALLOC(sizeof(GifLzwNode) * 4096); - memset(codetree, 0, sizeof(GifLzwNode)*4096); - int32_t curCode = -1; - uint32_t codeSize = (uint32_t)minCodeSize + 1; - uint32_t maxCode = clearCode+1; + memset(codetree, 0, sizeof(GifLzwNode) * 4096); + int32_t curCode = -1; + uint32_t codeSize = (uint32_t)minCodeSize + 1; + uint32_t maxCode = clearCode + 1; - GifBitStatus stat; - stat.byte = 0; - stat.bitIndex = 0; - stat.chunkIndex = 0; + GifBitStatus stat; + stat.byte = 0; + stat.bitIndex = 0; + stat.chunkIndex = 0; - GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary + GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary - for(uint32_t yy=0; yy= (1ul << codeSize) ) - { - // dictionary entry count has broken a size barrier, - // we need more bits for codes - codeSize++; - } - if( maxCode == 4095 ) - { - // the dictionary is full, clear it out and begin anew - GifWriteCode(f, stat, clearCode, codeSize); // clear tree + if (maxCode >= (1ul << codeSize)) + { + // dictionary entry count has broken a size barrier, + // we need more bits for codes + codeSize++; + } + if (maxCode == 4095) + { + // the dictionary is full, clear it out and begin anew + GifWriteCode(f, stat, clearCode, codeSize); // clear tree - memset(codetree, 0, sizeof(GifLzwNode)*4096); - codeSize = (uint32_t)(minCodeSize + 1); - maxCode = clearCode+1; - } + memset(codetree, 0, sizeof(GifLzwNode) * 4096); + codeSize = (uint32_t)(minCodeSize + 1); + maxCode = clearCode + 1; + } - curCode = nextValue; - } - } - } + curCode = nextValue; + } + } + } - // compression footer - GifWriteCode(f, stat, (uint32_t)curCode, codeSize); - GifWriteCode(f, stat, clearCode, codeSize); - GifWriteCode(f, stat, clearCode + 1, (uint32_t)minCodeSize + 1); + // compression footer + GifWriteCode(f, stat, (uint32_t)curCode, codeSize); + GifWriteCode(f, stat, clearCode, codeSize); + GifWriteCode(f, stat, clearCode + 1, (uint32_t)minCodeSize + 1); - // write out the last partial chunk - while( stat.bitIndex ) GifWriteBit(stat, 0); - if( stat.chunkIndex ) GifWriteChunk(f, stat); + // write out the last partial chunk + while (stat.bitIndex) GifWriteBit(stat, 0); + if (stat.chunkIndex) GifWriteChunk(f, stat); - fputc(0, f); // image block terminator + fputc(0, f); // image block terminator - GIF_TEMP_FREE(codetree); + GIF_TEMP_FREE(codetree); } struct GifWriter { - FILE* f; - uint8_t* oldImage; - bool firstFrame; + FILE* f; + uint8_t* oldImage; + bool firstFrame; }; // Creates a gif file. // The input GIFWriter is assumed to be uninitialized. // The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value. -bool GifBegin( GifWriter* writer, const char* filename, uint32_t width, uint32_t height, uint32_t delay, int32_t bitDepth = 8, bool dither = false ) +bool GifBegin(GifWriter* writer, const char* filename, uint32_t width, uint32_t height, uint32_t delay, + int32_t bitDepth = 8, bool dither = false) { - (void)bitDepth; (void)dither; // Mute "Unused argument" warnings + (void)bitDepth; + (void)dither; // Mute "Unused argument" warnings #if defined(_MSC_VER) && (_MSC_VER >= 1400) writer->f = 0; - fopen_s(&writer->f, filename, "wb"); + fopen_s(&writer->f, filename, "wb"); #else writer->f = fopen(filename, "wb"); #endif - if(!writer->f) return false; + if (!writer->f) return false; - writer->firstFrame = true; + writer->firstFrame = true; - // allocate - writer->oldImage = (uint8_t*)GIF_MALLOC(width*height*4); + // allocate + writer->oldImage = (uint8_t*)GIF_MALLOC(width * height * 4); - fputs("GIF89a", writer->f); + fputs("GIF89a", writer->f); - // screen descriptor - fputc(width & 0xff, writer->f); - fputc((width >> 8) & 0xff, writer->f); - fputc(height & 0xff, writer->f); - fputc((height >> 8) & 0xff, writer->f); + // screen descriptor + fputc(width & 0xff, writer->f); + fputc((width >> 8) & 0xff, writer->f); + fputc(height & 0xff, writer->f); + fputc((height >> 8) & 0xff, writer->f); - fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries - fputc(0, writer->f); // background color - fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989) + fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries + fputc(0, writer->f); // background color + fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989) - // now the "global" palette (really just a dummy palette) - // color 0: black - fputc(0, writer->f); - fputc(0, writer->f); - fputc(0, writer->f); - // color 1: also black - fputc(0, writer->f); - fputc(0, writer->f); - fputc(0, writer->f); + // now the "global" palette (really just a dummy palette) + // color 0: black + fputc(0, writer->f); + fputc(0, writer->f); + fputc(0, writer->f); + // color 1: also black + fputc(0, writer->f); + fputc(0, writer->f); + fputc(0, writer->f); - if( delay != 0 ) - { - // animation header - fputc(0x21, writer->f); // extension - fputc(0xff, writer->f); // application specific - fputc(11, writer->f); // length 11 - fputs("NETSCAPE2.0", writer->f); // yes, really - fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data + if (delay != 0) + { + // animation header + fputc(0x21, writer->f); // extension + fputc(0xff, writer->f); // application specific + fputc(11, writer->f); // length 11 + fputs("NETSCAPE2.0", writer->f); // yes, really + fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data - fputc(1, writer->f); // JUST BECAUSE - fputc(0, writer->f); // loop infinitely (byte 0) - fputc(0, writer->f); // loop infinitely (byte 1) + fputc(1, writer->f); // JUST BECAUSE + fputc(0, writer->f); // loop infinitely (byte 0) + fputc(0, writer->f); // loop infinitely (byte 1) - fputc(0, writer->f); // block terminator - } + fputc(0, writer->f); // block terminator + } - return true; + return true; } // Writes out a new frame to a GIF in progress. // The GIFWriter should have been created by GIFBegin. // AFAIK, it is legal to use different bit depths for different frames of an image - // this may be handy to save bits in animations that don't change much. -bool GifWriteFrame( GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8, bool dither = false ) +bool GifWriteFrame(GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, + int bitDepth = 8, bool dither = false) { - if(!writer->f) return false; + if (!writer->f) return false; - const uint8_t* oldImage = writer->firstFrame? NULL : writer->oldImage; - writer->firstFrame = false; + const uint8_t* oldImage = writer->firstFrame ? NULL : writer->oldImage; + writer->firstFrame = false; - GifPalette pal; - GifMakePalette((dither? NULL : oldImage), image, width, height, bitDepth, dither, &pal); + GifPalette pal; + GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal); - if(dither) - GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal); - else - GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal); + if (dither) + GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal); + else + GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal); - GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal); + GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal); - return true; + return true; } // Writes the EOF code, closes the file handle, and frees temp memory used by a GIF. // Many if not most viewers will still display a GIF properly if the EOF code is missing, // but it's still a good idea to write it out. -bool GifEnd( GifWriter* writer ) +bool GifEnd(GifWriter* writer) { - if(!writer->f) return false; + if (!writer->f) return false; - fputc(0x3b, writer->f); // end of file - fclose(writer->f); - GIF_FREE(writer->oldImage); + fputc(0x3b, writer->f); // end of file + fclose(writer->f); + GIF_FREE(writer->oldImage); - writer->f = NULL; - writer->oldImage = NULL; + writer->f = NULL; + writer->oldImage = NULL; - return true; + return true; } #endif diff --git a/Utilities/md5.cpp b/Utilities/md5.cpp index f7c1f7c..9ab38b3 100644 --- a/Utilities/md5.cpp +++ b/Utilities/md5.cpp @@ -90,26 +90,27 @@ * This processes one or more 64-byte data blocks, but does NOT update * the bit counters. There are no alignment requirements. */ -static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) +static const void* body(MD5_CTX* ctx, const void* data, unsigned long size) { - const unsigned char *ptr; + const unsigned char* ptr; MD5_u32plus a, b, c, d; MD5_u32plus saved_a, saved_b, saved_c, saved_d; - ptr = (const unsigned char *)data; + ptr = (const unsigned char*)data; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; - do { + do + { saved_a = a; saved_b = b; saved_c = c; saved_d = d; -/* Round 1 */ + /* Round 1 */ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) STEP(F, c, d, a, b, SET(2), 0x242070db, 17) @@ -127,7 +128,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) -/* Round 2 */ + /* Round 2 */ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) @@ -145,7 +146,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) -/* Round 3 */ + /* Round 3 */ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) @@ -163,7 +164,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) -/* Round 4 */ + /* Round 4 */ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) @@ -187,7 +188,8 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) d += saved_d; ptr += 64; - } while (size -= 64); + } + while (size -= 64); ctx->a = a; ctx->b = b; @@ -197,7 +199,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) return ptr; } -void MD5_Init(MD5_CTX *ctx) +void MD5_Init(MD5_CTX* ctx) { ctx->a = 0x67452301; ctx->b = 0xefcdab89; @@ -208,7 +210,7 @@ void MD5_Init(MD5_CTX *ctx) ctx->hi = 0; } -void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +void MD5_Update(MD5_CTX* ctx, const void* data, unsigned long size) { MD5_u32plus saved_lo; unsigned long used, available; @@ -220,21 +222,24 @@ void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) used = saved_lo & 0x3f; - if (used) { + if (used) + { available = 64 - used; - if (size < available) { + if (size < available) + { memcpy(&ctx->buffer[used], data, size); return; } memcpy(&ctx->buffer[used], data, available); - data = (const unsigned char *)data + available; + data = (const unsigned char*)data + available; size -= available; body(ctx, ctx->buffer, 64); } - if (size >= 64) { + if (size >= 64) + { data = body(ctx, data, size & ~(unsigned long)0x3f); size &= 0x3f; } @@ -242,7 +247,7 @@ void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) memcpy(ctx->buffer, data, size); } -void MD5_Final(unsigned char *result, MD5_CTX *ctx) +void MD5_Final(unsigned char* result, MD5_CTX* ctx) { unsigned long used, available; @@ -252,7 +257,8 @@ void MD5_Final(unsigned char *result, MD5_CTX *ctx) available = 64 - used; - if (available < 8) { + if (available < 8) + { memset(&ctx->buffer[used], 0, available); body(ctx, ctx->buffer, 64); used = 0; @@ -308,8 +314,9 @@ string GetMd5Sum(void* buffer, size_t size) std::stringstream ss; ss << std::hex << std::uppercase << std::setfill('0'); - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) + { ss << std::setw(2) << (int)result[i]; } return ss.str(); -} \ No newline at end of file +} diff --git a/Utilities/md5.h b/Utilities/md5.h index ed006ed..2456a6e 100644 --- a/Utilities/md5.h +++ b/Utilities/md5.h @@ -23,20 +23,21 @@ * See md5.c for more information. */ -#pragma once +#pragma once /* Any 32-bit or wider unsigned integer data type will do */ typedef unsigned int MD5_u32plus; -typedef struct { +typedef struct +{ MD5_u32plus lo, hi; MD5_u32plus a, b, c, d; unsigned char buffer[64]; MD5_u32plus block[16]; } MD5_CTX; -extern void MD5_Init(MD5_CTX *ctx); -extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); -extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); -extern void GetMd5Sum(unsigned char *result, void* buffer, unsigned long size); +extern void MD5_Init(MD5_CTX* ctx); +extern void MD5_Update(MD5_CTX* ctx, const void* data, unsigned long size); +extern void MD5_Final(unsigned char* result, MD5_CTX* ctx); +extern void GetMd5Sum(unsigned char* result, void* buffer, unsigned long size); extern string GetMd5Sum(void* buffer, size_t size); diff --git a/Utilities/miniz.cpp b/Utilities/miniz.cpp index 84ac43e..c43a70a 100644 --- a/Utilities/miniz.cpp +++ b/Utilities/miniz.cpp @@ -159,9 +159,9 @@ #include "stdafx.h" #include "miniz.h" -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; #include #include @@ -173,9 +173,9 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; #define MZ_FREE(x) (void)x, ((void)0) #define MZ_REALLOC(p, x) NULL #else - #define MZ_MALLOC(x) malloc(x) - #define MZ_FREE(x) free(x) - #define MZ_REALLOC(p, x) realloc(p, x) +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) #endif #define MZ_MAX(a,b) (((a)>(b))?(a):(b)) @@ -183,15 +183,15 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) - #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #ifdef _MSC_VER - #define MZ_FORCEINLINE __forceinline +#define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) #else @@ -199,388 +199,457 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; #endif #ifdef __cplusplus - extern "C" { +extern "C" { #endif // ------------------- zlib-style API's -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +mz_ulong mz_adler32(mz_ulong adler, const unsigned char* ptr, size_t buf_len) { - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; - if (!ptr) return MZ_ADLER32_INIT; - while (buf_len) { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - return (s2 << 16) + s1; + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; } // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ -mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8* ptr, size_t buf_len) { - static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; - mz_uint32 crcu32 = (mz_uint32)crc; - if (!ptr) return MZ_CRC32_INIT; - crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } - return ~crcu32; + static const mz_uint32 s_crc32[16] = { + 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) + { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; } -void mz_free(void *p) +void mz_free(void* p) { - MZ_FREE(p); + MZ_FREE(p); } #ifndef MINIZ_NO_ZLIB_APIS -static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } -static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } -static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } - -const char *mz_version(void) +static void* def_alloc_func(void* opaque, size_t items, size_t size) { - return MZ_VERSION; + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} + +static void def_free_func(void* opaque, void* address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} + +static void* def_realloc_func(void* opaque, void* address, size_t items, size_t size) +{ + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); +} + +const char* mz_version(void) +{ + return MZ_VERSION; } int mz_deflateInit(mz_streamp pStream, int level) { - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { - tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + tdefl_compressor* pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - if (!pStream) return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (- + window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; - pStream->data_type = 0; - pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; - pStream->reserved = 0; - pStream->total_in = 0; - pStream->total_out = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - return MZ_MEM_ERROR; + pComp = (tdefl_compressor*)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; - pStream->state = (struct mz_internal_state *)pComp; + pStream->state = (struct mz_internal_state*)pComp; - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { - mz_deflateEnd(pStream); - return MZ_PARAM_ERROR; - } + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } - return MZ_OK; + return MZ_OK; } int mz_deflateReset(mz_streamp pStream) { - if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; - pStream->total_in = pStream->total_out = 0; - tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); - return MZ_OK; + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + return MZ_OK; } int mz_deflate(mz_streamp pStream, int flush) { - size_t in_bytes, out_bytes; - mz_ulong orig_total_in, orig_total_out; - int mz_status = MZ_OK; + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; - if (!pStream->avail_out) return MZ_BUF_ERROR; + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return + MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) - return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; - for ( ; ; ) - { - tdefl_status defl_status; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (; ;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; - defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); + defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, + &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; - if (defl_status < 0) - { - mz_status = MZ_STREAM_ERROR; - break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { - mz_status = MZ_STREAM_END; - break; - } - else if (!pStream->avail_out) - break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) - break; - return MZ_BUF_ERROR; // Can't make forward progress without some input. - } - } - return mz_status; + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; } int mz_deflateEnd(mz_streamp pStream) { - if (!pStream) return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; } mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { - (void)pStream; - // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) - return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +int mz_compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len, + int level) { - int status; - mz_stream stream; - memset(&stream, 0, sizeof(stream)); + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); - // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; - status = mz_deflateInit(&stream, level); - if (status != MZ_OK) return status; + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; - status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_deflateEnd(&stream); - return (status == MZ_OK) ? MZ_BUF_ERROR : status; - } + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } - *pDest_len = stream.total_out; - return mz_deflateEnd(&stream); + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); } -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +int mz_compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len) { - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); } mz_ulong mz_compressBound(mz_ulong source_len) { - return mz_deflateBound(NULL, source_len); + return mz_deflateBound(NULL, source_len); } typedef struct { - tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; - mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; - tinfl_status m_last_status; + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; } inflate_state; int mz_inflateInit2(mz_streamp pStream, int window_bits) { - inflate_state *pDecomp; - if (!pStream) return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + inflate_state* pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; - pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) return MZ_MEM_ERROR; + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; - pStream->state = (struct mz_internal_state *)pDecomp; + pStream->state = (struct mz_internal_state*)pDecomp; - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - pDecomp->m_window_bits = window_bits; + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; - return MZ_OK; + return MZ_OK; } int mz_inflateInit(mz_streamp pStream) { - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } int mz_inflate(mz_streamp pStream, int flush) { - inflate_state* pState; - mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; - size_t in_bytes, out_bytes, orig_avail_in; - tinfl_status status; + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; - if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; - pState = (inflate_state*)pStream->state; - if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; - orig_avail_in = pStream->avail_in; + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; - first_call = pState->m_first_call; pState->m_first_call = 0; - if (pState->m_last_status < 0) return MZ_DATA_ERROR; + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; - if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; - pState->m_has_flushed |= (flush == MZ_FINISH); + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); - if ((flush == MZ_FINISH) && (first_call)) - { - // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. - decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); - pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + if ((flush == MZ_FINISH) && (first_call)) + { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, + &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; - if (status < 0) - return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { - pState->m_last_status = TINFL_STATUS_FAILED; - return MZ_BUF_ERROR; - } - return MZ_STREAM_END; - } - // flush != MZ_FINISH then we must assume there's more input. - if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - if (pState->m_dict_avail) - { - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; - } + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } - for ( ; ; ) - { - in_bytes = pStream->avail_in; - out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + for (; ;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); - pState->m_last_status = status; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, + pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pState->m_dict_avail = (mz_uint)out_bytes; + pState->m_dict_avail = (mz_uint)out_bytes; - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - if (status < 0) - return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). - else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. - else if (flush == MZ_FINISH) - { - // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) - break; - } + if (status < 0) + return MZ_DATA_ERROR; + // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; + // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + else if (flush == MZ_FINISH) + { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } int mz_inflateEnd(mz_streamp pStream) { - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; } -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +int mz_uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len) { - mz_stream stream; - int status; - memset(&stream, 0, sizeof(stream)); + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); - // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; - status = mz_inflateInit(&stream); - if (status != MZ_OK) - return status; + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; - status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; - } - *pDest_len = stream.total_out; + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; - return mz_inflateEnd(&stream); + return mz_inflateEnd(&stream); } -const char *mz_error(int err) +const char* mz_error(int err) { - static struct { int m_err; const char *m_pDesc; } s_error_descs[] = - { - { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, - { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } - }; - mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; - return NULL; + static struct + { + int m_err; + const char* m_pDesc; + } s_error_descs[] = + { + {MZ_OK, ""}, {MZ_STREAM_END, "stream end"}, {MZ_NEED_DICT, "need dictionary"}, {MZ_ERRNO, "file error"}, + {MZ_STREAM_ERROR, "stream error"}, + {MZ_DATA_ERROR, "data error"}, {MZ_MEM_ERROR, "out of memory"}, {MZ_BUF_ERROR, "buf error"}, + {MZ_VERSION_ERROR, "version error"}, {MZ_PARAM_ERROR, "parameter error"} + }; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return + s_error_descs[i].m_pDesc; + return NULL; } #endif //MINIZ_NO_ZLIB_APIS @@ -655,485 +724,769 @@ const char *mz_error(int err) code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_next, size_t* pIn_buf_size, + mz_uint8* pOut_buf_start, mz_uint8* pOut_buf_next, size_t* pOut_buf_size, + const mz_uint32 decomp_flags) { - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; + static const int s_length_base[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, + 0, 0 + }; + static const int s_length_extra[31] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 + }; + static const int s_dist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0 + }; + static const int s_dist_extra[32] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 + }; + static const mz_uint8 s_length_dezigzag[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + static const int s_min_table_sizes[3] = {257, 1, 4}; - tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) + ? (size_t)-1 + : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (unsigned int)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } - } + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > + 32768U) || ((out_buf_size_mask + 1) < (unsigned int)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } - do - { - TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) - { - TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { - TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); - } - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; - for ( ; i <= 255; ++i) *p++ = 9; - for ( ; i <= 279; ++i) *p++ = 7; - for ( ; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } - r->m_table_sizes[2] = 19; - } - for ( ; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for ( ; ; ) - { - mz_uint8 *pSrc; - for ( ; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; mz_uint code_len; + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | + (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8* p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table* pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; + if (!code_size) continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) + { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (; ;) + { + mz_uint8* pSrc; + for (; ;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; #if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } #else if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; - if (counter & 256) - break; + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } + while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; #if !TINFL_USE_64BIT_BITBUF if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - bit_buf >>= code_len; num_bits -= code_len; + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } + while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) break; + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8* pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32*)pOut_buf_cur)[0] = ((const mz_uint32*)pSrc)[0]; + ((mz_uint32*)pOut_buf_cur)[1] = ((const mz_uint32*)pSrc)[1]; + pOut_buf_cur += 8; + } + while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } #endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - TINFL_CR_FINISH + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } + while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } + while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH common_exit: - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf; + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8* ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r-> + m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; } // Higher level helper functions. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +void* tinfl_decompress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags) { - tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; - pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; - } - return pBuf; + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (; ;) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, + new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, + (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; } -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +size_t tinfl_decompress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, + int flags) { - tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, + &out_buf_len, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; } -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, + void* pPut_buf_user, int flags) { - int result = 0; - tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return TINFL_STATUS_FAILED; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); - } - MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; + int result = 0; + tinfl_decompressor decomp; + mz_uint8* pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for (; ;) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, + pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; } // ------------------- Low-level Compression (independent from all decompression API's) // Purposely making these tables static for faster init and thread safety. static const mz_uint16 s_tdefl_len_sym[256] = { - 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, - 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, - 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, - 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, - 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, - 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, - 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, - 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, + 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, + 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 285 +}; static const mz_uint8 s_tdefl_len_extra[256] = { - 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 +}; static const mz_uint8 s_tdefl_small_dist_sym[512] = { - 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, - 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 +}; static const mz_uint8 s_tdefl_small_dist_extra[512] = { - 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7 }; + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 +}; static const mz_uint8 s_tdefl_large_dist_sym[128] = { - 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, - 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; static const mz_uint8 s_tdefl_large_dist_extra[128] = { - 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13 +}; // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. -typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; + static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) { - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32* pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } - for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } - } - return pCur_syms; + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32* pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq* t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; } // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq* A, int n) { - int root, leaf, next, avbl, used, dpth; - if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } - A[0].m_key += A[1].m_key; root = 0; leaf = 2; - for (next=1; next < n-1; next++) - { - if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; - avbl = 1; used = dpth = 0; root = n-2; next = n-1; - while (avbl>0) - { - while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } - while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } - avbl = 2*used; dpth++; used = 0; - } + int root, leaf, next, avbl, used, dpth; + if (n == 0) return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } } // Limits canonical Huffman code table's max code size. enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) + +static void tdefl_huffman_enforce_max_code_size(int* pNum_codes, int code_list_len, int max_code_size) { - int i; mz_uint32 total = 0; if (code_list_len <= 1) return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } - total--; - } + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } } -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +static void tdefl_optimize_huffman_table(tdefl_compressor* d, int table_num, int table_len, int code_size_limit, + int static_table) { - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16* pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } - next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; - code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } } #define TDEFL_PUT_BITS(b, l) do { \ @@ -1164,178 +1517,199 @@ static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ } rle_z_count = 0; } } -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; -static void tdefl_start_dynamic_block(tdefl_compressor *d) +static void tdefl_start_dynamic_block(tdefl_compressor* d) { - int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[ + TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - d->m_huff_count[0][256] = 1; + d->m_huff_count[0][256] = 1; - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break + ; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; - } - else if (++rle_repeat_count == 6) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } + else { TDEFL_RLE_ZERO_CODE_SIZE(); } - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - TDEFL_PUT_BITS(2, 2); + TDEFL_PUT_BITS(2, 2); - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][ + s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } } -static void tdefl_start_static_block(tdefl_compressor *d) +static void tdefl_start_static_block(tdefl_compressor* d) { - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + mz_uint i; + mz_uint8* p = &d->m_huff_code_sizes[0][0]; - for (i = 0; i <= 143; ++i) *p++ = 8; - for ( ; i <= 255; ++i) *p++ = 9; - for ( ; i <= 279; ++i) *p++ = 7; - for ( ; i <= 287; ++i) *p++ = 8; + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; - memset(d->m_huff_code_sizes[1], 5, 32); + memset(d->m_huff_code_sizes[1], 5, 32); - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - TDEFL_PUT_BITS(1, 2); + TDEFL_PUT_BITS(1, 2); } -static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; +static const mz_uint mz_bitmasks[17] = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, + 0x3FFF, 0x7FFF, 0xFFFF +}; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +static mz_bool tdefl_compress_lz_codes(tdefl_compressor* d) { - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; + mz_uint flags; + mz_uint8* pLZ_codes; + mz_uint8* pOutput_buf = d->m_pOutput_buf; + mz_uint8* pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16*)(pLZ_codes + 1); + pLZ_codes += 3; - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - // This sequence coaxes MSVC into using cmov's vs. jmp's. - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; - *(mz_uint64*)pOutput_buf = bit_buffer; - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } + *(mz_uint64*)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } #undef TDEFL_PUT_BITS_FAST - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; - while (bits_in) - { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - return (d->m_pOutput_buf < d->m_pOutput_buf_end); + return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) @@ -1383,153 +1757,196 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +static mz_bool tdefl_compress_block(tdefl_compressor* d, mz_bool static_block) { - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); } -static int tdefl_flush_block(tdefl_compressor *d, int flush) +static int tdefl_flush_block(tdefl_compressor* d, int flush) { - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8* pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d-> + m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8* pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= + TDEFL_OUT_BUF_SIZE)) + ? ((mz_uint8*)d->m_pOut_buf + d->m_out_buf_ofs) + : d->m_output_buf; - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); - } + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; - if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block( + d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. - if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) - { - mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes + ))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } - } - else - { - mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } - } - } + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + } + } - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } - else - { - d->m_out_buf_ofs += n; - } - } + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8*)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8*)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } - return d->m_output_flush_remaining; + return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) + +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor* d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint* pMatch_dist, mz_uint* pMatch_len) { - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for ( ; ; ) - { - for ( ; ; ) - { - if (--num_probes_left == 0) return; - #define TDEFL_PROBE \ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos + , probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (; ;) + { + for (; ;) + { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; - } - if (!dist) break; - q = (const mz_uint16*)(d->m_dict + probe_pos); - if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; - p = s; probe_len = 32; - do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); - if (!probe_len) - { - *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + q = (const mz_uint16*)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; + p = s; + probe_len = 32; + do + { + } + while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) @@ -1562,471 +1979,600 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -static mz_bool tdefl_compress_fast(tdefl_compressor *d) +static mz_bool tdefl_compress_fast(tdefl_compressor* d) { - // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. - mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; - mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; - mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, + total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) - { - const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; - mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); - d->m_src_buf_left -= num_bytes_to_process; - lookahead_size += num_bytes_to_process; + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint) + MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; - while (num_bytes_to_process) - { - mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); - memcpy(d->m_dict + dst_pos, d->m_pSrc, n); - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); - d->m_pSrc += n; - dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; - num_bytes_to_process -= n; - } + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } - dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); - if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; - while (lookahead_size >= 4) - { - mz_uint cur_match_dist, cur_match_len = 1; - mz_uint8 *pCur_dict = d->m_dict + cur_pos; - mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; - mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; - mz_uint probe_pos = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)lookahead_pos; + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8* pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32*)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & + TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; - if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) - { - const mz_uint16 *p = (const mz_uint16 *)pCur_dict; - const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); - mz_uint32 probe_len = 32; - do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); - cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); - if (!probe_len) - cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32*)(d->m_dict + + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16* p = (const mz_uint16*)pCur_dict; + const mz_uint16* q = (const mz_uint16*)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do + { + } + while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) + == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16*)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const + mz_uint8*)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) - { - cur_match_len = 1; - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - else - { - mz_uint32 s0, s1; - cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= + 8U * 1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + MZ_ASSERT( + (cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= + TDEFL_LZ_DICT_SIZE)); - cur_match_dist--; + cur_match_dist--; - pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); - *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; - pLZ_code_buf += 3; - *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16*)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; - s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; - d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; - } - } - else - { - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } - total_lz_bytes += cur_match_len; - lookahead_pos += cur_match_len; - dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; - MZ_ASSERT(lookahead_size >= cur_match_len); - lookahead_size -= cur_match_len; + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; - } - } + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } - while (lookahead_size) - { - mz_uint8 lit = d->m_dict[cur_pos]; + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; - total_lz_bytes++; - *pLZ_code_buf++ = lit; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } - d->m_huff_count[0][lit]++; + d->m_huff_count[0][lit]++; - lookahead_pos++; - dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - lookahead_size--; + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; - } - } - } + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - return MZ_TRUE; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor* d, mz_uint8 lit) { - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } - d->m_huff_count[0][lit]++; + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; } -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor* d, mz_uint match_len, mz_uint match_dist) { - mz_uint32 s0, s1; + mz_uint32 s0, s1; - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - d->m_total_lz_bytes += match_len; + d->m_total_lz_bytes += match_len; - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } - s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; + if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } -static mz_bool tdefl_compress_normal(tdefl_compressor *d) +static mz_bool tdefl_compress_normal(tdefl_compressor* d) { - const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; + const mz_uint8* pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d-> + m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) + & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8* pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[ + (ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; - // Simple lazy/greedy parsing state machine. - len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; - } - } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - } - else - { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; - } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - // Move the lookahead forward by len_to_move bytes. - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); - // Check if it's time to flush the current LZ codes to the internal output buffer. - if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) - { - int n; - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } + // Simple lazy/greedy parsing state machine. + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; + else cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ( + (d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d-> + m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; - return MZ_TRUE; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; } -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor* d) { - if (d->m_pIn_buf_size) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8*)d->m_pIn_buf; + } - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8*)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +tdefl_status tdefl_compress(tdefl_compressor* d, const void* pIn_buf, size_t* pIn_buf_size, void* pOut_buf, + size_t* pOut_buf_size, tdefl_flush flush) { - if (!d) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } + if (!d) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } - d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8*)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; - if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != + TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size + && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && - ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && - ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) - { - if (!tdefl_compress_fast(d)) - return d->m_prev_return_status; - } - else + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8*)pIn_buf, + d->m_pSrc - (const mz_uint8*)pIn_buf); - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } - } + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +tdefl_status tdefl_compress_buffer(tdefl_compressor* d, const void* pIn_buf, size_t in_buf_size, tdefl_flush flush) { - MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags) { - d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) { - MZ_CLEAR_OBJ(d->m_hash); - MZ_CLEAR_OBJ(d->m_dict); - } - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; - d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_dict); + } + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d-> + m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d-> + m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; } -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +tdefl_status tdefl_get_prev_return_status(tdefl_compressor* d) { - return d->m_prev_return_status; + return d->m_prev_return_status; } -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +mz_uint32 tdefl_get_adler32(tdefl_compressor* d) { - return d->m_adler32; + return d->m_adler32; } -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +mz_bool tdefl_compress_mem_to_output(const void* pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, + void* pPut_buf_user, int flags) { - tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; - pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; - succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); - succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); - MZ_FREE(pComp); return succeeded; + tdefl_compressor* pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; } typedef struct { - size_t m_size, m_capacity; - mz_uint8 *m_pBuf; - mz_bool m_expandable; + size_t m_size, m_capacity; + mz_uint8* m_pBuf; + mz_bool m_expandable; } tdefl_output_buffer; -static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +static mz_bool tdefl_output_buffer_putter(const void* pBuf, int len, void* pUser) { - tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; - size_t new_size = p->m_size + len; - if (new_size > p->m_capacity) - { - size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; - do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); - pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; - p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; - } - memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; - return MZ_TRUE; + tdefl_output_buffer* p = (tdefl_output_buffer*)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; + mz_uint8* pNew_buf; + if (!p->m_expandable) return MZ_FALSE; + do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } + while (new_size > new_capacity); + pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; } -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +void* tdefl_compress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags) { - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; - out_buf.m_expandable = MZ_TRUE; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; - *pOut_len = out_buf.m_size; return out_buf.m_pBuf; + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) return MZ_FALSE; + else *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; } -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +size_t tdefl_compress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, + int flags) { - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_buf) return 0; - out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; - return out_buf.m_size; + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8*)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; + return out_buf.m_size; } #ifndef MINIZ_NO_ZLIB_APIS -static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; +static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; // level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ( + (level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; - return comp_flags; + return comp_flags; } #endif //MINIZ_NO_ZLIB_APIS @@ -2038,39 +2584,76 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. // This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +void* tdefl_write_image_to_png_file_in_memory_ex(const void* pImage, int w, int h, int num_chans, size_t* pLen_out, + mz_uint level, mz_bool flip) { - // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. - static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; - if (!pComp) return NULL; - MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } - // write dummy header - for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); - // compress image data - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - // write real header - *pLen_out = out_buf.m_size-41; - { - static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; - mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, - 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0, - (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; - c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); - memcpy(out_buf.m_pBuf, pnghdr, 41); - } - // write footer (IDAT CRC-32, followed by IEND chunk) - if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); - // compute final size of file, grab compressed data buffer and return - *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. + static const mz_uint s_tdefl_png_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; + tdefl_compressor* pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1+bpl)*h); + if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) + { + MZ_FREE(pComp); + return NULL; + } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, + s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) + { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) + { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + // write real header + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; + mz_uint8 pnghdr[41] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0, 0, (mz_uint8)(w >> 8), (mz_uint8)w, 0, 0, (mz_uint8)(h >> 8), (mz_uint8)h, 8, chans[num_chans], 0, 0, 0, 0, + 0, 0, 0, + (mz_uint8)(*pLen_out >> 24), (mz_uint8)(*pLen_out >> 16), (mz_uint8)(*pLen_out >> 8), (mz_uint8)*pLen_out, + 0x49, 0x44, 0x41, 0x54 + }; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) ((mz_uint8*)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) + { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; } -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) + +void* tdefl_write_image_to_png_file_in_memory(const void* pImage, int w, int h, int num_chans, size_t* pLen_out) { - // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) - return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); } #ifdef _MSC_VER @@ -2084,46 +2667,47 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else - #include - #include +#include +#include - #if defined(_MSC_VER) || defined(__MINGW64__) - static FILE *mz_fopen(const char *pFilename, const char *pMode) - { - FILE* pFile = NULL; - #ifdef _MSC_VER - _wfopen_s(&pFile, utf8::utf8::decode(pFilename).c_str(), utf8::utf8::decode(pMode).c_str()); - #else +#if defined(_MSC_VER) || defined(__MINGW64__) +static FILE* mz_fopen(const char* pFilename, const char* pMode) +{ + FILE* pFile = NULL; +#ifdef _MSC_VER + _wfopen_s(&pFile, utf8::utf8::decode(pFilename).c_str(), utf8::utf8::decode(pMode).c_str()); +#else fopen_s(&pFile, pFilename, pMode); - #endif - return pFile; - } - static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) - { - FILE* pFile = NULL; - if (freopen_s(&pFile, pPath, pMode, pStream)) - return NULL; - return pFile; - } - #ifndef MINIZ_NO_TIME +#endif + return pFile; +} + +static FILE* mz_freopen(const char* pPath, const char* pMode, FILE* pStream) +{ + FILE* pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) + return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN mz_fopen - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 _ftelli64 - #define MZ_FSEEK64 _fseeki64 - #define MZ_FILE_STAT_STRUCT _stat - #define MZ_FILE_STAT _stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN mz_freopen - #define MZ_DELETE_FILE remove - #elif defined(__MINGW32__) - #ifndef MINIZ_NO_TIME - #include - #endif +#endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose @@ -2136,10 +2720,10 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove - #elif defined(__TINYC__) - #ifndef MINIZ_NO_TIME +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME #include - #endif +#endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose @@ -2152,10 +2736,10 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove - #elif defined(__GNUC__) && _LARGEFILE64_SOURCE - #ifndef MINIZ_NO_TIME +#elif defined(__GNUC__) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME #include - #endif +#endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen64(f, m) #define MZ_FCLOSE fclose @@ -2168,10 +2752,10 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove - #else - #ifndef MINIZ_NO_TIME +#else +#ifndef MINIZ_NO_TIME #include - #endif +#endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose @@ -2184,7 +2768,7 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove - #endif // #ifdef _MSC_VER +#endif // #ifdef _MSC_VER #endif // #ifdef MINIZ_NO_STDIO #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) @@ -2192,1014 +2776,1155 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, // Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. enum { - // ZIP archive identifiers and record sizes - MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, - MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - // Central directory header record offsets - MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, - MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, - MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, - MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - // Local directory header offsets - MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, - MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, - MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, - // End of central directory offsets - MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, - MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, }; typedef struct { - void *m_p; - size_t m_size, m_capacity; - mz_uint m_element_size; + void* m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; } mz_zip_array; struct mz_zip_internal_state_tag { - mz_zip_array m_central_dir; - mz_zip_array m_central_dir_offsets; - mz_zip_array m_sorted_central_dir_offsets; - MZ_FILE *m_pFile; - void *m_pMem; - size_t m_mem_size; - size_t m_mem_capacity; + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE* m_pFile; + void* m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; }; #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] -static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive* pZip, mz_zip_array* pArray) { - pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); - memset(pArray, 0, sizeof(mz_zip_array)); + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); } -static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive* pZip, mz_zip_array* pArray, size_t min_new_capacity, + mz_uint growing) { - void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; - if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; - pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; - return MZ_TRUE; + void* pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) + { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive* pZip, mz_zip_array* pArray, size_t new_capacity, + mz_uint growing) { - if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } - return MZ_TRUE; + if (new_capacity > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; + } + return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive* pZip, mz_zip_array* pArray, size_t new_size, + mz_uint growing) { - if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } - pArray->m_size = new_size; - return MZ_TRUE; + if (new_size > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive* pZip, mz_zip_array* pArray, size_t n) { - return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } -static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive* pZip, mz_zip_array* pArray, const void* pElements, + size_t n) { - size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; - memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); - return MZ_TRUE; + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; + memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; } #ifndef MINIZ_NO_TIME static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { - struct tm tm; - memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; - tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; - tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; - return mktime(&tm); + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); } -static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +static void mz_zip_time_to_dos_time(time_t time, mz_uint16* pDOS_time, mz_uint16* pDOS_date) { #ifdef _MSC_VER - struct tm tm_struct; - struct tm *tm = &tm_struct; - errno_t err = localtime_s(tm, &time); - if (err) - { - *pDOS_date = 0; *pDOS_time = 0; - return; - } + struct tm tm_struct; + struct tm* tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) + { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } #else struct tm *tm = localtime(&time); #endif - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); - *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } #endif #ifndef MINIZ_NO_STDIO -static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +static mz_bool mz_zip_get_file_modified_time(const char* pFilename, mz_uint16* pDOS_time, mz_uint16* pDOS_date) { #ifdef MINIZ_NO_TIME (void)pFilename; *pDOS_date = *pDOS_time = 0; #else - struct MZ_FILE_STAT_STRUCT file_stat; - // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. - if (MZ_FILE_STAT(pFilename, &file_stat) != 0) - return MZ_FALSE; - mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); + struct MZ_FILE_STAT_STRUCT file_stat; + // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) + return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); #endif // #ifdef MINIZ_NO_TIME - return MZ_TRUE; + return MZ_TRUE; } #ifndef MINIZ_NO_TIME -static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) +static mz_bool mz_zip_set_file_times(const char* pFilename, time_t access_time, time_t modified_time) { - struct utimbuf t; t.actime = access_time; t.modtime = modified_time; - return !utime(pFilename, &t); + struct utimbuf t; + t.actime = access_time; + t.modtime = modified_time; + return !utime(pFilename, &t); } #endif // #ifndef MINIZ_NO_TIME #endif // #ifndef MINIZ_NO_STDIO -static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) +static mz_bool mz_zip_reader_init_internal(mz_zip_archive* pZip, mz_uint32 flags) { - (void)flags; - if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return MZ_FALSE; + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; - pZip->m_zip_mode = MZ_ZIP_MODE_READING; - pZip->m_archive_size = 0; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - return MZ_TRUE; + if (NULL == (pZip->m_pState = (mz_zip_internal_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array* pCentral_dir_array, + const mz_zip_array* pCentral_dir_offsets, mz_uint l_index, + mz_uint r_index) { - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (l_len < r_len) : (l < r); + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8* pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16( + pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); } #define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END // Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) -static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive* pZip) { - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const int size = pZip->m_total_files; - int start = (size - 2) >> 1, end; - while (start >= 0) - { - int child, root = start; - for ( ; ; ) - { - if ((child = (root << 1) + 1) >= size) - break; - child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - start--; - } + mz_zip_internal_state* pState = pZip->m_pState; + const mz_zip_array* pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array* pCentral_dir = &pState->m_central_dir; + mz_uint32* pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) + { + int child, root = start; + for (; ;) + { + if ((child = (root << 1) + 1) >= size) + break; + child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + start--; + } - end = size - 1; - while (end > 0) - { - int child, root = 0; - MZ_SWAP_UINT32(pIndices[end], pIndices[0]); - for ( ; ; ) - { - if ((child = (root << 1) + 1) >= end) - break; - child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - end--; - } + end = size - 1; + while (end > 0) + { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (; ;) + { + if ((child = (root << 1) + 1) >= end) + break; + child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } } -static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive* pZip, mz_uint32 flags) { - mz_uint cdir_size, num_this_disk, cdir_disk_index; - mz_uint64 cdir_ofs; - mz_int64 cur_file_ofs; - const mz_uint8 *p; - mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); - // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. - if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - // Find the end of central directory record by scanning the file from the end towards the beginning. - cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); - for ( ; ; ) - { - int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) - return MZ_FALSE; - for (i = n - 4; i >= 0; --i) - if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) - break; - if (i >= 0) - { - cur_file_ofs += i; - break; - } - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) - return MZ_FALSE; - cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); - } - // Read and verify the end of central directory record. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || - ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) - return MZ_FALSE; + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8* p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8* pBuf = (mz_uint8*)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end towards the beginning. + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (; ;) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + break; + if (i >= 0) + { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)) + ) + return MZ_FALSE; + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16( + pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + return MZ_FALSE; - num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); - cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); - if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) - return MZ_FALSE; + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; - if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; - cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) - return MZ_FALSE; + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return MZ_FALSE; - pZip->m_central_directory_file_ofs = cdir_ofs; + pZip->m_central_directory_file_ofs = cdir_ofs; - if (pZip->m_total_files) - { - mz_uint i, n; + if (pZip->m_total_files) + { + mz_uint i, n; - // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. - if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || - (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) - return MZ_FALSE; + // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; - if (sort_central_dir) - { - if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) - return MZ_FALSE; - } + if (sort_central_dir) + { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + return MZ_FALSE; + } - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) - return MZ_FALSE; + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return MZ_FALSE; - // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). - p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; - for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) - { - mz_uint total_header_size, comp_size, decomp_size, disk_index; - if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) - return MZ_FALSE; - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - if (sort_central_dir) - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) - return MZ_FALSE; - disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); - if ((disk_index != num_this_disk) && (disk_index != 1)) - return MZ_FALSE; - if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) - return MZ_FALSE; - if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) - return MZ_FALSE; - n -= total_header_size; p += total_header_size; - } - } + // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). + p = (const mz_uint8*)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8*) + pZip->m_pState->m_central_dir.m_p); + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) + || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) + return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > + pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return MZ_FALSE; + n -= total_header_size; + p += total_header_size; + } + } - if (sort_central_dir) - mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - return MZ_TRUE; + return MZ_TRUE; } -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) +mz_bool mz_zip_reader_init(mz_zip_archive* pZip, mz_uint64 size, mz_uint32 flags) { - if ((!pZip) || (!pZip->m_pRead)) - return MZ_FALSE; - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - pZip->m_archive_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; + if ((!pZip) || (!pZip->m_pRead)) + return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; } -static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +static size_t mz_zip_mem_read_func(void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n) { - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); - memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); - return s; + mz_zip_archive* pZip = (mz_zip_archive*)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8*)pZip->m_pState->m_pMem + file_ofs, s); + return s; } -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) +mz_bool mz_zip_reader_init_mem(mz_zip_archive* pZip, const void* pMem, size_t size, mz_uint32 flags) { - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - pZip->m_archive_size = size; - pZip->m_pRead = mz_zip_mem_read_func; - pZip->m_pIO_opaque = pZip; + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; #ifdef __cplusplus - pZip->m_pState->m_pMem = const_cast(pMem); + pZip->m_pState->m_pMem = const_cast(pMem); #else pZip->m_pState->m_pMem = (void *)pMem; #endif - pZip->m_pState->m_mem_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; } #ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +static size_t mz_zip_file_read_func(void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n) { - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); + mz_zip_archive* pZip = (mz_zip_archive*)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64( + pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +mz_bool mz_zip_reader_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint32 flags) { - mz_uint64 file_size; - MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); - if (!pFile) - return MZ_FALSE; - if (MZ_FSEEK64(pFile, 0, SEEK_END)) - { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - file_size = MZ_FTELL64(pFile); - if (!mz_zip_reader_init_internal(pZip, flags)) - { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - pZip->m_pRead = mz_zip_file_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pFile = pFile; - pZip->m_archive_size = file_size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; + mz_uint64 file_size; + MZ_FILE* pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +mz_uint mz_zip_reader_get_num_files(mz_zip_archive* pZip) { - return pZip ? pZip->m_total_files : 0; + return pZip ? pZip->m_total_files : 0; } -static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +static MZ_FORCEINLINE const mz_uint8* mz_zip_reader_get_cdh(mz_zip_archive* pZip, mz_uint file_index) { - if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return NULL; - return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive* pZip, mz_uint file_index) { - mz_uint m_bit_flag; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return MZ_FALSE; - m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - return (m_bit_flag & 1); + mz_uint m_bit_flag; + const mz_uint8* p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); } -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive* pZip, mz_uint file_index) { - mz_uint filename_len, external_attr; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return MZ_FALSE; + mz_uint filename_len, external_attr; + const mz_uint8* p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; - // First see if the filename ends with a '/' character. - filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_len) - { - if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') - return MZ_TRUE; - } + // First see if the filename ends with a '/' character. + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } - // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. - // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. - // FIXME: Remove this check? Is it necessary - we already check the filename. - external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - if ((external_attr & 0x10) != 0) - return MZ_TRUE; + // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. + // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. + // FIXME: Remove this check? Is it necessary - we already check the filename. + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & 0x10) != 0) + return MZ_TRUE; - return MZ_FALSE; + return MZ_FALSE; } -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +mz_bool mz_zip_reader_file_stat(mz_zip_archive* pZip, mz_uint file_index, mz_zip_archive_file_stat* pStat) { - mz_uint n; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if ((!p) || (!pStat)) - return MZ_FALSE; + mz_uint n; + const mz_uint8* p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) + return MZ_FALSE; - // Unpack the central directory record. - pStat->m_file_index = file_index; - pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); - pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); - pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); - pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME - pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); + pStat->m_time = mz_zip_dos_to_time_t( + MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif - pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); - pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); - pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - // Copy as much of the filename and comment as possible. - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); - memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; - n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); - pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16( + p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); + pStat->m_comment[n] = '\0'; - return MZ_TRUE; + return MZ_TRUE; } -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +mz_uint mz_zip_reader_get_filename(mz_zip_archive* pZip, mz_uint file_index, char* pFilename, mz_uint filename_buf_size) { - mz_uint n; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_buf_size) - { - n = MZ_MIN(n, filename_buf_size - 1); - memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); - pFilename[n] = '\0'; - } - return n + 1; + mz_uint n; + const mz_uint8* p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + { + if (filename_buf_size) pFilename[0] = '\0'; + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; } -static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char* pA, const char* pB, mz_uint len, mz_uint flags) { - mz_uint i; - if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) - return 0 == memcmp(pA, pB, len); - for (i = 0; i < len; ++i) - if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) - return MZ_FALSE; - return MZ_TRUE; + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; } -static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array* pCentral_dir_array, + const mz_zip_array* pCentral_dir_offsets, mz_uint l_index, + const char* pR, mz_uint r_len) { - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (int)(l_len - r_len) : (l - r); + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); } -static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive* pZip, const char* pFilename) { - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const int size = pZip->m_total_files; - const mz_uint filename_len = (mz_uint)strlen(pFilename); - int l = 0, h = size - 1; - while (l <= h) - { - int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); - if (!comp) - return file_index; - else if (comp < 0) - l = m + 1; - else - h = m - 1; - } - return -1; + mz_zip_internal_state* pState = pZip->m_pState; + const mz_zip_array* pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array* pCentral_dir = &pState->m_central_dir; + mz_uint32* pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) + { + int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare( + pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; } -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +int mz_zip_reader_locate_file(mz_zip_archive* pZip, const char* pName, const char* pComment, mz_uint flags) { - mz_uint file_index; size_t name_len, comment_len; - if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return -1; - if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) - return mz_zip_reader_locate_file_binary_search(pZip, pName); - name_len = strlen(pName); if (name_len > 0xFFFF) return -1; - comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; - for (file_index = 0; file_index < pZip->m_total_files; file_index++) - { - const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); - mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); - const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - if (filename_len < name_len) - continue; - if (comment_len) - { - mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); - const char *pFile_comment = pFilename + filename_len + file_extra_len; - if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) - continue; - } - if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) - { - int ofs = filename_len - 1; - do - { - if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) - break; - } while (--ofs >= 0); - ofs++; - pFilename += ofs; filename_len -= ofs; - } - if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) - return file_index; - } - return -1; + mz_uint file_index; + size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState-> + m_sorted_central_dir_offsets.m_size)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); + if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8* pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, + mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char* pFilename = (const char*)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16( + pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char* pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal( + pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } + while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; } -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, + mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size) { - int status = TINFL_STATUS_DONE; - mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; - mz_zip_archive_file_stat file_stat; - void *pRead_buf; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - tinfl_decompressor inflator; + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, + read_buf_avail; + mz_zip_archive_file_stat file_stat; + void* pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8* pLocal_header = (mz_uint8*)local_header_u32; + tinfl_decompressor inflator; - if ((buf_size) && (!pBuf)) - return MZ_FALSE; + if ((buf_size) && (!pBuf)) + return MZ_FALSE; - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) - if (!file_stat.m_comp_size) - return MZ_TRUE; + // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) + return MZ_TRUE; - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? - if (mz_zip_reader_is_file_a_directory(pZip, file_index)) - return MZ_TRUE; + // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) + return MZ_TRUE; - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return MZ_FALSE; + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; - // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return MZ_FALSE; + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; - // Ensure supplied output buffer is large enough. - needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; - if (buf_size < needed_size) - return MZ_FALSE; + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return MZ_FALSE; - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return MZ_FALSE; + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) - return MZ_FALSE; - return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); - } + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32( + MZ_CRC32_INIT, (const mz_uint8*)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } - // Decompress the file either directly from memory or from a file input buffer. - tinfl_init(&inflator); + // Decompress the file either directly from memory or from a file input buffer. + tinfl_init(&inflator); - if (pZip->m_pState->m_pMem) - { - // Read directly from the archive in memory. - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else if (pUser_read_buf) - { - // Use a user provided read buffer. - if (!user_read_buf_size) - return MZ_FALSE; - pRead_buf = (mz_uint8 *)pUser_read_buf; - read_buf_size = user_read_buf_size; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - else - { - // Temporarily allocate a read buffer. - read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (pZip->m_pState->m_pMem) + { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8*)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + // Use a user provided read buffer. + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8*)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + else + { + // Temporarily allocate a read buffer. + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); #ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #endif - return MZ_FALSE; - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } - do - { - size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - out_buf_ofs += out_buf_size; - } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + do + { + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8*)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8*)pBuf, + (mz_uint8*)pBuf + out_buf_ofs, &out_buf_size, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining + ? TINFL_FLAG_HAS_MORE_INPUT + : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } + while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - if (status == TINFL_STATUS_DONE) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) - status = TINFL_STATUS_FAILED; - } + if (status == TINFL_STATUS_DONE) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32( + MZ_CRC32_INIT, (const mz_uint8*)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } - if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - return status == TINFL_STATUS_DONE; + return status == TINFL_STATUS_DONE; } -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive* pZip, const char* pFilename, void* pBuf, + size_t buf_size, mz_uint flags, void* pUser_read_buf, + size_t user_read_buf_size) { - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, + user_read_buf_size); } -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, + mz_uint flags) { - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); } -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size, + mz_uint flags) { - return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); } -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, size_t* pSize, mz_uint flags) { - mz_uint64 comp_size, uncomp_size, alloc_size; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - void *pBuf; + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8* p = mz_zip_reader_get_cdh(pZip, file_index); + void* pBuf; - if (pSize) - *pSize = 0; - if (!p) - return NULL; + if (pSize) + *pSize = 0; + if (!p) + return NULL; - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; #ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #endif - return NULL; - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) - return NULL; + return NULL; + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; - if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return NULL; - } + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } - if (pSize) *pSize = (size_t)alloc_size; - return pBuf; + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; } -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +void* mz_zip_reader_extract_file_to_heap(mz_zip_archive* pZip, const char* pFilename, size_t* pSize, mz_uint flags) { - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - { - if (pSize) *pSize = 0; - return MZ_FALSE; - } - return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive* pZip, mz_uint file_index, mz_file_write_func pCallback, + void* pOpaque, mz_uint flags) { - int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; - mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; - mz_zip_archive_file_stat file_stat; - void *pRead_buf = NULL; void *pWrite_buf = NULL; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void* pRead_buf = NULL; + void* pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8* pLocal_header = (mz_uint8*)local_header_u32; - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) - if (!file_stat.m_comp_size) - return MZ_TRUE; + // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) + return MZ_TRUE; - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? - if (mz_zip_reader_is_file_a_directory(pZip, file_index)) - return MZ_TRUE; + // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) + return MZ_TRUE; - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return MZ_FALSE; + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; - // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return MZ_FALSE; + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return MZ_FALSE; + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; - // Decompress the file either directly from memory or from a file input buffer. - if (pZip->m_pState->m_pMem) - { - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } + // Decompress the file either directly from memory or from a file input buffer. + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8*)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pState->m_pMem) - { + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) + { #ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #endif - return MZ_FALSE; - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) - status = TINFL_STATUS_FAILED; - else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); - cur_file_ofs += file_stat.m_comp_size; - out_buf_ofs += file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - while (comp_remaining) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8*)pRead_buf, (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } - if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8*)pRead_buf, (size_t)read_buf_avail); - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - out_buf_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - } - } - } - else - { - tinfl_decompressor inflator; - tinfl_init(&inflator); + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); - if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) - status = TINFL_STATUS_FAILED; - else - { - do - { - mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else + { + do + { + mz_uint8* pWrite_buf_cur = (mz_uint8*)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8*)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8*)pWrite_buf, pWrite_buf_cur, &out_buf_size, + comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; - if (out_buf_size) - { - if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) - { - status = TINFL_STATUS_FAILED; - break; - } - file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); - if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) - { - status = TINFL_STATUS_FAILED; - break; - } - } - } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); - } - } + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + status = TINFL_STATUS_FAILED; + break; + } + } + } + while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } - if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) - status = TINFL_STATUS_FAILED; - } + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } - if (!pZip->m_pState->m_pMem) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - if (pWrite_buf) - pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - return status == TINFL_STATUS_DONE; + return status == TINFL_STATUS_DONE; } -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive* pZip, const char* pFilename, + mz_file_write_func pCallback, void* pOpaque, mz_uint flags) { - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); } #ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +static size_t mz_zip_file_write_callback(void* pOpaque, mz_uint64 ofs, const void* pBuf, size_t n) { - (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); + (void)ofs; + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); } -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive* pZip, mz_uint file_index, const char* pDst_filename, + mz_uint flags) { - mz_bool status; - mz_zip_archive_file_stat file_stat; - MZ_FILE *pFile; - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - pFile = MZ_FOPEN(pDst_filename, "wb"); - if (!pFile) - return MZ_FALSE; - status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - if (MZ_FCLOSE(pFile) == EOF) - return MZ_FALSE; + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE* pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return MZ_FALSE; + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) + return MZ_FALSE; #ifndef MINIZ_NO_TIME - if (status) - mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); #endif - return status; + return status; } #endif // #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +mz_bool mz_zip_reader_end(mz_zip_archive* pZip) { - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return MZ_FALSE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING + )) + return MZ_FALSE; - if (pZip->m_pState) - { - mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + if (pZip->m_pState) + { + mz_zip_internal_state* pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } #endif // #ifndef MINIZ_NO_STDIO - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - } - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - return MZ_TRUE; + return MZ_TRUE; } #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive* pZip, const char* pArchive_filename, + const char* pDst_filename, mz_uint flags) { - int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); + int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); } #endif @@ -3207,916 +3932,1002 @@ mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pAr #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } -static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } +static void mz_write_le16(mz_uint8* p, mz_uint16 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} + +static void mz_write_le32(mz_uint8* p, mz_uint32 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} + #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +mz_bool mz_zip_writer_init(mz_zip_archive* pZip, mz_uint64 existing_size) { - if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return MZ_FALSE; + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; - if (pZip->m_file_offset_alignment) - { - // Ensure user specified file offset alignment is a power of 2. - if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) - return MZ_FALSE; - } + if (pZip->m_file_offset_alignment) + { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - pZip->m_archive_size = existing_size; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - return MZ_TRUE; + if (NULL == (pZip->m_pState = (mz_zip_internal_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; } -static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +static size_t mz_zip_heap_write_func(void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n) { - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + mz_zip_archive* pZip = (mz_zip_archive*)pOpaque; + mz_zip_internal_state* pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); #ifdef _MSC_VER - if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) + if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) #else if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) #endif - return 0; - if (new_size > pState->m_mem_capacity) - { - void *pNew_block; - size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; - if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) - return 0; - pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; - } - memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); - pState->m_mem_size = (size_t)new_size; - return n; + return 0; + if (new_size > pState->m_mem_capacity) + { + void* pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8*)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; } -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +mz_bool mz_zip_writer_init_heap(mz_zip_archive* pZip, size_t size_to_reserve_at_beginning, + size_t initial_allocation_size) { - pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pIO_opaque = pZip; - if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) - return MZ_FALSE; - if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) - { - if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - pZip->m_pState->m_mem_capacity = initial_allocation_size; - } - return MZ_TRUE; + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; } #ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +static size_t mz_zip_file_write_func(void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n) { - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); + mz_zip_archive* pZip = (mz_zip_archive*)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64( + pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +mz_bool mz_zip_writer_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint64 size_to_reserve_at_beginning) { - MZ_FILE *pFile; - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pIO_opaque = pZip; - if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) - return MZ_FALSE; - if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - pZip->m_pState->m_pFile = pFile; - if (size_to_reserve_at_beginning) - { - mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); - do - { - size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - cur_ofs += n; size_to_reserve_at_beginning -= n; - } while (size_to_reserve_at_beginning); - } - return MZ_TRUE; + MZ_FILE* pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; + char buf[4096]; + MZ_CLEAR_OBJ(buf); + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } + while (size_to_reserve_at_beginning); + } + return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive* pZip, const char* pFilename) { - mz_zip_internal_state *pState; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return MZ_FALSE; - // No sense in trying to write to an archive that's already at the support max size - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; + mz_zip_internal_state* pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max size + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; - pState = pZip->m_pState; + pState = pZip->m_pState; - if (pState->m_pFile) - { + if (pState->m_pFile) + { #ifdef MINIZ_NO_STDIO pFilename; return MZ_FALSE; #else - // Archive is being read from stdio - try to reopen as writable. - if (pZip->m_pIO_opaque != pZip) - return MZ_FALSE; - if (!pFilename) - return MZ_FALSE; - pZip->m_pWrite = mz_zip_file_write_func; - if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) - { - // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. - mz_zip_reader_end(pZip); - return MZ_FALSE; - } + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + if (!pFilename) + return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } #endif // #ifdef MINIZ_NO_STDIO - } - else if (pState->m_pMem) - { - // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. - if (pZip->m_pIO_opaque != pZip) - return MZ_FALSE; - pState->m_mem_capacity = pState->m_mem_size; - pZip->m_pWrite = mz_zip_heap_write_func; - } - // Archive is being read via a user provided read function - make sure the user has specified a write function too. - else if (!pZip->m_pWrite) - return MZ_FALSE; + } + else if (pState->m_pMem) + { + // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; - // Start writing new files at the archive's current central directory location. - pZip->m_archive_size = pZip->m_central_directory_file_ofs; - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - pZip->m_central_directory_file_ofs = 0; + // Start writing new files at the archive's current central directory location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; - return MZ_TRUE; + return MZ_TRUE; } -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +mz_bool mz_zip_writer_add_mem(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, + mz_uint level_and_flags) { - return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); } typedef struct { - mz_zip_archive *m_pZip; - mz_uint64 m_cur_archive_file_ofs; - mz_uint64 m_comp_size; + mz_zip_archive* m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; } mz_zip_writer_add_state; -static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) +static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void* pUser) { - mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; - if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) - return MZ_FALSE; - pState->m_cur_archive_file_ofs += len; - pState->m_comp_size += len; - return MZ_TRUE; + mz_zip_writer_add_state* pState = (mz_zip_writer_add_state*)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; } -static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive* pZip, mz_uint8* pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date) { - (void)pZip; - memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); - return MZ_TRUE; + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; } -static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive* pZip, mz_uint8* pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { - (void)pZip; - memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); - return MZ_TRUE; + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; } -static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive* pZip, const char* pFilename, mz_uint16 filename_size, + const void* pExtra, mz_uint16 extra_size, const void* pComment, + mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, + mz_uint32 ext_attributes) { - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; - size_t orig_central_dir_size = pState->m_central_dir.m_size; - mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + mz_zip_internal_state* pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - // No zip64 support yet - if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) - return MZ_FALSE; + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; - if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) - return MZ_FALSE; + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, + dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; - if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) - { - // Try to push the central directory array back into its original state. - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } - return MZ_TRUE; + return MZ_TRUE; } -static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +static mz_bool mz_zip_writer_validate_archive_name(const char* pArchive_name) { - // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. - if (*pArchive_name == '/') - return MZ_FALSE; - while (*pArchive_name) - { - if ((*pArchive_name == '\\') || (*pArchive_name == ':')) - return MZ_FALSE; - pArchive_name++; - } - return MZ_TRUE; + // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. + if (*pArchive_name == '/') + return MZ_FALSE; + while (*pArchive_name) + { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) + return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; } -static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive* pZip) { - mz_uint32 n; - if (!pZip->m_file_offset_alignment) - return 0; - n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); - return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); } -static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive* pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { - char buf[4096]; - memset(buf, 0, MZ_MIN(sizeof(buf), n)); - while (n) - { - mz_uint32 s = MZ_MIN(sizeof(buf), n); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) - return MZ_FALSE; - cur_file_ofs += s; n -= s; - } - return MZ_TRUE; + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; } -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, + const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { - mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - tdefl_compressor *pComp = NULL; - mz_bool store_data_uncompressed; - mz_zip_internal_state *pState; + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor* pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state* pState; - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) - return MZ_FALSE; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (! + pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > + MZ_UBER_COMPRESSION)) + return MZ_FALSE; - pState = pZip->m_pState; + pState = pZip->m_pState; - if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) - return MZ_FALSE; - // No zip64 support yet - if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; #ifndef MINIZ_NO_TIME - { - time_t cur_time; time(&cur_time); - mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); - } + { + time_t cur_time; + time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } #endif // #ifndef MINIZ_NO_TIME - archive_name_size = strlen(pArchive_name); - if (archive_name_size > 0xFFFF) - return MZ_FALSE; + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) - return MZ_FALSE; + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; - if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) - { - // Set DOS Subdirectory attribute bit. - ext_attributes |= 0x10; - // Subdirectories cannot contain data. - if ((buf_size) || (uncomp_size)) - return MZ_FALSE; - } + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) + return MZ_FALSE; + } - // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) - if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) - return MZ_FALSE; + // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (! + mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; - if ((!store_data_uncompressed) && (buf_size)) - { - if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) - return MZ_FALSE; - } + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); - MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - cur_archive_file_ofs += archive_name_size; + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; - if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); - uncomp_size = buf_size; - if (uncomp_size <= 3) - { - level = 0; - store_data_uncompressed = MZ_TRUE; - } - } + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } - if (store_data_uncompressed) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } - cur_archive_file_ofs += buf_size; - comp_size = buf_size; + cur_archive_file_ofs += buf_size; + comp_size = buf_size; - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - method = MZ_DEFLATED; - } - else if (buf_size) - { - mz_zip_writer_add_state state; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + method = MZ_DEFLATED; + } + else if (buf_size) + { + mz_zip_writer_add_state state; - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; - if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || - (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; - method = MZ_DEFLATED; - } + method = MZ_DEFLATED; + } - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pComp = NULL; + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; - // no zip64 support yet - if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) - return MZ_FALSE; + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) - return MZ_FALSE; + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return MZ_FALSE; + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof( + local_dir_header)) + return MZ_FALSE; - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) - return MZ_FALSE; + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, + dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; - return MZ_TRUE; + return MZ_TRUE; } #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +mz_bool mz_zip_writer_add_file(mz_zip_archive* pZip, const char* pArchive_name, const char* pSrc_filename, + const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags) { - mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - MZ_FILE *pSrc_file = NULL; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, + comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE* pSrc_file = NULL; - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) + && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; - archive_name_size = strlen(pArchive_name); - if (archive_name_size > 0xFFFF) - return MZ_FALSE; + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) - return MZ_FALSE; + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; - if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) - return MZ_FALSE; - - pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); - if (!pSrc_file) - return MZ_FALSE; - MZ_FSEEK64(pSrc_file, 0, SEEK_END); - uncomp_size = MZ_FTELL64(pSrc_file); - MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; - if (uncomp_size > 0xFFFFFFFF) - { - // No zip64 support yet - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - if (uncomp_size <= 3) - level = 0; + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return MZ_FALSE; + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + if (uncomp_size > 0xFFFFFFFF) + { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) + level = 0; - MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - cur_archive_file_ofs += archive_name_size; + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); - if (uncomp_size) - { - mz_uint64 uncomp_remaining = uncomp_size; - void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); - if (!pRead_buf) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; - if (!level) - { - while (uncomp_remaining) - { - mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); - if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); - uncomp_remaining -= n; - cur_archive_file_ofs += n; - } - comp_size = uncomp_size; - } - else - { - mz_bool result = MZ_FALSE; - mz_zip_writer_add_state state; - tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } + if (uncomp_size) + { + mz_uint64 uncomp_remaining = uncomp_size; + void* pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; + if (!level) + { + while (uncomp_remaining) + { + mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite( + pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8*)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor* pComp = (tdefl_compressor*)pZip-> + m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } - if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; - for ( ; ; ) - { - size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); - tdefl_status status; + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } - if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) - break; + for (; ;) + { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); - uncomp_remaining -= in_buf_size; + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; - status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); - if (status == TDEFL_STATUS_DONE) - { - result = MZ_TRUE; - break; - } - else if (status != TDEFL_STATUS_OKAY) - break; - } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8*)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, + uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + break; + } - if (!result) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } - method = MZ_DEFLATED; - } + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - } + method = MZ_DEFLATED; + } - MZ_FCLOSE(pSrc_file); pSrc_file = NULL; + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } - // no zip64 support yet - if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) - return MZ_FALSE; + MZ_FCLOSE(pSrc_file); + pSrc_file = NULL; - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) - return MZ_FALSE; + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return MZ_FALSE; + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) - return MZ_FALSE; + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof( + local_dir_header)) + return MZ_FALSE; - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, + dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; - return MZ_TRUE; + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* pSource_zip, mz_uint file_index) { - mz_uint n, bit_flags, num_alignment_padding_bytes; - mz_uint64 comp_bytes_remaining, local_dir_header_ofs; - mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - size_t orig_central_dir_size; - mz_zip_internal_state *pState; - void *pBuf; const mz_uint8 *pSrc_central_header; + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8* pLocal_header = (mz_uint8*)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state* pState; + void* pBuf; + const mz_uint8* pSrc_central_header; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return MZ_FALSE; - if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) - return MZ_FALSE; - pState = pZip->m_pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; - cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - cur_dst_file_ofs = pZip->m_archive_size; + cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) - return MZ_FALSE; - cur_dst_file_ofs += num_alignment_padding_bytes; - local_dir_header_ofs = cur_dst_file_ofs; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16( + pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) - return MZ_FALSE; + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)MZ_MAX(sizeof(mz_uint32) * 4, + MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) + return MZ_FALSE; - while (comp_bytes_remaining) - { - n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - cur_src_file_ofs += n; + while (comp_bytes_remaining) + { + n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - cur_dst_file_ofs += n; + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; - comp_bytes_remaining -= n; - } + comp_bytes_remaining -= n; + } - bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); - if (bit_flags & 8) - { - // Copy data descriptor - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof( + mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } - n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } - cur_src_file_ofs += n; - cur_dst_file_ofs += n; - } - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - // no zip64 support yet - if (cur_dst_file_ofs > 0xFFFFFFFF) - return MZ_FALSE; + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) + return MZ_FALSE; - orig_central_dir_size = pState->m_central_dir.m_size; + orig_central_dir_size = pState->m_central_dir.m_size; - memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) - return MZ_FALSE; + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; - n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16( + pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } - if (pState->m_central_dir.m_size > 0xFFFFFFFF) - return MZ_FALSE; - n = (mz_uint32)orig_central_dir_size; - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } + if (pState->m_central_dir.m_size > 0xFFFFFFFF) + return MZ_FALSE; + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } - pZip->m_total_files++; - pZip->m_archive_size = cur_dst_file_ofs; + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; - return MZ_TRUE; + return MZ_TRUE; } -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip) { - mz_zip_internal_state *pState; - mz_uint64 central_dir_ofs, central_dir_size; - mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + mz_zip_internal_state* pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return MZ_FALSE; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; - pState = pZip->m_pState; + pState = pZip->m_pState; - // no zip64 support yet - if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; - central_dir_ofs = 0; - central_dir_size = 0; - if (pZip->m_total_files) - { - // Write central directory - central_dir_ofs = pZip->m_archive_size; - central_dir_size = pState->m_central_dir.m_size; - pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) - return MZ_FALSE; - pZip->m_archive_size += central_dir_size; - } + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != + central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } - // Write end of central directory record - MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) - return MZ_FALSE; + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; #ifndef MINIZ_NO_STDIO - if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) - return MZ_FALSE; + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return MZ_FALSE; #endif // #ifndef MINIZ_NO_STDIO - pZip->m_archive_size += sizeof(hdr); + pZip->m_archive_size += sizeof(hdr); - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; - return MZ_TRUE; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; } -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive* pZip, void** pBuf, size_t* pSize) { - if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) - return MZ_FALSE; - if (pZip->m_pWrite != mz_zip_heap_write_func) - return MZ_FALSE; - if (!mz_zip_writer_finalize_archive(pZip)) - return MZ_FALSE; + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) + return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) + return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; - *pBuf = pZip->m_pState->m_pMem; - *pSize = pZip->m_pState->m_mem_size; - pZip->m_pState->m_pMem = NULL; - pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - return MZ_TRUE; + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; } -mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +mz_bool mz_zip_writer_end(mz_zip_archive* pZip) { - mz_zip_internal_state *pState; - mz_bool status = MZ_TRUE; - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) - return MZ_FALSE; + mz_zip_internal_state* pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != + MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; - pState = pZip->m_pState; - pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } #endif // #ifndef MINIZ_NO_STDIO - if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); - pState->m_pMem = NULL; - } + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - return status; + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; } #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char* pZip_filename, const char* pArchive_name, const void* pBuf, + size_t buf_size, const void* pComment, mz_uint16 comment_size, + mz_uint level_and_flags) { - mz_bool status, created_new_archive = MZ_FALSE; - mz_zip_archive zip_archive; - struct MZ_FILE_STAT_STRUCT file_stat; - MZ_CLEAR_OBJ(zip_archive); - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) - { - // Create a new archive. - if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) - return MZ_FALSE; - created_new_archive = MZ_TRUE; - } - else - { - // Append to an existing archive. - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) - return MZ_FALSE; - if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) - { - mz_zip_reader_end(&zip_archive); - return MZ_FALSE; - } - } - status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); - // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) - if (!mz_zip_writer_finalize_archive(&zip_archive)) - status = MZ_FALSE; - if (!mz_zip_writer_end(&zip_archive)) - status = MZ_FALSE; - if ((!status) && (created_new_archive)) - { - // It's a new archive and something went wrong, so just delete it. - int ignoredStatus = MZ_DELETE_FILE(pZip_filename); - (void)ignoredStatus; - } - return status; + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || (( + level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } + else + { + // Append to an existing archive. + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, + level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) + { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, + level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) + status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) + status = MZ_FALSE; + if ((!status) && (created_new_archive)) + { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; } -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +void* mz_zip_extract_archive_file_to_heap(const char* pZip_filename, const char* pArchive_name, size_t* pSize, + mz_uint flags) { - int file_index; - mz_zip_archive zip_archive; - void *p = NULL; + int file_index; + mz_zip_archive zip_archive; + void* p = NULL; - if (pSize) - *pSize = 0; + if (pSize) + *pSize = 0; - if ((!pZip_filename) || (!pArchive_name)) - return NULL; + if ((!pZip_filename) || (!pArchive_name)) + return NULL; - MZ_CLEAR_OBJ(zip_archive); - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) - return NULL; + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; - if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) - p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); - mz_zip_reader_end(&zip_archive); - return p; + mz_zip_reader_end(&zip_archive); + return p; } #endif // #ifndef MINIZ_NO_STDIO diff --git a/Utilities/miniz.h b/Utilities/miniz.h index a7e550f..7b78c6d 100644 --- a/Utilities/miniz.h +++ b/Utilities/miniz.h @@ -199,7 +199,7 @@ #endif #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) - #include +#include #endif #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) @@ -232,15 +232,15 @@ extern "C" { typedef unsigned long mz_ulong; // mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. -void mz_free(void *p); +void mz_free(void* p); #define MZ_ADLER32_INIT (1) // mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); +mz_ulong mz_adler32(mz_ulong adler, const unsigned char* ptr, size_t buf_len); #define MZ_CRC32_INIT (0) // mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. -mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); +mz_ulong mz_crc32(mz_ulong crc, const unsigned char* ptr, size_t buf_len); // Compression strategies. enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; @@ -252,9 +252,9 @@ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3 // Heap allocation callbacks. // Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); +typedef void*(*mz_alloc_func)(void* opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void* opaque, void* address); +typedef void*(*mz_realloc_func)(void* opaque, void* address, size_t items, size_t size); #define MZ_VERSION "9.1.15" #define MZ_VERNUM 0x91F0 @@ -267,10 +267,30 @@ typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; // Return status codes. MZ_PARAM_ERROR is non-standard. -enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; // Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. -enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; // Window bits #define MZ_DEFAULT_WINDOW_BITS 15 @@ -280,30 +300,30 @@ struct mz_internal_state; // Compression/decompression stream struct. typedef struct mz_stream_s { - const unsigned char *next_in; // pointer to next byte to read - unsigned int avail_in; // number of bytes available at next_in - mz_ulong total_in; // total number of bytes consumed so far + const unsigned char* next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far - unsigned char *next_out; // pointer to next byte to write - unsigned int avail_out; // number of bytes that can be written to next_out - mz_ulong total_out; // total number of bytes produced so far + unsigned char* next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far - char *msg; // error msg (unused) - struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + char* msg; // error msg (unused) + struct mz_internal_state* state; // internal state, allocated by zalloc/zfree - mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) - mz_free_func zfree; // optional heap free function (defaults to free) - void *opaque; // heap alloc function user pointer + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void* opaque; // heap alloc function user pointer - int data_type; // data_type (unused) - mz_ulong adler; // adler32 of the source or uncompressed data - mz_ulong reserved; // not used + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used } mz_stream; -typedef mz_stream *mz_streamp; +typedef mz_stream* mz_streamp; // Returns the version string of miniz.c. -const char *mz_version(void); +const char* mz_version(void); // mz_deflateInit() initializes a compressor with default options: // Parameters: @@ -351,8 +371,9 @@ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); // Single-call compression functions mz_compress() and mz_compress2(): // Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); +int mz_compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len); +int mz_compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len, + int level); // mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). mz_ulong mz_compressBound(mz_ulong source_len); @@ -385,84 +406,84 @@ int mz_inflateEnd(mz_streamp pStream); // Single-call decompression. // Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len); // Returns a string description of the specified error code, or NULL if the error code is invalid. -const char *mz_error(int err); +const char* mz_error(int err); // Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES - typedef unsigned char Byte; - typedef unsigned int uInt; - typedef mz_ulong uLong; - typedef Byte Bytef; - typedef uInt uIntf; - typedef char charf; - typedef int intf; - typedef void *voidpf; - typedef uLong uLongf; - typedef void *voidp; - typedef void *const voidpc; - #define Z_NULL 0 - #define Z_NO_FLUSH MZ_NO_FLUSH - #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH - #define Z_SYNC_FLUSH MZ_SYNC_FLUSH - #define Z_FULL_FLUSH MZ_FULL_FLUSH - #define Z_FINISH MZ_FINISH - #define Z_BLOCK MZ_BLOCK - #define Z_OK MZ_OK - #define Z_STREAM_END MZ_STREAM_END - #define Z_NEED_DICT MZ_NEED_DICT - #define Z_ERRNO MZ_ERRNO - #define Z_STREAM_ERROR MZ_STREAM_ERROR - #define Z_DATA_ERROR MZ_DATA_ERROR - #define Z_MEM_ERROR MZ_MEM_ERROR - #define Z_BUF_ERROR MZ_BUF_ERROR - #define Z_VERSION_ERROR MZ_VERSION_ERROR - #define Z_PARAM_ERROR MZ_PARAM_ERROR - #define Z_NO_COMPRESSION MZ_NO_COMPRESSION - #define Z_BEST_SPEED MZ_BEST_SPEED - #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION - #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION - #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY - #define Z_FILTERED MZ_FILTERED - #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY - #define Z_RLE MZ_RLE - #define Z_FIXED MZ_FIXED - #define Z_DEFLATED MZ_DEFLATED - #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS - #define alloc_func mz_alloc_func - #define free_func mz_free_func - #define internal_state mz_internal_state - #define z_stream mz_stream - #define deflateInit mz_deflateInit - #define deflateInit2 mz_deflateInit2 - #define deflateReset mz_deflateReset - #define deflate mz_deflate - #define deflateEnd mz_deflateEnd - #define deflateBound mz_deflateBound - #define compress mz_compress - #define compress2 mz_compress2 - #define compressBound mz_compressBound - #define inflateInit mz_inflateInit - #define inflateInit2 mz_inflateInit2 - #define inflate mz_inflate - #define inflateEnd mz_inflateEnd - #define uncompress mz_uncompress - #define crc32 mz_crc32 - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 - #define zError mz_error - #define ZLIB_VERSION MZ_VERSION - #define ZLIB_VERNUM MZ_VERNUM - #define ZLIB_VER_MAJOR MZ_VER_MAJOR - #define ZLIB_VER_MINOR MZ_VER_MINOR - #define ZLIB_VER_REVISION MZ_VER_REVISION - #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION - #define zlibVersion mz_version - #define zlib_version mz_version() +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void* voidpf; +typedef uLong uLongf; +typedef void* voidp; +typedef void* const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES #endif // MINIZ_NO_ZLIB_APIS @@ -483,7 +504,7 @@ typedef int mz_bool; // An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. #ifdef _MSC_VER - #define MZ_MACRO_END while (0, 0) +#define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif @@ -494,143 +515,153 @@ typedef int mz_bool; enum { - MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, - MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, - MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 }; typedef struct { - mz_uint32 m_file_index; - mz_uint32 m_central_dir_ofs; - mz_uint16 m_version_made_by; - mz_uint16 m_version_needed; - mz_uint16 m_bit_flag; - mz_uint16 m_method; + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; #ifndef MINIZ_NO_TIME - time_t m_time; + time_t m_time; #endif - mz_uint32 m_crc32; - mz_uint64 m_comp_size; - mz_uint64 m_uncomp_size; - mz_uint16 m_internal_attr; - mz_uint32 m_external_attr; - mz_uint64 m_local_header_ofs; - mz_uint32 m_comment_size; - char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; } mz_zip_archive_file_stat; -typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +typedef size_t (*mz_file_read_func)(void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; typedef enum { - MZ_ZIP_MODE_INVALID = 0, - MZ_ZIP_MODE_READING = 1, - MZ_ZIP_MODE_WRITING = 2, - MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; typedef struct mz_zip_archive_tag { - mz_uint64 m_archive_size; - mz_uint64 m_central_directory_file_ofs; - mz_uint m_total_files; - mz_zip_mode m_zip_mode; + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; - mz_uint m_file_offset_alignment; + mz_uint m_file_offset_alignment; - mz_alloc_func m_pAlloc; - mz_free_func m_pFree; - mz_realloc_func m_pRealloc; - void *m_pAlloc_opaque; + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void* m_pAlloc_opaque; - mz_file_read_func m_pRead; - mz_file_write_func m_pWrite; - void *m_pIO_opaque; - - mz_zip_internal_state *m_pState; + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void* m_pIO_opaque; + mz_zip_internal_state* m_pState; } mz_zip_archive; typedef enum { - MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, - MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 } mz_zip_flags; // ZIP archive reading // Inits a ZIP archive reader. // These functions read and validate the archive's central directory. -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); +mz_bool mz_zip_reader_init(mz_zip_archive* pZip, mz_uint64 size, mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive* pZip, const void* pMem, size_t size, mz_uint32 flags); #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +mz_bool mz_zip_reader_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint32 flags); #endif // Returns the total number of files in the archive. -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); +mz_uint mz_zip_reader_get_num_files(mz_zip_archive* pZip); // Returns detailed information about an archive file entry. -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); +mz_bool mz_zip_reader_file_stat(mz_zip_archive* pZip, mz_uint file_index, mz_zip_archive_file_stat* pStat); // Determines if an archive file entry is a directory entry. -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive* pZip, mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive* pZip, mz_uint file_index); // Retrieves the filename of an archive file entry. // Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); +mz_uint mz_zip_reader_get_filename(mz_zip_archive* pZip, mz_uint file_index, char* pFilename, + mz_uint filename_buf_size); // Attempts to locates a file in the archive's central directory. // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH // Returns -1 if the file cannot be found. -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +int mz_zip_reader_locate_file(mz_zip_archive* pZip, const char* pName, const char* pComment, mz_uint flags); // Extracts a archive file to a memory buffer using no memory allocation. -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, + mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive* pZip, const char* pFilename, void* pBuf, + size_t buf_size, mz_uint flags, void* pUser_read_buf, + size_t user_read_buf_size); // Extracts a archive file to a memory buffer. -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, + mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size, + mz_uint flags); // Extracts a archive file to a dynamically allocated heap buffer. -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); +void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, size_t* pSize, mz_uint flags); +void* mz_zip_reader_extract_file_to_heap(mz_zip_archive* pZip, const char* pFilename, size_t* pSize, mz_uint flags); // Extracts a archive file using a callback function to output the file's data. -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive* pZip, mz_uint file_index, mz_file_write_func pCallback, + void* pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive* pZip, const char* pFilename, + mz_file_write_func pCallback, void* pOpaque, mz_uint flags); #ifndef MINIZ_NO_STDIO // Extracts a archive file to a disk file and sets its last accessed and modified times. // This function only extracts files, not archive directory records. -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive* pZip, mz_uint file_index, const char* pDst_filename, + mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive* pZip, const char* pArchive_filename, + const char* pDst_filename, mz_uint flags); #endif // Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. -mz_bool mz_zip_reader_end(mz_zip_archive *pZip); +mz_bool mz_zip_reader_end(mz_zip_archive* pZip); // ZIP archive writing #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS // Inits a ZIP archive writer. -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +mz_bool mz_zip_writer_init(mz_zip_archive* pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive* pZip, size_t size_to_reserve_at_beginning, + size_t initial_allocation_size); #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +mz_bool mz_zip_writer_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint64 size_to_reserve_at_beginning); #endif // Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. @@ -639,43 +670,50 @@ mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_ // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. // Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before // the archive is finalized the file's central directory will be hosed. -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive* pZip, const char* pFilename); // Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. // To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); +mz_bool mz_zip_writer_add_mem(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, + mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, + const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); #ifndef MINIZ_NO_STDIO // Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_add_file(mz_zip_archive* pZip, const char* pArchive_name, const char* pSrc_filename, + const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags); #endif // Adds a file to an archive by fully cloning the data from another archive. // This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* pSource_zip, mz_uint file_index); // Finalizes the archive by writing the central directory records followed by the end of central directory record. // After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). // An archive must be manually finalized by calling this function for it to be valid. -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive* pZip, void** pBuf, size_t* pSize); // Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. // Note for the archive to be valid, it must have been finalized before ending. -mz_bool mz_zip_writer_end(mz_zip_archive *pZip); +mz_bool mz_zip_writer_end(mz_zip_archive* pZip); // Misc. high-level helper functions: // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char* pZip_filename, const char* pArchive_name, const void* pBuf, + size_t buf_size, const void* pComment, mz_uint16 comment_size, + mz_uint level_and_flags); // Reads a single file from an archive into a heap block. // Returns NULL on failure. -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); +void* mz_zip_extract_archive_file_to_heap(const char* pZip_filename, const char* pArchive_name, size_t* pSize, + mz_uint zip_flags); #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS @@ -690,10 +728,10 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. enum { - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 }; // High level decompression functions: @@ -704,19 +742,22 @@ enum // Function returns a pointer to the decompressed data, or NULL on failure. // *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. // The caller must call mz_free() on the returned block when it's no longer needed. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); +void* tinfl_decompress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags); // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); +size_t tinfl_decompress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, + int flags); // tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. // Returns 1 on success or 0 on failure. -typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser); +int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, + void* pPut_buf_user, int flags); -struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; // Max size of LZ dictionary. #define TINFL_LZ_DICT_SIZE 32768 @@ -724,12 +765,12 @@ struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decom // Return status. typedef enum { - TINFL_STATUS_BAD_PARAM = -3, - TINFL_STATUS_ADLER32_MISMATCH = -2, - TINFL_STATUS_FAILED = -1, - TINFL_STATUS_DONE = 0, - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - TINFL_STATUS_HAS_MORE_OUTPUT = 2 + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; // Initializes the decompressor to its initial state. @@ -738,28 +779,34 @@ typedef enum // Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. // This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); +tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_next, size_t* pIn_buf_size, + mz_uint8* pOut_buf_start, mz_uint8* pOut_buf_next, size_t* pOut_buf_size, + const mz_uint32 decomp_flags); // Internal/private bits follow. enum { - TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; typedef struct { - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; } tinfl_huff_table; #if MINIZ_HAS_64BIT_REGISTERS - #define TINFL_USE_64BIT_BITBUF 1 +#define TINFL_USE_64BIT_BITBUF 1 #endif #if TINFL_USE_64BIT_BITBUF - typedef mz_uint64 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (64) +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) #else typedef mz_uint32 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (32) @@ -767,11 +814,12 @@ typedef struct struct tinfl_decompressor_tag { - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, + m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; // ------------------- Low-level Compression API Definitions @@ -783,7 +831,9 @@ struct tinfl_decompressor_tag // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). enum { - TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF }; // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. @@ -797,14 +847,14 @@ enum // The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). enum { - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; // High level compression functions: @@ -816,11 +866,12 @@ enum // Function returns a pointer to the compressed data, or NULL on failure. // *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. // The caller must free() the returned block when it's no longer needed. -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); +void* tdefl_compress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags); // tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. // Returns 0 on failure. -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); +size_t tdefl_compress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, + int flags); // Compresses an image to a compressed PNG file in memory. // On entry: @@ -832,68 +883,90 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void // Function returns a pointer to the compressed data, or NULL on failure. // *pLen_out will be set to the size of the PNG image file. // The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); +void* tdefl_write_image_to_png_file_in_memory_ex(const void* pImage, int w, int h, int num_chans, size_t* pLen_out, + mz_uint level, mz_bool flip); +void* tdefl_write_image_to_png_file_in_memory(const void* pImage, int w, int h, int num_chans, size_t* pLen_out); // Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser); // tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); +mz_bool tdefl_compress_mem_to_output(const void* pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, + void* pPut_buf_user, int flags); -enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #else -enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; #endif // The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. typedef enum { - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1, + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, } tdefl_status; // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums typedef enum { - TDEFL_NO_FLUSH = 0, - TDEFL_SYNC_FLUSH = 2, - TDEFL_FULL_FLUSH = 3, - TDEFL_FINISH = 4 + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 } tdefl_flush; // tdefl's compression state structure. typedef struct { - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; + tdefl_put_buf_func_ptr m_pPut_buf_func; + void* m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, + m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void* m_pIn_buf; + void* m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8* m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; // Initializes the compressor. @@ -901,17 +974,18 @@ typedef struct // pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. // If pBut_buf_func is NULL the user should always call the tdefl_compress() API. // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); +tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags); // Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); +tdefl_status tdefl_compress(tdefl_compressor* d, const void* pIn_buf, size_t* pIn_buf_size, void* pOut_buf, + size_t* pOut_buf_size, tdefl_flush flush); // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. // tdefl_compress_buffer() always consumes the entire input buffer. -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); +tdefl_status tdefl_compress_buffer(tdefl_compressor* d, const void* pIn_buf, size_t in_buf_size, tdefl_flush flush); -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -mz_uint32 tdefl_get_adler32(tdefl_compressor *d); +tdefl_status tdefl_get_prev_return_status(tdefl_compressor* d); +mz_uint32 tdefl_get_adler32(tdefl_compressor* d); // Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. #ifndef MINIZ_NO_ZLIB_APIS @@ -927,4 +1001,3 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int #endif #endif // MINIZ_HEADER_INCLUDED - diff --git a/Utilities/orfanidis_eq.h b/Utilities/orfanidis_eq.h index 012f448..a7938f3 100644 --- a/Utilities/orfanidis_eq.h +++ b/Utilities/orfanidis_eq.h @@ -6,7 +6,8 @@ using namespace std; -namespace orfanidis_eq { +namespace orfanidis_eq +{ //Eq data types. typedef double eq_single_t; typedef double eq_double_t; @@ -22,18 +23,20 @@ namespace orfanidis_eq { chebyshev2 } filter_type; - static const char *get_eq_text(filter_type type) { - switch(type) { - case none: - return "not initialized"; - case butterworth: - return "butterworth"; - case chebyshev1: - return "chebyshev1"; - case chebyshev2: - return "chebyshev2"; - default: - return "none"; + static const char* get_eq_text(filter_type type) + { + switch (type) + { + case none: + return "not initialized"; + case butterworth: + return "butterworth"; + case chebyshev1: + return "chebyshev1"; + case chebyshev2: + return "chebyshev2"; + default: + return "none"; } } @@ -83,36 +86,44 @@ namespace orfanidis_eq { int db_min_max; std::vector lin_gains; - int lin_gains_index(eq_double_t x) { + int lin_gains_index(eq_double_t x) + { int int_x = (int)x; - if((x >= -db_min_max) && (x < db_min_max - 1)) + if ((x >= -db_min_max) && (x < db_min_max - 1)) return db_min_max + int_x; return db_min_max; } - conversions() {} + conversions() + { + } public: - conversions(int min_max) { + conversions(int min_max) + { db_min_max = min_max; //Update table (vector elements) for fast conversions int step = -min_max; - while(step <= min_max) + while (step <= min_max) lin_gains.push_back(db_2_lin(step++)); } - inline eq_double_t fast_db_2_lin(eq_double_t x) { + inline eq_double_t fast_db_2_lin(eq_double_t x) + { int int_part = (int)x; eq_double_t frac_part = x - int_part; return lin_gains[lin_gains_index(int_part)] * (1 - frac_part) + - (lin_gains[lin_gains_index(int_part + 1)])*frac_part; + (lin_gains[lin_gains_index(int_part + 1)]) * frac_part; } - inline eq_double_t fast_lin_2_db(eq_double_t x) { - if((x >= lin_gains[0]) && (x < lin_gains[lin_gains.size() - 1])) { - for(unsigned int i = 0; i < lin_gains.size() - 2; i++) - if((x >= lin_gains[i]) && (x < lin_gains[i + 1])) { + inline eq_double_t fast_lin_2_db(eq_double_t x) + { + if ((x >= lin_gains[0]) && (x < lin_gains[lin_gains.size() - 1])) + { + for (unsigned int i = 0; i < lin_gains.size() - 2; i++) + if ((x >= lin_gains[i]) && (x < lin_gains[i + 1])) + { int int_part = i - db_min_max; eq_double_t frac_part = x - (int)(x); return int_part + frac_part; @@ -121,20 +132,24 @@ namespace orfanidis_eq { return 0; } - inline static eq_double_t db_2_lin(eq_double_t x) { + inline static eq_double_t db_2_lin(eq_double_t x) + { return pow(10, x / 20); } - inline static eq_double_t lin_2_db(eq_double_t x) { + inline static eq_double_t lin_2_db(eq_double_t x) + { return 20 * log10(x); } - inline static eq_double_t rad_2_hz(eq_double_t x, eq_double_t fs) { - return 2 * pi / x*fs; + inline static eq_double_t rad_2_hz(eq_double_t x, eq_double_t fs) + { + return 2 * pi / x * fs; } - inline static eq_double_t hz_2_rad(eq_double_t x, eq_double_t fs) { - return 2 * pi*x / fs; + inline static eq_double_t hz_2_rad(eq_double_t x, eq_double_t fs) + { + return 2 * pi * x / fs; } }; @@ -150,9 +165,13 @@ namespace orfanidis_eq { eq_double_t max_freq; band_freqs(eq_double_t f1, eq_double_t f0, eq_double_t f2) : - min_freq(f1), center_freq(f0), max_freq(f2) {} + min_freq(f1), center_freq(f0), max_freq(f2) + { + } - ~band_freqs() {} + ~band_freqs() + { + } }; //------------ Frequency grid class ------------ @@ -162,18 +181,26 @@ namespace orfanidis_eq { std::vector freqs_; public: - freq_grid() {} - freq_grid(const freq_grid& fg) { this->freqs_ = fg.freqs_; } - ~freq_grid() {} + freq_grid() + { + } - eq_error_t set_band(eq_double_t fmin, eq_double_t f0, eq_double_t fmax) { + freq_grid(const freq_grid& fg) { this->freqs_ = fg.freqs_; } + + ~freq_grid() + { + } + + eq_error_t set_band(eq_double_t fmin, eq_double_t f0, eq_double_t fmax) + { freqs_.clear(); return add_band(fmin, f0, fmax); } //fc, fmin, fmax - eq_error_t add_band(eq_double_t fmin, eq_double_t f0, eq_double_t fmax) { - if(fmin < f0 && f0 < fmax) + eq_error_t add_band(eq_double_t fmin, eq_double_t f0, eq_double_t fmax) + { + if (fmin < f0 && f0 < fmax) freqs_.push_back(band_freqs(fmin, f0, fmax)); else return invalid_input_data_error; @@ -181,106 +208,121 @@ namespace orfanidis_eq { } //f0, deltaf = fmax - fmin - eq_error_t add_band(eq_double_t f0, eq_double_t df) { - if(f0 >= df / 2) { + eq_error_t add_band(eq_double_t f0, eq_double_t df) + { + if (f0 >= df / 2) + { eq_double_t fmin = f0 - df / 2; eq_double_t fmax = f0 + df / 2; freqs_.push_back(band_freqs(fmin, f0, fmax)); - } else + } + else return invalid_input_data_error; return no_error; } - eq_error_t set_5_bands(eq_double_t center_freq = bands_grid_center_freq_hz) { + eq_error_t set_5_bands(eq_double_t center_freq = bands_grid_center_freq_hz) + { freqs_.clear(); - if(lowest_audio_freq_hz < center_freq && - center_freq < highest_audio_freq_hz) { - + if (lowest_audio_freq_hz < center_freq && + center_freq < highest_audio_freq_hz) + { //Find lowest center frequency in band eq_double_t lowest_center_freq = center_freq; - while(lowest_center_freq > lowest_grid_center_freq_hz) + while (lowest_center_freq > lowest_grid_center_freq_hz) lowest_center_freq /= 4.0; - if(lowest_center_freq < lowest_grid_center_freq_hz) + if (lowest_center_freq < lowest_grid_center_freq_hz) lowest_center_freq *= 4.0; //Calculate freq's eq_double_t f0 = lowest_center_freq; - for(unsigned int i = 0; i < 5; i++) { + for (unsigned int i = 0; i < 5; i++) + { freqs_.push_back(band_freqs(f0 / 2, f0, f0 * 2)); f0 *= 4; } - } else + } + else return invalid_input_data_error; return no_error; } - eq_error_t set_10_bands(eq_double_t center_freq = bands_grid_center_freq_hz) { + eq_error_t set_10_bands(eq_double_t center_freq = bands_grid_center_freq_hz) + { freqs_.clear(); - if(lowest_audio_freq_hz < center_freq && - center_freq < highest_audio_freq_hz) { - + if (lowest_audio_freq_hz < center_freq && + center_freq < highest_audio_freq_hz) + { //Find lowest center frequency in band eq_double_t lowest_center_freq = center_freq; - while(lowest_center_freq > lowest_grid_center_freq_hz) + while (lowest_center_freq > lowest_grid_center_freq_hz) lowest_center_freq /= 2; - if(lowest_center_freq < lowest_grid_center_freq_hz) + if (lowest_center_freq < lowest_grid_center_freq_hz) lowest_center_freq *= 2; //Calculate freq's eq_double_t f0 = lowest_center_freq; - for(unsigned int i = 0; i < 10; i++) { - freqs_.push_back(band_freqs(f0 / pow(2, 0.5), f0, f0*pow(2, 0.5))); + for (unsigned int i = 0; i < 10; i++) + { + freqs_.push_back(band_freqs(f0 / pow(2, 0.5), f0, f0 * pow(2, 0.5))); f0 *= 2; } - } else + } + else return invalid_input_data_error; return no_error; } - eq_error_t set_20_bands(eq_double_t center_freq = bands_grid_center_freq_hz) { + eq_error_t set_20_bands(eq_double_t center_freq = bands_grid_center_freq_hz) + { freqs_.clear(); - if(lowest_audio_freq_hz < center_freq && - center_freq < highest_audio_freq_hz) { - + if (lowest_audio_freq_hz < center_freq && + center_freq < highest_audio_freq_hz) + { //Find lowest center frequency in band eq_double_t lowest_center_freq = center_freq; - while(lowest_center_freq > lowest_audio_freq_hz) + while (lowest_center_freq > lowest_audio_freq_hz) lowest_center_freq /= pow(2, 0.5); - if(lowest_center_freq < lowest_audio_freq_hz) + if (lowest_center_freq < lowest_audio_freq_hz) lowest_center_freq *= pow(2, 0.5); //Calculate freq's eq_double_t f0 = lowest_center_freq; - for(unsigned int i = 0; i < 20; i++) { + for (unsigned int i = 0; i < 20; i++) + { freqs_.push_back(band_freqs(f0 / pow(2, 0.25), - f0, f0*pow(2, 0.25))); + f0, f0 * pow(2, 0.25))); f0 *= pow(2, 0.5); } - } else + } + else return invalid_input_data_error; return no_error; } - eq_error_t set_30_bands(eq_double_t center_freq = bands_grid_center_freq_hz) { + eq_error_t set_30_bands(eq_double_t center_freq = bands_grid_center_freq_hz) + { freqs_.clear(); - if(lowest_audio_freq_hz < center_freq && - center_freq < highest_audio_freq_hz) { - + if (lowest_audio_freq_hz < center_freq && + center_freq < highest_audio_freq_hz) + { //Find lowest center frequency in band eq_double_t lowest_center_freq = center_freq; - while(lowest_center_freq > lowest_audio_freq_hz) + while (lowest_center_freq > lowest_audio_freq_hz) lowest_center_freq /= pow(2.0, 1.0 / 3.0); - if(lowest_center_freq < lowest_audio_freq_hz) + if (lowest_center_freq < lowest_audio_freq_hz) lowest_center_freq *= pow(2.0, 1.0 / 3.0); //Calculate freq's eq_double_t f0 = lowest_center_freq; - for(unsigned int i = 0; i < 30; i++) { + for (unsigned int i = 0; i < 30; i++) + { freqs_.push_back(band_freqs(f0 / pow(2.0, 1.0 / 6.0), - f0, f0*pow(2.0, 1.0 / 6.0))); + f0, f0 * pow(2.0, 1.0 / 6.0))); f0 *= pow(2, 1.0 / 3.0); } - } else + } + else return invalid_input_data_error; return no_error; } @@ -289,33 +331,41 @@ namespace orfanidis_eq { std::vector get_freqs() { return freqs_; } - unsigned int get_freq(unsigned int number) { - if(number < freqs_.size()) + unsigned int get_freq(unsigned int number) + { + if (number < freqs_.size()) return (unsigned int)freqs_[number].center_freq; else return 0; } - unsigned int get_rounded_freq(unsigned int number) { - if(number < freqs_.size()) { + unsigned int get_rounded_freq(unsigned int number) + { + if (number < freqs_.size()) + { unsigned int freq = (unsigned int)freqs_[number].center_freq; - if(freq < 100) + if (freq < 100) return freq; - else if(freq >= 100 && freq < 1000) { + else if (freq >= 100 && freq < 1000) + { unsigned int rest = freq % 10; - if(rest < 5) + if (rest < 5) return freq - rest; else return freq - rest + 10; - } else if(freq >= 1000 && freq < 10000) { + } + else if (freq >= 1000 && freq < 10000) + { unsigned int rest = freq % 100; - if(rest < 50) + if (rest < 50) return freq - rest; else return freq - rest + 100; - } else if(freq >= 10000) { + } + else if (freq >= 10000) + { unsigned int rest = freq % 1000; - if(rest < 500) + if (rest < 500) return freq - rest; else return freq - rest + 1000; @@ -329,24 +379,34 @@ namespace orfanidis_eq { class fo_section { protected: - eq_single_t b0; eq_single_t b1; eq_single_t b2; eq_single_t b3; eq_single_t b4; - eq_single_t a0; eq_single_t a1; eq_single_t a2; eq_single_t a3; eq_single_t a4; + eq_single_t b0; + eq_single_t b1; + eq_single_t b2; + eq_single_t b3; + eq_single_t b4; + eq_single_t a0; + eq_single_t a1; + eq_single_t a2; + eq_single_t a3; + eq_single_t a4; eq_single_t numBuf[fo_section_order]; eq_single_t denumBuf[fo_section_order]; - inline eq_single_t df1_fo_process(eq_single_t in) { + inline eq_single_t df1_fo_process(eq_single_t in) + { eq_single_t out = 0; - out += b0*in; - out += (b1*numBuf[0] - denumBuf[0] * a1); - out += (b2*numBuf[1] - denumBuf[1] * a2); - out += (b3*numBuf[2] - denumBuf[2] * a3); - out += (b4*numBuf[3] - denumBuf[3] * a4); + out += b0 * in; + out += (b1 * numBuf[0] - denumBuf[0] * a1); + out += (b2 * numBuf[1] - denumBuf[1] * a2); + out += (b3 * numBuf[2] - denumBuf[2] * a3); + out += (b4 * numBuf[3] - denumBuf[3] * a4); numBuf[3] = numBuf[2]; numBuf[2] = numBuf[1]; numBuf[1] = numBuf[0]; - if(in < 0.000000000001 && in > -0.000000000001) { + if (in < 0.000000000001 && in > -0.000000000001) + { //Prevent denormalized values (causes extreme performance loss) in = 0; } @@ -355,56 +415,78 @@ namespace orfanidis_eq { denumBuf[3] = denumBuf[2]; denumBuf[2] = denumBuf[1]; denumBuf[1] = denumBuf[0]; - if(out < 0.000000000001 && out > -0.000000000001) { + if (out < 0.000000000001 && out > -0.000000000001) + { //Prevent denormalized values (causes extreme performance loss) out = 0; } *denumBuf = out; - return(out); + return (out); } public: - fo_section() { - b0 = 1; b1 = 0; b2 = 0; b3 = 0; b4 = 0; - a0 = 1; a1 = 0; a2 = 0; a3 = 0; a4 = 0; + fo_section() + { + b0 = 1; + b1 = 0; + b2 = 0; + b3 = 0; + b4 = 0; + a0 = 1; + a1 = 0; + a2 = 0; + a3 = 0; + a4 = 0; - for(unsigned int i = 0; i < fo_section_order; i++) { + for (unsigned int i = 0; i < fo_section_order; i++) + { numBuf[i] = 0; denumBuf[i] = 0; } } - virtual ~fo_section() {} + virtual ~fo_section() + { + } - eq_single_t process(eq_single_t in) { + eq_single_t process(eq_single_t in) + { return df1_fo_process(in); } - virtual fo_section get() { + virtual fo_section get() + { return *this; } }; class butterworth_fo_section : public fo_section { - butterworth_fo_section() {} - butterworth_fo_section(butterworth_fo_section&) {} + butterworth_fo_section() + { + } + + butterworth_fo_section(butterworth_fo_section&) + { + } + public: butterworth_fo_section(eq_double_t beta, - eq_double_t s, eq_double_t g, eq_double_t g0, - eq_double_t D, eq_double_t c0) { - b0 = (g*g*beta*beta + 2 * g*g0*s*beta + g0*g0) / D; - b1 = -4 * c0*(g0*g0 + g*g0*s*beta) / D; - b2 = 2 * (g0*g0*(1 + 2 * c0*c0) - g*g*beta*beta) / D; - b3 = -4 * c0*(g0*g0 - g*g0*s*beta) / D; - b4 = (g*g*beta*beta - 2 * g*g0*s*beta + g0*g0) / D; + eq_double_t s, eq_double_t g, eq_double_t g0, + eq_double_t D, eq_double_t c0) + { + b0 = (g * g * beta * beta + 2 * g * g0 * s * beta + g0 * g0) / D; + b1 = -4 * c0 * (g0 * g0 + g * g0 * s * beta) / D; + b2 = 2 * (g0 * g0 * (1 + 2 * c0 * c0) - g * g * beta * beta) / D; + b3 = -4 * c0 * (g0 * g0 - g * g0 * s * beta) / D; + b4 = (g * g * beta * beta - 2 * g * g0 * s * beta + g0 * g0) / D; a0 = 1; - a1 = -4 * c0*(1 + s*beta) / D; - a2 = 2 * (1 + 2 * c0*c0 - beta*beta) / D; - a3 = -4 * c0*(1 - s*beta) / D; - a4 = (beta*beta - 2 * s*beta + 1) / D; + a1 = -4 * c0 * (1 + s * beta) / D; + a2 = 2 * (1 + 2 * c0 * c0 - beta * beta) / D; + a3 = -4 * c0 * (1 - s * beta) / D; + a4 = (beta * beta - 2 * s * beta + 1) / D; } fo_section get() { return *this; } @@ -412,24 +494,31 @@ namespace orfanidis_eq { class chebyshev_type1_fo_section : public fo_section { - chebyshev_type1_fo_section() {} - chebyshev_type1_fo_section(chebyshev_type1_fo_section&) {} + chebyshev_type1_fo_section() + { + } + + chebyshev_type1_fo_section(chebyshev_type1_fo_section&) + { + } + public: chebyshev_type1_fo_section(eq_double_t a, - eq_double_t c, eq_double_t tetta_b, - eq_double_t g0, eq_double_t s, eq_double_t b, - eq_double_t D, eq_double_t c0) { - b0 = ((b*b + g0*g0*c*c)*tetta_b*tetta_b + 2 * g0*b*s*tetta_b + g0*g0) / D; - b1 = -4 * c0*(g0*g0 + g0*b*s*tetta_b) / D; - b2 = 2 * (g0*g0*(1 + 2 * c0*c0) - (b*b + g0*g0*c*c)*tetta_b*tetta_b) / D; - b3 = -4 * c0*(g0*g0 - g0*b*s*tetta_b) / D; - b4 = ((b*b + g0*g0*c*c)*tetta_b*tetta_b - 2 * g0*b*s*tetta_b + g0*g0) / D; + eq_double_t c, eq_double_t tetta_b, + eq_double_t g0, eq_double_t s, eq_double_t b, + eq_double_t D, eq_double_t c0) + { + b0 = ((b * b + g0 * g0 * c * c) * tetta_b * tetta_b + 2 * g0 * b * s * tetta_b + g0 * g0) / D; + b1 = -4 * c0 * (g0 * g0 + g0 * b * s * tetta_b) / D; + b2 = 2 * (g0 * g0 * (1 + 2 * c0 * c0) - (b * b + g0 * g0 * c * c) * tetta_b * tetta_b) / D; + b3 = -4 * c0 * (g0 * g0 - g0 * b * s * tetta_b) / D; + b4 = ((b * b + g0 * g0 * c * c) * tetta_b * tetta_b - 2 * g0 * b * s * tetta_b + g0 * g0) / D; a0 = 1; - a1 = -4 * c0*(1 + a*s*tetta_b) / D; - a2 = 2 * (1 + 2 * c0*c0 - (a*a + c*c)*tetta_b*tetta_b) / D; - a3 = -4 * c0*(1 - a*s*tetta_b) / D; - a4 = ((a*a + c*c)*tetta_b*tetta_b - 2 * a*s*tetta_b + 1) / D; + a1 = -4 * c0 * (1 + a * s * tetta_b) / D; + a2 = 2 * (1 + 2 * c0 * c0 - (a * a + c * c) * tetta_b * tetta_b) / D; + a3 = -4 * c0 * (1 - a * s * tetta_b) / D; + a4 = ((a * a + c * c) * tetta_b * tetta_b - 2 * a * s * tetta_b + 1) / D; } fo_section get() { return *this; } @@ -437,24 +526,31 @@ namespace orfanidis_eq { class chebyshev_type2_fo_section : public fo_section { - chebyshev_type2_fo_section() {} - chebyshev_type2_fo_section(chebyshev_type2_fo_section&) {} + chebyshev_type2_fo_section() + { + } + + chebyshev_type2_fo_section(chebyshev_type2_fo_section&) + { + } + public: chebyshev_type2_fo_section(eq_double_t a, - eq_double_t c, eq_double_t tetta_b, - eq_double_t g, eq_double_t s, eq_double_t b, - eq_double_t D, eq_double_t c0) { - b0 = (g*g*tetta_b*tetta_b + 2 * g*b*s*tetta_b + b*b + g*g*c*c) / D; - b1 = -4 * c0*(b*b + g*g*c*c + g*b*s*tetta_b) / D; - b2 = 2 * ((b*b + g*g*c*c)*(1 + 2 * c0*c0) - g*g*tetta_b*tetta_b) / D; - b3 = -4 * c0*(b*b + g*g*c*c - g*b*s*tetta_b) / D; - b4 = (g*g*tetta_b*tetta_b - 2 * g*b*s*tetta_b + b*b + g*g*c*c) / D; + eq_double_t c, eq_double_t tetta_b, + eq_double_t g, eq_double_t s, eq_double_t b, + eq_double_t D, eq_double_t c0) + { + b0 = (g * g * tetta_b * tetta_b + 2 * g * b * s * tetta_b + b * b + g * g * c * c) / D; + b1 = -4 * c0 * (b * b + g * g * c * c + g * b * s * tetta_b) / D; + b2 = 2 * ((b * b + g * g * c * c) * (1 + 2 * c0 * c0) - g * g * tetta_b * tetta_b) / D; + b3 = -4 * c0 * (b * b + g * g * c * c - g * b * s * tetta_b) / D; + b4 = (g * g * tetta_b * tetta_b - 2 * g * b * s * tetta_b + b * b + g * g * c * c) / D; a0 = 1; - a1 = -4 * c0*(a*a + c*c + a*s*tetta_b) / D; - a2 = 2 * ((a*a + c*c)*(1 + 2 * c0*c0) - tetta_b*tetta_b) / D; - a3 = -4 * c0*(a*a + c*c - a*s*tetta_b) / D; - a4 = (tetta_b*tetta_b - 2 * a*s*tetta_b + a*a + c*c) / D; + a1 = -4 * c0 * (a * a + c * c + a * s * tetta_b) / D; + a2 = 2 * ((a * a + c * c) * (1 + 2 * c0 * c0) - tetta_b * tetta_b) / D; + a3 = -4 * c0 * (a * a + c * c - a * s * tetta_b) / D; + a4 = (tetta_b * tetta_b - 2 * a * s * tetta_b + a * a + c * c) / D; } fo_section get() { return *this; } @@ -464,8 +560,13 @@ namespace orfanidis_eq { class bp_filter { public: - bp_filter() {} - virtual ~bp_filter() {} + bp_filter() + { + } + + virtual ~bp_filter() + { + } virtual eq_single_t process(eq_single_t in) = 0; }; @@ -475,17 +576,23 @@ namespace orfanidis_eq { private: std::vector sections_; - butterworth_bp_filter() {} + butterworth_bp_filter() + { + } + public: - butterworth_bp_filter(butterworth_bp_filter& f) { + butterworth_bp_filter(butterworth_bp_filter& f) + { this->sections_ = f.sections_; } butterworth_bp_filter(unsigned int N, - eq_double_t w0, eq_double_t wb, - eq_double_t G, eq_double_t Gb, eq_double_t G0) { + eq_double_t w0, eq_double_t wb, + eq_double_t G, eq_double_t Gb, eq_double_t G0) + { //Case if G == 0 : allpass - if(G == 0 && G0 == 0) { + if (G == 0 && G0 == 0) + { sections_.push_back(fo_section()); return; } @@ -499,49 +606,55 @@ namespace orfanidis_eq { Gb = conversions::db_2_lin(Gb); G0 = conversions::db_2_lin(G0); - eq_double_t epsilon = pow(((eq_double_t)(G*G - Gb*Gb)) / - (Gb*Gb - G0*G0), 0.5); + eq_double_t epsilon = pow(((eq_double_t)(G * G - Gb * Gb)) / + (Gb * Gb - G0 * G0), 0.5); eq_double_t g = pow(((eq_double_t)G), 1.0 / ((eq_double_t)N)); eq_double_t g0 = pow(((eq_double_t)G0), 1.0 / ((eq_double_t)N)); - eq_double_t beta = pow(((eq_double_t)epsilon), -1.0 / ((eq_double_t)N))* + eq_double_t beta = pow(((eq_double_t)epsilon), -1.0 / ((eq_double_t)N)) * tan(wb / 2.0); eq_double_t c0 = cos(w0); - if(w0 == 0) c0 = 1; - if(w0 == pi / 2) c0 = 0; - if(w0 == pi) c0 = -1; + if (w0 == 0) c0 = 1; + if (w0 == pi / 2) c0 = 0; + if (w0 == pi) c0 = -1; //Calculate every section - for(unsigned int i = 1; i <= L; i++) { - eq_double_t ui = (2.0*i - 1) / N; - eq_double_t si = sin(pi*ui / 2.0); + for (unsigned int i = 1; i <= L; i++) + { + eq_double_t ui = (2.0 * i - 1) / N; + eq_double_t si = sin(pi * ui / 2.0); - eq_double_t Di = beta*beta + 2 * si*beta + 1; + eq_double_t Di = beta * beta + 2 * si * beta + 1; sections_.push_back - (butterworth_fo_section(beta, si, g, g0, Di, c0)); + (butterworth_fo_section(beta, si, g, g0, Di, c0)); } } - ~butterworth_bp_filter() {} + ~butterworth_bp_filter() + { + } - static eq_single_t compute_bw_gain_db(eq_single_t gain) { + static eq_single_t compute_bw_gain_db(eq_single_t gain) + { eq_single_t bw_gain = 0; - if(gain <= -6) + if (gain <= -6) bw_gain = gain + common_base_gain_db; - else if(gain > -6 && gain < 6) - bw_gain = gain*0.5; - else if(gain >= 6) + else if (gain > -6 && gain < 6) + bw_gain = gain * 0.5; + else if (gain >= 6) bw_gain = gain - common_base_gain_db; return bw_gain; } - virtual eq_single_t process(eq_single_t in) { + virtual eq_single_t process(eq_single_t in) + { eq_single_t p0 = in; eq_single_t p1 = 0; //Process FO sections in serial connection - for(size_t i = 0, len = sections_.size(); i < len; i++) { + for (size_t i = 0, len = sections_.size(); i < len; i++) + { p1 = sections_[i].process(p0); p0 = p1; } @@ -555,13 +668,18 @@ namespace orfanidis_eq { private: std::vector sections_; - chebyshev_type1_bp_filter() {} + chebyshev_type1_bp_filter() + { + } + public: chebyshev_type1_bp_filter(unsigned int N, - eq_double_t w0, eq_double_t wb, - eq_double_t G, eq_double_t Gb, eq_double_t G0) { + eq_double_t w0, eq_double_t wb, + eq_double_t G, eq_double_t Gb, eq_double_t G0) + { //Case if G == 0 : allpass - if(G == 0 && G0 == 0) { + if (G == 0 && G0 == 0) + { sections_.push_back(fo_section()); return; } @@ -575,55 +693,61 @@ namespace orfanidis_eq { Gb = conversions::db_2_lin(Gb); G0 = conversions::db_2_lin(G0); - eq_double_t epsilon = pow((eq_double_t)(G*G - Gb*Gb) / - (Gb*Gb - G0*G0), 0.5); + eq_double_t epsilon = pow((eq_double_t)(G * G - Gb * Gb) / + (Gb * Gb - G0 * G0), 0.5); eq_double_t g0 = pow((eq_double_t)(G0), 1.0 / N); eq_double_t alfa = pow(1.0 / epsilon + pow(1 + pow(epsilon, -2.0), 0.5), 1.0 / N); eq_double_t beta = - pow(G / epsilon + Gb*pow(1 + pow(epsilon, -2.0), 0.5), 1.0 / N); - eq_double_t a = 0.5*(alfa - 1.0 / alfa); - eq_double_t b = 0.5*(beta - g0*g0*(1 / beta)); + pow(G / epsilon + Gb * pow(1 + pow(epsilon, -2.0), 0.5), 1.0 / N); + eq_double_t a = 0.5 * (alfa - 1.0 / alfa); + eq_double_t b = 0.5 * (beta - g0 * g0 * (1 / beta)); eq_double_t tetta_b = tan(wb / 2); eq_double_t c0 = cos(w0); - if(w0 == 0) c0 = 1; - if(w0 == pi / 2) c0 = 0; - if(w0 == pi) c0 = -1; + if (w0 == 0) c0 = 1; + if (w0 == pi / 2) c0 = 0; + if (w0 == pi) c0 = -1; //Calculate every section - for(unsigned int i = 1; i <= L; i++) { - eq_double_t ui = (2.0*i - 1.0) / N; - eq_double_t ci = cos(pi*ui / 2.0); - eq_double_t si = sin(pi*ui / 2.0); + for (unsigned int i = 1; i <= L; i++) + { + eq_double_t ui = (2.0 * i - 1.0) / N; + eq_double_t ci = cos(pi * ui / 2.0); + eq_double_t si = sin(pi * ui / 2.0); - eq_double_t Di = (a*a + ci*ci)*tetta_b*tetta_b + - 2.0*a*si*tetta_b + 1; + eq_double_t Di = (a * a + ci * ci) * tetta_b * tetta_b + + 2.0 * a * si * tetta_b + 1; sections_.push_back( chebyshev_type1_fo_section(a, ci, tetta_b, g0, si, b, Di, c0)); } } - ~chebyshev_type1_bp_filter() {} + ~chebyshev_type1_bp_filter() + { + } - static eq_single_t compute_bw_gain_db(eq_single_t gain) { + static eq_single_t compute_bw_gain_db(eq_single_t gain) + { eq_single_t bw_gain = 0; - if(gain <= -6) + if (gain <= -6) bw_gain = gain + 1; - else if(gain > -6 && gain < 6) - bw_gain = gain*0.9; - else if(gain >= 6) + else if (gain > -6 && gain < 6) + bw_gain = gain * 0.9; + else if (gain >= 6) bw_gain = gain - 1; return bw_gain; } - eq_single_t process(eq_single_t in) { + eq_single_t process(eq_single_t in) + { eq_single_t p0 = in; eq_single_t p1 = 0; //Process FO sections in serial connection - for(size_t i = 0, len = sections_.size(); i < len; i++) { + for (size_t i = 0, len = sections_.size(); i < len; i++) + { p1 = sections_[i].process(p0); p0 = p1; } @@ -637,13 +761,18 @@ namespace orfanidis_eq { private: std::vector sections_; - chebyshev_type2_bp_filter() {} + chebyshev_type2_bp_filter() + { + } + public: chebyshev_type2_bp_filter(unsigned int N, - eq_double_t w0, eq_double_t wb, - eq_double_t G, eq_double_t Gb, eq_double_t G0) { + eq_double_t w0, eq_double_t wb, + eq_double_t G, eq_double_t Gb, eq_double_t G0) + { //Case if G == 0 : allpass - if(G == 0 && G0 == 0) { + if (G == 0 && G0 == 0) + { sections_.push_back(fo_section()); return; } @@ -657,52 +786,58 @@ namespace orfanidis_eq { Gb = conversions::db_2_lin(Gb); G0 = conversions::db_2_lin(G0); - eq_double_t epsilon = pow((eq_double_t)((G*G - Gb*Gb) / - (Gb*Gb - G0*G0)), 0.5); + eq_double_t epsilon = pow((eq_double_t)((G * G - Gb * Gb) / + (Gb * Gb - G0 * G0)), 0.5); eq_double_t g = pow((eq_double_t)(G), 1.0 / N); - eq_double_t eu = pow(epsilon + sqrt(1 + epsilon*epsilon), 1.0 / N); - eq_double_t ew = pow(G0*epsilon + Gb*sqrt(1 + epsilon*epsilon), 1.0 / N); + eq_double_t eu = pow(epsilon + sqrt(1 + epsilon * epsilon), 1.0 / N); + eq_double_t ew = pow(G0 * epsilon + Gb * sqrt(1 + epsilon * epsilon), 1.0 / N); eq_double_t a = (eu - 1.0 / eu) / 2.0; - eq_double_t b = (ew - g*g / ew) / 2.0; + eq_double_t b = (ew - g * g / ew) / 2.0; eq_double_t tetta_b = tan(wb / 2); eq_double_t c0 = cos(w0); - if(w0 == 0) c0 = 1; - if(w0 == pi / 2) c0 = 0; - if(w0 == pi) c0 = -1; + if (w0 == 0) c0 = 1; + if (w0 == pi / 2) c0 = 0; + if (w0 == pi) c0 = -1; //Calculate every section - for(unsigned int i = 1; i <= L; i++) { - eq_double_t ui = (2.0*i - 1.0) / N; - eq_double_t ci = cos(pi*ui / 2.0); - eq_double_t si = sin(pi*ui / 2.0); - eq_double_t Di = tetta_b*tetta_b + 2 * a*si*tetta_b + a*a + ci*ci; + for (unsigned int i = 1; i <= L; i++) + { + eq_double_t ui = (2.0 * i - 1.0) / N; + eq_double_t ci = cos(pi * ui / 2.0); + eq_double_t si = sin(pi * ui / 2.0); + eq_double_t Di = tetta_b * tetta_b + 2 * a * si * tetta_b + a * a + ci * ci; sections_.push_back( chebyshev_type2_fo_section(a, ci, tetta_b, g, si, b, Di, c0)); } } - ~chebyshev_type2_bp_filter() {} + ~chebyshev_type2_bp_filter() + { + } - static eq_single_t compute_bw_gain_db(eq_single_t gain) { + static eq_single_t compute_bw_gain_db(eq_single_t gain) + { eq_single_t bw_gain = 0; - if(gain <= -6) + if (gain <= -6) bw_gain = -common_base_gain_db; - else if(gain > -6 && gain < 6) - bw_gain = gain*0.3; - else if(gain >= 6) + else if (gain > -6 && gain < 6) + bw_gain = gain * 0.3; + else if (gain >= 6) bw_gain = common_base_gain_db; return bw_gain; } - eq_single_t process(eq_single_t in) { + eq_single_t process(eq_single_t in) + { eq_single_t p0 = in; eq_single_t p1 = 0; //Process FO sections in serial connection - for(size_t i = 0, len = sections_.size(); i < len; i++) { + for (size_t i = 0, len = sections_.size(); i < len; i++) + { p1 = sections_[i].process(p0); p0 = p1; } @@ -723,31 +858,40 @@ namespace orfanidis_eq { std::vector filters_; filter_type current_eq_type_; - eq1() :conv_(eq_min_max_gain_db) {} - eq1(const eq1&) :conv_(eq_min_max_gain_db) {} + eq1() : conv_(eq_min_max_gain_db) + { + } - void cleanup_filters_array() { - for(unsigned int j = 0; j < filters_.size(); j++) + eq1(const eq1&) : conv_(eq_min_max_gain_db) + { + } + + void cleanup_filters_array() + { + for (unsigned int j = 0; j < filters_.size(); j++) delete filters_[j]; } public: - eq1(const freq_grid *fg, filter_type eq_t) : conv_(eq_min_max_gain_db) { + eq1(const freq_grid* fg, filter_type eq_t) : conv_(eq_min_max_gain_db) + { sampling_frequency_ = default_sample_freq_hz; freq_grid_ = *fg; current_eq_type_ = eq_t; set_eq(freq_grid_, eq_t); } + ~eq1() { cleanup_filters_array(); } - eq_error_t set_eq(freq_grid& fg, filter_type eqt) { + eq_error_t set_eq(freq_grid& fg, filter_type eqt) + { band_gains_.clear(); cleanup_filters_array(); filters_.clear(); freq_grid_ = fg; - for(unsigned int i = 0; i < freq_grid_.get_number_of_bands(); i++) { - + for (unsigned int i = 0; i < freq_grid_.get_number_of_bands(); i++) + { eq_double_t wb = conversions::hz_2_rad( freq_grid_.get_freqs()[i].max_freq - freq_grid_.get_freqs()[i].min_freq, @@ -757,8 +901,10 @@ namespace orfanidis_eq { freq_grid_.get_freqs()[i].center_freq, sampling_frequency_); - switch(eqt) { - case (butterworth): { + switch (eqt) + { + case (butterworth): + { butterworth_bp_filter* bf = new butterworth_bp_filter( default_eq_band_filters_order, @@ -773,7 +919,8 @@ namespace orfanidis_eq { break; } - case (chebyshev1): { + case (chebyshev1): + { chebyshev_type1_bp_filter* cf1 = new chebyshev_type1_bp_filter( default_eq_band_filters_order, @@ -788,7 +935,8 @@ namespace orfanidis_eq { break; } - case (chebyshev2): { + case (chebyshev2): + { chebyshev_type2_bp_filter* cf2 = new chebyshev_type2_bp_filter( default_eq_band_filters_order, @@ -803,10 +951,9 @@ namespace orfanidis_eq { break; } - default: - current_eq_type_ = none; - return invalid_input_data_error; - + default: + current_eq_type_ = none; + return invalid_input_data_error; } band_gains_.push_back(max_base_gain_db); } @@ -820,7 +967,8 @@ namespace orfanidis_eq { return set_eq(freq_grid_, eqt); } - eq_error_t set_sample_rate(eq_double_t sr) { + eq_error_t set_sample_rate(eq_double_t sr) + { eq_error_t err = no_error; sampling_frequency_ = sr; err = set_eq(freq_grid_, current_eq_type_); @@ -828,8 +976,9 @@ namespace orfanidis_eq { return err; } - eq_error_t change_gains(std::vector band_gains) { - if(band_gains_.size() == band_gains.size()) + eq_error_t change_gains(std::vector band_gains) + { + if (band_gains_.size() == band_gains.size()) band_gains_ = band_gains; else return invalid_input_data_error; @@ -837,9 +986,10 @@ namespace orfanidis_eq { return no_error; } - eq_error_t change_gains_db(std::vector band_gains) { - if(band_gains_.size() == band_gains.size()) - for(unsigned int j = 0; j < get_number_of_bands(); j++) + eq_error_t change_gains_db(std::vector band_gains) + { + if (band_gains_.size() == band_gains.size()) + for (unsigned int j = 0; j < get_number_of_bands(); j++) band_gains_[j] = conv_.fast_db_2_lin(band_gains[j]); else return invalid_input_data_error; @@ -848,8 +998,9 @@ namespace orfanidis_eq { } eq_error_t change_band_gain(unsigned int band_number, - eq_single_t band_gain) { - if(band_number < get_number_of_bands()) + eq_single_t band_gain) + { + if (band_number < get_number_of_bands()) band_gains_[band_number] = band_gain; else return invalid_input_data_error; @@ -857,8 +1008,9 @@ namespace orfanidis_eq { return no_error; } - eq_error_t change_band_gain_db(unsigned int band_number, eq_single_t band_gain) { - if(band_number < get_number_of_bands()) + eq_error_t change_band_gain_db(unsigned int band_number, eq_single_t band_gain) + { + if (band_number < get_number_of_bands()) band_gains_[band_number] = conv_.fast_db_2_lin(band_gain); else return invalid_input_data_error; @@ -866,20 +1018,23 @@ namespace orfanidis_eq { return no_error; } - eq_error_t sbs_process_band(unsigned int band_number, eq_single_t *in, eq_single_t *out) { + eq_error_t sbs_process_band(unsigned int band_number, eq_single_t* in, eq_single_t* out) + { //if(band_number < get_number_of_bands()) - *out = band_gains_[band_number] * + *out = band_gains_[band_number] * filters_[band_number]->process(*in); //else - //return invalid_input_data_error; + //return invalid_input_data_error; return no_error; } - eq_error_t sbs_process(eq_single_t *in, eq_single_t *out) { + eq_error_t sbs_process(eq_single_t* in, eq_single_t* out) + { eq_error_t err = no_error; eq_single_t acc_out = 0; - for(unsigned int j = 0, len = get_number_of_bands(); j < len; j++) { + for (unsigned int j = 0, len = get_number_of_bands(); j < len; j++) + { eq_single_t band_out = 0; err = sbs_process_band(j, in, &band_out); acc_out += band_out; @@ -891,9 +1046,12 @@ namespace orfanidis_eq { filter_type get_eq_type() { return current_eq_type_; } const char* get_string_eq_type() { return get_eq_text(current_eq_type_); } - unsigned int get_number_of_bands() { + + unsigned int get_number_of_bands() + { return freq_grid_.get_number_of_bands(); } + const char* get_version() { return eq_version; } }; @@ -916,25 +1074,29 @@ namespace orfanidis_eq { std::vector filters_; filter_type current_channel_type_; - eq_channel() {} - - unsigned int get_flt_index(eq_single_t gain_db) { - unsigned int number_of_filters = (unsigned int)filters_.size(); - eq_single_t scale_coef = gain_db / min_max_gain_db_; - return (unsigned int)((number_of_filters / 2) + (number_of_filters / 2)*scale_coef); + eq_channel() + { } - void cleanup_filters_array() { - for(unsigned int j = 0; j < filters_.size(); j++) + unsigned int get_flt_index(eq_single_t gain_db) + { + unsigned int number_of_filters = (unsigned int)filters_.size(); + eq_single_t scale_coef = gain_db / min_max_gain_db_; + return (unsigned int)((number_of_filters / 2) + (number_of_filters / 2) * scale_coef); + } + + void cleanup_filters_array() + { + for (unsigned int j = 0; j < filters_.size(); j++) delete filters_[j]; } public: eq_channel(filter_type ft, - eq_single_t fs, eq_single_t f0, eq_single_t fb, - eq_single_t min_max_gain_db = p_eq_min_max_gain_db, - eq_single_t step_db = p_eq_gain_step_db) { - + eq_single_t fs, eq_single_t f0, eq_single_t fb, + eq_single_t min_max_gain_db = p_eq_min_max_gain_db, + eq_single_t step_db = p_eq_gain_step_db) + { //Init data fields sampling_frequency_ = fs; f0_ = f0; @@ -952,16 +1114,18 @@ namespace orfanidis_eq { ~eq_channel() { cleanup_filters_array(); } - eq_error_t set_channel(filter_type ft, eq_single_t fs) { - + eq_error_t set_channel(filter_type ft, eq_single_t fs) + { eq_double_t wb = conversions::hz_2_rad(fb_, sampling_frequency_); eq_double_t w0 = conversions::hz_2_rad(f0_, sampling_frequency_); - for(eq_single_t gain = -min_max_gain_db_; gain <= min_max_gain_db_; - gain += gain_step_db_) { - - switch(ft) { - case (butterworth): { + for (eq_single_t gain = -min_max_gain_db_; gain <= min_max_gain_db_; + gain += gain_step_db_) + { + switch (ft) + { + case (butterworth): + { eq_single_t bw_gain = butterworth_bp_filter::compute_bw_gain_db(gain); @@ -978,7 +1142,8 @@ namespace orfanidis_eq { filters_.push_back(bf); break; } - case (chebyshev1): { + case (chebyshev1): + { eq_single_t bw_gain = chebyshev_type1_bp_filter::compute_bw_gain_db(gain); @@ -995,7 +1160,8 @@ namespace orfanidis_eq { filters_.push_back(cf1); break; } - case (chebyshev2): { + case (chebyshev2): + { eq_single_t bw_gain = chebyshev_type2_bp_filter::compute_bw_gain_db(gain); @@ -1012,7 +1178,8 @@ namespace orfanidis_eq { filters_.push_back(cf2); break; } - default: { + default: + { current_channel_type_ = none; return invalid_input_data_error; } @@ -1026,17 +1193,21 @@ namespace orfanidis_eq { return no_error; } - eq_error_t set_gain_db(eq_single_t db) { - if(db > -min_max_gain_db_ && db < min_max_gain_db_) { + eq_error_t set_gain_db(eq_single_t db) + { + if (db > -min_max_gain_db_ && db < min_max_gain_db_) + { current_gain_db_ = db; current_filter_index_ = get_flt_index(db); - } else + } + else return invalid_input_data_error; return no_error; } - eq_error_t sbs_process(eq_single_t *in, eq_single_t *out) { + eq_error_t sbs_process(eq_single_t* in, eq_single_t* out) + { *out = filters_[current_filter_index_]->process(*in); return no_error; } @@ -1053,30 +1224,35 @@ namespace orfanidis_eq { std::vector channels_; filter_type current_eq_type_; - void cleanup_channels_array() { - for(unsigned int j = 0; j < channels_.size(); j++) + void cleanup_channels_array() + { + for (unsigned int j = 0; j < channels_.size(); j++) delete channels_[j]; } public: - eq2(freq_grid &fg, filter_type eq_t) : conv_(eq_min_max_gain_db) { + eq2(freq_grid& fg, filter_type eq_t) : conv_(eq_min_max_gain_db) + { sampling_frequency_ = default_sample_freq_hz; freq_grid_ = fg; current_eq_type_ = eq_t; set_eq(freq_grid_, eq_t); } + ~eq2() { cleanup_channels_array(); } - eq_error_t set_eq(const freq_grid& fg, filter_type ft) { + eq_error_t set_eq(const freq_grid& fg, filter_type ft) + { cleanup_channels_array(); channels_.clear(); freq_grid_ = fg; - for(unsigned int i = 0; i < freq_grid_.get_number_of_bands(); i++) { + for (unsigned int i = 0; i < freq_grid_.get_number_of_bands(); i++) + { band_freqs b_fres = freq_grid_.get_freqs()[i]; eq_channel* eq_ch = new eq_channel(ft, sampling_frequency_, - b_fres.center_freq, b_fres.max_freq - b_fres.min_freq); + b_fres.center_freq, b_fres.max_freq - b_fres.min_freq); channels_.push_back(eq_ch); channels_[i]->set_gain_db(p_eq_default_gain_db); @@ -1086,20 +1262,23 @@ namespace orfanidis_eq { return no_error; } - eq_error_t set_eq(filter_type ft) { + eq_error_t set_eq(filter_type ft) + { eq_error_t err = set_eq(freq_grid_, ft); return err; } - eq_error_t set_sample_rate(eq_double_t sr) { + eq_error_t set_sample_rate(eq_double_t sr) + { sampling_frequency_ = sr; eq_error_t err = set_eq(current_eq_type_); return err; } - eq_error_t change_gains(std::vector band_gains) { - if(channels_.size() == band_gains.size()) - for(unsigned int j = 0; j < channels_.size(); j++) + eq_error_t change_gains(std::vector band_gains) + { + if (channels_.size() == band_gains.size()) + for (unsigned int j = 0; j < channels_.size(); j++) channels_[j]->set_gain_db(conv_.fast_lin_2_db(band_gains[j])); else return invalid_input_data_error; @@ -1107,9 +1286,10 @@ namespace orfanidis_eq { return no_error; } - eq_error_t change_gains_db(std::vector band_gains) { - if(channels_.size() == band_gains.size()) - for(unsigned int j = 0; j < channels_.size(); j++) + eq_error_t change_gains_db(std::vector band_gains) + { + if (channels_.size() == band_gains.size()) + for (unsigned int j = 0; j < channels_.size(); j++) channels_[j]->set_gain_db(band_gains[j]); else return invalid_input_data_error; @@ -1118,8 +1298,9 @@ namespace orfanidis_eq { } eq_error_t change_band_gain(unsigned int band_number, - eq_single_t band_gain) { - if(band_number < channels_.size()) + eq_single_t band_gain) + { + if (band_number < channels_.size()) channels_[band_number]->set_gain_db(conv_.fast_lin_2_db(band_gain)); else return invalid_input_data_error; @@ -1128,8 +1309,9 @@ namespace orfanidis_eq { } eq_error_t change_band_gain_db(unsigned int band_number, - eq_single_t band_gain) { - if(band_number < channels_.size()) + eq_single_t band_gain) + { + if (band_number < channels_.size()) channels_[band_number]->set_gain_db(band_gain); else return invalid_input_data_error; @@ -1138,8 +1320,9 @@ namespace orfanidis_eq { } eq_error_t sbs_process_band(unsigned int band_number, - eq_single_t *in, eq_single_t *out) { - if(band_number < get_number_of_bands()) + eq_single_t* in, eq_single_t* out) + { + if (band_number < get_number_of_bands()) channels_[band_number]->sbs_process(in, out); else return invalid_input_data_error; @@ -1147,10 +1330,11 @@ namespace orfanidis_eq { return no_error; } - eq_error_t sbs_process(eq_single_t *in, eq_single_t *out) { + eq_error_t sbs_process(eq_single_t* in, eq_single_t* out) + { eq_error_t err = no_error; eq_single_t in_out = *in; - for(unsigned int i = 0; i < get_number_of_bands(); i++) + for (unsigned int i = 0; i < get_number_of_bands(); i++) err = sbs_process_band(i, &in_out, &in_out); *out = in_out; @@ -1160,11 +1344,13 @@ namespace orfanidis_eq { filter_type get_eq_type() { return current_eq_type_; } const char* get_string_eq_type() { return get_eq_text(current_eq_type_); } - unsigned int get_number_of_bands() { + + unsigned int get_number_of_bands() + { return freq_grid_.get_number_of_bands(); } + const char* get_version() { return eq_version; } }; - } //namespace orfanidis_eq #endif //ORFANIDIS_EQ_H_ diff --git a/Utilities/sha1.cpp b/Utilities/sha1.cpp index e794dab..8d3b2b8 100644 --- a/Utilities/sha1.cpp +++ b/Utilities/sha1.cpp @@ -24,11 +24,11 @@ #include -static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ +static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ static const size_t BLOCK_BYTES = BLOCK_INTS * 4; -static void reset(uint32_t digest[], std::string &buffer, uint64_t &transforms) +static void reset(uint32_t digest[], std::string& buffer, uint64_t& transforms) { /* SHA1 initialization constants */ digest[0] = 0x67452301; @@ -59,41 +59,46 @@ static uint32_t blk(const uint32_t block[BLOCK_INTS], const size_t i) * (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y, + uint32_t& z, const size_t i) { - z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); + z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); w = rol(w, 30); } -static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y, + uint32_t& z, const size_t i) { block[i] = blk(block, i); - z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); + z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); w = rol(w, 30); } -static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y, + uint32_t& z, const size_t i) { block[i] = blk(block, i); - z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5); + z += (w ^ x ^ y) + block[i] + 0x6ed9eba1 + rol(v, 5); w = rol(w, 30); } -static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y, + uint32_t& z, const size_t i) { block[i] = blk(block, i); - z += (((w | x)&y) | (w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5); + z += (((w | x) & y) | (w & x)) + block[i] + 0x8f1bbcdc + rol(v, 5); w = rol(w, 30); } -static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y, + uint32_t& z, const size_t i) { block[i] = blk(block, i); - z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5); + z += (w ^ x ^ y) + block[i] + 0xca62c1d6 + rol(v, 5); w = rol(w, 30); } @@ -102,7 +107,7 @@ static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const * Hash a single 512-bit block. This is the core of the algorithm. */ -static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &transforms) +static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t& transforms) { /* Copy digest[] to working vars */ uint32_t a = digest[0]; @@ -205,10 +210,11 @@ static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &t } -static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]) +static void buffer_to_block(const std::string& buffer, uint32_t block[BLOCK_INTS]) { /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ - for(size_t i = 0; i < BLOCK_INTS; i++) { + for (size_t i = 0; i < BLOCK_INTS; i++) + { block[i] = (buffer[4 * i + 3] & 0xff) | (buffer[4 * i + 2] & 0xff) << 8 | (buffer[4 * i + 1] & 0xff) << 16 @@ -223,22 +229,24 @@ SHA1::SHA1() } -void SHA1::update(const std::string &s) +void SHA1::update(const std::string& s) { std::istringstream is(s); update(is); } -void SHA1::update(std::istream &is) +void SHA1::update(std::istream& is) { char sbuf[BLOCK_BYTES]; uint32_t block[BLOCK_INTS]; - while(true) { + while (true) + { is.read(sbuf, BLOCK_BYTES - buffer.size()); buffer.append(sbuf, (size_t)is.gcount()); - if(buffer.size() != BLOCK_BYTES) { + if (buffer.size() != BLOCK_BYTES) + { return; } @@ -256,21 +264,24 @@ void SHA1::update(std::istream &is) std::string SHA1::final() { /* Total number of hashed bits */ - uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; + uint64_t total_bits = (transforms * BLOCK_BYTES + buffer.size()) * 8; /* Padding */ buffer += (char)0x80; size_t orig_size = buffer.size(); - while(buffer.size() < BLOCK_BYTES) { + while (buffer.size() < BLOCK_BYTES) + { buffer += (char)0x00; } uint32_t block[BLOCK_INTS]; buffer_to_block(buffer, block); - if(orig_size > BLOCK_BYTES - 8) { + if (orig_size > BLOCK_BYTES - 8) + { transform(digest, block, transforms); - for(size_t i = 0; i < BLOCK_INTS - 2; i++) { + for (size_t i = 0; i < BLOCK_INTS - 2; i++) + { block[i] = 0; } } @@ -282,7 +293,8 @@ std::string SHA1::final() /* Hex std::string */ std::ostringstream result; - for(size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++) { + for (size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++) + { result << std::uppercase << std::hex << std::setfill('0') << std::setw(8); result << digest[i]; } @@ -293,11 +305,11 @@ std::string SHA1::final() return result.str(); } -std::string SHA1::GetHash(vector &data) +std::string SHA1::GetHash(vector& data) { std::stringstream ss; ss.write((char*)data.data(), data.size()); - + SHA1 checksum; checksum.update(ss); return checksum.final(); @@ -313,14 +325,14 @@ std::string SHA1::GetHash(uint8_t* data, size_t size) return checksum.final(); } -std::string SHA1::GetHash(std::istream &stream) +std::string SHA1::GetHash(std::istream& stream) { SHA1 checksum; checksum.update(stream); return checksum.final(); } -std::string SHA1::GetHash(const std::string &filename) +std::string SHA1::GetHash(const std::string& filename) { std::ifstream stream(filename.c_str(), std::ios::binary); SHA1 checksum; diff --git a/Utilities/sha1.h b/Utilities/sha1.h index d25250c..2a6a8e6 100644 --- a/Utilities/sha1.h +++ b/Utilities/sha1.h @@ -26,17 +26,17 @@ class SHA1 { public: - SHA1(); - void update(const std::string &s); - void update(std::istream &is); - std::string final(); - static std::string GetHash(const std::string &filename); - static std::string GetHash(std::istream &stream); - static std::string GetHash(vector &data); - static std::string GetHash(uint8_t* data, size_t size); + SHA1(); + void update(const std::string& s); + void update(std::istream& is); + std::string final(); + static std::string GetHash(const std::string& filename); + static std::string GetHash(std::istream& stream); + static std::string GetHash(vector& data); + static std::string GetHash(uint8_t* data, size_t size); private: - uint32_t digest[5]; - std::string buffer; - uint64_t transforms; + uint32_t digest[5]; + std::string buffer; + uint64_t transforms; }; diff --git a/Utilities/snes_ntsc.cpp b/Utilities/snes_ntsc.cpp index 85ff666..be0218c 100644 --- a/Utilities/snes_ntsc.cpp +++ b/Utilities/snes_ntsc.cpp @@ -14,10 +14,10 @@ details. You should have received a copy of the GNU Lesser General Public License along with this module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 }; -snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; -snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 }; -snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_monochrome = {0, -1, 0, 0, .2, 0, .2, -.2, -.2, -1, 1, 0, 0}; +snes_ntsc_setup_t const snes_ntsc_composite = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; +snes_ntsc_setup_t const snes_ntsc_svideo = {0, 0, 0, 0, .2, 0, .2, -1, -1, 0, 1, 0, 0}; +snes_ntsc_setup_t const snes_ntsc_rgb = {0, 0, 0, 0, .2, 0, .7, -1, -1, -1, 1, 0, 0}; #define alignment_count 3 #define burst_count 3 @@ -34,62 +34,62 @@ snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1 #include "snes_ntsc_impl.h" /* 3 input pixels -> 8 composite samples */ -pixel_info_t const snes_ntsc_pixels [alignment_count] = { - { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, - { PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } }, - { PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } }, +pixel_info_t const snes_ntsc_pixels[alignment_count] = { + {PIXEL_OFFSET(-4, -9), {1, 1, .6667f, 0}}, + {PIXEL_OFFSET(-2, -7), {.3333f, 1, 1, .3333f}}, + {PIXEL_OFFSET(0, -5), {0, .6667f, 1, 1}}, }; -static void merge_kernel_fields( snes_ntsc_rgb_t* io ) +static void merge_kernel_fields(snes_ntsc_rgb_t* io) { int n; - for ( n = burst_size; n; --n ) + for (n = burst_size; n; --n) { - snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias; - snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias; - snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias; + snes_ntsc_rgb_t p0 = io[burst_size * 0] + rgb_bias; + snes_ntsc_rgb_t p1 = io[burst_size * 1] + rgb_bias; + snes_ntsc_rgb_t p2 = io[burst_size * 2] + rgb_bias; /* merge colors without losing precision */ - io [burst_size * 0] = - ((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; - io [burst_size * 1] = - ((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; - io [burst_size * 2] = - ((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io[burst_size * 0] = + ((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io[burst_size * 1] = + ((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io[burst_size * 2] = + ((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; ++io; } } -static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ) +static void correct_errors(snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out) { int n; - for ( n = burst_count; n; --n ) + for (n = burst_count; n; --n) { unsigned i; - for ( i = 0; i < rgb_kernel_size / 2; i++ ) + for (i = 0; i < rgb_kernel_size / 2; i++) { snes_ntsc_rgb_t error = color - - out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - - out [i + 7] - out [i + 5 +14] - out [i + 3 +28]; - DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 ); + out[i] - out[(i + 12) % 14 + 14] - out[(i + 10) % 14 + 28] - + out[i + 7] - out[i + 5 + 14] - out[i + 3 + 28]; + DISTRIBUTE_ERROR(i+3+28, i+5+14, i+7); } out += alignment_count * rgb_kernel_size; } } -void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ) +void snes_ntsc_init(snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup) { int merge_fields; int entry; init_t impl; - if ( !setup ) + if (!setup) setup = &snes_ntsc_composite; - init( &impl, setup ); - + init(&impl, setup); + merge_fields = setup->merge_fields; - if ( setup->artifacts <= -1 && setup->fringing <= -1 ) + if (setup->artifacts <= -1 && setup->fringing <= -1) merge_fields = 1; - - for ( entry = 0; entry < snes_ntsc_palette_size; entry++ ) + + for (entry = 0; entry < snes_ntsc_palette_size; entry++) { /* Reduce number of significant bits of source color. Clearing the low bits of R and B were least notictable. Modifying green was too @@ -97,8 +97,8 @@ void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ) int ir = entry >> 8 & 0x1E; int ig = entry >> 4 & 0x1F; int ib = entry << 1 & 0x1E; - - #if SNES_NTSC_BSNES_COLORTBL + +#if SNES_NTSC_BSNES_COLORTBL if ( setup->bsnes_colortbl ) { int bgr15 = (ib << 10) | (ig << 5) | ir; @@ -107,145 +107,145 @@ void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ) ig = rgb16 >> 6 & 0x1F; ib = rgb16 & 0x1E; } - #endif - +#endif + { - float rr = impl.to_float [ir]; - float gg = impl.to_float [ig]; - float bb = impl.to_float [ib]; - - float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i ); - - int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); - snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b ); - - snes_ntsc_rgb_t* out = ntsc->table [entry]; - gen_kernel( &impl, y, i, q, out ); - if ( merge_fields ) - merge_kernel_fields( out ); - correct_errors( rgb, out ); + float rr = impl.to_float[ir]; + float gg = impl.to_float[ig]; + float bb = impl.to_float[ib]; + + float y, i, q = RGB_TO_YIQ(rr, gg, bb, y, i); + + int r, g, b = YIQ_TO_RGB(y, i, q, impl.to_rgb, int, r, g); + snes_ntsc_rgb_t rgb = PACK_RGB(r, g, b); + + snes_ntsc_rgb_t* out = ntsc->table[entry]; + gen_kernel(&impl, y, i, q, out); + if (merge_fields) + merge_kernel_fields(out); + correct_errors(rgb, out); } } } #ifndef SNES_NTSC_NO_BLITTERS -void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, - int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +void snes_ntsc_blit(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch) { int chunk_count = (in_width - 1) / snes_ntsc_in_chunk; - for ( ; in_height; --in_height ) + for (; in_height; --in_height) { SNES_NTSC_IN_T const* line_in = input; - SNES_NTSC_BEGIN_ROW( ntsc, burst_phase, - snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) ); - snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out; + SNES_NTSC_BEGIN_ROW(ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in )); + snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*)rgb_out; int n; ++line_in; - - for ( n = chunk_count; n; --n ) + + for (n = chunk_count; n; --n) { /* order of input and output pixels must not be altered */ - SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); - SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); - SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); - SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); - - line_in += 3; + SNES_NTSC_COLOR_IN(0, SNES_NTSC_ADJ_IN( line_in [0] )); + SNES_NTSC_RGB_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(1, SNES_NTSC_ADJ_IN( line_in [1] )); + SNES_NTSC_RGB_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(2, SNES_NTSC_ADJ_IN( line_in [2] )); + SNES_NTSC_RGB_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH); + + line_in += 3; line_out += 7; } - + /* finish final pixels */ - SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); - SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); - SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); - SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); - + SNES_NTSC_COLOR_IN(0, snes_ntsc_black); + SNES_NTSC_RGB_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(1, snes_ntsc_black); + SNES_NTSC_RGB_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(2, snes_ntsc_black); + SNES_NTSC_RGB_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_RGB_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH); + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; input += in_row_width; - rgb_out = (char*) rgb_out + out_pitch; + rgb_out = (char*)rgb_out + out_pitch; } } -void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, - int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +void snes_ntsc_blit_hires(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch) { int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2); - for ( ; in_height; --in_height ) + for (; in_height; --in_height) { SNES_NTSC_IN_T const* line_in = input; - SNES_NTSC_HIRES_ROW( ntsc, burst_phase, - snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, - SNES_NTSC_ADJ_IN( line_in [0] ), - SNES_NTSC_ADJ_IN( line_in [1] ) ); - snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out; + SNES_NTSC_HIRES_ROW(ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, + SNES_NTSC_ADJ_IN( line_in [0] ), + SNES_NTSC_ADJ_IN( line_in [1] )); + snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*)rgb_out; int n; line_in += 2; - - for ( n = chunk_count; n; --n ) + + for (n = chunk_count; n; --n) { /* twice as many input pixels per chunk */ - SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); - SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); - SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); - SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) ); - SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) ); - SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) ); - SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); - - line_in += 6; + SNES_NTSC_COLOR_IN(0, SNES_NTSC_ADJ_IN( line_in [0] )); + SNES_NTSC_HIRES_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(1, SNES_NTSC_ADJ_IN( line_in [1] )); + SNES_NTSC_HIRES_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(2, SNES_NTSC_ADJ_IN( line_in [2] )); + SNES_NTSC_HIRES_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(3, SNES_NTSC_ADJ_IN( line_in [3] )); + SNES_NTSC_HIRES_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(4, SNES_NTSC_ADJ_IN( line_in [4] )); + SNES_NTSC_HIRES_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(5, SNES_NTSC_ADJ_IN( line_in [5] )); + SNES_NTSC_HIRES_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_HIRES_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH); + + line_in += 6; line_out += 7; } - - SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); - SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); - SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); - SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 3, snes_ntsc_black ); - SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 4, snes_ntsc_black ); - SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); - - SNES_NTSC_COLOR_IN( 5, snes_ntsc_black ); - SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); - SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); - + + SNES_NTSC_COLOR_IN(0, snes_ntsc_black); + SNES_NTSC_HIRES_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(1, snes_ntsc_black); + SNES_NTSC_HIRES_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(2, snes_ntsc_black); + SNES_NTSC_HIRES_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(3, snes_ntsc_black); + SNES_NTSC_HIRES_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(4, snes_ntsc_black); + SNES_NTSC_HIRES_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH); + + SNES_NTSC_COLOR_IN(5, snes_ntsc_black); + SNES_NTSC_HIRES_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH); + SNES_NTSC_HIRES_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH); + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; input += in_row_width; - rgb_out = (char*) rgb_out + out_pitch; + rgb_out = (char*)rgb_out + out_pitch; } } diff --git a/Utilities/snes_ntsc.h b/Utilities/snes_ntsc.h index 9f2f28f..eae5b2a 100644 --- a/Utilities/snes_ntsc.h +++ b/Utilities/snes_ntsc.h @@ -7,7 +7,7 @@ #include "snes_ntsc_config.h" #ifdef __cplusplus - extern "C" { +extern "C" { #endif /* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown @@ -15,46 +15,46 @@ in parenthesis and should remain fairly stable in future versions. */ typedef struct snes_ntsc_setup_t { /* Basic parameters */ - double hue; /* -1 = -180 degrees +1 = +180 degrees */ + double hue; /* -1 = -180 degrees +1 = +180 degrees */ double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ - double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ + double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ - double sharpness; /* edge contrast enhancement/blurring */ - + double sharpness; /* edge contrast enhancement/blurring */ + /* Advanced parameters */ - double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ + double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ double resolution; /* image resolution */ - double artifacts; /* artifacts caused by color changes */ - double fringing; /* color artifacts caused by brightness changes */ - double bleed; /* color bleed (color resolution reduction) */ - int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ + double artifacts; /* artifacts caused by color changes */ + double fringing; /* color artifacts caused by brightness changes */ + double bleed; /* color bleed (color resolution reduction) */ + int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ - + unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */ } snes_ntsc_setup_t; /* Video format presets */ extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */ -extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */ -extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */ -extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */ +extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */ +extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */ +extern snes_ntsc_setup_t const snes_ntsc_monochrome; /* desaturated + artifacts */ /* Initializes and adjusts parameters. Can be called multiple times on the same snes_ntsc_t object. Can pass NULL for either parameter. */ typedef struct snes_ntsc_t snes_ntsc_t; -void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ); +void snes_ntsc_init(snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup); /* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB. In_row_width is the number of pixels to get to the next input row. Out_pitch is the number of *bytes* to get to the next output row. */ -void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, - long in_row_width, int burst_phase, int in_width, int in_height, - void* rgb_out, long out_pitch ); +void snes_ntsc_blit(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch); -void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, - long in_row_width, int burst_phase, int in_width, int in_height, - void* rgb_out, long out_pitch ); +void snes_ntsc_blit_hires(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch); /* Number of output pixels written by low-res blitter for given input width. Width might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded @@ -71,10 +71,10 @@ value. */ /* Interface for user-defined custom blitters */ -enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ -enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ -enum { snes_ntsc_black = 0 }; /* palette index for black */ -enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ +enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ +enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ +enum { snes_ntsc_black = 0 }; /* palette index for black */ +enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ /* Begins outputting row and starts three pixels. First pixel will be cut off a bit. Use snes_ntsc_black for unused pixels. Declares variables, so must be before first @@ -132,11 +132,16 @@ statement in a block (unless you're using C++). */ /* private */ enum { snes_ntsc_entry_size = 128 }; + enum { snes_ntsc_palette_size = 0x2000 }; + typedef unsigned long snes_ntsc_rgb_t; -struct snes_ntsc_t { - snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size]; + +struct snes_ntsc_t +{ + snes_ntsc_rgb_t table[snes_ntsc_palette_size][snes_ntsc_entry_size]; }; + enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count }; #define SNES_NTSC_RGB16( ktable, n ) \ @@ -200,7 +205,7 @@ enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count }; } #ifdef __cplusplus - } +} #endif #endif diff --git a/Utilities/snes_ntsc_impl.h b/Utilities/snes_ntsc_impl.h index 1d7adc7..c52e72c 100644 --- a/Utilities/snes_ntsc_impl.h +++ b/Utilities/snes_ntsc_impl.h @@ -22,7 +22,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define PI 3.14159265358979323846f #ifndef LUMA_CUTOFF - #define LUMA_CUTOFF 0.20 +#define LUMA_CUTOFF 0.20 #endif #ifndef gamma_size #define gamma_size 1 @@ -31,32 +31,34 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define rgb_bits 8 #endif #ifndef artifacts_max - #define artifacts_max (artifacts_mid * 1.5f) +#define artifacts_max (artifacts_mid * 1.5f) #endif #ifndef fringing_max - #define fringing_max (fringing_mid * 2) +#define fringing_max (fringing_mid * 2) #endif #ifndef STD_HUE_CONDITION - #define STD_HUE_CONDITION( setup ) 1 +#define STD_HUE_CONDITION( setup ) 1 #endif #define ext_decoder_hue (std_decoder_hue + 15) #define rgb_unit (1 << rgb_bits) #define rgb_offset (rgb_unit * 2 + 0.5f) -enum { burst_size = snes_ntsc_entry_size / burst_count }; +enum { burst_size = snes_ntsc_entry_size / burst_count }; + enum { kernel_half = 16 }; + enum { kernel_size = kernel_half * 2 + 1 }; typedef struct init_t { - float to_rgb [burst_count * 6]; - float to_float [gamma_size]; + float to_rgb[burst_count * 6]; + float to_float[gamma_size]; float contrast; float brightness; float artifacts; float fringing; - float kernel [rescale_out * kernel_size * 2]; + float kernel[rescale_out * kernel_size * 2]; } init_t; #define ROTATE_IQ( i, q, sin_b, cos_b ) {\ @@ -66,10 +68,10 @@ typedef struct init_t i = t;\ } -static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) +static void init_filters(init_t* impl, snes_ntsc_setup_t const* setup) { #if rescale_out > 1 - float kernels [kernel_size * 2]; + float kernels[kernel_size * 2]; #else float* const kernels = impl->kernel; #endif @@ -77,59 +79,59 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) /* generate luma (y) filter using sinc kernel */ { /* sinc with rolloff (dsf) */ - float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; + float const rolloff = 1 + (float)setup->sharpness * (float)0.032; float const maxh = 32; - float const pow_a_n = (float) pow( rolloff, maxh ); + float const pow_a_n = (float)pow(rolloff, maxh); float sum; int i; /* quadratic mapping to reduce negative (blurring) range */ - float to_angle = (float) setup->resolution + 1; - to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); - - kernels [kernel_size * 3 / 2] = maxh; /* default center value */ - for ( i = 0; i < kernel_half * 2 + 1; i++ ) + float to_angle = (float)setup->resolution + 1; + to_angle = PI / maxh * (float)LUMA_CUTOFF * (to_angle * to_angle + 1); + + kernels[kernel_size * 3 / 2] = maxh; /* default center value */ + for (i = 0; i < kernel_half * 2 + 1; i++) { int x = i - kernel_half; float angle = x * to_angle; /* instability occurs at center point with rolloff very close to 1.0 */ - if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) + if (x || pow_a_n > (float)1.056 || pow_a_n < (float)0.981) { - float rolloff_cos_a = rolloff * (float) cos( angle ); + float rolloff_cos_a = rolloff * (float)cos(angle); float num = 1 - rolloff_cos_a - - pow_a_n * (float) cos( maxh * angle ) + - pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); + pow_a_n * (float)cos(maxh * angle) + + pow_a_n * rolloff * (float)cos((maxh - 1) * angle); float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; float dsf = num / den; - kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; + kernels[kernel_size * 3 / 2 - kernel_half + i] = dsf - (float)0.5; } } - + /* apply blackman window and find sum */ sum = 0; - for ( i = 0; i < kernel_half * 2 + 1; i++ ) + for (i = 0; i < kernel_half * 2 + 1; i++) { float x = PI * 2 / (kernel_half * 2) * i; - float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); - sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); + float blackman = 0.42f - 0.5f * (float)cos(x) + 0.08f * (float)cos(x * 2); + sum += (kernels[kernel_size * 3 / 2 - kernel_half + i] *= blackman); } - + /* normalize kernel */ sum = 1.0f / sum; - for ( i = 0; i < kernel_half * 2 + 1; i++ ) + for (i = 0; i < kernel_half * 2 + 1; i++) { int x = kernel_size * 3 / 2 - kernel_half + i; - kernels [x] *= sum; - assert( kernels [x] == kernels [x] ); /* catch numerical instability */ + kernels[x] *= sum; + assert(kernels [x] == kernels [x]); /* catch numerical instability */ } } /* generate chroma (iq) filter using gaussian kernel */ { float const cutoff_factor = -0.03125f; - float cutoff = (float) setup->bleed; + float cutoff = (float)setup->bleed; int i; - - if ( cutoff < 0 ) + + if (cutoff < 0) { /* keep extreme value accessible only near upper end of scale (1.0) */ cutoff *= cutoff; @@ -138,27 +140,27 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) cutoff *= -30.0f / 0.65f; } cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; - - for ( i = -kernel_half; i <= kernel_half; i++ ) - kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); - + + for (i = -kernel_half; i <= kernel_half; i++) + kernels[kernel_size / 2 + i] = (float)exp(i * i * cutoff); + /* normalize even and odd phases separately */ - for ( i = 0; i < 2; i++ ) + for (i = 0; i < 2; i++) { float sum = 0; int x; - for ( x = i; x < kernel_size; x += 2 ) - sum += kernels [x]; - + for (x = i; x < kernel_size; x += 2) + sum += kernels[x]; + sum = 1.0f / sum; - for ( x = i; x < kernel_size; x += 2 ) + for (x = i; x < kernel_size; x += 2) { - kernels [x] *= sum; - assert( kernels [x] == kernels [x] ); /* catch numerical instability */ + kernels[x] *= sum; + assert(kernels [x] == kernels [x]); /* catch numerical instability */ } } } - + /* printf( "luma:\n" ); for ( i = kernel_size; i < kernel_size * 2; i++ ) @@ -167,9 +169,9 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) for ( i = 0; i < kernel_size; i++ ) printf( "%f\n", kernels [i] ); */ - + /* generate linear rescale kernels */ - #if rescale_out > 1 +#if rescale_out > 1 { float weight = 1.0f; float* out = impl->kernel; @@ -179,73 +181,73 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) float remain = 0; int i; weight -= 1.0f / rescale_in; - for ( i = 0; i < kernel_size * 2; i++ ) + for (i = 0; i < kernel_size * 2; i++) { - float cur = kernels [i]; + float cur = kernels[i]; float m = cur * weight; *out++ = m + remain; remain = cur - m; } } - while ( --n ); + while (--n); } - #endif +#endif } -static float const default_decoder [6] = - { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; +static float const default_decoder[6] = + {0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f}; -static void init( init_t* impl, snes_ntsc_setup_t const* setup ) +static void init(init_t* impl, snes_ntsc_setup_t const* setup) { - impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; - impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; - #ifdef default_palette_contrast + impl->brightness = (float)setup->brightness * (0.5f * rgb_unit) + rgb_offset; + impl->contrast = (float)setup->contrast * (0.5f * rgb_unit) + rgb_unit; +#ifdef default_palette_contrast if ( !setup->palette ) impl->contrast *= default_palette_contrast; - #endif - - impl->artifacts = (float) setup->artifacts; - if ( impl->artifacts > 0 ) +#endif + + impl->artifacts = (float)setup->artifacts; + if (impl->artifacts > 0) impl->artifacts *= artifacts_max - artifacts_mid; impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; - impl->fringing = (float) setup->fringing; - if ( impl->fringing > 0 ) + impl->fringing = (float)setup->fringing; + if (impl->fringing > 0) impl->fringing *= fringing_max - fringing_mid; impl->fringing = impl->fringing * fringing_mid + fringing_mid; - - init_filters( impl, setup ); - + + init_filters(impl, setup); + /* generate gamma table */ - if ( gamma_size > 1 ) + if (gamma_size > 1) { float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); - float const gamma = 1.1333f - (float) setup->gamma * 0.5f; + float const gamma = 1.1333f - (float)setup->gamma * 0.5f; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ int i; - for ( i = 0; i < gamma_size; i++ ) - impl->to_float [i] = - (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; + for (i = 0; i < gamma_size; i++) + impl->to_float[i] = + (float)pow(i * to_float, gamma) * impl->contrast + impl->brightness; } - + /* setup decoder matricies */ { - float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; - float sat = (float) setup->saturation + 1; + float hue = (float)setup->hue * PI + PI / 180 * ext_decoder_hue; + float sat = (float)setup->saturation + 1; float const* decoder = setup->decoder_matrix; - if ( !decoder ) + if (!decoder) { decoder = default_decoder; - if ( STD_HUE_CONDITION( setup ) ) + if (STD_HUE_CONDITION(setup)) hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); } - + { - float s = (float) sin( hue ) * sat; - float c = (float) cos( hue ) * sat; + float s = (float)sin(hue) * sat; + float c = (float)cos(hue) * sat; float* out = impl->to_rgb; int n; - + n = burst_count; do { @@ -258,12 +260,12 @@ static void init( init_t* impl, snes_ntsc_setup_t const* setup ) *out++ = i * c - q * s; *out++ = i * s + q * c; } - while ( --n ); - if ( burst_count <= 1 ) + while (--n); + if (burst_count <= 1) break; - ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ + ROTATE_IQ(s, c, 0.866025f, -0.5f); /* +120 degrees */ } - while ( --n ); + while (--n); } } } @@ -285,21 +287,22 @@ static void init( init_t* impl, snes_ntsc_setup_t const* setup ) #define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) enum { rgb_kernel_size = burst_size / alignment_count }; + enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder }; typedef struct pixel_info_t { int offset; float negate; - float kernel [4]; + float kernel[4]; } pixel_info_t; #if rescale_in > 1 - #define PIXEL_OFFSET_( ntsc, scaled ) \ +#define PIXEL_OFFSET_( ntsc, scaled ) \ (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ (kernel_size * 2 * scaled)) - #define PIXEL_OFFSET( ntsc, scaled ) \ +#define PIXEL_OFFSET( ntsc, scaled ) \ PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ (((scaled) + rescale_out * 10) % rescale_out) ),\ (1.0f - (((ntsc) + 100) & 2)) @@ -309,10 +312,10 @@ typedef struct pixel_info_t (1.0f - (((ntsc) + 100) & 2)) #endif -extern pixel_info_t const snes_ntsc_pixels [alignment_count]; +extern pixel_info_t const snes_ntsc_pixels[alignment_count]; /* Generate pixel at all burst phases and column alignments */ -static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out ) +static void gen_kernel(init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out) { /* generate for each scanline burst phase */ float const* to_rgb = impl->to_rgb; @@ -330,61 +333,61 @@ static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t { /* negate is -1 when composite starts at odd multiple of 2 */ float const yy = y * impl->fringing * pixel->negate; - float const ic0 = (i + yy) * pixel->kernel [0]; - float const qc1 = (q + yy) * pixel->kernel [1]; - float const ic2 = (i - yy) * pixel->kernel [2]; - float const qc3 = (q - yy) * pixel->kernel [3]; - + float const ic0 = (i + yy) * pixel->kernel[0]; + float const qc1 = (q + yy) * pixel->kernel[1]; + float const ic2 = (i - yy) * pixel->kernel[2]; + float const qc3 = (q - yy) * pixel->kernel[3]; + float const factor = impl->artifacts * pixel->negate; float const ii = i * factor; - float const yc0 = (y + ii) * pixel->kernel [0]; - float const yc2 = (y - ii) * pixel->kernel [2]; - + float const yc0 = (y + ii) * pixel->kernel[0]; + float const yc2 = (y - ii) * pixel->kernel[2]; + float const qq = q * factor; - float const yc1 = (y + qq) * pixel->kernel [1]; - float const yc3 = (y - qq) * pixel->kernel [3]; - - float const* k = &impl->kernel [pixel->offset]; + float const yc1 = (y + qq) * pixel->kernel[1]; + float const yc3 = (y - qq) * pixel->kernel[3]; + + float const* k = &impl->kernel[pixel->offset]; int n; ++pixel; - for ( n = rgb_kernel_size; n; --n ) + for (n = rgb_kernel_size; n; --n) { - float i = k[0]*ic0 + k[2]*ic2; - float q = k[1]*qc1 + k[3]*qc3; - float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + - k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; - if ( rescale_out <= 1 ) + float i = k[0] * ic0 + k[2] * ic2; + float q = k[1] * qc1 + k[3] * qc3; + float y = k[kernel_size + 0] * yc0 + k[kernel_size + 1] * yc1 + + k[kernel_size + 2] * yc2 + k[kernel_size + 3] * yc3 + rgb_offset; + if (rescale_out <= 1) k--; - else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) + else if (k < &impl->kernel[kernel_size * 2 * (rescale_out - 1)]) k += kernel_size * 2 - 1; else k -= kernel_size * 2 * (rescale_out - 1) + 2; { - int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); - *out++ = PACK_RGB( r, g, b ) - rgb_bias; + int r, g, b = YIQ_TO_RGB(y, i, q, to_rgb, int, r, g); + *out++ = PACK_RGB(r, g, b) - rgb_bias; } } } - while ( alignment_count > 1 && --alignment_remain ); - - if ( burst_count <= 1 ) + while (alignment_count > 1 && --alignment_remain); + + if (burst_count <= 1) break; - + to_rgb += 6; - - ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ + + ROTATE_IQ(i, q, -0.866025f, -0.5f); /* -120 degrees */ } - while ( --burst_remain ); + while (--burst_remain); } -static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ); +static void correct_errors(snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out); #if DISABLE_CORRECTION #define CORRECT_ERROR( a ) { out [i] += rgb_bias; } #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } #else - #define CORRECT_ERROR( a ) { out [a] += error; } - #define DISTRIBUTE_ERROR( a, b, c ) {\ +#define CORRECT_ERROR( a ) { out [a] += error; } +#define DISTRIBUTE_ERROR( a, b, c ) {\ snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\ fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\ fourth -= rgb_bias >> 2;\ @@ -408,32 +411,32 @@ static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ); /* blitter related */ #ifndef restrict - #if defined (__GNUC__) +#if defined (__GNUC__) #define restrict __restrict__ - #elif defined (_MSC_VER) && _MSC_VER > 1300 - #define restrict __restrict - #else +#elif defined (_MSC_VER) && _MSC_VER > 1300 +#define restrict __restrict +#else /* no support for restricted pointers */ #define restrict - #endif +#endif #endif #include #if SNES_NTSC_OUT_DEPTH <= 16 - #if USHRT_MAX == 0xFFFF +#if USHRT_MAX == 0xFFFF typedef unsigned short snes_ntsc_out_t; - #else +#else #error "Need 16-bit int type" - #endif +#endif #else - #if UINT_MAX == 0xFFFFFFFF - typedef unsigned int snes_ntsc_out_t; - #elif ULONG_MAX == 0xFFFFFFFF +#if UINT_MAX == 0xFFFFFFFF +typedef unsigned int snes_ntsc_out_t; +#elif ULONG_MAX == 0xFFFFFFFF typedef unsigned long snes_ntsc_out_t; - #else +#else #error "Need 32-bit int type" - #endif +#endif #endif diff --git a/Utilities/stb_vorbis.cpp b/Utilities/stb_vorbis.cpp index ff35e8f..18c2fec 100644 --- a/Utilities/stb_vorbis.cpp +++ b/Utilities/stb_vorbis.cpp @@ -181,8 +181,6 @@ // #define STB_VORBIS_NO_DEFER_FLOOR - - ////////////////////////////////////////////////////////////////////////////// #ifdef STB_VORBIS_NO_PULLDATA_API @@ -197,14 +195,14 @@ #ifndef STB_VORBIS_NO_INTEGER_CONVERSION #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT - // only need endianness for fast-float-to-int, which we don't - // use for pushdata +// only need endianness for fast-float-to-int, which we don't +// use for pushdata - #ifndef STB_VORBIS_BIG_ENDIAN - #define STB_VORBIS_ENDIAN 0 - #else +#ifndef STB_VORBIS_BIG_ENDIAN +#define STB_VORBIS_ENDIAN 0 +#else #define STB_VORBIS_ENDIAN 1 - #endif +#endif #endif #endif @@ -215,18 +213,18 @@ #endif #ifndef STB_VORBIS_NO_CRT - #include - #include - #include - #include +#include +#include +#include +#include - // find definition of alloca if it's not in stdlib.h: - #if defined(_MSC_VER) || defined(__MINGW32__) - #include - #endif - #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) +// find definition of alloca if it's not in stdlib.h: +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#endif +#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) #include - #endif +#endif #else // STB_VORBIS_NO_CRT #define NULL 0 #define malloc(s) 0 @@ -237,25 +235,25 @@ #include #ifdef __MINGW32__ - // eff you mingw: - // "fixed": - // http://sourceforge.net/p/mingw-w64/mailman/message/32882927/ - // "no that broke the build, reverted, who cares about C": - // http://sourceforge.net/p/mingw-w64/mailman/message/32890381/ - #ifdef __forceinline +// eff you mingw: +// "fixed": +// http://sourceforge.net/p/mingw-w64/mailman/message/32882927/ +// "no that broke the build, reverted, who cares about C": +// http://sourceforge.net/p/mingw-w64/mailman/message/32890381/ +#ifdef __forceinline #undef __forceinline - #endif +#endif #define __forceinline #define alloca __builtin_alloca #elif !defined(_MSC_VER) - #ifdef __forceinline +#ifdef __forceinline #undef __forceinline - #endif - #if __GNUC__ +#endif +#if __GNUC__ #define __forceinline inline - #else +#else #define __forceinline - #endif +#endif #endif #if STB_VORBIS_MAX_CHANNELS > 256 @@ -278,12 +276,12 @@ #define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) -typedef unsigned char uint8; -typedef signed char int8; +typedef unsigned char uint8; +typedef signed char int8; typedef unsigned short uint16; -typedef signed short int16; -typedef unsigned int uint32; -typedef signed int int32; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; #ifndef TRUE #define TRUE 1 @@ -310,218 +308,218 @@ typedef float codetype; typedef struct { - int dimensions, entries; - uint8 *codeword_lengths; - float minimum_value; - float delta_value; - uint8 value_bits; - uint8 lookup_type; - uint8 sequence_p; - uint8 sparse; - uint32 lookup_values; - codetype *multiplicands; - uint32 *codewords; - #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT - int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; - #else + int dimensions, entries; + uint8* codeword_lengths; + float minimum_value; + float delta_value; + uint8 value_bits; + uint8 lookup_type; + uint8 sequence_p; + uint8 sparse; + uint32 lookup_values; + codetype* multiplicands; + uint32* codewords; +#ifdef STB_VORBIS_FAST_HUFFMAN_SHORT + int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; +#else int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; - #endif - uint32 *sorted_codewords; - int *sorted_values; - int sorted_entries; +#endif + uint32* sorted_codewords; + int* sorted_values; + int sorted_entries; } Codebook; typedef struct { - uint8 order; - uint16 rate; - uint16 bark_map_size; - uint8 amplitude_bits; - uint8 amplitude_offset; - uint8 number_of_books; - uint8 book_list[16]; // varies + uint8 order; + uint16 rate; + uint16 bark_map_size; + uint8 amplitude_bits; + uint8 amplitude_offset; + uint8 number_of_books; + uint8 book_list[16]; // varies } Floor0; typedef struct { - uint8 partitions; - uint8 partition_class_list[32]; // varies - uint8 class_dimensions[16]; // varies - uint8 class_subclasses[16]; // varies - uint8 class_masterbooks[16]; // varies - int16 subclass_books[16][8]; // varies - uint16 Xlist[31*8+2]; // varies - uint8 sorted_order[31*8+2]; - uint8 neighbors[31*8+2][2]; - uint8 floor1_multiplier; - uint8 rangebits; - int values; + uint8 partitions; + uint8 partition_class_list[32]; // varies + uint8 class_dimensions[16]; // varies + uint8 class_subclasses[16]; // varies + uint8 class_masterbooks[16]; // varies + int16 subclass_books[16][8]; // varies + uint16 Xlist[31 * 8 + 2]; // varies + uint8 sorted_order[31 * 8 + 2]; + uint8 neighbors[31 * 8 + 2][2]; + uint8 floor1_multiplier; + uint8 rangebits; + int values; } Floor1; typedef union { - Floor0 floor0; - Floor1 floor1; + Floor0 floor0; + Floor1 floor1; } Floor; typedef struct { - uint32 begin, end; - uint32 part_size; - uint8 classifications; - uint8 classbook; - uint8 **classdata; - int16 (*residue_books)[8]; + uint32 begin, end; + uint32 part_size; + uint8 classifications; + uint8 classbook; + uint8** classdata; + int16 (*residue_books)[8]; } Residue; typedef struct { - uint8 magnitude; - uint8 angle; - uint8 mux; + uint8 magnitude; + uint8 angle; + uint8 mux; } MappingChannel; typedef struct { - uint16 coupling_steps; - MappingChannel *chan; - uint8 submaps; - uint8 submap_floor[15]; // varies - uint8 submap_residue[15]; // varies + uint16 coupling_steps; + MappingChannel* chan; + uint8 submaps; + uint8 submap_floor[15]; // varies + uint8 submap_residue[15]; // varies } Mapping; typedef struct { - uint8 blockflag; - uint8 mapping; - uint16 windowtype; - uint16 transformtype; + uint8 blockflag; + uint8 mapping; + uint16 windowtype; + uint16 transformtype; } Mode; typedef struct { - uint32 goal_crc; // expected crc if match - int bytes_left; // bytes left in packet - uint32 crc_so_far; // running crc - int bytes_done; // bytes processed in _current_ chunk - uint32 sample_loc; // granule pos encoded in page + uint32 goal_crc; // expected crc if match + int bytes_left; // bytes left in packet + uint32 crc_so_far; // running crc + int bytes_done; // bytes processed in _current_ chunk + uint32 sample_loc; // granule pos encoded in page } CRCscan; typedef struct { - uint32 page_start, page_end; - uint32 last_decoded_sample; + uint32 page_start, page_end; + uint32 last_decoded_sample; } ProbedPage; struct stb_vorbis { - // user-accessible info - unsigned int sample_rate; - int channels; + // user-accessible info + unsigned int sample_rate; + int channels; - unsigned int setup_memory_required; - unsigned int temp_memory_required; - unsigned int setup_temp_memory_required; + unsigned int setup_memory_required; + unsigned int temp_memory_required; + unsigned int setup_temp_memory_required; - // input config + // input config #ifndef STB_VORBIS_NO_STDIO - FILE *f; - uint32 f_start; - int close_on_free; + FILE* f; + uint32 f_start; + int close_on_free; #endif - uint8 *stream; - uint8 *stream_start; - uint8 *stream_end; + uint8* stream; + uint8* stream_start; + uint8* stream_end; - uint32 stream_len; + uint32 stream_len; - uint8 push_mode; + uint8 push_mode; - uint32 first_audio_page_offset; + uint32 first_audio_page_offset; - ProbedPage p_first, p_last; + ProbedPage p_first, p_last; - // memory management - stb_vorbis_alloc alloc; - int setup_offset; - int temp_offset; + // memory management + stb_vorbis_alloc alloc; + int setup_offset; + int temp_offset; - // run-time results - int eof; - enum STBVorbisError error; + // run-time results + int eof; + enum STBVorbisError error; - // user-useful data + // user-useful data - // header info - int blocksize[2]; - int blocksize_0, blocksize_1; - int codebook_count; - Codebook *codebooks; - int floor_count; - uint16 floor_types[64]; // varies - Floor *floor_config; - int residue_count; - uint16 residue_types[64]; // varies - Residue *residue_config; - int mapping_count; - Mapping *mapping; - int mode_count; - Mode mode_config[64]; // varies + // header info + int blocksize[2]; + int blocksize_0, blocksize_1; + int codebook_count; + Codebook* codebooks; + int floor_count; + uint16 floor_types[64]; // varies + Floor* floor_config; + int residue_count; + uint16 residue_types[64]; // varies + Residue* residue_config; + int mapping_count; + Mapping* mapping; + int mode_count; + Mode mode_config[64]; // varies - uint32 total_samples; + uint32 total_samples; - // decode buffer - float *channel_buffers[STB_VORBIS_MAX_CHANNELS]; - float *outputs [STB_VORBIS_MAX_CHANNELS]; + // decode buffer + float* channel_buffers[STB_VORBIS_MAX_CHANNELS]; + float* outputs[STB_VORBIS_MAX_CHANNELS]; - float *previous_window[STB_VORBIS_MAX_CHANNELS]; - int previous_length; + float* previous_window[STB_VORBIS_MAX_CHANNELS]; + int previous_length; - #ifndef STB_VORBIS_NO_DEFER_FLOOR - int16 *finalY[STB_VORBIS_MAX_CHANNELS]; - #else +#ifndef STB_VORBIS_NO_DEFER_FLOOR + int16* finalY[STB_VORBIS_MAX_CHANNELS]; +#else float *floor_buffers[STB_VORBIS_MAX_CHANNELS]; - #endif - - uint32 current_loc; // sample location of next frame to decode - int current_loc_valid; - - // per-blocksize precomputed data - - // twiddle factors - float *A[2],*B[2],*C[2]; - float *window[2]; - uint16 *bit_reverse[2]; - - // current page/packet/segment streaming info - uint32 serial; // stream serial number for verification - int last_page; - int segment_count; - uint8 segments[255]; - uint8 page_flag; - uint8 bytes_in_seg; - uint8 first_decode; - int next_seg; - int last_seg; // flag that we're on the last segment - int last_seg_which; // what was the segment number of the last seg? - uint32 acc; - int valid_bits; - int packet_bytes; - int end_seg_with_known_loc; - uint32 known_loc_for_packet; - int discard_samples_deferred; - uint32 samples_output; - - // push mode scanning - int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching -#ifndef STB_VORBIS_NO_PUSHDATA_API - CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; #endif - // sample-access - int channel_buffer_start; - int channel_buffer_end; + uint32 current_loc; // sample location of next frame to decode + int current_loc_valid; + + // per-blocksize precomputed data + + // twiddle factors + float *A[2], *B[2], *C[2]; + float* window[2]; + uint16* bit_reverse[2]; + + // current page/packet/segment streaming info + uint32 serial; // stream serial number for verification + int last_page; + int segment_count; + uint8 segments[255]; + uint8 page_flag; + uint8 bytes_in_seg; + uint8 first_decode; + int next_seg; + int last_seg; // flag that we're on the last segment + int last_seg_which; // what was the segment number of the last seg? + uint32 acc; + int valid_bits; + int packet_bytes; + int end_seg_with_known_loc; + uint32 known_loc_for_packet; + int discard_samples_deferred; + uint32 samples_output; + + // push mode scanning + int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching +#ifndef STB_VORBIS_NO_PUSHDATA_API + CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; +#endif + + // sample-access + int channel_buffer_start; + int channel_buffer_end; }; #if defined(STB_VORBIS_NO_PUSHDATA_API) @@ -529,18 +527,19 @@ struct stb_vorbis #elif defined(STB_VORBIS_NO_PULLDATA_API) #define IS_PUSH_MODE(f) TRUE #else - #define IS_PUSH_MODE(f) ((f)->push_mode) +#define IS_PUSH_MODE(f) ((f)->push_mode) #endif typedef struct stb_vorbis vorb; -static int error(vorb *f, enum STBVorbisError e) +static int error(vorb* f, enum STBVorbisError e) { - f->error = e; - if (!f->eof && e != VORBIS_need_more_data) { - f->error=e; // breakpoint for debugging - } - return 0; + f->error = e; + if (!f->eof && e != VORBIS_need_more_data) + { + f->error = e; // breakpoint for debugging + } + return 0; } @@ -558,90 +557,96 @@ static int error(vorb *f, enum STBVorbisError e) #define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size) // given a sufficiently large block of memory, make an array of pointers to subblocks of it -static void *make_block_array(void *mem, int count, int size) +static void* make_block_array(void* mem, int count, int size) { - int i; - void ** p = (void **) mem; - char *q = (char *) (p + count); - for (i=0; i < count; ++i) { - p[i] = q; - q += size; - } - return p; + int i; + void** p = (void**)mem; + char* q = (char*)(p + count); + for (i = 0; i < count; ++i) + { + p[i] = q; + q += size; + } + return p; } -static void *setup_malloc(vorb *f, int sz) +static void* setup_malloc(vorb* f, int sz) { - sz = (sz+3) & ~3; - f->setup_memory_required += sz; - if (f->alloc.alloc_buffer) { - void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; - if (f->setup_offset + sz > f->temp_offset) return NULL; - f->setup_offset += sz; - return p; - } - return sz ? malloc(sz) : NULL; + sz = (sz + 3) & ~3; + f->setup_memory_required += sz; + if (f->alloc.alloc_buffer) + { + void* p = (char*)f->alloc.alloc_buffer + f->setup_offset; + if (f->setup_offset + sz > f->temp_offset) return NULL; + f->setup_offset += sz; + return p; + } + return sz ? malloc(sz) : NULL; } -static void setup_free(vorb *f, void *p) +static void setup_free(vorb* f, void* p) { - if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack - free(p); + if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack + free(p); } -static void *setup_temp_malloc(vorb *f, int sz) +static void* setup_temp_malloc(vorb* f, int sz) { - sz = (sz+3) & ~3; - if (f->alloc.alloc_buffer) { - if (f->temp_offset - sz < f->setup_offset) return NULL; - f->temp_offset -= sz; - return (char *) f->alloc.alloc_buffer + f->temp_offset; - } - return malloc(sz); + sz = (sz + 3) & ~3; + if (f->alloc.alloc_buffer) + { + if (f->temp_offset - sz < f->setup_offset) return NULL; + f->temp_offset -= sz; + return (char*)f->alloc.alloc_buffer + f->temp_offset; + } + return malloc(sz); } -static void setup_temp_free(vorb *f, void *p, int sz) +static void setup_temp_free(vorb* f, void* p, int sz) { - if (f->alloc.alloc_buffer) { - f->temp_offset += (sz+3)&~3; - return; - } - free(p); + if (f->alloc.alloc_buffer) + { + f->temp_offset += (sz + 3) & ~3; + return; + } + free(p); } #define CRC32_POLY 0x04c11db7 // from spec static uint32 crc_table[256]; + static void crc32_init(void) { - int i,j; - uint32 s; - for(i=0; i < 256; i++) { - for (s=(uint32) i << 24, j=0; j < 8; ++j) - s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0); - crc_table[i] = s; - } + int i, j; + uint32 s; + for (i = 0; i < 256; i++) + { + for (s = (uint32)i << 24, j = 0; j < 8; ++j) + s = (s << 1) ^ (s >= (1U << 31) ? CRC32_POLY : 0); + crc_table[i] = s; + } } static __forceinline uint32 crc32_update(uint32 crc, uint8 byte) { - return (crc << 8) ^ crc_table[byte ^ (crc >> 24)]; + return (crc << 8) ^ crc_table[byte ^ (crc >> 24)]; } // used in setup, and for huffman that doesn't go fast path static unsigned int bit_reverse(unsigned int n) { - n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); - n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); - n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); - n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); - return (n >> 16) | (n << 16); + n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); + n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); + n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); + n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); + return (n >> 16) | (n << 16); } static float square(float x) { - return x*x; + return x * x; } // this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3 @@ -649,24 +654,24 @@ static float square(float x) // @OPTIMIZE: called multiple times per-packet with "constants"; move to setup static int ilog(int32 n) { - static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; + static signed char log2_4[16] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4}; - if (n < 0) return 0; // signed n returns 0 + if (n < 0) return 0; // signed n returns 0 - // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29) - if (n < (1 << 14)) - if (n < (1 << 4)) return 0 + log2_4[n ]; - else if (n < (1 << 9)) return 5 + log2_4[n >> 5]; - else return 10 + log2_4[n >> 10]; - else if (n < (1 << 24)) - if (n < (1 << 19)) return 15 + log2_4[n >> 15]; - else return 20 + log2_4[n >> 20]; - else if (n < (1 << 29)) return 25 + log2_4[n >> 25]; - else return 30 + log2_4[n >> 30]; + // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29) + if (n < (1 << 14)) + if (n < (1 << 4)) return 0 + log2_4[n]; + else if (n < (1 << 9)) return 5 + log2_4[n >> 5]; + else return 10 + log2_4[n >> 10]; + else if (n < (1 << 24)) + if (n < (1 << 19)) return 15 + log2_4[n >> 15]; + else return 20 + log2_4[n >> 20]; + else if (n < (1 << 29)) return 25 + log2_4[n >> 25]; + else return 30 + log2_4[n >> 30]; } #ifndef M_PI - #define M_PI 3.14159265358979323846264f // from CRC +#define M_PI 3.14159265358979323846264f // from CRC #endif // code length assigned to a value with no huffman encoding @@ -679,12 +684,12 @@ static int ilog(int32 n) static float float32_unpack(uint32 x) { - // from the specification - uint32 mantissa = x & 0x1fffff; - uint32 sign = x & 0x80000000; - uint32 exp = (x & 0x7fe00000) >> 21; - double res = sign ? -(double)mantissa : (double)mantissa; - return (float) ldexp((float)res, exp-788); + // from the specification + uint32 mantissa = x & 0x1fffff; + uint32 sign = x & 0x80000000; + uint32 exp = (x & 0x7fe00000) >> 21; + double res = sign ? -(double)mantissa : (double)mantissa; + return (float)ldexp((float)res, exp - 788); } @@ -695,85 +700,98 @@ static float float32_unpack(uint32 x) // vorbis allows a huffman table with non-sorted lengths. This // requires a more sophisticated construction, since symbols in // order do not map to huffman codes "in order". -static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values) +static void add_entry(Codebook* c, uint32 huff_code, int symbol, int count, int len, uint32* values) { - if (!c->sparse) { - c->codewords [symbol] = huff_code; - } else { - c->codewords [count] = huff_code; - c->codeword_lengths[count] = len; - values [count] = symbol; - } + if (!c->sparse) + { + c->codewords[symbol] = huff_code; + } + else + { + c->codewords[count] = huff_code; + c->codeword_lengths[count] = len; + values[count] = symbol; + } } -static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) +static int compute_codewords(Codebook* c, uint8* len, int n, uint32* values) { - int i,k,m=0; - uint32 available[32]; + int i, k, m = 0; + uint32 available[32]; - memset(available, 0, sizeof(available)); - // find the first entry - for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; - if (k == n) { assert(c->sorted_entries == 0); return TRUE; } - // add to the list - add_entry(c, 0, k, m++, len[k], values); - // add all available leaves - for (i=1; i <= len[k]; ++i) - available[i] = 1U << (32-i); - // note that the above code treats the first case specially, - // but it's really the same as the following code, so they - // could probably be combined (except the initial code is 0, - // and I use 0 in available[] to mean 'empty') - for (i=k+1; i < n; ++i) { - uint32 res; - int z = len[i], y; - if (z == NO_CODE) continue; - // find lowest available leaf (should always be earliest, - // which is what the specification calls for) - // note that this property, and the fact we can never have - // more than one free leaf at a given level, isn't totally - // trivial to prove, but it seems true and the assert never - // fires, so! - while (z > 0 && !available[z]) --z; - if (z == 0) { return FALSE; } - res = available[z]; - assert(z >= 0 && z < 32); - available[z] = 0; - add_entry(c, bit_reverse(res), i, m++, len[i], values); - // propogate availability up the tree - if (z != len[i]) { - assert(len[i] >= 0 && len[i] < 32); - for (y=len[i]; y > z; --y) { - assert(available[y] == 0); - available[y] = res + (1 << (32-y)); - } - } - } - return TRUE; + memset(available, 0, sizeof(available)); + // find the first entry + for (k = 0; k < n; ++k) if (len[k] < NO_CODE) break; + if (k == n) + { + assert(c->sorted_entries == 0); + return TRUE; + } + // add to the list + add_entry(c, 0, k, m++, len[k], values); + // add all available leaves + for (i = 1; i <= len[k]; ++i) + available[i] = 1U << (32 - i); + // note that the above code treats the first case specially, + // but it's really the same as the following code, so they + // could probably be combined (except the initial code is 0, + // and I use 0 in available[] to mean 'empty') + for (i = k + 1; i < n; ++i) + { + uint32 res; + int z = len[i], y; + if (z == NO_CODE) continue; + // find lowest available leaf (should always be earliest, + // which is what the specification calls for) + // note that this property, and the fact we can never have + // more than one free leaf at a given level, isn't totally + // trivial to prove, but it seems true and the assert never + // fires, so! + while (z > 0 && !available[z]) --z; + if (z == 0) { return FALSE; } + res = available[z]; + assert(z >= 0 && z < 32); + available[z] = 0; + add_entry(c, bit_reverse(res), i, m++, len[i], values); + // propogate availability up the tree + if (z != len[i]) + { + assert(len[i] >= 0 && len[i] < 32); + for (y = len[i]; y > z; --y) + { + assert(available[y] == 0); + available[y] = res + (1 << (32 - y)); + } + } + } + return TRUE; } // accelerated huffman table allows fast O(1) match of all symbols // of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH -static void compute_accelerated_huffman(Codebook *c) +static void compute_accelerated_huffman(Codebook* c) { - int i, len; - for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i) - c->fast_huffman[i] = -1; + int i, len; + for (i = 0; i < FAST_HUFFMAN_TABLE_SIZE; ++i) + c->fast_huffman[i] = -1; - len = c->sparse ? c->sorted_entries : c->entries; - #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT - if (len > 32767) len = 32767; // largest possible value we can encode! - #endif - for (i=0; i < len; ++i) { - if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) { - uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; - // set table entries for all bit combinations in the higher bits - while (z < FAST_HUFFMAN_TABLE_SIZE) { - c->fast_huffman[z] = i; - z += 1 << c->codeword_lengths[i]; - } - } - } + len = c->sparse ? c->sorted_entries : c->entries; +#ifdef STB_VORBIS_FAST_HUFFMAN_SHORT + if (len > 32767) len = 32767; // largest possible value we can encode! +#endif + for (i = 0; i < len; ++i) + { + if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) + { + uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; + // set table entries for all bit combinations in the higher bits + while (z < FAST_HUFFMAN_TABLE_SIZE) + { + c->fast_huffman[z] = i; + z += 1 << c->codeword_lengths[i]; + } + } + } } #ifdef _MSC_VER @@ -782,167 +800,194 @@ static void compute_accelerated_huffman(Codebook *c) #define STBV_CDECL #endif -static int STBV_CDECL uint32_compare(const void *p, const void *q) +static int STBV_CDECL uint32_compare(const void* p, const void* q) { - uint32 x = * (uint32 *) p; - uint32 y = * (uint32 *) q; - return x < y ? -1 : x > y; + uint32 x = *(uint32*)p; + uint32 y = *(uint32*)q; + return x < y ? -1 : x > y; } -static int include_in_sort(Codebook *c, uint8 len) +static int include_in_sort(Codebook* c, uint8 len) { - if (c->sparse) { assert(len != NO_CODE); return TRUE; } - if (len == NO_CODE) return FALSE; - if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE; - return FALSE; + if (c->sparse) + { + assert(len != NO_CODE); + return TRUE; + } + if (len == NO_CODE) return FALSE; + if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE; + return FALSE; } // if the fast table above doesn't work, we want to binary // search them... need to reverse the bits -static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) +static void compute_sorted_huffman(Codebook* c, uint8* lengths, uint32* values) { - int i, len; - // build a list of all the entries - // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN. - // this is kind of a frivolous optimization--I don't see any performance improvement, - // but it's like 4 extra lines of code, so. - if (!c->sparse) { - int k = 0; - for (i=0; i < c->entries; ++i) - if (include_in_sort(c, lengths[i])) - c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); - assert(k == c->sorted_entries); - } else { - for (i=0; i < c->sorted_entries; ++i) - c->sorted_codewords[i] = bit_reverse(c->codewords[i]); - } + int i, len; + // build a list of all the entries + // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN. + // this is kind of a frivolous optimization--I don't see any performance improvement, + // but it's like 4 extra lines of code, so. + if (!c->sparse) + { + int k = 0; + for (i = 0; i < c->entries; ++i) + if (include_in_sort(c, lengths[i])) + c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); + assert(k == c->sorted_entries); + } + else + { + for (i = 0; i < c->sorted_entries; ++i) + c->sorted_codewords[i] = bit_reverse(c->codewords[i]); + } - qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare); - c->sorted_codewords[c->sorted_entries] = 0xffffffff; + qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare); + c->sorted_codewords[c->sorted_entries] = 0xffffffff; - len = c->sparse ? c->sorted_entries : c->entries; - // now we need to indicate how they correspond; we could either - // #1: sort a different data structure that says who they correspond to - // #2: for each sorted entry, search the original list to find who corresponds - // #3: for each original entry, find the sorted entry - // #1 requires extra storage, #2 is slow, #3 can use binary search! - for (i=0; i < len; ++i) { - int huff_len = c->sparse ? lengths[values[i]] : lengths[i]; - if (include_in_sort(c,huff_len)) { - uint32 code = bit_reverse(c->codewords[i]); - int x=0, n=c->sorted_entries; - while (n > 1) { - // invariant: sc[x] <= code < sc[x+n] - int m = x + (n >> 1); - if (c->sorted_codewords[m] <= code) { - x = m; - n -= (n>>1); - } else { - n >>= 1; - } - } - assert(c->sorted_codewords[x] == code); - if (c->sparse) { - c->sorted_values[x] = values[i]; - c->codeword_lengths[x] = huff_len; - } else { - c->sorted_values[x] = i; - } - } - } + len = c->sparse ? c->sorted_entries : c->entries; + // now we need to indicate how they correspond; we could either + // #1: sort a different data structure that says who they correspond to + // #2: for each sorted entry, search the original list to find who corresponds + // #3: for each original entry, find the sorted entry + // #1 requires extra storage, #2 is slow, #3 can use binary search! + for (i = 0; i < len; ++i) + { + int huff_len = c->sparse ? lengths[values[i]] : lengths[i]; + if (include_in_sort(c, huff_len)) + { + uint32 code = bit_reverse(c->codewords[i]); + int x = 0, n = c->sorted_entries; + while (n > 1) + { + // invariant: sc[x] <= code < sc[x+n] + int m = x + (n >> 1); + if (c->sorted_codewords[m] <= code) + { + x = m; + n -= (n >> 1); + } + else + { + n >>= 1; + } + } + assert(c->sorted_codewords[x] == code); + if (c->sparse) + { + c->sorted_values[x] = values[i]; + c->codeword_lengths[x] = huff_len; + } + else + { + c->sorted_values[x] = i; + } + } + } } // only run while parsing the header (3 times) -static int vorbis_validate(uint8 *data) +static int vorbis_validate(uint8* data) { - static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; - return memcmp(data, vorbis, 6) == 0; + static uint8 vorbis[6] = {'v', 'o', 'r', 'b', 'i', 's'}; + return memcmp(data, vorbis, 6) == 0; } // called from setup only, once per code book // (formula implied by specification) static int lookup1_values(int entries, int dim) { - int r = (int) floor(exp((float) log((float) entries) / dim)); - if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; - ++r; // floor() to avoid _ftol() when non-CRT - assert(pow((float) r+1, dim) > entries); - assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above - return r; + int r = (int)floor(exp((float)log((float)entries) / dim)); + if ((int)floor(pow((float)r + 1, dim)) <= entries) // (int) cast for MinGW warning; + ++r; // floor() to avoid _ftol() when non-CRT + assert(pow((float) r+1, dim) > entries); + assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above + return r; } // called twice per file -static void compute_twiddle_factors(int n, float *A, float *B, float *C) +static void compute_twiddle_factors(int n, float* A, float* B, float* C) { - int n4 = n >> 2, n8 = n >> 3; - int k,k2; + int n4 = n >> 2, n8 = n >> 3; + int k, k2; - for (k=k2=0; k < n4; ++k,k2+=2) { - A[k2 ] = (float) cos(4*k*M_PI/n); - A[k2+1] = (float) -sin(4*k*M_PI/n); - B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f; - B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f; - } - for (k=k2=0; k < n8; ++k,k2+=2) { - C[k2 ] = (float) cos(2*(k2+1)*M_PI/n); - C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n); - } + for (k = k2 = 0; k < n4; ++k, k2 += 2) + { + A[k2] = (float)cos(4 * k * M_PI / n); + A[k2 + 1] = (float)-sin(4 * k * M_PI / n); + B[k2] = (float)cos((k2 + 1) * M_PI / n / 2) * 0.5f; + B[k2 + 1] = (float)sin((k2 + 1) * M_PI / n / 2) * 0.5f; + } + for (k = k2 = 0; k < n8; ++k, k2 += 2) + { + C[k2] = (float)cos(2 * (k2 + 1) * M_PI / n); + C[k2 + 1] = (float)-sin(2 * (k2 + 1) * M_PI / n); + } } -static void compute_window(int n, float *window) +static void compute_window(int n, float* window) { - int n2 = n >> 1, i; - for (i=0; i < n2; ++i) - window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); + int n2 = n >> 1, i; + for (i = 0; i < n2; ++i) + window[i] = (float)sin(0.5 * M_PI * square((float)sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); } -static void compute_bitreverse(int n, uint16 *rev) +static void compute_bitreverse(int n, uint16* rev) { - int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions - int i, n8 = n >> 3; - for (i=0; i < n8; ++i) - rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2; + int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + int i, n8 = n >> 3; + for (i = 0; i < n8; ++i) + rev[i] = (bit_reverse(i) >> (32 - ld + 3)) << 2; } -static int init_blocksize(vorb *f, int b, int n) +static int init_blocksize(vorb* f, int b, int n) { - int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3; - f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2); - f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2); - f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4); - if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem); - compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); - f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2); - if (!f->window[b]) return error(f, VORBIS_outofmem); - compute_window(n, f->window[b]); - f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8); - if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem); - compute_bitreverse(n, f->bit_reverse[b]); - return TRUE; + int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3; + f->A[b] = (float*)setup_malloc(f, sizeof(float) * n2); + f->B[b] = (float*)setup_malloc(f, sizeof(float) * n2); + f->C[b] = (float*)setup_malloc(f, sizeof(float) * n4); + if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem); + compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); + f->window[b] = (float*)setup_malloc(f, sizeof(float) * n2); + if (!f->window[b]) return error(f, VORBIS_outofmem); + compute_window(n, f->window[b]); + f->bit_reverse[b] = (uint16*)setup_malloc(f, sizeof(uint16) * n8); + if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem); + compute_bitreverse(n, f->bit_reverse[b]); + return TRUE; } -static void neighbors(uint16 *x, int n, int *plow, int *phigh) +static void neighbors(uint16* x, int n, int* plow, int* phigh) { - int low = -1; - int high = 65536; - int i; - for (i=0; i < n; ++i) { - if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; } - if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; } - } + int low = -1; + int high = 65536; + int i; + for (i = 0; i < n; ++i) + { + if (x[i] > low && x[i] < x[n]) + { + *plow = i; + low = x[i]; + } + if (x[i] < high && x[i] > x[n]) + { + *phigh = i; + high = x[i]; + } + } } // this has been repurposed so y is now the original index instead of y typedef struct { - uint16 x,id; + uint16 x, id; } stbv__floor_ordering; -static int STBV_CDECL point_compare(const void *p, const void *q) +static int STBV_CDECL point_compare(const void* p, const void* q) { - stbv__floor_ordering *a = (stbv__floor_ordering *) p; - stbv__floor_ordering *b = (stbv__floor_ordering *) q; - return a->x < b->x ? -1 : a->x > b->x; + stbv__floor_ordering* a = (stbv__floor_ordering*)p; + stbv__floor_ordering* b = (stbv__floor_ordering*)q; + return a->x < b->x ? -1 : a->x > b->x; } // @@ -952,374 +997,427 @@ static int STBV_CDECL point_compare(const void *p, const void *q) #if defined(STB_VORBIS_NO_STDIO) #define USE_MEMORY(z) TRUE #else - #define USE_MEMORY(z) ((z)->stream) +#define USE_MEMORY(z) ((z)->stream) #endif -static uint8 get8(vorb *z) +static uint8 get8(vorb* z) { - if (USE_MEMORY(z)) { - if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; } - return *z->stream++; - } + if (USE_MEMORY(z)) + { + if (z->stream >= z->stream_end) + { + z->eof = TRUE; + return 0; + } + return *z->stream++; + } - #ifndef STB_VORBIS_NO_STDIO - { - int c = fgetc(z->f); - if (c == EOF) { z->eof = TRUE; return 0; } - return c; - } - #endif +#ifndef STB_VORBIS_NO_STDIO + { + int c = fgetc(z->f); + if (c == EOF) + { + z->eof = TRUE; + return 0; + } + return c; + } +#endif } -static uint32 get32(vorb *f) +static uint32 get32(vorb* f) { - uint32 x; - x = get8(f); - x += get8(f) << 8; - x += get8(f) << 16; - x += (uint32) get8(f) << 24; - return x; + uint32 x; + x = get8(f); + x += get8(f) << 8; + x += get8(f) << 16; + x += (uint32)get8(f) << 24; + return x; } -static int getn(vorb *z, uint8 *data, int n) +static int getn(vorb* z, uint8* data, int n) { - if (USE_MEMORY(z)) { - if (z->stream+n > z->stream_end) { z->eof = 1; return 0; } - memcpy(data, z->stream, n); - z->stream += n; - return 1; - } + if (USE_MEMORY(z)) + { + if (z->stream + n > z->stream_end) + { + z->eof = 1; + return 0; + } + memcpy(data, z->stream, n); + z->stream += n; + return 1; + } - #ifndef STB_VORBIS_NO_STDIO - if (fread(data, n, 1, z->f) == 1) - return 1; - else { - z->eof = 1; - return 0; - } - #endif +#ifndef STB_VORBIS_NO_STDIO + if (fread(data, n, 1, z->f) == 1) + return 1; + else + { + z->eof = 1; + return 0; + } +#endif } -static void skip(vorb *z, int n) +static void skip(vorb* z, int n) { - if (USE_MEMORY(z)) { - z->stream += n; - if (z->stream >= z->stream_end) z->eof = 1; - return; - } - #ifndef STB_VORBIS_NO_STDIO - { - long x = ftell(z->f); - fseek(z->f, x+n, SEEK_SET); - } - #endif + if (USE_MEMORY(z)) + { + z->stream += n; + if (z->stream >= z->stream_end) z->eof = 1; + return; + } +#ifndef STB_VORBIS_NO_STDIO + { + long x = ftell(z->f); + fseek(z->f, x + n, SEEK_SET); + } +#endif } -static int set_file_offset(stb_vorbis *f, unsigned int loc) +static int set_file_offset(stb_vorbis* f, unsigned int loc) { - #ifndef STB_VORBIS_NO_PUSHDATA_API - if (f->push_mode) return 0; - #endif - f->eof = 0; - if (USE_MEMORY(f)) { - if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) { - f->stream = f->stream_end; - f->eof = 1; - return 0; - } else { - f->stream = f->stream_start + loc; - return 1; - } - } - #ifndef STB_VORBIS_NO_STDIO - if (loc + f->f_start < loc || loc >= 0x80000000) { - loc = 0x7fffffff; - f->eof = 1; - } else { - loc += f->f_start; - } - if (!fseek(f->f, loc, SEEK_SET)) - return 1; - f->eof = 1; - fseek(f->f, f->f_start, SEEK_END); - return 0; - #endif +#ifndef STB_VORBIS_NO_PUSHDATA_API + if (f->push_mode) return 0; +#endif + f->eof = 0; + if (USE_MEMORY(f)) + { + if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) + { + f->stream = f->stream_end; + f->eof = 1; + return 0; + } + else + { + f->stream = f->stream_start + loc; + return 1; + } + } +#ifndef STB_VORBIS_NO_STDIO + if (loc + f->f_start < loc || loc >= 0x80000000) + { + loc = 0x7fffffff; + f->eof = 1; + } + else + { + loc += f->f_start; + } + if (!fseek(f->f, loc, SEEK_SET)) + return 1; + f->eof = 1; + fseek(f->f, f->f_start, SEEK_END); + return 0; +#endif } -static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; +static uint8 ogg_page_header[4] = {0x4f, 0x67, 0x67, 0x53}; -static int capture_pattern(vorb *f) +static int capture_pattern(vorb* f) { - if (0x4f != get8(f)) return FALSE; - if (0x67 != get8(f)) return FALSE; - if (0x67 != get8(f)) return FALSE; - if (0x53 != get8(f)) return FALSE; - return TRUE; + if (0x4f != get8(f)) return FALSE; + if (0x67 != get8(f)) return FALSE; + if (0x67 != get8(f)) return FALSE; + if (0x53 != get8(f)) return FALSE; + return TRUE; } #define PAGEFLAG_continued_packet 1 #define PAGEFLAG_first_page 2 #define PAGEFLAG_last_page 4 -static int start_page_no_capturepattern(vorb *f) +static int start_page_no_capturepattern(vorb* f) { - uint32 loc0,loc1,n; - // stream structure version - if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); - // header flag - f->page_flag = get8(f); - // absolute granule position - loc0 = get32(f); - loc1 = get32(f); - // @TODO: validate loc0,loc1 as valid positions? - // stream serial number -- vorbis doesn't interleave, so discard - get32(f); - //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number); - // page sequence number - n = get32(f); - f->last_page = n; - // CRC32 - get32(f); - // page_segments - f->segment_count = get8(f); - if (!getn(f, f->segments, f->segment_count)) - return error(f, VORBIS_unexpected_eof); - // assume we _don't_ know any the sample position of any segments - f->end_seg_with_known_loc = -2; - if (loc0 != ~0U || loc1 != ~0U) { - int i; - // determine which packet is the last one that will complete - for (i=f->segment_count-1; i >= 0; --i) - if (f->segments[i] < 255) - break; - // 'i' is now the index of the _last_ segment of a packet that ends - if (i >= 0) { - f->end_seg_with_known_loc = i; - f->known_loc_for_packet = loc0; - } - } - if (f->first_decode) { - int i,len; - ProbedPage p; - len = 0; - for (i=0; i < f->segment_count; ++i) - len += f->segments[i]; - len += 27 + f->segment_count; - p.page_start = f->first_audio_page_offset; - p.page_end = p.page_start + len; - p.last_decoded_sample = loc0; - f->p_first = p; - } - f->next_seg = 0; - return TRUE; + uint32 loc0, loc1, n; + // stream structure version + if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); + // header flag + f->page_flag = get8(f); + // absolute granule position + loc0 = get32(f); + loc1 = get32(f); + // @TODO: validate loc0,loc1 as valid positions? + // stream serial number -- vorbis doesn't interleave, so discard + get32(f); + //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number); + // page sequence number + n = get32(f); + f->last_page = n; + // CRC32 + get32(f); + // page_segments + f->segment_count = get8(f); + if (!getn(f, f->segments, f->segment_count)) + return error(f, VORBIS_unexpected_eof); + // assume we _don't_ know any the sample position of any segments + f->end_seg_with_known_loc = -2; + if (loc0 != ~0U || loc1 != ~0U) + { + int i; + // determine which packet is the last one that will complete + for (i = f->segment_count - 1; i >= 0; --i) + if (f->segments[i] < 255) + break; + // 'i' is now the index of the _last_ segment of a packet that ends + if (i >= 0) + { + f->end_seg_with_known_loc = i; + f->known_loc_for_packet = loc0; + } + } + if (f->first_decode) + { + int i, len; + ProbedPage p; + len = 0; + for (i = 0; i < f->segment_count; ++i) + len += f->segments[i]; + len += 27 + f->segment_count; + p.page_start = f->first_audio_page_offset; + p.page_end = p.page_start + len; + p.last_decoded_sample = loc0; + f->p_first = p; + } + f->next_seg = 0; + return TRUE; } -static int start_page(vorb *f) +static int start_page(vorb* f) { - if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern); - return start_page_no_capturepattern(f); + if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern); + return start_page_no_capturepattern(f); } -static int start_packet(vorb *f) +static int start_packet(vorb* f) { - while (f->next_seg == -1) { - if (!start_page(f)) return FALSE; - if (f->page_flag & PAGEFLAG_continued_packet) - return error(f, VORBIS_continued_packet_flag_invalid); - } - f->last_seg = FALSE; - f->valid_bits = 0; - f->packet_bytes = 0; - f->bytes_in_seg = 0; - // f->next_seg is now valid - return TRUE; + while (f->next_seg == -1) + { + if (!start_page(f)) return FALSE; + if (f->page_flag & PAGEFLAG_continued_packet) + return error(f, VORBIS_continued_packet_flag_invalid); + } + f->last_seg = FALSE; + f->valid_bits = 0; + f->packet_bytes = 0; + f->bytes_in_seg = 0; + // f->next_seg is now valid + return TRUE; } -static int maybe_start_packet(vorb *f) +static int maybe_start_packet(vorb* f) { - if (f->next_seg == -1) { - int x = get8(f); - if (f->eof) return FALSE; // EOF at page boundary is not an error! - if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern); - if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); - if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); - if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern); - if (!start_page_no_capturepattern(f)) return FALSE; - if (f->page_flag & PAGEFLAG_continued_packet) { - // set up enough state that we can read this packet if we want, - // e.g. during recovery - f->last_seg = FALSE; - f->bytes_in_seg = 0; - return error(f, VORBIS_continued_packet_flag_invalid); - } - } - return start_packet(f); + if (f->next_seg == -1) + { + int x = get8(f); + if (f->eof) return FALSE; // EOF at page boundary is not an error! + if (0x4f != x) return error(f, VORBIS_missing_capture_pattern); + if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (!start_page_no_capturepattern(f)) return FALSE; + if (f->page_flag & PAGEFLAG_continued_packet) + { + // set up enough state that we can read this packet if we want, + // e.g. during recovery + f->last_seg = FALSE; + f->bytes_in_seg = 0; + return error(f, VORBIS_continued_packet_flag_invalid); + } + } + return start_packet(f); } -static int next_segment(vorb *f) +static int next_segment(vorb* f) { - int len; - if (f->last_seg) return 0; - if (f->next_seg == -1) { - f->last_seg_which = f->segment_count-1; // in case start_page fails - if (!start_page(f)) { f->last_seg = 1; return 0; } - if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid); - } - len = f->segments[f->next_seg++]; - if (len < 255) { - f->last_seg = TRUE; - f->last_seg_which = f->next_seg-1; - } - if (f->next_seg >= f->segment_count) - f->next_seg = -1; - assert(f->bytes_in_seg == 0); - f->bytes_in_seg = len; - return len; + int len; + if (f->last_seg) return 0; + if (f->next_seg == -1) + { + f->last_seg_which = f->segment_count - 1; // in case start_page fails + if (!start_page(f)) + { + f->last_seg = 1; + return 0; + } + if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid); + } + len = f->segments[f->next_seg++]; + if (len < 255) + { + f->last_seg = TRUE; + f->last_seg_which = f->next_seg - 1; + } + if (f->next_seg >= f->segment_count) + f->next_seg = -1; + assert(f->bytes_in_seg == 0); + f->bytes_in_seg = len; + return len; } #define EOP (-1) #define INVALID_BITS (-1) -static int get8_packet_raw(vorb *f) +static int get8_packet_raw(vorb* f) { - if (!f->bytes_in_seg) { // CLANG! - if (f->last_seg) return EOP; - else if (!next_segment(f)) return EOP; - } - assert(f->bytes_in_seg > 0); - --f->bytes_in_seg; - ++f->packet_bytes; - return get8(f); + if (!f->bytes_in_seg) + { + // CLANG! + if (f->last_seg) return EOP; + else if (!next_segment(f)) return EOP; + } + assert(f->bytes_in_seg > 0); + --f->bytes_in_seg; + ++f->packet_bytes; + return get8(f); } -static int get8_packet(vorb *f) +static int get8_packet(vorb* f) { - int x = get8_packet_raw(f); - f->valid_bits = 0; - return x; + int x = get8_packet_raw(f); + f->valid_bits = 0; + return x; } -static void flush_packet(vorb *f) +static void flush_packet(vorb* f) { - while (get8_packet_raw(f) != EOP); + while (get8_packet_raw(f) != EOP); } // @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important // as the huffman decoder? -static uint32 get_bits(vorb *f, int n) +static uint32 get_bits(vorb* f, int n) { - uint32 z; + uint32 z; - if (f->valid_bits < 0) return 0; - if (f->valid_bits < n) { - if (n > 24) { - // the accumulator technique below would not work correctly in this case - z = get_bits(f, 24); - z += get_bits(f, n-24) << 24; - return z; - } - if (f->valid_bits == 0) f->acc = 0; - while (f->valid_bits < n) { - int z = get8_packet_raw(f); - if (z == EOP) { - f->valid_bits = INVALID_BITS; - return 0; - } - f->acc += z << f->valid_bits; - f->valid_bits += 8; - } - } - if (f->valid_bits < 0) return 0; - z = f->acc & ((1 << n)-1); - f->acc >>= n; - f->valid_bits -= n; - return z; + if (f->valid_bits < 0) return 0; + if (f->valid_bits < n) + { + if (n > 24) + { + // the accumulator technique below would not work correctly in this case + z = get_bits(f, 24); + z += get_bits(f, n - 24) << 24; + return z; + } + if (f->valid_bits == 0) f->acc = 0; + while (f->valid_bits < n) + { + int z = get8_packet_raw(f); + if (z == EOP) + { + f->valid_bits = INVALID_BITS; + return 0; + } + f->acc += z << f->valid_bits; + f->valid_bits += 8; + } + } + if (f->valid_bits < 0) return 0; + z = f->acc & ((1 << n) - 1); + f->acc >>= n; + f->valid_bits -= n; + return z; } // @OPTIMIZE: primary accumulator for huffman // expand the buffer to as many bits as possible without reading off end of packet // it might be nice to allow f->valid_bits and f->acc to be stored in registers, // e.g. cache them locally and decode locally -static __forceinline void prep_huffman(vorb *f) +static __forceinline void prep_huffman(vorb* f) { - if (f->valid_bits <= 24) { - if (f->valid_bits == 0) f->acc = 0; - do { - int z; - if (f->last_seg && !f->bytes_in_seg) return; - z = get8_packet_raw(f); - if (z == EOP) return; - f->acc += (unsigned) z << f->valid_bits; - f->valid_bits += 8; - } while (f->valid_bits <= 24); - } + if (f->valid_bits <= 24) + { + if (f->valid_bits == 0) f->acc = 0; + do + { + int z; + if (f->last_seg && !f->bytes_in_seg) return; + z = get8_packet_raw(f); + if (z == EOP) return; + f->acc += (unsigned)z << f->valid_bits; + f->valid_bits += 8; + } + while (f->valid_bits <= 24); + } } enum { - VORBIS_packet_id = 1, - VORBIS_packet_comment = 3, - VORBIS_packet_setup = 5 + VORBIS_packet_id = 1, + VORBIS_packet_comment = 3, + VORBIS_packet_setup = 5 }; -static int codebook_decode_scalar_raw(vorb *f, Codebook *c) +static int codebook_decode_scalar_raw(vorb* f, Codebook* c) { - int i; - prep_huffman(f); + int i; + prep_huffman(f); - if (c->codewords == NULL && c->sorted_codewords == NULL) - return -1; + if (c->codewords == NULL && c->sorted_codewords == NULL) + return -1; - // cases to use binary search: sorted_codewords && !c->codewords - // sorted_codewords && c->entries > 8 - if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { - // binary search - uint32 code = bit_reverse(f->acc); - int x=0, n=c->sorted_entries, len; + // cases to use binary search: sorted_codewords && !c->codewords + // sorted_codewords && c->entries > 8 + if (c->entries > 8 ? c->sorted_codewords != NULL : !c->codewords) + { + // binary search + uint32 code = bit_reverse(f->acc); + int x = 0, n = c->sorted_entries, len; - while (n > 1) { - // invariant: sc[x] <= code < sc[x+n] - int m = x + (n >> 1); - if (c->sorted_codewords[m] <= code) { - x = m; - n -= (n>>1); - } else { - n >>= 1; - } - } - // x is now the sorted index - if (!c->sparse) x = c->sorted_values[x]; - // x is now sorted index if sparse, or symbol otherwise - len = c->codeword_lengths[x]; - if (f->valid_bits >= len) { - f->acc >>= len; - f->valid_bits -= len; - return x; - } + while (n > 1) + { + // invariant: sc[x] <= code < sc[x+n] + int m = x + (n >> 1); + if (c->sorted_codewords[m] <= code) + { + x = m; + n -= (n >> 1); + } + else + { + n >>= 1; + } + } + // x is now the sorted index + if (!c->sparse) x = c->sorted_values[x]; + // x is now sorted index if sparse, or symbol otherwise + len = c->codeword_lengths[x]; + if (f->valid_bits >= len) + { + f->acc >>= len; + f->valid_bits -= len; + return x; + } - f->valid_bits = 0; - return -1; - } + f->valid_bits = 0; + return -1; + } - // if small, linear search - assert(!c->sparse); - for (i=0; i < c->entries; ++i) { - if (c->codeword_lengths[i] == NO_CODE) continue; - if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i])-1))) { - if (f->valid_bits >= c->codeword_lengths[i]) { - f->acc >>= c->codeword_lengths[i]; - f->valid_bits -= c->codeword_lengths[i]; - return i; - } - f->valid_bits = 0; - return -1; - } - } + // if small, linear search + assert(!c->sparse); + for (i = 0; i < c->entries; ++i) + { + if (c->codeword_lengths[i] == NO_CODE) continue; + if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i]) - 1))) + { + if (f->valid_bits >= c->codeword_lengths[i]) + { + f->acc >>= c->codeword_lengths[i]; + f->valid_bits -= c->codeword_lengths[i]; + return i; + } + f->valid_bits = 0; + return -1; + } + } - error(f, VORBIS_invalid_stream); - f->valid_bits = 0; - return -1; + error(f, VORBIS_invalid_stream); + f->valid_bits = 0; + return -1; } #ifndef STB_VORBIS_NO_INLINE_DECODE @@ -1366,47 +1464,47 @@ static int codebook_decode_scalar(vorb *f, Codebook *c) if (c->sparse) var = c->sorted_values[var]; #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c) +#define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c) #else #define DECODE_VQ(var,f,c) DECODE(var,f,c) #endif - - - - // CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case // where we avoid one addition #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) #define CODEBOOK_ELEMENT_BASE(c) (0) -static int codebook_decode_start(vorb *f, Codebook *c) +static int codebook_decode_start(vorb* f, Codebook* c) { - int z = -1; + int z = -1; - // type 0 is only legal in a scalar context - if (c->lookup_type == 0) - error(f, VORBIS_invalid_stream); - else { - DECODE_VQ(z,f,c); - if (c->sparse) assert(z < c->sorted_entries); - if (z < 0) { // check for EOP - if (!f->bytes_in_seg) - if (f->last_seg) - return z; - error(f, VORBIS_invalid_stream); - } - } - return z; + // type 0 is only legal in a scalar context + if (c->lookup_type == 0) + error(f, VORBIS_invalid_stream); + else + { + DECODE_VQ(z, f, c); + if (c->sparse) + assert(z < c->sorted_entries); + if (z < 0) + { + // check for EOP + if (!f->bytes_in_seg) + if (f->last_seg) + return z; + error(f, VORBIS_invalid_stream); + } + } + return z; } -static int codebook_decode(vorb *f, Codebook *c, float *output, int len) +static int codebook_decode(vorb* f, Codebook* c, float* output, int len) { - int i,z = codebook_decode_start(f,c); - if (z < 0) return FALSE; - if (len > c->dimensions) len = c->dimensions; + int i, z = codebook_decode_start(f, c); + if (z < 0) return FALSE; + if (len > c->dimensions) len = c->dimensions; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { @@ -1423,30 +1521,35 @@ static int codebook_decode(vorb *f, Codebook *c, float *output, int len) } #endif - z *= c->dimensions; - if (c->sequence_p) { - float last = CODEBOOK_ELEMENT_BASE(c); - for (i=0; i < len; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; - output[i] += val; - last = val + c->minimum_value; - } - } else { - float last = CODEBOOK_ELEMENT_BASE(c); - for (i=0; i < len; ++i) { - output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last; - } - } + z *= c->dimensions; + if (c->sequence_p) + { + float last = CODEBOOK_ELEMENT_BASE(c); + for (i = 0; i < len; ++i) + { + float val = CODEBOOK_ELEMENT_FAST(c, z+i) + last; + output[i] += val; + last = val + c->minimum_value; + } + } + else + { + float last = CODEBOOK_ELEMENT_BASE(c); + for (i = 0; i < len; ++i) + { + output[i] += CODEBOOK_ELEMENT_FAST(c, z+i) + last; + } + } - return TRUE; + return TRUE; } -static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step) +static int codebook_decode_step(vorb* f, Codebook* c, float* output, int len, int step) { - int i,z = codebook_decode_start(f,c); - float last = CODEBOOK_ELEMENT_BASE(c); - if (z < 0) return FALSE; - if (len > c->dimensions) len = c->dimensions; + int i, z = codebook_decode_start(f, c); + float last = CODEBOOK_ELEMENT_BASE(c); + if (z < 0) return FALSE; + if (len > c->dimensions) len = c->dimensions; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { @@ -1462,46 +1565,51 @@ static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, in } #endif - z *= c->dimensions; - for (i=0; i < len; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; - output[i*step] += val; - if (c->sequence_p) last = val; - } + z *= c->dimensions; + for (i = 0; i < len; ++i) + { + float val = CODEBOOK_ELEMENT_FAST(c, z+i) + last; + output[i * step] += val; + if (c->sequence_p) last = val; + } - return TRUE; + return TRUE; } -static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) +static int codebook_decode_deinterleave_repeat(vorb* f, Codebook* c, float** outputs, int ch, int* c_inter_p, + int* p_inter_p, int len, int total_decode) { - int c_inter = *c_inter_p; - int p_inter = *p_inter_p; - int i,z, effective = c->dimensions; + int c_inter = *c_inter_p; + int p_inter = *p_inter_p; + int i, z, effective = c->dimensions; - // type 0 is only legal in a scalar context - if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); + // type 0 is only legal in a scalar context + if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); - while (total_decode > 0) { - float last = CODEBOOK_ELEMENT_BASE(c); - DECODE_VQ(z,f,c); - #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - assert(!c->sparse || z < c->sorted_entries); - #endif - if (z < 0) { - if (!f->bytes_in_seg) - if (f->last_seg) return FALSE; - return error(f, VORBIS_invalid_stream); - } + while (total_decode > 0) + { + float last = CODEBOOK_ELEMENT_BASE(c); + DECODE_VQ(z, f, c); +#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK + assert(!c->sparse || z < c->sorted_entries); +#endif + if (z < 0) + { + if (!f->bytes_in_seg) + if (f->last_seg) return FALSE; + return error(f, VORBIS_invalid_stream); + } - // if this will take us off the end of the buffers, stop short! - // we check by computing the length of the virtual interleaved - // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter), - // and the length we'll be using (effective) - if (c_inter + p_inter*ch + effective > len * ch) { - effective = len*ch - (p_inter*ch - c_inter); - } + // if this will take us off the end of the buffers, stop short! + // we check by computing the length of the virtual interleaved + // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter), + // and the length we'll be using (effective) + if (c_inter + p_inter * ch + effective > len * ch) + { + effective = len * ch - (p_inter * ch - c_inter); + } - #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK +#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { int div = 1; for (i=0; i < effective; ++i) { @@ -1514,111 +1622,124 @@ static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **out div *= c->lookup_values; } } else - #endif - { - z *= c->dimensions; - if (c->sequence_p) { - for (i=0; i < effective; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; - if (outputs[c_inter]) - outputs[c_inter][p_inter] += val; - if (++c_inter == ch) { c_inter = 0; ++p_inter; } - last = val; - } - } else { - for (i=0; i < effective; ++i) { - float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; - if (outputs[c_inter]) - outputs[c_inter][p_inter] += val; - if (++c_inter == ch) { c_inter = 0; ++p_inter; } - } - } - } +#endif + { + z *= c->dimensions; + if (c->sequence_p) + { + for (i = 0; i < effective; ++i) + { + float val = CODEBOOK_ELEMENT_FAST(c, z+i) + last; + if (outputs[c_inter]) + outputs[c_inter][p_inter] += val; + if (++c_inter == ch) + { + c_inter = 0; + ++p_inter; + } + last = val; + } + } + else + { + for (i = 0; i < effective; ++i) + { + float val = CODEBOOK_ELEMENT_FAST(c, z+i) + last; + if (outputs[c_inter]) + outputs[c_inter][p_inter] += val; + if (++c_inter == ch) + { + c_inter = 0; + ++p_inter; + } + } + } + } - total_decode -= effective; - } - *c_inter_p = c_inter; - *p_inter_p = p_inter; - return TRUE; + total_decode -= effective; + } + *c_inter_p = c_inter; + *p_inter_p = p_inter; + return TRUE; } static int predict_point(int x, int x0, int x1, int y0, int y1) { - int dy = y1 - y0; - int adx = x1 - x0; - // @OPTIMIZE: force int division to round in the right direction... is this necessary on x86? - int err = abs(dy) * (x - x0); - int off = err / adx; - return dy < 0 ? y0 - off : y0 + off; + int dy = y1 - y0; + int adx = x1 - x0; + // @OPTIMIZE: force int division to round in the right direction... is this necessary on x86? + int err = abs(dy) * (x - x0); + int off = err / adx; + return dy < 0 ? y0 - off : y0 + off; } // the following table is block-copied from the specification static float inverse_db_table[256] = { - 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, - 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, - 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, - 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, - 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, - 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, - 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, - 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, - 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, - 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, - 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, - 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, - 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, - 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, - 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, - 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, - 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, - 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, - 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, - 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, - 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, - 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, - 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, - 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, - 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, - 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, - 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, - 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, - 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, - 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, - 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, - 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, - 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, - 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, - 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, - 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, - 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, - 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, - 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, - 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, - 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, - 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, - 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, - 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, - 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, - 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, - 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, - 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, - 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, - 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, - 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, - 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, - 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, - 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, - 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, - 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, - 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, - 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, - 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, - 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, - 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, - 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, - 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, - 0.82788260f, 0.88168307f, 0.9389798f, 1.0f + 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, + 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, + 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, + 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, + 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, + 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, + 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, + 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, + 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, + 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, + 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, + 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, + 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, + 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, + 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, + 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, + 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, + 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, + 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, + 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, + 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, + 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, + 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, + 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, + 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, + 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, + 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, + 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, + 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, + 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, + 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, + 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, + 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, + 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, + 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, + 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, + 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, + 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, + 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, + 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, + 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, + 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, + 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, + 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, + 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, + 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, + 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, + 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, + 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, + 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, + 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, + 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, + 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, + 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, + 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, + 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, + 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, + 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, + 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, + 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, + 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, + 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, + 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, + 0.82788260f, 0.88168307f, 0.9389798f, 1.0f }; @@ -1641,15 +1762,15 @@ static float inverse_db_table[256] = int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB #endif -static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n) +static __forceinline void draw_line(float* output, int x0, int y0, int x1, int y1, int n) { - int dy = y1 - y0; - int adx = x1 - x0; - int ady = abs(dy); - int base; - int x=x0,y=y0; - int err = 0; - int sy; + int dy = y1 - y0; + int adx = x1 - x0; + int ady = abs(dy); + int base; + int x = x0, y = y0; + int err = 0; + int sy; #ifdef STB_VORBIS_DIVIDE_TABLE if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) { @@ -1668,259 +1789,304 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y sy = base+1; } #else - base = dy / adx; - if (dy < 0) - sy = base - 1; - else - sy = base+1; + base = dy / adx; + if (dy < 0) + sy = base - 1; + else + sy = base + 1; #endif - ady -= abs(base) * adx; - if (x1 > n) x1 = n; - if (x < x1) { - LINE_OP(output[x], inverse_db_table[y]); - for (++x; x < x1; ++x) { - err += ady; - if (err >= adx) { - err -= adx; - y += sy; - } else - y += base; - LINE_OP(output[x], inverse_db_table[y]); - } - } + ady -= abs(base) * adx; + if (x1 > n) x1 = n; + if (x < x1) + { + LINE_OP(output[x], inverse_db_table[y]); + for (++x; x < x1; ++x) + { + err += ady; + if (err >= adx) + { + err -= adx; + y += sy; + } + else + y += base; + LINE_OP(output[x], inverse_db_table[y]); + } + } } -static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype) +static int residue_decode(vorb* f, Codebook* book, float* target, int offset, int n, int rtype) { - int k; - if (rtype == 0) { - int step = n / book->dimensions; - for (k=0; k < step; ++k) - if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) - return FALSE; - } else { - for (k=0; k < n; ) { - if (!codebook_decode(f, book, target+offset, n-k)) - return FALSE; - k += book->dimensions; - offset += book->dimensions; - } - } - return TRUE; + int k; + if (rtype == 0) + { + int step = n / book->dimensions; + for (k = 0; k < step; ++k) + if (!codebook_decode_step(f, book, target + offset + k, n - offset - k, step)) + return FALSE; + } + else + { + for (k = 0; k < n;) + { + if (!codebook_decode(f, book, target + offset, n - k)) + return FALSE; + k += book->dimensions; + offset += book->dimensions; + } + } + return TRUE; } -static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) +static void decode_residue(vorb* f, float* residue_buffers[], int ch, int n, int rn, uint8* do_not_decode) { - int i,j,pass; - Residue *r = f->residue_config + rn; - int rtype = f->residue_types[rn]; - int c = r->classbook; - int classwords = f->codebooks[c].dimensions; - int n_read = r->end - r->begin; - int part_read = n_read / r->part_size; - int temp_alloc_point = temp_alloc_save(f); - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); - #else + int i, j, pass; + Residue* r = f->residue_config + rn; + int rtype = f->residue_types[rn]; + int c = r->classbook; + int classwords = f->codebooks[c].dimensions; + int n_read = r->end - r->begin; + int part_read = n_read / r->part_size; + int temp_alloc_point = temp_alloc_save(f); +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + uint8*** part_classdata = (uint8***)temp_block_array(f, f->channels, part_read * sizeof(**part_classdata)); +#else int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); - #endif +#endif - CHECK(f); + CHECK(f); - for (i=0; i < ch; ++i) - if (!do_not_decode[i]) - memset(residue_buffers[i], 0, sizeof(float) * n); + for (i = 0; i < ch; ++i) + if (!do_not_decode[i]) + memset(residue_buffers[i], 0, sizeof(float) * n); - if (rtype == 2 && ch != 1) { - for (j=0; j < ch; ++j) - if (!do_not_decode[j]) - break; - if (j == ch) - goto done; + if (rtype == 2 && ch != 1) + { + for (j = 0; j < ch; ++j) + if (!do_not_decode[j]) + break; + if (j == ch) + goto done; - for (pass=0; pass < 8; ++pass) { - int pcount = 0, class_set = 0; - if (ch == 2) { - while (pcount < part_read) { - int z = r->begin + pcount*r->part_size; - int c_inter = (z & 1), p_inter = z>>1; - if (pass == 0) { - Codebook *c = f->codebooks+r->classbook; - int q; - DECODE(q,f,c); - if (q == EOP) goto done; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - part_classdata[0][class_set] = r->classdata[q]; - #else + for (pass = 0; pass < 8; ++pass) + { + int pcount = 0, class_set = 0; + if (ch == 2) + { + while (pcount < part_read) + { + int z = r->begin + pcount * r->part_size; + int c_inter = (z & 1), p_inter = z >> 1; + if (pass == 0) + { + Codebook* c = f->codebooks + r->classbook; + int q; + DECODE(q, f, c); + if (q == EOP) goto done; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[0][class_set] = r->classdata[q]; +#else for (i=classwords-1; i >= 0; --i) { classifications[0][i+pcount] = q % r->classifications; q /= r->classifications; } - #endif - } - for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { - int z = r->begin + pcount*r->part_size; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - int c = part_classdata[0][class_set][i]; - #else +#endif + } + for (i = 0; i < classwords && pcount < part_read; ++i, ++pcount) + { + int z = r->begin + pcount * r->part_size; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[0][class_set][i]; +#else int c = classifications[0][pcount]; - #endif - int b = r->residue_books[c][pass]; - if (b >= 0) { - Codebook *book = f->codebooks + b; - #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK +#endif + int b = r->residue_books[c][pass]; + if (b >= 0) + { + Codebook* book = f->codebooks + b; +#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; - #else - // saves 1% - if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) - goto done; - #endif - } else { - z += r->part_size; - c_inter = z & 1; - p_inter = z >> 1; - } - } - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - ++class_set; - #endif - } - } else if (ch == 1) { - while (pcount < part_read) { - int z = r->begin + pcount*r->part_size; - int c_inter = 0, p_inter = z; - if (pass == 0) { - Codebook *c = f->codebooks+r->classbook; - int q; - DECODE(q,f,c); - if (q == EOP) goto done; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - part_classdata[0][class_set] = r->classdata[q]; - #else +#else + // saves 1% + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, + r->part_size)) + goto done; +#endif + } + else + { + z += r->part_size; + c_inter = z & 1; + p_inter = z >> 1; + } + } +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; +#endif + } + } + else if (ch == 1) + { + while (pcount < part_read) + { + int z = r->begin + pcount * r->part_size; + int c_inter = 0, p_inter = z; + if (pass == 0) + { + Codebook* c = f->codebooks + r->classbook; + int q; + DECODE(q, f, c); + if (q == EOP) goto done; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[0][class_set] = r->classdata[q]; +#else for (i=classwords-1; i >= 0; --i) { classifications[0][i+pcount] = q % r->classifications; q /= r->classifications; } - #endif - } - for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { - int z = r->begin + pcount*r->part_size; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - int c = part_classdata[0][class_set][i]; - #else +#endif + } + for (i = 0; i < classwords && pcount < part_read; ++i, ++pcount) + { + int z = r->begin + pcount * r->part_size; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[0][class_set][i]; +#else int c = classifications[0][pcount]; - #endif - int b = r->residue_books[c][pass]; - if (b >= 0) { - Codebook *book = f->codebooks + b; - if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) - goto done; - } else { - z += r->part_size; - c_inter = 0; - p_inter = z; - } - } - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - ++class_set; - #endif - } - } else { - while (pcount < part_read) { - int z = r->begin + pcount*r->part_size; - int c_inter = z % ch, p_inter = z/ch; - if (pass == 0) { - Codebook *c = f->codebooks+r->classbook; - int q; - DECODE(q,f,c); - if (q == EOP) goto done; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - part_classdata[0][class_set] = r->classdata[q]; - #else +#endif + int b = r->residue_books[c][pass]; + if (b >= 0) + { + Codebook* book = f->codebooks + b; + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, + r->part_size)) + goto done; + } + else + { + z += r->part_size; + c_inter = 0; + p_inter = z; + } + } +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; +#endif + } + } + else + { + while (pcount < part_read) + { + int z = r->begin + pcount * r->part_size; + int c_inter = z % ch, p_inter = z / ch; + if (pass == 0) + { + Codebook* c = f->codebooks + r->classbook; + int q; + DECODE(q, f, c); + if (q == EOP) goto done; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[0][class_set] = r->classdata[q]; +#else for (i=classwords-1; i >= 0; --i) { classifications[0][i+pcount] = q % r->classifications; q /= r->classifications; } - #endif - } - for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { - int z = r->begin + pcount*r->part_size; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - int c = part_classdata[0][class_set][i]; - #else +#endif + } + for (i = 0; i < classwords && pcount < part_read; ++i, ++pcount) + { + int z = r->begin + pcount * r->part_size; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[0][class_set][i]; +#else int c = classifications[0][pcount]; - #endif - int b = r->residue_books[c][pass]; - if (b >= 0) { - Codebook *book = f->codebooks + b; - if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) - goto done; - } else { - z += r->part_size; - c_inter = z % ch; - p_inter = z / ch; - } - } - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - ++class_set; - #endif - } - } - } - goto done; - } - CHECK(f); +#endif + int b = r->residue_books[c][pass]; + if (b >= 0) + { + Codebook* book = f->codebooks + b; + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, + r->part_size)) + goto done; + } + else + { + z += r->part_size; + c_inter = z % ch; + p_inter = z / ch; + } + } +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; +#endif + } + } + } + goto done; + } + CHECK(f); - for (pass=0; pass < 8; ++pass) { - int pcount = 0, class_set=0; - while (pcount < part_read) { - if (pass == 0) { - for (j=0; j < ch; ++j) { - if (!do_not_decode[j]) { - Codebook *c = f->codebooks+r->classbook; - int temp; - DECODE(temp,f,c); - if (temp == EOP) goto done; - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - part_classdata[j][class_set] = r->classdata[temp]; - #else + for (pass = 0; pass < 8; ++pass) + { + int pcount = 0, class_set = 0; + while (pcount < part_read) + { + if (pass == 0) + { + for (j = 0; j < ch; ++j) + { + if (!do_not_decode[j]) + { + Codebook* c = f->codebooks + r->classbook; + int temp; + DECODE(temp, f, c); + if (temp == EOP) goto done; +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[j][class_set] = r->classdata[temp]; +#else for (i=classwords-1; i >= 0; --i) { classifications[j][i+pcount] = temp % r->classifications; temp /= r->classifications; } - #endif - } - } - } - for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { - for (j=0; j < ch; ++j) { - if (!do_not_decode[j]) { - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - int c = part_classdata[j][class_set][i]; - #else +#endif + } + } + } + for (i = 0; i < classwords && pcount < part_read; ++i, ++pcount) + { + for (j = 0; j < ch; ++j) + { + if (!do_not_decode[j]) + { +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[j][class_set][i]; +#else int c = classifications[j][pcount]; - #endif - int b = r->residue_books[c][pass]; - if (b >= 0) { - float *target = residue_buffers[j]; - int offset = r->begin + pcount * r->part_size; - int n = r->part_size; - Codebook *book = f->codebooks + b; - if (!residue_decode(f, book, target, offset, n, rtype)) - goto done; - } - } - } - } - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - ++class_set; - #endif - } - } - done: - CHECK(f); - temp_alloc_restore(f,temp_alloc_point); +#endif + int b = r->residue_books[c][pass]; + if (b >= 0) + { + float* target = residue_buffers[j]; + int offset = r->begin + pcount * r->part_size; + int n = r->part_size; + Codebook* book = f->codebooks + b; + if (!residue_decode(f, book, target, offset, n, rtype)) + goto done; + } + } + } + } +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; +#endif + } + } +done: + CHECK(f); + temp_alloc_restore(f, temp_alloc_point); } @@ -2045,527 +2211,540 @@ void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) // the following were split out into separate functions while optimizing; // they could be pushed back up but eh. __forceinline showed no change; // they're probably already being inlined. -static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) +static void imdct_step3_iter0_loop(int n, float* e, int i_off, int k_off, float* A) { - float *ee0 = e + i_off; - float *ee2 = ee0 + k_off; - int i; + float* ee0 = e + i_off; + float* ee2 = ee0 + k_off; + int i; - assert((n & 3) == 0); - for (i=(n>>2); i > 0; --i) { - float k00_20, k01_21; - k00_20 = ee0[ 0] - ee2[ 0]; - k01_21 = ee0[-1] - ee2[-1]; - ee0[ 0] += ee2[ 0];//ee0[ 0] = ee0[ 0] + ee2[ 0]; - ee0[-1] += ee2[-1];//ee0[-1] = ee0[-1] + ee2[-1]; - ee2[ 0] = k00_20 * A[0] - k01_21 * A[1]; - ee2[-1] = k01_21 * A[0] + k00_20 * A[1]; - A += 8; + assert((n & 3) == 0); + for (i = (n >> 2); i > 0; --i) + { + float k00_20, k01_21; + k00_20 = ee0[0] - ee2[0]; + k01_21 = ee0[-1] - ee2[-1]; + ee0[0] += ee2[0]; //ee0[ 0] = ee0[ 0] + ee2[ 0]; + ee0[-1] += ee2[-1]; //ee0[-1] = ee0[-1] + ee2[-1]; + ee2[0] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-1] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; - k00_20 = ee0[-2] - ee2[-2]; - k01_21 = ee0[-3] - ee2[-3]; - ee0[-2] += ee2[-2];//ee0[-2] = ee0[-2] + ee2[-2]; - ee0[-3] += ee2[-3];//ee0[-3] = ee0[-3] + ee2[-3]; - ee2[-2] = k00_20 * A[0] - k01_21 * A[1]; - ee2[-3] = k01_21 * A[0] + k00_20 * A[1]; - A += 8; + k00_20 = ee0[-2] - ee2[-2]; + k01_21 = ee0[-3] - ee2[-3]; + ee0[-2] += ee2[-2]; //ee0[-2] = ee0[-2] + ee2[-2]; + ee0[-3] += ee2[-3]; //ee0[-3] = ee0[-3] + ee2[-3]; + ee2[-2] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-3] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; - k00_20 = ee0[-4] - ee2[-4]; - k01_21 = ee0[-5] - ee2[-5]; - ee0[-4] += ee2[-4];//ee0[-4] = ee0[-4] + ee2[-4]; - ee0[-5] += ee2[-5];//ee0[-5] = ee0[-5] + ee2[-5]; - ee2[-4] = k00_20 * A[0] - k01_21 * A[1]; - ee2[-5] = k01_21 * A[0] + k00_20 * A[1]; - A += 8; + k00_20 = ee0[-4] - ee2[-4]; + k01_21 = ee0[-5] - ee2[-5]; + ee0[-4] += ee2[-4]; //ee0[-4] = ee0[-4] + ee2[-4]; + ee0[-5] += ee2[-5]; //ee0[-5] = ee0[-5] + ee2[-5]; + ee2[-4] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-5] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; - k00_20 = ee0[-6] - ee2[-6]; - k01_21 = ee0[-7] - ee2[-7]; - ee0[-6] += ee2[-6];//ee0[-6] = ee0[-6] + ee2[-6]; - ee0[-7] += ee2[-7];//ee0[-7] = ee0[-7] + ee2[-7]; - ee2[-6] = k00_20 * A[0] - k01_21 * A[1]; - ee2[-7] = k01_21 * A[0] + k00_20 * A[1]; - A += 8; - ee0 -= 8; - ee2 -= 8; - } + k00_20 = ee0[-6] - ee2[-6]; + k01_21 = ee0[-7] - ee2[-7]; + ee0[-6] += ee2[-6]; //ee0[-6] = ee0[-6] + ee2[-6]; + ee0[-7] += ee2[-7]; //ee0[-7] = ee0[-7] + ee2[-7]; + ee2[-6] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-7] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; + ee0 -= 8; + ee2 -= 8; + } } -static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) +static void imdct_step3_inner_r_loop(int lim, float* e, int d0, int k_off, float* A, int k1) { - int i; - float k00_20, k01_21; + int i; + float k00_20, k01_21; - float *e0 = e + d0; - float *e2 = e0 + k_off; + float* e0 = e + d0; + float* e2 = e0 + k_off; - for (i=lim >> 2; i > 0; --i) { - k00_20 = e0[-0] - e2[-0]; - k01_21 = e0[-1] - e2[-1]; - e0[-0] += e2[-0];//e0[-0] = e0[-0] + e2[-0]; - e0[-1] += e2[-1];//e0[-1] = e0[-1] + e2[-1]; - e2[-0] = (k00_20)*A[0] - (k01_21) * A[1]; - e2[-1] = (k01_21)*A[0] + (k00_20) * A[1]; + for (i = lim >> 2; i > 0; --i) + { + k00_20 = e0[-0] - e2[-0]; + k01_21 = e0[-1] - e2[-1]; + e0[-0] += e2[-0]; //e0[-0] = e0[-0] + e2[-0]; + e0[-1] += e2[-1]; //e0[-1] = e0[-1] + e2[-1]; + e2[-0] = (k00_20) * A[0] - (k01_21) * A[1]; + e2[-1] = (k01_21) * A[0] + (k00_20) * A[1]; - A += k1; + A += k1; - k00_20 = e0[-2] - e2[-2]; - k01_21 = e0[-3] - e2[-3]; - e0[-2] += e2[-2];//e0[-2] = e0[-2] + e2[-2]; - e0[-3] += e2[-3];//e0[-3] = e0[-3] + e2[-3]; - e2[-2] = (k00_20)*A[0] - (k01_21) * A[1]; - e2[-3] = (k01_21)*A[0] + (k00_20) * A[1]; + k00_20 = e0[-2] - e2[-2]; + k01_21 = e0[-3] - e2[-3]; + e0[-2] += e2[-2]; //e0[-2] = e0[-2] + e2[-2]; + e0[-3] += e2[-3]; //e0[-3] = e0[-3] + e2[-3]; + e2[-2] = (k00_20) * A[0] - (k01_21) * A[1]; + e2[-3] = (k01_21) * A[0] + (k00_20) * A[1]; - A += k1; + A += k1; - k00_20 = e0[-4] - e2[-4]; - k01_21 = e0[-5] - e2[-5]; - e0[-4] += e2[-4];//e0[-4] = e0[-4] + e2[-4]; - e0[-5] += e2[-5];//e0[-5] = e0[-5] + e2[-5]; - e2[-4] = (k00_20)*A[0] - (k01_21) * A[1]; - e2[-5] = (k01_21)*A[0] + (k00_20) * A[1]; + k00_20 = e0[-4] - e2[-4]; + k01_21 = e0[-5] - e2[-5]; + e0[-4] += e2[-4]; //e0[-4] = e0[-4] + e2[-4]; + e0[-5] += e2[-5]; //e0[-5] = e0[-5] + e2[-5]; + e2[-4] = (k00_20) * A[0] - (k01_21) * A[1]; + e2[-5] = (k01_21) * A[0] + (k00_20) * A[1]; - A += k1; + A += k1; - k00_20 = e0[-6] - e2[-6]; - k01_21 = e0[-7] - e2[-7]; - e0[-6] += e2[-6];//e0[-6] = e0[-6] + e2[-6]; - e0[-7] += e2[-7];//e0[-7] = e0[-7] + e2[-7]; - e2[-6] = (k00_20)*A[0] - (k01_21) * A[1]; - e2[-7] = (k01_21)*A[0] + (k00_20) * A[1]; + k00_20 = e0[-6] - e2[-6]; + k01_21 = e0[-7] - e2[-7]; + e0[-6] += e2[-6]; //e0[-6] = e0[-6] + e2[-6]; + e0[-7] += e2[-7]; //e0[-7] = e0[-7] + e2[-7]; + e2[-6] = (k00_20) * A[0] - (k01_21) * A[1]; + e2[-7] = (k01_21) * A[0] + (k00_20) * A[1]; - e0 -= 8; - e2 -= 8; + e0 -= 8; + e2 -= 8; - A += k1; - } + A += k1; + } } -static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) +static void imdct_step3_inner_s_loop(int n, float* e, int i_off, int k_off, float* A, int a_off, int k0) { - int i; - float A0 = A[0]; - float A1 = A[0+1]; - float A2 = A[0+a_off]; - float A3 = A[0+a_off+1]; - float A4 = A[0+a_off*2+0]; - float A5 = A[0+a_off*2+1]; - float A6 = A[0+a_off*3+0]; - float A7 = A[0+a_off*3+1]; + int i; + float A0 = A[0]; + float A1 = A[0 + 1]; + float A2 = A[0 + a_off]; + float A3 = A[0 + a_off + 1]; + float A4 = A[0 + a_off * 2 + 0]; + float A5 = A[0 + a_off * 2 + 1]; + float A6 = A[0 + a_off * 3 + 0]; + float A7 = A[0 + a_off * 3 + 1]; - float k00,k11; + float k00, k11; - float *ee0 = e +i_off; - float *ee2 = ee0+k_off; + float* ee0 = e + i_off; + float* ee2 = ee0 + k_off; - for (i=n; i > 0; --i) { - k00 = ee0[ 0] - ee2[ 0]; - k11 = ee0[-1] - ee2[-1]; - ee0[ 0] = ee0[ 0] + ee2[ 0]; - ee0[-1] = ee0[-1] + ee2[-1]; - ee2[ 0] = (k00) * A0 - (k11) * A1; - ee2[-1] = (k11) * A0 + (k00) * A1; + for (i = n; i > 0; --i) + { + k00 = ee0[0] - ee2[0]; + k11 = ee0[-1] - ee2[-1]; + ee0[0] = ee0[0] + ee2[0]; + ee0[-1] = ee0[-1] + ee2[-1]; + ee2[0] = (k00) * A0 - (k11) * A1; + ee2[-1] = (k11) * A0 + (k00) * A1; - k00 = ee0[-2] - ee2[-2]; - k11 = ee0[-3] - ee2[-3]; - ee0[-2] = ee0[-2] + ee2[-2]; - ee0[-3] = ee0[-3] + ee2[-3]; - ee2[-2] = (k00) * A2 - (k11) * A3; - ee2[-3] = (k11) * A2 + (k00) * A3; + k00 = ee0[-2] - ee2[-2]; + k11 = ee0[-3] - ee2[-3]; + ee0[-2] = ee0[-2] + ee2[-2]; + ee0[-3] = ee0[-3] + ee2[-3]; + ee2[-2] = (k00) * A2 - (k11) * A3; + ee2[-3] = (k11) * A2 + (k00) * A3; - k00 = ee0[-4] - ee2[-4]; - k11 = ee0[-5] - ee2[-5]; - ee0[-4] = ee0[-4] + ee2[-4]; - ee0[-5] = ee0[-5] + ee2[-5]; - ee2[-4] = (k00) * A4 - (k11) * A5; - ee2[-5] = (k11) * A4 + (k00) * A5; + k00 = ee0[-4] - ee2[-4]; + k11 = ee0[-5] - ee2[-5]; + ee0[-4] = ee0[-4] + ee2[-4]; + ee0[-5] = ee0[-5] + ee2[-5]; + ee2[-4] = (k00) * A4 - (k11) * A5; + ee2[-5] = (k11) * A4 + (k00) * A5; - k00 = ee0[-6] - ee2[-6]; - k11 = ee0[-7] - ee2[-7]; - ee0[-6] = ee0[-6] + ee2[-6]; - ee0[-7] = ee0[-7] + ee2[-7]; - ee2[-6] = (k00) * A6 - (k11) * A7; - ee2[-7] = (k11) * A6 + (k00) * A7; + k00 = ee0[-6] - ee2[-6]; + k11 = ee0[-7] - ee2[-7]; + ee0[-6] = ee0[-6] + ee2[-6]; + ee0[-7] = ee0[-7] + ee2[-7]; + ee2[-6] = (k00) * A6 - (k11) * A7; + ee2[-7] = (k11) * A6 + (k00) * A7; - ee0 -= k0; - ee2 -= k0; - } + ee0 -= k0; + ee2 -= k0; + } } -static __forceinline void iter_54(float *z) +static __forceinline void iter_54(float* z) { - float k00,k11,k22,k33; - float y0,y1,y2,y3; + float k00, k11, k22, k33; + float y0, y1, y2, y3; - k00 = z[ 0] - z[-4]; - y0 = z[ 0] + z[-4]; - y2 = z[-2] + z[-6]; - k22 = z[-2] - z[-6]; + k00 = z[0] - z[-4]; + y0 = z[0] + z[-4]; + y2 = z[-2] + z[-6]; + k22 = z[-2] - z[-6]; - z[-0] = y0 + y2; // z0 + z4 + z2 + z6 - z[-2] = y0 - y2; // z0 + z4 - z2 - z6 + z[-0] = y0 + y2; // z0 + z4 + z2 + z6 + z[-2] = y0 - y2; // z0 + z4 - z2 - z6 - // done with y0,y2 + // done with y0,y2 - k33 = z[-3] - z[-7]; + k33 = z[-3] - z[-7]; - z[-4] = k00 + k33; // z0 - z4 + z3 - z7 - z[-6] = k00 - k33; // z0 - z4 - z3 + z7 + z[-4] = k00 + k33; // z0 - z4 + z3 - z7 + z[-6] = k00 - k33; // z0 - z4 - z3 + z7 - // done with k33 + // done with k33 - k11 = z[-1] - z[-5]; - y1 = z[-1] + z[-5]; - y3 = z[-3] + z[-7]; + k11 = z[-1] - z[-5]; + y1 = z[-1] + z[-5]; + y3 = z[-3] + z[-7]; - z[-1] = y1 + y3; // z1 + z5 + z3 + z7 - z[-3] = y1 - y3; // z1 + z5 - z3 - z7 - z[-5] = k11 - k22; // z1 - z5 + z2 - z6 - z[-7] = k11 + k22; // z1 - z5 - z2 + z6 + z[-1] = y1 + y3; // z1 + z5 + z3 + z7 + z[-3] = y1 - y3; // z1 + z5 - z3 - z7 + z[-5] = k11 - k22; // z1 - z5 + z2 - z6 + z[-7] = k11 + k22; // z1 - z5 - z2 + z6 } -static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) +static void imdct_step3_inner_s_loop_ld654(int n, float* e, int i_off, float* A, int base_n) { - int a_off = base_n >> 3; - float A2 = A[0+a_off]; - float *z = e + i_off; - float *base = z - 16 * n; + int a_off = base_n >> 3; + float A2 = A[0 + a_off]; + float* z = e + i_off; + float* base = z - 16 * n; - while (z > base) { - float k00,k11; + while (z > base) + { + float k00, k11; - k00 = z[-0] - z[-8]; - k11 = z[-1] - z[-9]; - z[-0] = z[-0] + z[-8]; - z[-1] = z[-1] + z[-9]; - z[-8] = k00; - z[-9] = k11 ; + k00 = z[-0] - z[-8]; + k11 = z[-1] - z[-9]; + z[-0] = z[-0] + z[-8]; + z[-1] = z[-1] + z[-9]; + z[-8] = k00; + z[-9] = k11; - k00 = z[ -2] - z[-10]; - k11 = z[ -3] - z[-11]; - z[ -2] = z[ -2] + z[-10]; - z[ -3] = z[ -3] + z[-11]; - z[-10] = (k00+k11) * A2; - z[-11] = (k11-k00) * A2; + k00 = z[-2] - z[-10]; + k11 = z[-3] - z[-11]; + z[-2] = z[-2] + z[-10]; + z[-3] = z[-3] + z[-11]; + z[-10] = (k00 + k11) * A2; + z[-11] = (k11 - k00) * A2; - k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation - k11 = z[ -5] - z[-13]; - z[ -4] = z[ -4] + z[-12]; - z[ -5] = z[ -5] + z[-13]; - z[-12] = k11; - z[-13] = k00; + k00 = z[-12] - z[-4]; // reverse to avoid a unary negation + k11 = z[-5] - z[-13]; + z[-4] = z[-4] + z[-12]; + z[-5] = z[-5] + z[-13]; + z[-12] = k11; + z[-13] = k00; - k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation - k11 = z[ -7] - z[-15]; - z[ -6] = z[ -6] + z[-14]; - z[ -7] = z[ -7] + z[-15]; - z[-14] = (k00+k11) * A2; - z[-15] = (k00-k11) * A2; + k00 = z[-14] - z[-6]; // reverse to avoid a unary negation + k11 = z[-7] - z[-15]; + z[-6] = z[-6] + z[-14]; + z[-7] = z[-7] + z[-15]; + z[-14] = (k00 + k11) * A2; + z[-15] = (k00 - k11) * A2; - iter_54(z); - iter_54(z-8); - z -= 16; - } + iter_54(z); + iter_54(z - 8); + z -= 16; + } } -static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) +static void inverse_mdct(float* buffer, int n, vorb* f, int blocktype) { - int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; - int ld; - // @OPTIMIZE: reduce register pressure by using fewer variables? - int save_point = temp_alloc_save(f); - float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2)); - float *u=NULL,*v=NULL; - // twiddle factors - float *A = f->A[blocktype]; + int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; + int ld; + // @OPTIMIZE: reduce register pressure by using fewer variables? + int save_point = temp_alloc_save(f); + float* buf2 = (float*)temp_alloc(f, n2 * sizeof(*buf2)); + float *u = NULL, *v = NULL; + // twiddle factors + float* A = f->A[blocktype]; - // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" - // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' after this function. + // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" + // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' after this function. - // kernel from paper + // kernel from paper - // merged: - // copy and reflect spectral data - // step 0 + // merged: + // copy and reflect spectral data + // step 0 - // note that it turns out that the items added together during - // this step are, in fact, being added to themselves (as reflected - // by step 0). inexplicable inefficiency! this became obvious - // once I combined the passes. + // note that it turns out that the items added together during + // this step are, in fact, being added to themselves (as reflected + // by step 0). inexplicable inefficiency! this became obvious + // once I combined the passes. - // so there's a missing 'times 2' here (for adding X to itself). - // this propogates through linearly to the end, where the numbers - // are 1/2 too small, and need to be compensated for. + // so there's a missing 'times 2' here (for adding X to itself). + // this propogates through linearly to the end, where the numbers + // are 1/2 too small, and need to be compensated for. - { - float *d,*e, *AA, *e_stop; - d = &buf2[n2-2]; - AA = A; - e = &buffer[0]; - e_stop = &buffer[n2]; - while (e != e_stop) { - d[1] = (e[0] * AA[0] - e[2]*AA[1]); - d[0] = (e[0] * AA[1] + e[2]*AA[0]); - d -= 2; - AA += 2; - e += 4; - } + { + float *d, *e, *AA, *e_stop; + d = &buf2[n2 - 2]; + AA = A; + e = &buffer[0]; + e_stop = &buffer[n2]; + while (e != e_stop) + { + d[1] = (e[0] * AA[0] - e[2] * AA[1]); + d[0] = (e[0] * AA[1] + e[2] * AA[0]); + d -= 2; + AA += 2; + e += 4; + } - e = &buffer[n2-3]; - while (d >= buf2) { - d[1] = (-e[2] * AA[0] - -e[0]*AA[1]); - d[0] = (-e[2] * AA[1] + -e[0]*AA[0]); - d -= 2; - AA += 2; - e -= 4; - } - } + e = &buffer[n2 - 3]; + while (d >= buf2) + { + d[1] = (-e[2] * AA[0] - -e[0] * AA[1]); + d[0] = (-e[2] * AA[1] + -e[0] * AA[0]); + d -= 2; + AA += 2; + e -= 4; + } + } - // now we use symbolic names for these, so that we can - // possibly swap their meaning as we change which operations - // are in place + // now we use symbolic names for these, so that we can + // possibly swap their meaning as we change which operations + // are in place - u = buffer; - v = buf2; + u = buffer; + v = buf2; - // step 2 (paper output is w, now u) - // this could be in place, but the data ends up in the wrong - // place... _somebody_'s got to swap it, so this is nominated - { - float *AA = &A[n2-8]; - float *d0,*d1, *e0, *e1; + // step 2 (paper output is w, now u) + // this could be in place, but the data ends up in the wrong + // place... _somebody_'s got to swap it, so this is nominated + { + float* AA = &A[n2 - 8]; + float *d0, *d1, *e0, *e1; - e0 = &v[n4]; - e1 = &v[0]; + e0 = &v[n4]; + e1 = &v[0]; - d0 = &u[n4]; - d1 = &u[0]; + d0 = &u[n4]; + d1 = &u[0]; - while (AA >= A) { - float v40_20, v41_21; + while (AA >= A) + { + float v40_20, v41_21; - v41_21 = e0[1] - e1[1]; - v40_20 = e0[0] - e1[0]; - d0[1] = e0[1] + e1[1]; - d0[0] = e0[0] + e1[0]; - d1[1] = v41_21*AA[4] - v40_20*AA[5]; - d1[0] = v40_20*AA[4] + v41_21*AA[5]; + v41_21 = e0[1] - e1[1]; + v40_20 = e0[0] - e1[0]; + d0[1] = e0[1] + e1[1]; + d0[0] = e0[0] + e1[0]; + d1[1] = v41_21 * AA[4] - v40_20 * AA[5]; + d1[0] = v40_20 * AA[4] + v41_21 * AA[5]; - v41_21 = e0[3] - e1[3]; - v40_20 = e0[2] - e1[2]; - d0[3] = e0[3] + e1[3]; - d0[2] = e0[2] + e1[2]; - d1[3] = v41_21*AA[0] - v40_20*AA[1]; - d1[2] = v40_20*AA[0] + v41_21*AA[1]; + v41_21 = e0[3] - e1[3]; + v40_20 = e0[2] - e1[2]; + d0[3] = e0[3] + e1[3]; + d0[2] = e0[2] + e1[2]; + d1[3] = v41_21 * AA[0] - v40_20 * AA[1]; + d1[2] = v40_20 * AA[0] + v41_21 * AA[1]; - AA -= 8; + AA -= 8; - d0 += 4; - d1 += 4; - e0 += 4; - e1 += 4; - } - } + d0 += 4; + d1 += 4; + e0 += 4; + e1 += 4; + } + } - // step 3 - ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + // step 3 + ld = ilog(n) - 1; // ilog is off-by-one from normal definitions - // optimized step 3: + // optimized step 3: - // the original step3 loop can be nested r inside s or s inside r; - // it's written originally as s inside r, but this is dumb when r - // iterates many times, and s few. So I have two copies of it and - // switch between them halfway. + // the original step3 loop can be nested r inside s or s inside r; + // it's written originally as s inside r, but this is dumb when r + // iterates many times, and s few. So I have two copies of it and + // switch between them halfway. - // this is iteration 0 of step 3 - imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); - imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); + // this is iteration 0 of step 3 + imdct_step3_iter0_loop(n >> 4, u, n2 - 1 - n4 * 0, -(n >> 3), A); + imdct_step3_iter0_loop(n >> 4, u, n2 - 1 - n4 * 1, -(n >> 3), A); - // this is iteration 1 of step 3 - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); - imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); + // this is iteration 1 of step 3 + imdct_step3_inner_r_loop(n >> 5, u, n2 - 1 - n8 * 0, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2 - 1 - n8 * 1, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2 - 1 - n8 * 2, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2 - 1 - n8 * 3, -(n >> 4), A, 16); - l=2; - for (; l < (ld-3)>>1; ++l) { - int k0 = n >> (l+2), k0_2 = k0>>1; - int lim = 1 << (l+1); - int i; - for (i=0; i < lim; ++i) - imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); - } + l = 2; + for (; l < (ld - 3) >> 1; ++l) + { + int k0 = n >> (l + 2), k0_2 = k0 >> 1; + int lim = 1 << (l + 1); + int i; + for (i = 0; i < lim; ++i) + imdct_step3_inner_r_loop(n >> (l + 4), u, n2 - 1 - k0 * i, -k0_2, A, 1 << (l + 3)); + } - for (; l < ld-6; ++l) { - int k0 = n >> (l+2), k1 = 1 << (l+3), k0_2 = k0>>1; - int rlim = n >> (l+6), r; - int lim = 1 << (l+1); - int i_off; - float *A0 = A; - i_off = n2-1; - for (r=rlim; r > 0; --r) { - imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); - A0 += k1*4; - i_off -= 8; - } - } + for (; l < ld - 6; ++l) + { + int k0 = n >> (l + 2), k1 = 1 << (l + 3), k0_2 = k0 >> 1; + int rlim = n >> (l + 6), r; + int lim = 1 << (l + 1); + int i_off; + float* A0 = A; + i_off = n2 - 1; + for (r = rlim; r > 0; --r) + { + imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); + A0 += k1 * 4; + i_off -= 8; + } + } - // iterations with count: - // ld-6,-5,-4 all interleaved together - // the big win comes from getting rid of needless flops - // due to the constants on pass 5 & 4 being all 1 and 0; - // combining them to be simultaneous to improve cache made little difference - imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); + // iterations with count: + // ld-6,-5,-4 all interleaved together + // the big win comes from getting rid of needless flops + // due to the constants on pass 5 & 4 being all 1 and 0; + // combining them to be simultaneous to improve cache made little difference + imdct_step3_inner_s_loop_ld654(n >> 5, u, n2 - 1, A, n); - // output is u + // output is u - // step 4, 5, and 6 - // cannot be in-place because of step 5 - { - uint16 *bitrev = f->bit_reverse[blocktype]; - // weirdly, I'd have thought reading sequentially and writing - // erratically would have been better than vice-versa, but in - // fact that's not what my testing showed. (That is, with - // j = bitreverse(i), do you read i and write j, or read j and write i.) + // step 4, 5, and 6 + // cannot be in-place because of step 5 + { + uint16* bitrev = f->bit_reverse[blocktype]; + // weirdly, I'd have thought reading sequentially and writing + // erratically would have been better than vice-versa, but in + // fact that's not what my testing showed. (That is, with + // j = bitreverse(i), do you read i and write j, or read j and write i.) - float *d0 = &v[n4-4]; - float *d1 = &v[n2-4]; - while (d0 >= v) { - int k4; + float* d0 = &v[n4 - 4]; + float* d1 = &v[n2 - 4]; + while (d0 >= v) + { + int k4; - k4 = bitrev[0]; - d1[3] = u[k4+0]; - d1[2] = u[k4+1]; - d0[3] = u[k4+2]; - d0[2] = u[k4+3]; + k4 = bitrev[0]; + d1[3] = u[k4 + 0]; + d1[2] = u[k4 + 1]; + d0[3] = u[k4 + 2]; + d0[2] = u[k4 + 3]; - k4 = bitrev[1]; - d1[1] = u[k4+0]; - d1[0] = u[k4+1]; - d0[1] = u[k4+2]; - d0[0] = u[k4+3]; - - d0 -= 4; - d1 -= 4; - bitrev += 2; - } - } - // (paper output is u, now v) + k4 = bitrev[1]; + d1[1] = u[k4 + 0]; + d1[0] = u[k4 + 1]; + d0[1] = u[k4 + 2]; + d0[0] = u[k4 + 3]; + + d0 -= 4; + d1 -= 4; + bitrev += 2; + } + } + // (paper output is u, now v) - // data must be in buf2 - assert(v == buf2); + // data must be in buf2 + assert(v == buf2); - // step 7 (paper output is v, now v) - // this is now in place - { - float *C = f->C[blocktype]; - float *d, *e; + // step 7 (paper output is v, now v) + // this is now in place + { + float* C = f->C[blocktype]; + float *d, *e; - d = v; - e = v + n2 - 4; + d = v; + e = v + n2 - 4; - while (d < e) { - float a02,a11,b0,b1,b2,b3; + while (d < e) + { + float a02, a11, b0, b1, b2, b3; - a02 = d[0] - e[2]; - a11 = d[1] + e[3]; + a02 = d[0] - e[2]; + a11 = d[1] + e[3]; - b0 = C[1]*a02 + C[0]*a11; - b1 = C[1]*a11 - C[0]*a02; + b0 = C[1] * a02 + C[0] * a11; + b1 = C[1] * a11 - C[0] * a02; - b2 = d[0] + e[ 2]; - b3 = d[1] - e[ 3]; + b2 = d[0] + e[2]; + b3 = d[1] - e[3]; - d[0] = b2 + b0; - d[1] = b3 + b1; - e[2] = b2 - b0; - e[3] = b1 - b3; + d[0] = b2 + b0; + d[1] = b3 + b1; + e[2] = b2 - b0; + e[3] = b1 - b3; - a02 = d[2] - e[0]; - a11 = d[3] + e[1]; + a02 = d[2] - e[0]; + a11 = d[3] + e[1]; - b0 = C[3]*a02 + C[2]*a11; - b1 = C[3]*a11 - C[2]*a02; + b0 = C[3] * a02 + C[2] * a11; + b1 = C[3] * a11 - C[2] * a02; - b2 = d[2] + e[ 0]; - b3 = d[3] - e[ 1]; + b2 = d[2] + e[0]; + b3 = d[3] - e[1]; - d[2] = b2 + b0; - d[3] = b3 + b1; - e[0] = b2 - b0; - e[1] = b1 - b3; + d[2] = b2 + b0; + d[3] = b3 + b1; + e[0] = b2 - b0; + e[1] = b1 - b3; - C += 4; - d += 4; - e -= 4; - } - } + C += 4; + d += 4; + e -= 4; + } + } - // data must be in buf2 + // data must be in buf2 - // step 8+decode (paper output is X, now buffer) - // this generates pairs of data a la 8 and pushes them directly through - // the decode kernel (pushing rather than pulling) to avoid having - // to make another pass later + // step 8+decode (paper output is X, now buffer) + // this generates pairs of data a la 8 and pushes them directly through + // the decode kernel (pushing rather than pulling) to avoid having + // to make another pass later - // this cannot POSSIBLY be in place, so we refer to the buffers directly + // this cannot POSSIBLY be in place, so we refer to the buffers directly - { - float *d0,*d1,*d2,*d3; + { + float *d0, *d1, *d2, *d3; - float *B = f->B[blocktype] + n2 - 8; - float *e = buf2 + n2 - 8; - d0 = &buffer[0]; - d1 = &buffer[n2-4]; - d2 = &buffer[n2]; - d3 = &buffer[n-4]; - while (e >= v) { - float p0,p1,p2,p3; + float* B = f->B[blocktype] + n2 - 8; + float* e = buf2 + n2 - 8; + d0 = &buffer[0]; + d1 = &buffer[n2 - 4]; + d2 = &buffer[n2]; + d3 = &buffer[n - 4]; + while (e >= v) + { + float p0, p1, p2, p3; - p3 = e[6]*B[7] - e[7]*B[6]; - p2 = -e[6]*B[6] - e[7]*B[7]; + p3 = e[6] * B[7] - e[7] * B[6]; + p2 = -e[6] * B[6] - e[7] * B[7]; - d0[0] = p3; - d1[3] = - p3; - d2[0] = p2; - d3[3] = p2; + d0[0] = p3; + d1[3] = - p3; + d2[0] = p2; + d3[3] = p2; - p1 = e[4]*B[5] - e[5]*B[4]; - p0 = -e[4]*B[4] - e[5]*B[5]; + p1 = e[4] * B[5] - e[5] * B[4]; + p0 = -e[4] * B[4] - e[5] * B[5]; - d0[1] = p1; - d1[2] = - p1; - d2[1] = p0; - d3[2] = p0; + d0[1] = p1; + d1[2] = - p1; + d2[1] = p0; + d3[2] = p0; - p3 = e[2]*B[3] - e[3]*B[2]; - p2 = -e[2]*B[2] - e[3]*B[3]; + p3 = e[2] * B[3] - e[3] * B[2]; + p2 = -e[2] * B[2] - e[3] * B[3]; - d0[2] = p3; - d1[1] = - p3; - d2[2] = p2; - d3[1] = p2; + d0[2] = p3; + d1[1] = - p3; + d2[2] = p2; + d3[1] = p2; - p1 = e[0]*B[1] - e[1]*B[0]; - p0 = -e[0]*B[0] - e[1]*B[1]; + p1 = e[0] * B[1] - e[1] * B[0]; + p0 = -e[0] * B[0] - e[1] * B[1]; - d0[3] = p1; - d1[0] = - p1; - d2[3] = p0; - d3[0] = p0; + d0[3] = p1; + d1[0] = - p1; + d2[3] = p0; + d3[0] = p0; - B -= 8; - e -= 8; - d0 += 4; - d2 += 4; - d1 -= 4; - d3 -= 4; - } - } + B -= 8; + e -= 8; + d0 += 4; + d2 += 4; + d1 -= 4; + d3 -= 4; + } + } - temp_alloc_restore(f,save_point); + temp_alloc_restore(f, save_point); } #if 0 @@ -2696,13 +2875,13 @@ void inverse_mdct_naive(float *buffer, int n) } #endif -static float *get_window(vorb *f, int len) +static float* get_window(vorb* f, int len) { - len <<= 1; - if (len == f->blocksize_0) return f->window[0]; - if (len == f->blocksize_1) return f->window[1]; - assert(0); - return NULL; + len <<= 1; + if (len == f->blocksize_0) return f->window[0]; + if (len == f->blocksize_1) return f->window[1]; + assert(0); + return NULL; } #ifndef STB_VORBIS_NO_DEFER_FLOOR @@ -2710,41 +2889,46 @@ typedef int16 YTYPE; #else typedef int YTYPE; #endif -static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag) +static int do_floor(vorb* f, Mapping* map, int i, int n, float* target, YTYPE* finalY, uint8* step2_flag) { - int n2 = n >> 1; - int s = map->chan[i].mux, floor; - floor = map->submap_floor[s]; - if (f->floor_types[floor] == 0) { - return error(f, VORBIS_invalid_stream); - } else { - Floor1 *g = &f->floor_config[floor].floor1; - int j,q; - int lx = 0, ly = finalY[0] * g->floor1_multiplier; - for (q=1; q < g->values; ++q) { - j = g->sorted_order[q]; - #ifndef STB_VORBIS_NO_DEFER_FLOOR - if (finalY[j] >= 0) - #else + int n2 = n >> 1; + int s = map->chan[i].mux, floor; + floor = map->submap_floor[s]; + if (f->floor_types[floor] == 0) + { + return error(f, VORBIS_invalid_stream); + } + else + { + Floor1* g = &f->floor_config[floor].floor1; + int j, q; + int lx = 0, ly = finalY[0] * g->floor1_multiplier; + for (q = 1; q < g->values; ++q) + { + j = g->sorted_order[q]; +#ifndef STB_VORBIS_NO_DEFER_FLOOR + if (finalY[j] >= 0) +#else if (step2_flag[j]) - #endif - { - int hy = finalY[j] * g->floor1_multiplier; - int hx = g->Xlist[j]; - if (lx != hx) - draw_line(target, lx,ly, hx,hy, n2); - CHECK(f); - lx = hx, ly = hy; - } - } - if (lx < n2) { - // optimization of: draw_line(target, lx,ly, n,ly, n2); - for (j=lx; j < n2; ++j) - LINE_OP(target[j], inverse_db_table[ly]); - CHECK(f); - } - } - return TRUE; +#endif + { + int hy = finalY[j] * g->floor1_multiplier; + int hx = g->Xlist[j]; + if (lx != hx) + draw_line(target, lx, ly, hx, hy, n2); + CHECK(f); + lx = hx, ly = hy; + } + } + if (lx < n2) + { + // optimization of: draw_line(target, lx,ly, n,ly, n2); + for (j = lx; j < n2; ++j) + LINE_OP(target[j], inverse_db_table[ly]); + CHECK(f); + } + } + return TRUE; } // The meaning of "left" and "right" @@ -2761,242 +2945,282 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f // has to be the same as frame N+1's left_end-left_start (which they are by // construction) -static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +static int vorbis_decode_initial(vorb* f, int* p_left_start, int* p_left_end, int* p_right_start, int* p_right_end, + int* mode) { - Mode *m; - int i, n, prev, next, window_center; - f->channel_buffer_start = f->channel_buffer_end = 0; + Mode* m; + int i, n, prev, next, window_center; + f->channel_buffer_start = f->channel_buffer_end = 0; - retry: - if (f->eof) return FALSE; - if (!maybe_start_packet(f)) - return FALSE; - // check packet type - if (get_bits(f,1) != 0) { - if (IS_PUSH_MODE(f)) - return error(f,VORBIS_bad_packet_type); - while (EOP != get8_packet(f)); - goto retry; - } +retry: + if (f->eof) return FALSE; + if (!maybe_start_packet(f)) + return FALSE; + // check packet type + if (get_bits(f, 1) != 0) + { + if (IS_PUSH_MODE(f)) + return error(f, VORBIS_bad_packet_type); + while (EOP != get8_packet(f)); + goto retry; + } - if (f->alloc.alloc_buffer) - assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - i = get_bits(f, ilog(f->mode_count-1)); - if (i == EOP) return FALSE; - if (i >= f->mode_count) return FALSE; - *mode = i; - m = f->mode_config + i; - if (m->blockflag) { - n = f->blocksize_1; - prev = get_bits(f,1); - next = get_bits(f,1); - } else { - prev = next = 0; - n = f->blocksize_0; - } + i = get_bits(f, ilog(f->mode_count - 1)); + if (i == EOP) return FALSE; + if (i >= f->mode_count) return FALSE; + *mode = i; + m = f->mode_config + i; + if (m->blockflag) + { + n = f->blocksize_1; + prev = get_bits(f, 1); + next = get_bits(f, 1); + } + else + { + prev = next = 0; + n = f->blocksize_0; + } -// WINDOWING + // WINDOWING - window_center = n >> 1; - if (m->blockflag && !prev) { - *p_left_start = (n - f->blocksize_0) >> 2; - *p_left_end = (n + f->blocksize_0) >> 2; - } else { - *p_left_start = 0; - *p_left_end = window_center; - } - if (m->blockflag && !next) { - *p_right_start = (n*3 - f->blocksize_0) >> 2; - *p_right_end = (n*3 + f->blocksize_0) >> 2; - } else { - *p_right_start = window_center; - *p_right_end = n; - } + window_center = n >> 1; + if (m->blockflag && !prev) + { + *p_left_start = (n - f->blocksize_0) >> 2; + *p_left_end = (n + f->blocksize_0) >> 2; + } + else + { + *p_left_start = 0; + *p_left_end = window_center; + } + if (m->blockflag && !next) + { + *p_right_start = (n * 3 - f->blocksize_0) >> 2; + *p_right_end = (n * 3 + f->blocksize_0) >> 2; + } + else + { + *p_right_start = window_center; + *p_right_end = n; + } - return TRUE; + return TRUE; } -static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) +static int vorbis_decode_packet_rest(vorb* f, int* len, Mode* m, int left_start, int left_end, int right_start, + int right_end, int* p_left) { - Mapping *map; - int i,j,k,n,n2; - int zero_channel[256]; - int really_zero_channel[256]; + Mapping* map; + int i, j, k, n, n2; + int zero_channel[256]; + int really_zero_channel[256]; -// WINDOWING + // WINDOWING - n = f->blocksize[m->blockflag]; - map = &f->mapping[m->mapping]; + n = f->blocksize[m->blockflag]; + map = &f->mapping[m->mapping]; -// FLOORS - n2 = n >> 1; + // FLOORS + n2 = n >> 1; - CHECK(f); + CHECK(f); - for (i=0; i < f->channels; ++i) { - int s = map->chan[i].mux, floor; - zero_channel[i] = FALSE; - floor = map->submap_floor[s]; - if (f->floor_types[floor] == 0) { - return error(f, VORBIS_invalid_stream); - } else { - Floor1 *g = &f->floor_config[floor].floor1; - if (get_bits(f, 1)) { - short *finalY; - uint8 step2_flag[256]; - static int range_list[4] = { 256, 128, 86, 64 }; - int range = range_list[g->floor1_multiplier-1]; - int offset = 2; - finalY = f->finalY[i]; - finalY[0] = get_bits(f, ilog(range)-1); - finalY[1] = get_bits(f, ilog(range)-1); - for (j=0; j < g->partitions; ++j) { - int pclass = g->partition_class_list[j]; - int cdim = g->class_dimensions[pclass]; - int cbits = g->class_subclasses[pclass]; - int csub = (1 << cbits)-1; - int cval = 0; - if (cbits) { - Codebook *c = f->codebooks + g->class_masterbooks[pclass]; - DECODE(cval,f,c); - } - for (k=0; k < cdim; ++k) { - int book = g->subclass_books[pclass][cval & csub]; - cval = cval >> cbits; - if (book >= 0) { - int temp; - Codebook *c = f->codebooks + book; - DECODE(temp,f,c); - finalY[offset++] = temp; - } else - finalY[offset++] = 0; - } - } - if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec - step2_flag[0] = step2_flag[1] = 1; - for (j=2; j < g->values; ++j) { - int low, high, pred, highroom, lowroom, room, val; - low = g->neighbors[j][0]; - high = g->neighbors[j][1]; - //neighbors(g->Xlist, j, &low, &high); - pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); - val = finalY[j]; - highroom = range - pred; - lowroom = pred; - if (highroom < lowroom) - room = highroom * 2; - else - room = lowroom * 2; - if (val) { - step2_flag[low] = step2_flag[high] = 1; - step2_flag[j] = 1; - if (val >= room) - if (highroom > lowroom) - finalY[j] = val - lowroom + pred; - else - finalY[j] = pred - val + highroom - 1; - else - if (val & 1) - finalY[j] = pred - ((val+1)>>1); - else - finalY[j] = pred + (val>>1); - } else { - step2_flag[j] = 0; - finalY[j] = pred; - } - } + for (i = 0; i < f->channels; ++i) + { + int s = map->chan[i].mux, floor; + zero_channel[i] = FALSE; + floor = map->submap_floor[s]; + if (f->floor_types[floor] == 0) + { + return error(f, VORBIS_invalid_stream); + } + else + { + Floor1* g = &f->floor_config[floor].floor1; + if (get_bits(f, 1)) + { + short* finalY; + uint8 step2_flag[256]; + static int range_list[4] = {256, 128, 86, 64}; + int range = range_list[g->floor1_multiplier - 1]; + int offset = 2; + finalY = f->finalY[i]; + finalY[0] = get_bits(f, ilog(range) - 1); + finalY[1] = get_bits(f, ilog(range) - 1); + for (j = 0; j < g->partitions; ++j) + { + int pclass = g->partition_class_list[j]; + int cdim = g->class_dimensions[pclass]; + int cbits = g->class_subclasses[pclass]; + int csub = (1 << cbits) - 1; + int cval = 0; + if (cbits) + { + Codebook* c = f->codebooks + g->class_masterbooks[pclass]; + DECODE(cval, f, c); + } + for (k = 0; k < cdim; ++k) + { + int book = g->subclass_books[pclass][cval & csub]; + cval = cval >> cbits; + if (book >= 0) + { + int temp; + Codebook* c = f->codebooks + book; + DECODE(temp, f, c); + finalY[offset++] = temp; + } + else + finalY[offset++] = 0; + } + } + if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec + step2_flag[0] = step2_flag[1] = 1; + for (j = 2; j < g->values; ++j) + { + int low, high, pred, highroom, lowroom, room, val; + low = g->neighbors[j][0]; + high = g->neighbors[j][1]; + //neighbors(g->Xlist, j, &low, &high); + pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); + val = finalY[j]; + highroom = range - pred; + lowroom = pred; + if (highroom < lowroom) + room = highroom * 2; + else + room = lowroom * 2; + if (val) + { + step2_flag[low] = step2_flag[high] = 1; + step2_flag[j] = 1; + if (val >= room) + if (highroom > lowroom) + finalY[j] = val - lowroom + pred; + else + finalY[j] = pred - val + highroom - 1; + else if (val & 1) + finalY[j] = pred - ((val + 1) >> 1); + else + finalY[j] = pred + (val >> 1); + } + else + { + step2_flag[j] = 0; + finalY[j] = pred; + } + } #ifdef STB_VORBIS_NO_DEFER_FLOOR do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); #else - // defer final floor computation until _after_ residue - for (j=0; j < g->values; ++j) { - if (!step2_flag[j]) - finalY[j] = -1; - } + // defer final floor computation until _after_ residue + for (j = 0; j < g->values; ++j) + { + if (!step2_flag[j]) + finalY[j] = -1; + } #endif - } else { - error: - zero_channel[i] = TRUE; - } - // So we just defer everything else to later + } + else + { + error: + zero_channel[i] = TRUE; + } + // So we just defer everything else to later - // at this point we've decoded the floor into buffer - } - } - CHECK(f); - // at this point we've decoded all floors + // at this point we've decoded the floor into buffer + } + } + CHECK(f); + // at this point we've decoded all floors - if (f->alloc.alloc_buffer) - assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - // re-enable coupled channels if necessary - memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels); - for (i=0; i < map->coupling_steps; ++i) - if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) { - zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; - } + // re-enable coupled channels if necessary + memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels); + for (i = 0; i < map->coupling_steps; ++i) + if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) + { + zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; + } - CHECK(f); -// RESIDUE DECODE - for (i=0; i < map->submaps; ++i) { - float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; - int r; - uint8 do_not_decode[256]; - int ch = 0; - for (j=0; j < f->channels; ++j) { - if (map->chan[j].mux == i) { - if (zero_channel[j]) { - do_not_decode[ch] = TRUE; - residue_buffers[ch] = NULL; - } else { - do_not_decode[ch] = FALSE; - residue_buffers[ch] = f->channel_buffers[j]; - } - ++ch; - } - } - r = map->submap_residue[i]; - decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); - } + CHECK(f); + // RESIDUE DECODE + for (i = 0; i < map->submaps; ++i) + { + float* residue_buffers[STB_VORBIS_MAX_CHANNELS]; + int r; + uint8 do_not_decode[256]; + int ch = 0; + for (j = 0; j < f->channels; ++j) + { + if (map->chan[j].mux == i) + { + if (zero_channel[j]) + { + do_not_decode[ch] = TRUE; + residue_buffers[ch] = NULL; + } + else + { + do_not_decode[ch] = FALSE; + residue_buffers[ch] = f->channel_buffers[j]; + } + ++ch; + } + } + r = map->submap_residue[i]; + decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); + } - if (f->alloc.alloc_buffer) - assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - CHECK(f); + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + CHECK(f); -// INVERSE COUPLING - for (i = map->coupling_steps-1; i >= 0; --i) { - int n2 = n >> 1; - float *m = f->channel_buffers[map->chan[i].magnitude]; - float *a = f->channel_buffers[map->chan[i].angle ]; - for (j=0; j < n2; ++j) { - float a2,m2; - if (m[j] > 0) - if (a[j] > 0) - m2 = m[j], a2 = m[j] - a[j]; - else - a2 = m[j], m2 = m[j] + a[j]; - else - if (a[j] > 0) - m2 = m[j], a2 = m[j] + a[j]; - else - a2 = m[j], m2 = m[j] - a[j]; - m[j] = m2; - a[j] = a2; - } - } - CHECK(f); + // INVERSE COUPLING + for (i = map->coupling_steps - 1; i >= 0; --i) + { + int n2 = n >> 1; + float* m = f->channel_buffers[map->chan[i].magnitude]; + float* a = f->channel_buffers[map->chan[i].angle]; + for (j = 0; j < n2; ++j) + { + float a2, m2; + if (m[j] > 0) + if (a[j] > 0) + m2 = m[j], a2 = m[j] - a[j]; + else + a2 = m[j], m2 = m[j] + a[j]; + else if (a[j] > 0) + m2 = m[j], a2 = m[j] + a[j]; + else + a2 = m[j], m2 = m[j] - a[j]; + m[j] = m2; + a[j] = a2; + } + } + CHECK(f); - // finish decoding the floors + // finish decoding the floors #ifndef STB_VORBIS_NO_DEFER_FLOOR - for (i=0; i < f->channels; ++i) { - if (really_zero_channel[i]) { - memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); - } else { - do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); - } - } + for (i = 0; i < f->channels; ++i) + { + if (really_zero_channel[i]) + { + memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); + } + else + { + do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); + } + } #else for (i=0; i < f->channels; ++i) { if (really_zero_channel[i]) { @@ -3008,719 +3232,833 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, } #endif -// INVERSE MDCT - CHECK(f); - for (i=0; i < f->channels; ++i) - inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); - CHECK(f); + // INVERSE MDCT + CHECK(f); + for (i = 0; i < f->channels; ++i) + inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); + CHECK(f); - // this shouldn't be necessary, unless we exited on an error - // and want to flush to get to the next packet - flush_packet(f); + // this shouldn't be necessary, unless we exited on an error + // and want to flush to get to the next packet + flush_packet(f); - if (f->first_decode) { - // assume we start so first non-discarded sample is sample 0 - // this isn't to spec, but spec would require us to read ahead - // and decode the size of all current frames--could be done, - // but presumably it's not a commonly used feature - f->current_loc = -n2; // start of first frame is positioned for discard - // we might have to discard samples "from" the next frame too, - // if we're lapping a large block then a small at the start? - f->discard_samples_deferred = n - right_end; - f->current_loc_valid = TRUE; - f->first_decode = FALSE; - } else if (f->discard_samples_deferred) { - if (f->discard_samples_deferred >= right_start - left_start) { - f->discard_samples_deferred -= (right_start - left_start); - left_start = right_start; - *p_left = left_start; - } else { - left_start += f->discard_samples_deferred; - *p_left = left_start; - f->discard_samples_deferred = 0; - } - } else if (f->previous_length == 0 && f->current_loc_valid) { - // we're recovering from a seek... that means we're going to discard - // the samples from this packet even though we know our position from - // the last page header, so we need to update the position based on - // the discarded samples here - // but wait, the code below is going to add this in itself even - // on a discard, so we don't need to do it here... - } + if (f->first_decode) + { + // assume we start so first non-discarded sample is sample 0 + // this isn't to spec, but spec would require us to read ahead + // and decode the size of all current frames--could be done, + // but presumably it's not a commonly used feature + f->current_loc = -n2; // start of first frame is positioned for discard + // we might have to discard samples "from" the next frame too, + // if we're lapping a large block then a small at the start? + f->discard_samples_deferred = n - right_end; + f->current_loc_valid = TRUE; + f->first_decode = FALSE; + } + else if (f->discard_samples_deferred) + { + if (f->discard_samples_deferred >= right_start - left_start) + { + f->discard_samples_deferred -= (right_start - left_start); + left_start = right_start; + *p_left = left_start; + } + else + { + left_start += f->discard_samples_deferred; + *p_left = left_start; + f->discard_samples_deferred = 0; + } + } + else if (f->previous_length == 0 && f->current_loc_valid) + { + // we're recovering from a seek... that means we're going to discard + // the samples from this packet even though we know our position from + // the last page header, so we need to update the position based on + // the discarded samples here + // but wait, the code below is going to add this in itself even + // on a discard, so we don't need to do it here... + } - // check if we have ogg information about the sample # for this packet - if (f->last_seg_which == f->end_seg_with_known_loc) { - // if we have a valid current loc, and this is final: - if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { - uint32 current_end = f->known_loc_for_packet - (n-right_end); - // then let's infer the size of the (probably) short final frame - if (current_end < f->current_loc + (right_end-left_start)) { - if (current_end < f->current_loc) { - // negative truncation, that's impossible! - *len = 0; - } else { - *len = current_end - f->current_loc; - } - *len += left_start; - if (*len > right_end) *len = right_end; // this should never happen - f->current_loc += *len; - return TRUE; - } - } - // otherwise, just set our sample loc - // guess that the ogg granule pos refers to the _middle_ of the - // last frame? - // set f->current_loc to the position of left_start - f->current_loc = f->known_loc_for_packet - (n2-left_start); - f->current_loc_valid = TRUE; - } - if (f->current_loc_valid) - f->current_loc += (right_start - left_start); + // check if we have ogg information about the sample # for this packet + if (f->last_seg_which == f->end_seg_with_known_loc) + { + // if we have a valid current loc, and this is final: + if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) + { + uint32 current_end = f->known_loc_for_packet - (n - right_end); + // then let's infer the size of the (probably) short final frame + if (current_end < f->current_loc + (right_end - left_start)) + { + if (current_end < f->current_loc) + { + // negative truncation, that's impossible! + *len = 0; + } + else + { + *len = current_end - f->current_loc; + } + *len += left_start; + if (*len > right_end) *len = right_end; // this should never happen + f->current_loc += *len; + return TRUE; + } + } + // otherwise, just set our sample loc + // guess that the ogg granule pos refers to the _middle_ of the + // last frame? + // set f->current_loc to the position of left_start + f->current_loc = f->known_loc_for_packet - (n2 - left_start); + f->current_loc_valid = TRUE; + } + if (f->current_loc_valid) + f->current_loc += (right_start - left_start); - if (f->alloc.alloc_buffer) - assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); - *len = right_end; // ignore samples after the window goes to 0 - CHECK(f); + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + *len = right_end; // ignore samples after the window goes to 0 + CHECK(f); - return TRUE; + return TRUE; } -static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right) +static int vorbis_decode_packet(vorb* f, int* len, int* p_left, int* p_right) { - int mode, left_end, right_end; - if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; - return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); + int mode, left_end, right_end; + if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; + return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); } -static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) +static int vorbis_finish_frame(stb_vorbis* f, int len, int left, int right) { - int prev,i,j; - // we use right&left (the start of the right- and left-window sin()-regions) - // to determine how much to return, rather than inferring from the rules - // (same result, clearer code); 'left' indicates where our sin() window - // starts, therefore where the previous window's right edge starts, and - // therefore where to start mixing from the previous buffer. 'right' - // indicates where our sin() ending-window starts, therefore that's where - // we start saving, and where our returned-data ends. + int prev, i, j; + // we use right&left (the start of the right- and left-window sin()-regions) + // to determine how much to return, rather than inferring from the rules + // (same result, clearer code); 'left' indicates where our sin() window + // starts, therefore where the previous window's right edge starts, and + // therefore where to start mixing from the previous buffer. 'right' + // indicates where our sin() ending-window starts, therefore that's where + // we start saving, and where our returned-data ends. - // mixin from previous window - if (f->previous_length) { - int i,j, n = f->previous_length; - float *w = get_window(f, n); - for (i=0; i < f->channels; ++i) { - for (j=0; j < n; ++j) - f->channel_buffers[i][left+j] = - f->channel_buffers[i][left+j]*w[ j] + - f->previous_window[i][ j]*w[n-1-j]; - } - } + // mixin from previous window + if (f->previous_length) + { + int i, j, n = f->previous_length; + float* w = get_window(f, n); + for (i = 0; i < f->channels; ++i) + { + for (j = 0; j < n; ++j) + f->channel_buffers[i][left + j] = + f->channel_buffers[i][left + j] * w[j] + + f->previous_window[i][j] * w[n - 1 - j]; + } + } - prev = f->previous_length; + prev = f->previous_length; - // last half of this data becomes previous window - f->previous_length = len - right; + // last half of this data becomes previous window + f->previous_length = len - right; - // @OPTIMIZE: could avoid this copy by double-buffering the - // output (flipping previous_window with channel_buffers), but - // then previous_window would have to be 2x as large, and - // channel_buffers couldn't be temp mem (although they're NOT - // currently temp mem, they could be (unless we want to level - // performance by spreading out the computation)) - for (i=0; i < f->channels; ++i) - for (j=0; right+j < len; ++j) - f->previous_window[i][j] = f->channel_buffers[i][right+j]; + // @OPTIMIZE: could avoid this copy by double-buffering the + // output (flipping previous_window with channel_buffers), but + // then previous_window would have to be 2x as large, and + // channel_buffers couldn't be temp mem (although they're NOT + // currently temp mem, they could be (unless we want to level + // performance by spreading out the computation)) + for (i = 0; i < f->channels; ++i) + for (j = 0; right + j < len; ++j) + f->previous_window[i][j] = f->channel_buffers[i][right + j]; - if (!prev) - // there was no previous packet, so this data isn't valid... - // this isn't entirely true, only the would-have-overlapped data - // isn't valid, but this seems to be what the spec requires - return 0; + if (!prev) + // there was no previous packet, so this data isn't valid... + // this isn't entirely true, only the would-have-overlapped data + // isn't valid, but this seems to be what the spec requires + return 0; - // truncate a short frame - if (len < right) right = len; + // truncate a short frame + if (len < right) right = len; - f->samples_output += right-left; + f->samples_output += right - left; - return right - left; + return right - left; } -static int vorbis_pump_first_frame(stb_vorbis *f) +static int vorbis_pump_first_frame(stb_vorbis* f) { - int len, right, left, res; - res = vorbis_decode_packet(f, &len, &left, &right); - if (res) - vorbis_finish_frame(f, len, left, right); - return res; + int len, right, left, res; + res = vorbis_decode_packet(f, &len, &left, &right); + if (res) + vorbis_finish_frame(f, len, left, right); + return res; } #ifndef STB_VORBIS_NO_PUSHDATA_API -static int is_whole_packet_present(stb_vorbis *f, int end_page) +static int is_whole_packet_present(stb_vorbis* f, int end_page) { - // make sure that we have the packet available before continuing... - // this requires a full ogg parse, but we know we can fetch from f->stream + // make sure that we have the packet available before continuing... + // this requires a full ogg parse, but we know we can fetch from f->stream - // instead of coding this out explicitly, we could save the current read state, - // read the next packet with get8() until end-of-packet, check f->eof, then - // reset the state? but that would be slower, esp. since we'd have over 256 bytes - // of state to restore (primarily the page segment table) + // instead of coding this out explicitly, we could save the current read state, + // read the next packet with get8() until end-of-packet, check f->eof, then + // reset the state? but that would be slower, esp. since we'd have over 256 bytes + // of state to restore (primarily the page segment table) - int s = f->next_seg, first = TRUE; - uint8 *p = f->stream; + int s = f->next_seg, first = TRUE; + uint8* p = f->stream; - if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag - for (; s < f->segment_count; ++s) { - p += f->segments[s]; - if (f->segments[s] < 255) // stop at first short segment - break; - } - // either this continues, or it ends it... - if (end_page) - if (s < f->segment_count-1) return error(f, VORBIS_invalid_stream); - if (s == f->segment_count) - s = -1; // set 'crosses page' flag - if (p > f->stream_end) return error(f, VORBIS_need_more_data); - first = FALSE; - } - for (; s == -1;) { - uint8 *q; - int n; + if (s != -1) + { + // if we're not starting the packet with a 'continue on next page' flag + for (; s < f->segment_count; ++s) + { + p += f->segments[s]; + if (f->segments[s] < 255) // stop at first short segment + break; + } + // either this continues, or it ends it... + if (end_page) + if (s < f->segment_count - 1) return error(f, VORBIS_invalid_stream); + if (s == f->segment_count) + s = -1; // set 'crosses page' flag + if (p > f->stream_end) return error(f, VORBIS_need_more_data); + first = FALSE; + } + for (; s == -1;) + { + uint8* q; + int n; - // check that we have the page header ready - if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data); - // validate the page - if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream); - if (p[4] != 0) return error(f, VORBIS_invalid_stream); - if (first) { // the first segment must NOT have 'continued_packet', later ones MUST - if (f->previous_length) - if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); - // if no previous length, we're resynching, so we can come in on a continued-packet, - // which we'll just drop - } else { - if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); - } - n = p[26]; // segment counts - q = p+27; // q points to segment table - p = q + n; // advance past header - // make sure we've read the segment table - if (p > f->stream_end) return error(f, VORBIS_need_more_data); - for (s=0; s < n; ++s) { - p += q[s]; - if (q[s] < 255) - break; - } - if (end_page) - if (s < n-1) return error(f, VORBIS_invalid_stream); - if (s == n) - s = -1; // set 'crosses page' flag - if (p > f->stream_end) return error(f, VORBIS_need_more_data); - first = FALSE; - } - return TRUE; + // check that we have the page header ready + if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data); + // validate the page + if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream); + if (p[4] != 0) return error(f, VORBIS_invalid_stream); + if (first) + { + // the first segment must NOT have 'continued_packet', later ones MUST + if (f->previous_length) + if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); + // if no previous length, we're resynching, so we can come in on a continued-packet, + // which we'll just drop + } + else + { + if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); + } + n = p[26]; // segment counts + q = p + 27; // q points to segment table + p = q + n; // advance past header + // make sure we've read the segment table + if (p > f->stream_end) return error(f, VORBIS_need_more_data); + for (s = 0; s < n; ++s) + { + p += q[s]; + if (q[s] < 255) + break; + } + if (end_page) + if (s < n - 1) return error(f, VORBIS_invalid_stream); + if (s == n) + s = -1; // set 'crosses page' flag + if (p > f->stream_end) return error(f, VORBIS_need_more_data); + first = FALSE; + } + return TRUE; } #endif // !STB_VORBIS_NO_PUSHDATA_API -static int start_decoder(vorb *f) +static int start_decoder(vorb* f) { - uint8 header[6], x,y; - int len,i,j,k, max_submaps = 0; - int longest_floorlist=0; + uint8 header[6], x, y; + int len, i, j, k, max_submaps = 0; + int longest_floorlist = 0; - // first page, first packet + // first page, first packet - if (!start_page(f)) return FALSE; - // validate page flag - if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page); - if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page); - if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); - // check for expected packet length - if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); - if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page); - // read packet - // check packet header - if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); - if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof); - if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page); - // vorbis_version - if (get32(f) != 0) return error(f, VORBIS_invalid_first_page); - f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page); - if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels); - f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page); - get32(f); // bitrate_maximum - get32(f); // bitrate_nominal - get32(f); // bitrate_minimum - x = get8(f); - { - int log0,log1; - log0 = x & 15; - log1 = x >> 4; - f->blocksize_0 = 1 << log0; - f->blocksize_1 = 1 << log1; - if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); - if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); - if (log0 > log1) return error(f, VORBIS_invalid_setup); - } + if (!start_page(f)) return FALSE; + // validate page flag + if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page); + if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page); + if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); + // check for expected packet length + if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); + if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page); + // read packet + // check packet header + if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); + if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page); + // vorbis_version + if (get32(f) != 0) return error(f, VORBIS_invalid_first_page); + f->channels = get8(f); + if (!f->channels) return error(f, VORBIS_invalid_first_page); + if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels); + f->sample_rate = get32(f); + if (!f->sample_rate) return error(f, VORBIS_invalid_first_page); + get32(f); // bitrate_maximum + get32(f); // bitrate_nominal + get32(f); // bitrate_minimum + x = get8(f); + { + int log0, log1; + log0 = x & 15; + log1 = x >> 4; + f->blocksize_0 = 1 << log0; + f->blocksize_1 = 1 << log1; + if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); + if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); + if (log0 > log1) return error(f, VORBIS_invalid_setup); + } - // framing_flag - x = get8(f); - if (!(x & 1)) return error(f, VORBIS_invalid_first_page); + // framing_flag + x = get8(f); + if (!(x & 1)) return error(f, VORBIS_invalid_first_page); - // second packet! - if (!start_page(f)) return FALSE; + // second packet! + if (!start_page(f)) return FALSE; - if (!start_packet(f)) return FALSE; - do { - len = next_segment(f); - skip(f, len); - f->bytes_in_seg = 0; - } while (len); + if (!start_packet(f)) return FALSE; + do + { + len = next_segment(f); + skip(f, len); + f->bytes_in_seg = 0; + } + while (len); - // third packet! - if (!start_packet(f)) return FALSE; + // third packet! + if (!start_packet(f)) return FALSE; - #ifndef STB_VORBIS_NO_PUSHDATA_API - if (IS_PUSH_MODE(f)) { - if (!is_whole_packet_present(f, TRUE)) { - // convert error in ogg header to write type - if (f->error == VORBIS_invalid_stream) - f->error = VORBIS_invalid_setup; - return FALSE; - } - } - #endif +#ifndef STB_VORBIS_NO_PUSHDATA_API + if (IS_PUSH_MODE(f)) + { + if (!is_whole_packet_present(f, TRUE)) + { + // convert error in ogg header to write type + if (f->error == VORBIS_invalid_stream) + f->error = VORBIS_invalid_setup; + return FALSE; + } + } +#endif - crc32_init(); // always init it, to avoid multithread race conditions + crc32_init(); // always init it, to avoid multithread race conditions - if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup); - for (i=0; i < 6; ++i) header[i] = get8_packet(f); - if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); + if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup); + for (i = 0; i < 6; ++i) header[i] = get8_packet(f); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); - // codebooks + // codebooks - f->codebook_count = get_bits(f,8) + 1; - f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); - if (f->codebooks == NULL) return error(f, VORBIS_outofmem); - memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count); - for (i=0; i < f->codebook_count; ++i) { - uint32 *values; - int ordered, sorted_count; - int total=0; - uint8 *lengths; - Codebook *c = f->codebooks+i; - CHECK(f); - x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); - x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); - x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); - x = get_bits(f, 8); - c->dimensions = (get_bits(f, 8)<<8) + x; - x = get_bits(f, 8); - y = get_bits(f, 8); - c->entries = (get_bits(f, 8)<<16) + (y<<8) + x; - ordered = get_bits(f,1); - c->sparse = ordered ? 0 : get_bits(f,1); + f->codebook_count = get_bits(f, 8) + 1; + f->codebooks = (Codebook*)setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); + if (f->codebooks == NULL) return error(f, VORBIS_outofmem); + memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count); + for (i = 0; i < f->codebook_count; ++i) + { + uint32* values; + int ordered, sorted_count; + int total = 0; + uint8* lengths; + Codebook* c = f->codebooks + i; + CHECK(f); + x = get_bits(f, 8); + if (x != 0x42) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); + if (x != 0x43) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); + if (x != 0x56) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); + c->dimensions = (get_bits(f, 8) << 8) + x; + x = get_bits(f, 8); + y = get_bits(f, 8); + c->entries = (get_bits(f, 8) << 16) + (y << 8) + x; + ordered = get_bits(f, 1); + c->sparse = ordered ? 0 : get_bits(f, 1); - if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup); + if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup); - if (c->sparse) - lengths = (uint8 *) setup_temp_malloc(f, c->entries); - else - lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); + if (c->sparse) + lengths = (uint8*)setup_temp_malloc(f, c->entries); + else + lengths = c->codeword_lengths = (uint8*)setup_malloc(f, c->entries); - if (!lengths) return error(f, VORBIS_outofmem); + if (!lengths) return error(f, VORBIS_outofmem); - if (ordered) { - int current_entry = 0; - int current_length = get_bits(f,5) + 1; - while (current_entry < c->entries) { - int limit = c->entries - current_entry; - int n = get_bits(f, ilog(limit)); - if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } - memset(lengths + current_entry, current_length, n); - current_entry += n; - ++current_length; - } - } else { - for (j=0; j < c->entries; ++j) { - int present = c->sparse ? get_bits(f,1) : 1; - if (present) { - lengths[j] = get_bits(f, 5) + 1; - ++total; - if (lengths[j] == 32) - return error(f, VORBIS_invalid_setup); - } else { - lengths[j] = NO_CODE; - } - } - } + if (ordered) + { + int current_entry = 0; + int current_length = get_bits(f, 5) + 1; + while (current_entry < c->entries) + { + int limit = c->entries - current_entry; + int n = get_bits(f, ilog(limit)); + if (current_entry + n > (int)c->entries) { return error(f, VORBIS_invalid_setup); } + memset(lengths + current_entry, current_length, n); + current_entry += n; + ++current_length; + } + } + else + { + for (j = 0; j < c->entries; ++j) + { + int present = c->sparse ? get_bits(f, 1) : 1; + if (present) + { + lengths[j] = get_bits(f, 5) + 1; + ++total; + if (lengths[j] == 32) + return error(f, VORBIS_invalid_setup); + } + else + { + lengths[j] = NO_CODE; + } + } + } - if (c->sparse && total >= c->entries >> 2) { - // convert sparse items to non-sparse! - if (c->entries > (int) f->setup_temp_memory_required) - f->setup_temp_memory_required = c->entries; + if (c->sparse && total >= c->entries >> 2) + { + // convert sparse items to non-sparse! + if (c->entries > (int)f->setup_temp_memory_required) + f->setup_temp_memory_required = c->entries; - c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); - if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem); - memcpy(c->codeword_lengths, lengths, c->entries); - setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! - lengths = c->codeword_lengths; - c->sparse = 0; - } + c->codeword_lengths = (uint8*)setup_malloc(f, c->entries); + if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem); + memcpy(c->codeword_lengths, lengths, c->entries); + setup_temp_free(f, lengths, c->entries); + // note this is only safe if there have been no intervening temp mallocs! + lengths = c->codeword_lengths; + c->sparse = 0; + } - // compute the size of the sorted tables - if (c->sparse) { - sorted_count = total; - } else { - sorted_count = 0; - #ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH - for (j=0; j < c->entries; ++j) - if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE) - ++sorted_count; - #endif - } + // compute the size of the sorted tables + if (c->sparse) + { + sorted_count = total; + } + else + { + sorted_count = 0; +#ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH + for (j = 0; j < c->entries; ++j) + if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE) + ++sorted_count; +#endif + } - c->sorted_entries = sorted_count; - values = NULL; + c->sorted_entries = sorted_count; + values = NULL; - CHECK(f); - if (!c->sparse) { - c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); - if (!c->codewords) return error(f, VORBIS_outofmem); - } else { - unsigned int size; - if (c->sorted_entries) { - c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries); - if (!c->codeword_lengths) return error(f, VORBIS_outofmem); - c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); - if (!c->codewords) return error(f, VORBIS_outofmem); - values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); - if (!values) return error(f, VORBIS_outofmem); - } - size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries; - if (size > f->setup_temp_memory_required) - f->setup_temp_memory_required = size; - } + CHECK(f); + if (!c->sparse) + { + c->codewords = (uint32*)setup_malloc(f, sizeof(c->codewords[0]) * c->entries); + if (!c->codewords) return error(f, VORBIS_outofmem); + } + else + { + unsigned int size; + if (c->sorted_entries) + { + c->codeword_lengths = (uint8*)setup_malloc(f, c->sorted_entries); + if (!c->codeword_lengths) return error(f, VORBIS_outofmem); + c->codewords = (uint32*)setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); + if (!c->codewords) return error(f, VORBIS_outofmem); + values = (uint32*)setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); + if (!values) return error(f, VORBIS_outofmem); + } + size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries; + if (size > f->setup_temp_memory_required) + f->setup_temp_memory_required = size; + } - if (!compute_codewords(c, lengths, c->entries, values)) { - if (c->sparse) setup_temp_free(f, values, 0); - return error(f, VORBIS_invalid_setup); - } + if (!compute_codewords(c, lengths, c->entries, values)) + { + if (c->sparse) setup_temp_free(f, values, 0); + return error(f, VORBIS_invalid_setup); + } - if (c->sorted_entries) { - // allocate an extra slot for sentinels - c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); - if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem); - // allocate an extra slot at the front so that c->sorted_values[-1] is defined - // so that we can catch that case without an extra if - c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); - if (c->sorted_values == NULL) return error(f, VORBIS_outofmem); - ++c->sorted_values; - c->sorted_values[-1] = -1; - compute_sorted_huffman(c, lengths, values); - } + if (c->sorted_entries) + { + // allocate an extra slot for sentinels + c->sorted_codewords = (uint32*)setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries + 1)); + if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem); + // allocate an extra slot at the front so that c->sorted_values[-1] is defined + // so that we can catch that case without an extra if + c->sorted_values = (int*)setup_malloc(f, sizeof(*c->sorted_values) * (c->sorted_entries + 1)); + if (c->sorted_values == NULL) return error(f, VORBIS_outofmem); + ++c->sorted_values; + c->sorted_values[-1] = -1; + compute_sorted_huffman(c, lengths, values); + } - if (c->sparse) { - setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); - setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); - setup_temp_free(f, lengths, c->entries); - c->codewords = NULL; - } + if (c->sparse) + { + setup_temp_free(f, values, sizeof(*values) * c->sorted_entries); + setup_temp_free(f, c->codewords, sizeof(*c->codewords) * c->sorted_entries); + setup_temp_free(f, lengths, c->entries); + c->codewords = NULL; + } - compute_accelerated_huffman(c); + compute_accelerated_huffman(c); - CHECK(f); - c->lookup_type = get_bits(f, 4); - if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); - if (c->lookup_type > 0) { - uint16 *mults; - c->minimum_value = float32_unpack(get_bits(f, 32)); - c->delta_value = float32_unpack(get_bits(f, 32)); - c->value_bits = get_bits(f, 4)+1; - c->sequence_p = get_bits(f,1); - if (c->lookup_type == 1) { - c->lookup_values = lookup1_values(c->entries, c->dimensions); - } else { - c->lookup_values = c->entries * c->dimensions; - } - if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup); - mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); - if (mults == NULL) return error(f, VORBIS_outofmem); - for (j=0; j < (int) c->lookup_values; ++j) { - int q = get_bits(f, c->value_bits); - if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); } - mults[j] = q; - } + CHECK(f); + c->lookup_type = get_bits(f, 4); + if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); + if (c->lookup_type > 0) + { + uint16* mults; + c->minimum_value = float32_unpack(get_bits(f, 32)); + c->delta_value = float32_unpack(get_bits(f, 32)); + c->value_bits = get_bits(f, 4) + 1; + c->sequence_p = get_bits(f, 1); + if (c->lookup_type == 1) + { + c->lookup_values = lookup1_values(c->entries, c->dimensions); + } + else + { + c->lookup_values = c->entries * c->dimensions; + } + if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup); + mults = (uint16*)setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); + if (mults == NULL) return error(f, VORBIS_outofmem); + for (j = 0; j < (int)c->lookup_values; ++j) + { + int q = get_bits(f, c->value_bits); + if (q == EOP) + { + setup_temp_free(f, mults, sizeof(mults[0]) * c->lookup_values); + return error(f, VORBIS_invalid_setup); + } + mults[j] = q; + } #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - if (c->lookup_type == 1) { - int len, sparse = c->sparse; - float last=0; - // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop - if (sparse) { - if (c->sorted_entries == 0) goto skip; - c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); - } else - c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); - if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } - len = sparse ? c->sorted_entries : c->entries; - for (j=0; j < len; ++j) { - unsigned int z = sparse ? c->sorted_values[j] : j; - unsigned int div=1; - for (k=0; k < c->dimensions; ++k) { - int off = (z / div) % c->lookup_values; - float val = mults[off]; - val = mults[off]*c->delta_value + c->minimum_value + last; - c->multiplicands[j*c->dimensions + k] = val; - if (c->sequence_p) - last = val; - if (k+1 < c->dimensions) { - if (div > UINT_MAX / (unsigned int) c->lookup_values) { - setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); - return error(f, VORBIS_invalid_setup); - } - div *= c->lookup_values; - } - } - } - c->lookup_type = 2; - } - else + if (c->lookup_type == 1) + { + int len, sparse = c->sparse; + float last = 0; + // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop + if (sparse) + { + if (c->sorted_entries == 0) goto skip; + c->multiplicands = (codetype*)setup_malloc( + f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); + } + else + c->multiplicands = (codetype*)setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); + if (c->multiplicands == NULL) + { + setup_temp_free(f, mults, sizeof(mults[0]) * c->lookup_values); + return error(f, VORBIS_outofmem); + } + len = sparse ? c->sorted_entries : c->entries; + for (j = 0; j < len; ++j) + { + unsigned int z = sparse ? c->sorted_values[j] : j; + unsigned int div = 1; + for (k = 0; k < c->dimensions; ++k) + { + int off = (z / div) % c->lookup_values; + float val = mults[off]; + val = mults[off] * c->delta_value + c->minimum_value + last; + c->multiplicands[j * c->dimensions + k] = val; + if (c->sequence_p) + last = val; + if (k + 1 < c->dimensions) + { + if (div > UINT_MAX / (unsigned int)c->lookup_values) + { + setup_temp_free(f, mults, sizeof(mults[0]) * c->lookup_values); + return error(f, VORBIS_invalid_setup); + } + div *= c->lookup_values; + } + } + } + c->lookup_type = 2; + } + else #endif - { - float last=0; - CHECK(f); - c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); - if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } - for (j=0; j < (int) c->lookup_values; ++j) { - float val = mults[j] * c->delta_value + c->minimum_value + last; - c->multiplicands[j] = val; - if (c->sequence_p) - last = val; - } - } + { + float last = 0; + CHECK(f); + c->multiplicands = (codetype*)setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); + if (c->multiplicands == NULL) + { + setup_temp_free(f, mults, sizeof(mults[0]) * c->lookup_values); + return error(f, VORBIS_outofmem); + } + for (j = 0; j < (int)c->lookup_values; ++j) + { + float val = mults[j] * c->delta_value + c->minimum_value + last; + c->multiplicands[j] = val; + if (c->sequence_p) + last = val; + } + } #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK - skip:; + skip:; #endif - setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values); + setup_temp_free(f, mults, sizeof(mults[0]) * c->lookup_values); - CHECK(f); - } - CHECK(f); - } + CHECK(f); + } + CHECK(f); + } - // time domain transfers (notused) + // time domain transfers (notused) - x = get_bits(f, 6) + 1; - for (i=0; i < x; ++i) { - uint32 z = get_bits(f, 16); - if (z != 0) return error(f, VORBIS_invalid_setup); - } + x = get_bits(f, 6) + 1; + for (i = 0; i < x; ++i) + { + uint32 z = get_bits(f, 16); + if (z != 0) return error(f, VORBIS_invalid_setup); + } - // Floors - f->floor_count = get_bits(f, 6)+1; - f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); - if (f->floor_config == NULL) return error(f, VORBIS_outofmem); - for (i=0; i < f->floor_count; ++i) { - f->floor_types[i] = get_bits(f, 16); - if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup); - if (f->floor_types[i] == 0) { - Floor0 *g = &f->floor_config[i].floor0; - g->order = get_bits(f,8); - g->rate = get_bits(f,16); - g->bark_map_size = get_bits(f,16); - g->amplitude_bits = get_bits(f,6); - g->amplitude_offset = get_bits(f,8); - g->number_of_books = get_bits(f,4) + 1; - for (j=0; j < g->number_of_books; ++j) - g->book_list[j] = get_bits(f,8); - return error(f, VORBIS_feature_not_supported); - } else { - stbv__floor_ordering p[31*8+2]; - Floor1 *g = &f->floor_config[i].floor1; - int max_class = -1; - g->partitions = get_bits(f, 5); - for (j=0; j < g->partitions; ++j) { - g->partition_class_list[j] = get_bits(f, 4); - if (g->partition_class_list[j] > max_class) - max_class = g->partition_class_list[j]; - } - for (j=0; j <= max_class; ++j) { - g->class_dimensions[j] = get_bits(f, 3)+1; - g->class_subclasses[j] = get_bits(f, 2); - if (g->class_subclasses[j]) { - g->class_masterbooks[j] = get_bits(f, 8); - if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); - } - for (k=0; k < 1 << g->class_subclasses[j]; ++k) { - g->subclass_books[j][k] = get_bits(f,8)-1; - if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); - } - } - g->floor1_multiplier = get_bits(f,2)+1; - g->rangebits = get_bits(f,4); - g->Xlist[0] = 0; - g->Xlist[1] = 1 << g->rangebits; - g->values = 2; - for (j=0; j < g->partitions; ++j) { - int c = g->partition_class_list[j]; - for (k=0; k < g->class_dimensions[c]; ++k) { - g->Xlist[g->values] = get_bits(f, g->rangebits); - ++g->values; - } - } - // precompute the sorting - for (j=0; j < g->values; ++j) { - p[j].x = g->Xlist[j]; - p[j].id = j; - } - qsort(p, g->values, sizeof(p[0]), point_compare); - for (j=0; j < g->values; ++j) - g->sorted_order[j] = (uint8) p[j].id; - // precompute the neighbors - for (j=2; j < g->values; ++j) { - int low=0,hi=0; - neighbors(g->Xlist, j, &low,&hi); - g->neighbors[j][0] = low; - g->neighbors[j][1] = hi; - } + // Floors + f->floor_count = get_bits(f, 6) + 1; + f->floor_config = (Floor*)setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); + if (f->floor_config == NULL) return error(f, VORBIS_outofmem); + for (i = 0; i < f->floor_count; ++i) + { + f->floor_types[i] = get_bits(f, 16); + if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup); + if (f->floor_types[i] == 0) + { + Floor0* g = &f->floor_config[i].floor0; + g->order = get_bits(f, 8); + g->rate = get_bits(f, 16); + g->bark_map_size = get_bits(f, 16); + g->amplitude_bits = get_bits(f, 6); + g->amplitude_offset = get_bits(f, 8); + g->number_of_books = get_bits(f, 4) + 1; + for (j = 0; j < g->number_of_books; ++j) + g->book_list[j] = get_bits(f, 8); + return error(f, VORBIS_feature_not_supported); + } + else + { + stbv__floor_ordering p[31 * 8 + 2]; + Floor1* g = &f->floor_config[i].floor1; + int max_class = -1; + g->partitions = get_bits(f, 5); + for (j = 0; j < g->partitions; ++j) + { + g->partition_class_list[j] = get_bits(f, 4); + if (g->partition_class_list[j] > max_class) + max_class = g->partition_class_list[j]; + } + for (j = 0; j <= max_class; ++j) + { + g->class_dimensions[j] = get_bits(f, 3) + 1; + g->class_subclasses[j] = get_bits(f, 2); + if (g->class_subclasses[j]) + { + g->class_masterbooks[j] = get_bits(f, 8); + if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + } + for (k = 0; k < 1 << g->class_subclasses[j]; ++k) + { + g->subclass_books[j][k] = get_bits(f, 8) - 1; + if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + } + } + g->floor1_multiplier = get_bits(f, 2) + 1; + g->rangebits = get_bits(f, 4); + g->Xlist[0] = 0; + g->Xlist[1] = 1 << g->rangebits; + g->values = 2; + for (j = 0; j < g->partitions; ++j) + { + int c = g->partition_class_list[j]; + for (k = 0; k < g->class_dimensions[c]; ++k) + { + g->Xlist[g->values] = get_bits(f, g->rangebits); + ++g->values; + } + } + // precompute the sorting + for (j = 0; j < g->values; ++j) + { + p[j].x = g->Xlist[j]; + p[j].id = j; + } + qsort(p, g->values, sizeof(p[0]), point_compare); + for (j = 0; j < g->values; ++j) + g->sorted_order[j] = (uint8)p[j].id; + // precompute the neighbors + for (j = 2; j < g->values; ++j) + { + int low = 0, hi = 0; + neighbors(g->Xlist, j, &low, &hi); + g->neighbors[j][0] = low; + g->neighbors[j][1] = hi; + } - if (g->values > longest_floorlist) - longest_floorlist = g->values; - } - } + if (g->values > longest_floorlist) + longest_floorlist = g->values; + } + } - // Residue - f->residue_count = get_bits(f, 6)+1; - f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); - if (f->residue_config == NULL) return error(f, VORBIS_outofmem); - memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0])); - for (i=0; i < f->residue_count; ++i) { - uint8 residue_cascade[64]; - Residue *r = f->residue_config+i; - f->residue_types[i] = get_bits(f, 16); - if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); - r->begin = get_bits(f, 24); - r->end = get_bits(f, 24); - if (r->end < r->begin) return error(f, VORBIS_invalid_setup); - r->part_size = get_bits(f,24)+1; - r->classifications = get_bits(f,6)+1; - r->classbook = get_bits(f,8); - if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup); - for (j=0; j < r->classifications; ++j) { - uint8 high_bits=0; - uint8 low_bits=get_bits(f,3); - if (get_bits(f,1)) - high_bits = get_bits(f,5); - residue_cascade[j] = high_bits*8 + low_bits; - } - r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); - if (r->residue_books == NULL) return error(f, VORBIS_outofmem); - for (j=0; j < r->classifications; ++j) { - for (k=0; k < 8; ++k) { - if (residue_cascade[j] & (1 << k)) { - r->residue_books[j][k] = get_bits(f, 8); - if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); - } else { - r->residue_books[j][k] = -1; - } - } - } - // precompute the classifications[] array to avoid inner-loop mod/divide - // call it 'classdata' since we already have r->classifications - r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); - if (!r->classdata) return error(f, VORBIS_outofmem); - memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); - for (j=0; j < f->codebooks[r->classbook].entries; ++j) { - int classwords = f->codebooks[r->classbook].dimensions; - int temp = j; - r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); - if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem); - for (k=classwords-1; k >= 0; --k) { - r->classdata[j][k] = temp % r->classifications; - temp /= r->classifications; - } - } - } + // Residue + f->residue_count = get_bits(f, 6) + 1; + f->residue_config = (Residue*)setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); + if (f->residue_config == NULL) return error(f, VORBIS_outofmem); + memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0])); + for (i = 0; i < f->residue_count; ++i) + { + uint8 residue_cascade[64]; + Residue* r = f->residue_config + i; + f->residue_types[i] = get_bits(f, 16); + if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); + r->begin = get_bits(f, 24); + r->end = get_bits(f, 24); + if (r->end < r->begin) return error(f, VORBIS_invalid_setup); + r->part_size = get_bits(f, 24) + 1; + r->classifications = get_bits(f, 6) + 1; + r->classbook = get_bits(f, 8); + if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup); + for (j = 0; j < r->classifications; ++j) + { + uint8 high_bits = 0; + uint8 low_bits = get_bits(f, 3); + if (get_bits(f, 1)) + high_bits = get_bits(f, 5); + residue_cascade[j] = high_bits * 8 + low_bits; + } + r->residue_books = (short (*)[8])setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); + if (r->residue_books == NULL) return error(f, VORBIS_outofmem); + for (j = 0; j < r->classifications; ++j) + { + for (k = 0; k < 8; ++k) + { + if (residue_cascade[j] & (1 << k)) + { + r->residue_books[j][k] = get_bits(f, 8); + if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + } + else + { + r->residue_books[j][k] = -1; + } + } + } + // precompute the classifications[] array to avoid inner-loop mod/divide + // call it 'classdata' since we already have r->classifications + r->classdata = (uint8**)setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); + if (!r->classdata) return error(f, VORBIS_outofmem); + memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); + for (j = 0; j < f->codebooks[r->classbook].entries; ++j) + { + int classwords = f->codebooks[r->classbook].dimensions; + int temp = j; + r->classdata[j] = (uint8*)setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); + if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem); + for (k = classwords - 1; k >= 0; --k) + { + r->classdata[j][k] = temp % r->classifications; + temp /= r->classifications; + } + } + } - f->mapping_count = get_bits(f,6)+1; - f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); - if (f->mapping == NULL) return error(f, VORBIS_outofmem); - memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping)); - for (i=0; i < f->mapping_count; ++i) { - Mapping *m = f->mapping + i; - int mapping_type = get_bits(f,16); - if (mapping_type != 0) return error(f, VORBIS_invalid_setup); - m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan)); - if (m->chan == NULL) return error(f, VORBIS_outofmem); - if (get_bits(f,1)) - m->submaps = get_bits(f,4)+1; - else - m->submaps = 1; - if (m->submaps > max_submaps) - max_submaps = m->submaps; - if (get_bits(f,1)) { - m->coupling_steps = get_bits(f,8)+1; - for (k=0; k < m->coupling_steps; ++k) { - m->chan[k].magnitude = get_bits(f, ilog(f->channels-1)); - m->chan[k].angle = get_bits(f, ilog(f->channels-1)); - if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup); - if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup); - if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup); - } - } else - m->coupling_steps = 0; + f->mapping_count = get_bits(f, 6) + 1; + f->mapping = (Mapping*)setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); + if (f->mapping == NULL) return error(f, VORBIS_outofmem); + memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping)); + for (i = 0; i < f->mapping_count; ++i) + { + Mapping* m = f->mapping + i; + int mapping_type = get_bits(f, 16); + if (mapping_type != 0) return error(f, VORBIS_invalid_setup); + m->chan = (MappingChannel*)setup_malloc(f, f->channels * sizeof(*m->chan)); + if (m->chan == NULL) return error(f, VORBIS_outofmem); + if (get_bits(f, 1)) + m->submaps = get_bits(f, 4) + 1; + else + m->submaps = 1; + if (m->submaps > max_submaps) + max_submaps = m->submaps; + if (get_bits(f, 1)) + { + m->coupling_steps = get_bits(f, 8) + 1; + for (k = 0; k < m->coupling_steps; ++k) + { + m->chan[k].magnitude = get_bits(f, ilog(f->channels - 1)); + m->chan[k].angle = get_bits(f, ilog(f->channels - 1)); + if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup); + if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup); + if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup); + } + } + else + m->coupling_steps = 0; - // reserved field - if (get_bits(f,2)) return error(f, VORBIS_invalid_setup); - if (m->submaps > 1) { - for (j=0; j < f->channels; ++j) { - m->chan[j].mux = get_bits(f, 4); - if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup); - } - } else - // @SPECIFICATION: this case is missing from the spec - for (j=0; j < f->channels; ++j) - m->chan[j].mux = 0; + // reserved field + if (get_bits(f, 2)) return error(f, VORBIS_invalid_setup); + if (m->submaps > 1) + { + for (j = 0; j < f->channels; ++j) + { + m->chan[j].mux = get_bits(f, 4); + if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup); + } + } + else + // @SPECIFICATION: this case is missing from the spec + for (j = 0; j < f->channels; ++j) + m->chan[j].mux = 0; - for (j=0; j < m->submaps; ++j) { - get_bits(f,8); // discard - m->submap_floor[j] = get_bits(f,8); - m->submap_residue[j] = get_bits(f,8); - if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup); - if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup); - } - } + for (j = 0; j < m->submaps; ++j) + { + get_bits(f, 8); // discard + m->submap_floor[j] = get_bits(f, 8); + m->submap_residue[j] = get_bits(f, 8); + if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup); + if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup); + } + } - // Modes - f->mode_count = get_bits(f, 6)+1; - for (i=0; i < f->mode_count; ++i) { - Mode *m = f->mode_config+i; - m->blockflag = get_bits(f,1); - m->windowtype = get_bits(f,16); - m->transformtype = get_bits(f,16); - m->mapping = get_bits(f,8); - if (m->windowtype != 0) return error(f, VORBIS_invalid_setup); - if (m->transformtype != 0) return error(f, VORBIS_invalid_setup); - if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup); - } + // Modes + f->mode_count = get_bits(f, 6) + 1; + for (i = 0; i < f->mode_count; ++i) + { + Mode* m = f->mode_config + i; + m->blockflag = get_bits(f, 1); + m->windowtype = get_bits(f, 16); + m->transformtype = get_bits(f, 16); + m->mapping = get_bits(f, 8); + if (m->windowtype != 0) return error(f, VORBIS_invalid_setup); + if (m->transformtype != 0) return error(f, VORBIS_invalid_setup); + if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup); + } - flush_packet(f); + flush_packet(f); - f->previous_length = 0; + f->previous_length = 0; - for (i=0; i < f->channels; ++i) { - f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1); - f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); - f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); - if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); - #ifdef STB_VORBIS_NO_DEFER_FLOOR + for (i = 0; i < f->channels; ++i) + { + f->channel_buffers[i] = (float*)setup_malloc(f, sizeof(float) * f->blocksize_1); + f->previous_window[i] = (float*)setup_malloc(f, sizeof(float) * f->blocksize_1 / 2); + f->finalY[i] = (int16*)setup_malloc(f, sizeof(int16) * longest_floorlist); + if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error( + f, VORBIS_outofmem); +#ifdef STB_VORBIS_NO_DEFER_FLOOR f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); - #endif - } +#endif + } - if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE; - if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE; - f->blocksize[0] = f->blocksize_0; - f->blocksize[1] = f->blocksize_1; + if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE; + if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE; + f->blocksize[0] = f->blocksize_0; + f->blocksize[1] = f->blocksize_1; #ifdef STB_VORBIS_DIVIDE_TABLE if (integer_divide_table[1][1]==0) @@ -3729,374 +4067,405 @@ static int start_decoder(vorb *f) integer_divide_table[i][j] = i / j; #endif - // compute how much temporary memory is needed + // compute how much temporary memory is needed - // 1. - { - uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); - uint32 classify_mem; - int i,max_part_read=0; - for (i=0; i < f->residue_count; ++i) { - Residue *r = f->residue_config + i; - int n_read = r->end - r->begin; - int part_read = n_read / r->part_size; - if (part_read > max_part_read) - max_part_read = part_read; - } - #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE - classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *)); - #else + // 1. + { + uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); + uint32 classify_mem; + int i, max_part_read = 0; + for (i = 0; i < f->residue_count; ++i) + { + Residue* r = f->residue_config + i; + int n_read = r->end - r->begin; + int part_read = n_read / r->part_size; + if (part_read > max_part_read) + max_part_read = part_read; + } +#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8*)); +#else classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); - #endif +#endif - f->temp_memory_required = classify_mem; - if (imdct_mem > f->temp_memory_required) - f->temp_memory_required = imdct_mem; - } + f->temp_memory_required = classify_mem; + if (imdct_mem > f->temp_memory_required) + f->temp_memory_required = imdct_mem; + } - f->first_decode = TRUE; + f->first_decode = TRUE; - if (f->alloc.alloc_buffer) { - assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); - // check if there's enough temp memory so we don't error later - if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset) - return error(f, VORBIS_outofmem); - } + if (f->alloc.alloc_buffer) + { + assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); + // check if there's enough temp memory so we don't error later + if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned)f->temp_offset) + return error(f, VORBIS_outofmem); + } - f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + f->first_audio_page_offset = stb_vorbis_get_file_offset(f); - return TRUE; + return TRUE; } -static void vorbis_deinit(stb_vorbis *p) +static void vorbis_deinit(stb_vorbis* p) { - int i,j; - if (p->residue_config) { - for (i=0; i < p->residue_count; ++i) { - Residue *r = p->residue_config+i; - if (r->classdata) { - for (j=0; j < p->codebooks[r->classbook].entries; ++j) - setup_free(p, r->classdata[j]); - setup_free(p, r->classdata); - } - setup_free(p, r->residue_books); - } - } + int i, j; + if (p->residue_config) + { + for (i = 0; i < p->residue_count; ++i) + { + Residue* r = p->residue_config + i; + if (r->classdata) + { + for (j = 0; j < p->codebooks[r->classbook].entries; ++j) + setup_free(p, r->classdata[j]); + setup_free(p, r->classdata); + } + setup_free(p, r->residue_books); + } + } - if (p->codebooks) { - CHECK(p); - for (i=0; i < p->codebook_count; ++i) { - Codebook *c = p->codebooks + i; - setup_free(p, c->codeword_lengths); - setup_free(p, c->multiplicands); - setup_free(p, c->codewords); - setup_free(p, c->sorted_codewords); - // c->sorted_values[-1] is the first entry in the array - setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); - } - setup_free(p, p->codebooks); - } - setup_free(p, p->floor_config); - setup_free(p, p->residue_config); - if (p->mapping) { - for (i=0; i < p->mapping_count; ++i) - setup_free(p, p->mapping[i].chan); - setup_free(p, p->mapping); - } - CHECK(p); - for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) { - setup_free(p, p->channel_buffers[i]); - setup_free(p, p->previous_window[i]); - #ifdef STB_VORBIS_NO_DEFER_FLOOR + if (p->codebooks) + { + CHECK(p); + for (i = 0; i < p->codebook_count; ++i) + { + Codebook* c = p->codebooks + i; + setup_free(p, c->codeword_lengths); + setup_free(p, c->multiplicands); + setup_free(p, c->codewords); + setup_free(p, c->sorted_codewords); + // c->sorted_values[-1] is the first entry in the array + setup_free(p, c->sorted_values ? c->sorted_values - 1 : NULL); + } + setup_free(p, p->codebooks); + } + setup_free(p, p->floor_config); + setup_free(p, p->residue_config); + if (p->mapping) + { + for (i = 0; i < p->mapping_count; ++i) + setup_free(p, p->mapping[i].chan); + setup_free(p, p->mapping); + } + CHECK(p); + for (i = 0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) + { + setup_free(p, p->channel_buffers[i]); + setup_free(p, p->previous_window[i]); +#ifdef STB_VORBIS_NO_DEFER_FLOOR setup_free(p, p->floor_buffers[i]); - #endif - setup_free(p, p->finalY[i]); - } - for (i=0; i < 2; ++i) { - setup_free(p, p->A[i]); - setup_free(p, p->B[i]); - setup_free(p, p->C[i]); - setup_free(p, p->window[i]); - setup_free(p, p->bit_reverse[i]); - } - #ifndef STB_VORBIS_NO_STDIO - if (p->close_on_free) fclose(p->f); - #endif +#endif + setup_free(p, p->finalY[i]); + } + for (i = 0; i < 2; ++i) + { + setup_free(p, p->A[i]); + setup_free(p, p->B[i]); + setup_free(p, p->C[i]); + setup_free(p, p->window[i]); + setup_free(p, p->bit_reverse[i]); + } +#ifndef STB_VORBIS_NO_STDIO + if (p->close_on_free) fclose(p->f); +#endif } -void stb_vorbis_close(stb_vorbis *p) +void stb_vorbis_close(stb_vorbis* p) { - if (p == NULL) return; - vorbis_deinit(p); - setup_free(p,p); + if (p == NULL) return; + vorbis_deinit(p); + setup_free(p, p); } -static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) +static void vorbis_init(stb_vorbis* p, const stb_vorbis_alloc* z) { - memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start - if (z) { - p->alloc = *z; - p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3; - p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; - } - p->eof = 0; - p->error = VORBIS__no_error; - p->stream = NULL; - p->codebooks = NULL; - p->page_crc_tests = -1; - #ifndef STB_VORBIS_NO_STDIO - p->close_on_free = FALSE; - p->f = NULL; - #endif + memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start + if (z) + { + p->alloc = *z; + p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes + 3) & ~3; + p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; + } + p->eof = 0; + p->error = VORBIS__no_error; + p->stream = NULL; + p->codebooks = NULL; + p->page_crc_tests = -1; +#ifndef STB_VORBIS_NO_STDIO + p->close_on_free = FALSE; + p->f = NULL; +#endif } -int stb_vorbis_get_sample_offset(stb_vorbis *f) +int stb_vorbis_get_sample_offset(stb_vorbis* f) { - if (f->current_loc_valid) - return f->current_loc; - else - return -1; + if (f->current_loc_valid) + return f->current_loc; + else + return -1; } -stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) +stb_vorbis_info stb_vorbis_get_info(stb_vorbis* f) { - stb_vorbis_info d; - d.channels = f->channels; - d.sample_rate = f->sample_rate; - d.setup_memory_required = f->setup_memory_required; - d.setup_temp_memory_required = f->setup_temp_memory_required; - d.temp_memory_required = f->temp_memory_required; - d.max_frame_size = f->blocksize_1 >> 1; - return d; + stb_vorbis_info d; + d.channels = f->channels; + d.sample_rate = f->sample_rate; + d.setup_memory_required = f->setup_memory_required; + d.setup_temp_memory_required = f->setup_temp_memory_required; + d.temp_memory_required = f->temp_memory_required; + d.max_frame_size = f->blocksize_1 >> 1; + return d; } -int stb_vorbis_get_error(stb_vorbis *f) +int stb_vorbis_get_error(stb_vorbis* f) { - int e = f->error; - f->error = VORBIS__no_error; - return e; + int e = f->error; + f->error = VORBIS__no_error; + return e; } -static stb_vorbis * vorbis_alloc(stb_vorbis *f) +static stb_vorbis* vorbis_alloc(stb_vorbis* f) { - stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p)); - return p; + stb_vorbis* p = (stb_vorbis*)setup_malloc(f, sizeof(*p)); + return p; } #ifndef STB_VORBIS_NO_PUSHDATA_API -void stb_vorbis_flush_pushdata(stb_vorbis *f) +void stb_vorbis_flush_pushdata(stb_vorbis* f) { - f->previous_length = 0; - f->page_crc_tests = 0; - f->discard_samples_deferred = 0; - f->current_loc_valid = FALSE; - f->first_decode = FALSE; - f->samples_output = 0; - f->channel_buffer_start = 0; - f->channel_buffer_end = 0; + f->previous_length = 0; + f->page_crc_tests = 0; + f->discard_samples_deferred = 0; + f->current_loc_valid = FALSE; + f->first_decode = FALSE; + f->samples_output = 0; + f->channel_buffer_start = 0; + f->channel_buffer_end = 0; } -static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) +static int vorbis_search_for_page_pushdata(vorb* f, uint8* data, int data_len) { - int i,n; - for (i=0; i < f->page_crc_tests; ++i) - f->scan[i].bytes_done = 0; + int i, n; + for (i = 0; i < f->page_crc_tests; ++i) + f->scan[i].bytes_done = 0; - // if we have room for more scans, search for them first, because - // they may cause us to stop early if their header is incomplete - if (f->page_crc_tests < STB_VORBIS_PUSHDATA_CRC_COUNT) { - if (data_len < 4) return 0; - data_len -= 3; // need to look for 4-byte sequence, so don't miss - // one that straddles a boundary - for (i=0; i < data_len; ++i) { - if (data[i] == 0x4f) { - if (0==memcmp(data+i, ogg_page_header, 4)) { - int j,len; - uint32 crc; - // make sure we have the whole page header - if (i+26 >= data_len || i+27+data[i+26] >= data_len) { - // only read up to this page start, so hopefully we'll - // have the whole page header start next time - data_len = i; - break; - } - // ok, we have it all; compute the length of the page - len = 27 + data[i+26]; - for (j=0; j < data[i+26]; ++j) - len += data[i+27+j]; - // scan everything up to the embedded crc (which we must 0) - crc = 0; - for (j=0; j < 22; ++j) - crc = crc32_update(crc, data[i+j]); - // now process 4 0-bytes - for ( ; j < 26; ++j) - crc = crc32_update(crc, 0); - // len is the total number of bytes we need to scan - n = f->page_crc_tests++; - f->scan[n].bytes_left = len-j; - f->scan[n].crc_so_far = crc; - f->scan[n].goal_crc = data[i+22] + (data[i+23] << 8) + (data[i+24]<<16) + (data[i+25]<<24); - // if the last frame on a page is continued to the next, then - // we can't recover the sample_loc immediately - if (data[i+27+data[i+26]-1] == 255) - f->scan[n].sample_loc = ~0; - else - f->scan[n].sample_loc = data[i+6] + (data[i+7] << 8) + (data[i+ 8]<<16) + (data[i+ 9]<<24); - f->scan[n].bytes_done = i+j; - if (f->page_crc_tests == STB_VORBIS_PUSHDATA_CRC_COUNT) - break; - // keep going if we still have room for more - } - } - } - } + // if we have room for more scans, search for them first, because + // they may cause us to stop early if their header is incomplete + if (f->page_crc_tests < STB_VORBIS_PUSHDATA_CRC_COUNT) + { + if (data_len < 4) return 0; + data_len -= 3; // need to look for 4-byte sequence, so don't miss + // one that straddles a boundary + for (i = 0; i < data_len; ++i) + { + if (data[i] == 0x4f) + { + if (0 == memcmp(data + i, ogg_page_header, 4)) + { + int j, len; + uint32 crc; + // make sure we have the whole page header + if (i + 26 >= data_len || i + 27 + data[i + 26] >= data_len) + { + // only read up to this page start, so hopefully we'll + // have the whole page header start next time + data_len = i; + break; + } + // ok, we have it all; compute the length of the page + len = 27 + data[i + 26]; + for (j = 0; j < data[i + 26]; ++j) + len += data[i + 27 + j]; + // scan everything up to the embedded crc (which we must 0) + crc = 0; + for (j = 0; j < 22; ++j) + crc = crc32_update(crc, data[i + j]); + // now process 4 0-bytes + for (; j < 26; ++j) + crc = crc32_update(crc, 0); + // len is the total number of bytes we need to scan + n = f->page_crc_tests++; + f->scan[n].bytes_left = len - j; + f->scan[n].crc_so_far = crc; + f->scan[n].goal_crc = data[i + 22] + (data[i + 23] << 8) + (data[i + 24] << 16) + (data[i + 25] << 24); + // if the last frame on a page is continued to the next, then + // we can't recover the sample_loc immediately + if (data[i + 27 + data[i + 26] - 1] == 255) + f->scan[n].sample_loc = ~0; + else + f->scan[n].sample_loc = data[i + 6] + (data[i + 7] << 8) + (data[i + 8] << 16) + (data[i + 9] << 24); + f->scan[n].bytes_done = i + j; + if (f->page_crc_tests == STB_VORBIS_PUSHDATA_CRC_COUNT) + break; + // keep going if we still have room for more + } + } + } + } - for (i=0; i < f->page_crc_tests;) { - uint32 crc; - int j; - int n = f->scan[i].bytes_done; - int m = f->scan[i].bytes_left; - if (m > data_len - n) m = data_len - n; - // m is the bytes to scan in the current chunk - crc = f->scan[i].crc_so_far; - for (j=0; j < m; ++j) - crc = crc32_update(crc, data[n+j]); - f->scan[i].bytes_left -= m; - f->scan[i].crc_so_far = crc; - if (f->scan[i].bytes_left == 0) { - // does it match? - if (f->scan[i].crc_so_far == f->scan[i].goal_crc) { - // Houston, we have page - data_len = n+m; // consumption amount is wherever that scan ended - f->page_crc_tests = -1; // drop out of page scan mode - f->previous_length = 0; // decode-but-don't-output one frame - f->next_seg = -1; // start a new page - f->current_loc = f->scan[i].sample_loc; // set the current sample location - // to the amount we'd have decoded had we decoded this page - f->current_loc_valid = f->current_loc != ~0U; - return data_len; - } - // delete entry - f->scan[i] = f->scan[--f->page_crc_tests]; - } else { - ++i; - } - } + for (i = 0; i < f->page_crc_tests;) + { + uint32 crc; + int j; + int n = f->scan[i].bytes_done; + int m = f->scan[i].bytes_left; + if (m > data_len - n) m = data_len - n; + // m is the bytes to scan in the current chunk + crc = f->scan[i].crc_so_far; + for (j = 0; j < m; ++j) + crc = crc32_update(crc, data[n + j]); + f->scan[i].bytes_left -= m; + f->scan[i].crc_so_far = crc; + if (f->scan[i].bytes_left == 0) + { + // does it match? + if (f->scan[i].crc_so_far == f->scan[i].goal_crc) + { + // Houston, we have page + data_len = n + m; // consumption amount is wherever that scan ended + f->page_crc_tests = -1; // drop out of page scan mode + f->previous_length = 0; // decode-but-don't-output one frame + f->next_seg = -1; // start a new page + f->current_loc = f->scan[i].sample_loc; // set the current sample location + // to the amount we'd have decoded had we decoded this page + f->current_loc_valid = f->current_loc != ~0U; + return data_len; + } + // delete entry + f->scan[i] = f->scan[--f->page_crc_tests]; + } + else + { + ++i; + } + } - return data_len; + return data_len; } // return value: number of bytes we used int stb_vorbis_decode_frame_pushdata( - stb_vorbis *f, // the file we're decoding - const uint8 *data, int data_len, // the memory available for decoding - int *channels, // place to write number of float * buffers - float ***output, // place to write float ** array of float * buffers - int *samples // place to write number of output samples - ) + stb_vorbis* f, // the file we're decoding + const uint8* data, int data_len, // the memory available for decoding + int* channels, // place to write number of float * buffers + float*** output, // place to write float ** array of float * buffers + int* samples // place to write number of output samples +) { - int i; - int len,right,left; + int i; + int len, right, left; - if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); - if (f->page_crc_tests >= 0) { - *samples = 0; - return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len); - } + if (f->page_crc_tests >= 0) + { + *samples = 0; + return vorbis_search_for_page_pushdata(f, (uint8*)data, data_len); + } - f->stream = (uint8 *) data; - f->stream_end = (uint8 *) data + data_len; - f->error = VORBIS__no_error; + f->stream = (uint8*)data; + f->stream_end = (uint8*)data + data_len; + f->error = VORBIS__no_error; - // check that we have the entire packet in memory - if (!is_whole_packet_present(f, FALSE)) { - *samples = 0; - return 0; - } + // check that we have the entire packet in memory + if (!is_whole_packet_present(f, FALSE)) + { + *samples = 0; + return 0; + } - if (!vorbis_decode_packet(f, &len, &left, &right)) { - // save the actual error we encountered - enum STBVorbisError error = f->error; - if (error == VORBIS_bad_packet_type) { - // flush and resynch - f->error = VORBIS__no_error; - while (get8_packet(f) != EOP) - if (f->eof) break; - *samples = 0; - return (int) (f->stream - data); - } - if (error == VORBIS_continued_packet_flag_invalid) { - if (f->previous_length == 0) { - // we may be resynching, in which case it's ok to hit one - // of these; just discard the packet - f->error = VORBIS__no_error; - while (get8_packet(f) != EOP) - if (f->eof) break; - *samples = 0; - return (int) (f->stream - data); - } - } - // if we get an error while parsing, what to do? - // well, it DEFINITELY won't work to continue from where we are! - stb_vorbis_flush_pushdata(f); - // restore the error that actually made us bail - f->error = error; - *samples = 0; - return 1; - } + if (!vorbis_decode_packet(f, &len, &left, &right)) + { + // save the actual error we encountered + enum STBVorbisError error = f->error; + if (error == VORBIS_bad_packet_type) + { + // flush and resynch + f->error = VORBIS__no_error; + while (get8_packet(f) != EOP) + if (f->eof) break; + *samples = 0; + return (int)(f->stream - data); + } + if (error == VORBIS_continued_packet_flag_invalid) + { + if (f->previous_length == 0) + { + // we may be resynching, in which case it's ok to hit one + // of these; just discard the packet + f->error = VORBIS__no_error; + while (get8_packet(f) != EOP) + if (f->eof) break; + *samples = 0; + return (int)(f->stream - data); + } + } + // if we get an error while parsing, what to do? + // well, it DEFINITELY won't work to continue from where we are! + stb_vorbis_flush_pushdata(f); + // restore the error that actually made us bail + f->error = error; + *samples = 0; + return 1; + } - // success! - len = vorbis_finish_frame(f, len, left, right); - for (i=0; i < f->channels; ++i) - f->outputs[i] = f->channel_buffers[i] + left; + // success! + len = vorbis_finish_frame(f, len, left, right); + for (i = 0; i < f->channels; ++i) + f->outputs[i] = f->channel_buffers[i] + left; - if (channels) *channels = f->channels; - *samples = len; - *output = f->outputs; - return (int) (f->stream - data); + if (channels) *channels = f->channels; + *samples = len; + *output = f->outputs; + return (int)(f->stream - data); } -stb_vorbis *stb_vorbis_open_pushdata( - const unsigned char *data, int data_len, // the memory available for decoding - int *data_used, // only defined if result is not NULL - int *error, const stb_vorbis_alloc *alloc) +stb_vorbis* stb_vorbis_open_pushdata( + const unsigned char* data, int data_len, // the memory available for decoding + int* data_used, // only defined if result is not NULL + int* error, const stb_vorbis_alloc* alloc) { - stb_vorbis *f, p; - vorbis_init(&p, alloc); - p.stream = (uint8 *) data; - p.stream_end = (uint8 *) data + data_len; - p.push_mode = TRUE; - if (!start_decoder(&p)) { - if (p.eof) - *error = VORBIS_need_more_data; - else - *error = p.error; - return NULL; - } - f = vorbis_alloc(&p); - if (f) { - *f = p; - *data_used = (int) (f->stream - data); - *error = 0; - return f; - } else { - vorbis_deinit(&p); - return NULL; - } + stb_vorbis *f, p; + vorbis_init(&p, alloc); + p.stream = (uint8*)data; + p.stream_end = (uint8*)data + data_len; + p.push_mode = TRUE; + if (!start_decoder(&p)) + { + if (p.eof) + *error = VORBIS_need_more_data; + else + *error = p.error; + return NULL; + } + f = vorbis_alloc(&p); + if (f) + { + *f = p; + *data_used = (int)(f->stream - data); + *error = 0; + return f; + } + else + { + vorbis_deinit(&p); + return NULL; + } } #endif // STB_VORBIS_NO_PUSHDATA_API -unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) +unsigned int stb_vorbis_get_file_offset(stb_vorbis* f) { - #ifndef STB_VORBIS_NO_PUSHDATA_API - if (f->push_mode) return 0; - #endif - if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start); - #ifndef STB_VORBIS_NO_STDIO - return (unsigned int) (ftell(f->f) - f->f_start); - #endif +#ifndef STB_VORBIS_NO_PUSHDATA_API + if (f->push_mode) return 0; +#endif + if (USE_MEMORY(f)) return (unsigned int)(f->stream - f->stream_start); +#ifndef STB_VORBIS_NO_STDIO + return (unsigned int)(ftell(f->f) - f->f_start); +#endif } #ifndef STB_VORBIS_NO_PULLDATA_API @@ -4104,74 +4473,81 @@ unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) // DATA-PULLING API // -static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) +static uint32 vorbis_find_page(stb_vorbis* f, uint32* end, uint32* last) { - for(;;) { - int n; - if (f->eof) return 0; - n = get8(f); - if (n == 0x4f) { // page header candidate - unsigned int retry_loc = stb_vorbis_get_file_offset(f); - int i; - // check if we're off the end of a file_section stream - if (retry_loc - 25 > f->stream_len) - return 0; - // check the rest of the header - for (i=1; i < 4; ++i) - if (get8(f) != ogg_page_header[i]) - break; - if (f->eof) return 0; - if (i == 4) { - uint8 header[27]; - uint32 i, crc, goal, len; - for (i=0; i < 4; ++i) - header[i] = ogg_page_header[i]; - for (; i < 27; ++i) - header[i] = get8(f); - if (f->eof) return 0; - if (header[4] != 0) goto invalid; - goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); - for (i=22; i < 26; ++i) - header[i] = 0; - crc = 0; - for (i=0; i < 27; ++i) - crc = crc32_update(crc, header[i]); - len = 0; - for (i=0; i < header[26]; ++i) { - int s = get8(f); - crc = crc32_update(crc, s); - len += s; - } - if (len && f->eof) return 0; - for (i=0; i < len; ++i) - crc = crc32_update(crc, get8(f)); - // finished parsing probable page - if (crc == goal) { - // we could now check that it's either got the last - // page flag set, OR it's followed by the capture - // pattern, but I guess TECHNICALLY you could have - // a file with garbage between each ogg page and recover - // from it automatically? So even though that paranoia - // might decrease the chance of an invalid decode by - // another 2^32, not worth it since it would hose those - // invalid-but-useful files? - if (end) - *end = stb_vorbis_get_file_offset(f); - if (last) { - if (header[5] & 0x04) - *last = 1; - else - *last = 0; - } - set_file_offset(f, retry_loc-1); - return 1; - } - } - invalid: - // not a valid page, so rewind and look for next one - set_file_offset(f, retry_loc); - } - } + for (;;) + { + int n; + if (f->eof) return 0; + n = get8(f); + if (n == 0x4f) + { + // page header candidate + unsigned int retry_loc = stb_vorbis_get_file_offset(f); + int i; + // check if we're off the end of a file_section stream + if (retry_loc - 25 > f->stream_len) + return 0; + // check the rest of the header + for (i = 1; i < 4; ++i) + if (get8(f) != ogg_page_header[i]) + break; + if (f->eof) return 0; + if (i == 4) + { + uint8 header[27]; + uint32 i, crc, goal, len; + for (i = 0; i < 4; ++i) + header[i] = ogg_page_header[i]; + for (; i < 27; ++i) + header[i] = get8(f); + if (f->eof) return 0; + if (header[4] != 0) goto invalid; + goal = header[22] + (header[23] << 8) + (header[24] << 16) + (header[25] << 24); + for (i = 22; i < 26; ++i) + header[i] = 0; + crc = 0; + for (i = 0; i < 27; ++i) + crc = crc32_update(crc, header[i]); + len = 0; + for (i = 0; i < header[26]; ++i) + { + int s = get8(f); + crc = crc32_update(crc, s); + len += s; + } + if (len && f->eof) return 0; + for (i = 0; i < len; ++i) + crc = crc32_update(crc, get8(f)); + // finished parsing probable page + if (crc == goal) + { + // we could now check that it's either got the last + // page flag set, OR it's followed by the capture + // pattern, but I guess TECHNICALLY you could have + // a file with garbage between each ogg page and recover + // from it automatically? So even though that paranoia + // might decrease the chance of an invalid decode by + // another 2^32, not worth it since it would hose those + // invalid-but-useful files? + if (end) + *end = stb_vorbis_get_file_offset(f); + if (last) + { + if (header[5] & 0x04) + *last = 1; + else + *last = 0; + } + set_file_offset(f, retry_loc - 1); + return 1; + } + } + invalid: + // not a valid page, so rewind and look for next one + set_file_offset(f, retry_loc); + } + } } @@ -4186,478 +4562,511 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) // to try to bound either side of the binary search sensibly, while still // working in O(log n) time if they fail. -static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) +static int get_seek_page_info(stb_vorbis* f, ProbedPage* z) { - uint8 header[27], lacing[255]; - int i,len; + uint8 header[27], lacing[255]; + int i, len; - // record where the page starts - z->page_start = stb_vorbis_get_file_offset(f); + // record where the page starts + z->page_start = stb_vorbis_get_file_offset(f); - // parse the header - getn(f, header, 27); - if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S') - return 0; - getn(f, lacing, header[26]); + // parse the header + getn(f, header, 27); + if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S') + return 0; + getn(f, lacing, header[26]); - // determine the length of the payload - len = 0; - for (i=0; i < header[26]; ++i) - len += lacing[i]; + // determine the length of the payload + len = 0; + for (i = 0; i < header[26]; ++i) + len += lacing[i]; - // this implies where the page ends - z->page_end = z->page_start + 27 + header[26] + len; + // this implies where the page ends + z->page_end = z->page_start + 27 + header[26] + len; - // read the last-decoded sample out of the data - z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24); + // read the last-decoded sample out of the data + z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24); - // restore file state to where we were - set_file_offset(f, z->page_start); - return 1; + // restore file state to where we were + set_file_offset(f, z->page_start); + return 1; } // rarely used function to seek back to the preceeding page while finding the // start of a packet -static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) +static int go_to_page_before(stb_vorbis* f, unsigned int limit_offset) { - unsigned int previous_safe, end; + unsigned int previous_safe, end; - // now we want to seek back 64K from the limit - if (limit_offset >= 65536 && limit_offset-65536 >= f->first_audio_page_offset) - previous_safe = limit_offset - 65536; - else - previous_safe = f->first_audio_page_offset; + // now we want to seek back 64K from the limit + if (limit_offset >= 65536 && limit_offset - 65536 >= f->first_audio_page_offset) + previous_safe = limit_offset - 65536; + else + previous_safe = f->first_audio_page_offset; - set_file_offset(f, previous_safe); + set_file_offset(f, previous_safe); - while (vorbis_find_page(f, &end, NULL)) { - if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset) - return 1; - set_file_offset(f, end); - } + while (vorbis_find_page(f, &end, NULL)) + { + if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset) + return 1; + set_file_offset(f, end); + } - return 0; + return 0; } // implements the search logic for finding a page and starting decoding. if // the function succeeds, current_loc_valid will be true and current_loc will // be less than or equal to the provided sample number (the closer the // better). -static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) +static int seek_to_sample_coarse(stb_vorbis* f, uint32 sample_number) { - ProbedPage left, right, mid; - int i, start_seg_with_known_loc, end_pos, page_start; - uint32 delta, stream_length, padding; - double offset = 0, bytes_per_sample = 0; - int probe = 0; + ProbedPage left, right, mid; + int i, start_seg_with_known_loc, end_pos, page_start; + uint32 delta, stream_length, padding; + double offset = 0, bytes_per_sample = 0; + int probe = 0; - // find the last page and validate the target sample - stream_length = stb_vorbis_stream_length_in_samples(f); - if (stream_length == 0) return error(f, VORBIS_seek_without_length); - if (sample_number > stream_length) return error(f, VORBIS_seek_invalid); + // find the last page and validate the target sample + stream_length = stb_vorbis_stream_length_in_samples(f); + if (stream_length == 0) return error(f, VORBIS_seek_without_length); + if (sample_number > stream_length) return error(f, VORBIS_seek_invalid); - // this is the maximum difference between the window-center (which is the - // actual granule position value), and the right-start (which the spec - // indicates should be the granule position (give or take one)). - padding = ((f->blocksize_1 - f->blocksize_0) >> 2); - if (sample_number < padding) - sample_number = 0; - else - sample_number -= padding; + // this is the maximum difference between the window-center (which is the + // actual granule position value), and the right-start (which the spec + // indicates should be the granule position (give or take one)). + padding = ((f->blocksize_1 - f->blocksize_0) >> 2); + if (sample_number < padding) + sample_number = 0; + else + sample_number -= padding; - left = f->p_first; - while (left.last_decoded_sample == ~0U) { - // (untested) the first page does not have a 'last_decoded_sample' - set_file_offset(f, left.page_end); - if (!get_seek_page_info(f, &left)) goto error; - } + left = f->p_first; + while (left.last_decoded_sample == ~0U) + { + // (untested) the first page does not have a 'last_decoded_sample' + set_file_offset(f, left.page_end); + if (!get_seek_page_info(f, &left)) goto error; + } - right = f->p_last; - assert(right.last_decoded_sample != ~0U); + right = f->p_last; + assert(right.last_decoded_sample != ~0U); - // starting from the start is handled differently - if (sample_number <= left.last_decoded_sample) { - if (stb_vorbis_seek_start(f)) - return 1; - return 0; - } + // starting from the start is handled differently + if (sample_number <= left.last_decoded_sample) + { + if (stb_vorbis_seek_start(f)) + return 1; + return 0; + } - while (left.page_end != right.page_start) { - assert(left.page_end < right.page_start); - // search range in bytes - delta = right.page_start - left.page_end; - if (delta <= 65536) { - // there's only 64K left to search - handle it linearly - set_file_offset(f, left.page_end); - } else { - if (probe < 2) { - if (probe == 0) { - // first probe (interpolate) - double data_bytes = right.page_end - left.page_start; - bytes_per_sample = data_bytes / right.last_decoded_sample; - offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample); - } else { - // second probe (try to bound the other side) - double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample; - if (error >= 0 && error < 8000) error = 8000; - if (error < 0 && error > -8000) error = -8000; - offset += error * 2; - } + while (left.page_end != right.page_start) + { + assert(left.page_end < right.page_start); + // search range in bytes + delta = right.page_start - left.page_end; + if (delta <= 65536) + { + // there's only 64K left to search - handle it linearly + set_file_offset(f, left.page_end); + } + else + { + if (probe < 2) + { + if (probe == 0) + { + // first probe (interpolate) + double data_bytes = right.page_end - left.page_start; + bytes_per_sample = data_bytes / right.last_decoded_sample; + offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample); + } + else + { + // second probe (try to bound the other side) + double error = ((double)sample_number - mid.last_decoded_sample) * bytes_per_sample; + if (error >= 0 && error < 8000) error = 8000; + if (error < 0 && error > -8000) error = -8000; + offset += error * 2; + } - // ensure the offset is valid - if (offset < left.page_end) - offset = left.page_end; - if (offset > right.page_start - 65536) - offset = right.page_start - 65536; + // ensure the offset is valid + if (offset < left.page_end) + offset = left.page_end; + if (offset > right.page_start - 65536) + offset = right.page_start - 65536; - set_file_offset(f, (unsigned int) offset); - } else { - // binary search for large ranges (offset by 32K to ensure - // we don't hit the right page) - set_file_offset(f, left.page_end + (delta / 2) - 32768); - } + set_file_offset(f, (unsigned int)offset); + } + else + { + // binary search for large ranges (offset by 32K to ensure + // we don't hit the right page) + set_file_offset(f, left.page_end + (delta / 2) - 32768); + } - if (!vorbis_find_page(f, NULL, NULL)) goto error; - } + if (!vorbis_find_page(f, NULL, NULL)) goto error; + } - for (;;) { - if (!get_seek_page_info(f, &mid)) goto error; - if (mid.last_decoded_sample != ~0U) break; - // (untested) no frames end on this page - set_file_offset(f, mid.page_end); - assert(mid.page_start < right.page_start); - } + for (;;) + { + if (!get_seek_page_info(f, &mid)) goto error; + if (mid.last_decoded_sample != ~0U) break; + // (untested) no frames end on this page + set_file_offset(f, mid.page_end); + assert(mid.page_start < right.page_start); + } - // if we've just found the last page again then we're in a tricky file, - // and we're close enough. - if (mid.page_start == right.page_start) - break; + // if we've just found the last page again then we're in a tricky file, + // and we're close enough. + if (mid.page_start == right.page_start) + break; - if (sample_number < mid.last_decoded_sample) - right = mid; - else - left = mid; + if (sample_number < mid.last_decoded_sample) + right = mid; + else + left = mid; - ++probe; - } + ++probe; + } - // seek back to start of the last packet - page_start = left.page_start; - set_file_offset(f, page_start); - if (!start_page(f)) return error(f, VORBIS_seek_failed); - end_pos = f->end_seg_with_known_loc; - assert(end_pos >= 0); + // seek back to start of the last packet + page_start = left.page_start; + set_file_offset(f, page_start); + if (!start_page(f)) return error(f, VORBIS_seek_failed); + end_pos = f->end_seg_with_known_loc; + assert(end_pos >= 0); - for (;;) { - for (i = end_pos; i > 0; --i) - if (f->segments[i-1] != 255) - break; + for (;;) + { + for (i = end_pos; i > 0; --i) + if (f->segments[i - 1] != 255) + break; - start_seg_with_known_loc = i; + start_seg_with_known_loc = i; - if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet)) - break; + if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet)) + break; - // (untested) the final packet begins on an earlier page - if (!go_to_page_before(f, page_start)) - goto error; + // (untested) the final packet begins on an earlier page + if (!go_to_page_before(f, page_start)) + goto error; - page_start = stb_vorbis_get_file_offset(f); - if (!start_page(f)) goto error; - end_pos = f->segment_count - 1; - } + page_start = stb_vorbis_get_file_offset(f); + if (!start_page(f)) goto error; + end_pos = f->segment_count - 1; + } - // prepare to start decoding - f->current_loc_valid = FALSE; - f->last_seg = FALSE; - f->valid_bits = 0; - f->packet_bytes = 0; - f->bytes_in_seg = 0; - f->previous_length = 0; - f->next_seg = start_seg_with_known_loc; + // prepare to start decoding + f->current_loc_valid = FALSE; + f->last_seg = FALSE; + f->valid_bits = 0; + f->packet_bytes = 0; + f->bytes_in_seg = 0; + f->previous_length = 0; + f->next_seg = start_seg_with_known_loc; - for (i = 0; i < start_seg_with_known_loc; i++) - skip(f, f->segments[i]); + for (i = 0; i < start_seg_with_known_loc; i++) + skip(f, f->segments[i]); - // start decoding (optimizable - this frame is generally discarded) - if (!vorbis_pump_first_frame(f)) - return 0; - if (f->current_loc > sample_number) - return error(f, VORBIS_seek_failed); - return 1; + // start decoding (optimizable - this frame is generally discarded) + if (!vorbis_pump_first_frame(f)) + return 0; + if (f->current_loc > sample_number) + return error(f, VORBIS_seek_failed); + return 1; error: - // try to restore the file to a valid state - stb_vorbis_seek_start(f); - return error(f, VORBIS_seek_failed); + // try to restore the file to a valid state + stb_vorbis_seek_start(f); + return error(f, VORBIS_seek_failed); } // the same as vorbis_decode_initial, but without advancing -static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +static int peek_decode_initial(vorb* f, int* p_left_start, int* p_left_end, int* p_right_start, int* p_right_end, + int* mode) { - int bits_read, bytes_read; + int bits_read, bytes_read; - if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) - return 0; + if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) + return 0; - // either 1 or 2 bytes were read, figure out which so we can rewind - bits_read = 1 + ilog(f->mode_count-1); - if (f->mode_config[*mode].blockflag) - bits_read += 2; - bytes_read = (bits_read + 7) / 8; + // either 1 or 2 bytes were read, figure out which so we can rewind + bits_read = 1 + ilog(f->mode_count - 1); + if (f->mode_config[*mode].blockflag) + bits_read += 2; + bytes_read = (bits_read + 7) / 8; - f->bytes_in_seg += bytes_read; - f->packet_bytes -= bytes_read; - skip(f, -bytes_read); - if (f->next_seg == -1) - f->next_seg = f->segment_count - 1; - else - f->next_seg--; - f->valid_bits = 0; + f->bytes_in_seg += bytes_read; + f->packet_bytes -= bytes_read; + skip(f, -bytes_read); + if (f->next_seg == -1) + f->next_seg = f->segment_count - 1; + else + f->next_seg--; + f->valid_bits = 0; - return 1; + return 1; } -int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) +int stb_vorbis_seek_frame(stb_vorbis* f, unsigned int sample_number) { - uint32 max_frame_samples; + uint32 max_frame_samples; - if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); - // fast page-level search - if (!seek_to_sample_coarse(f, sample_number)) - return 0; + // fast page-level search + if (!seek_to_sample_coarse(f, sample_number)) + return 0; - assert(f->current_loc_valid); - assert(f->current_loc <= sample_number); + assert(f->current_loc_valid); + assert(f->current_loc <= sample_number); - // linear search for the relevant packet - max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2; - while (f->current_loc < sample_number) { - int left_start, left_end, right_start, right_end, mode, frame_samples; - if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) - return error(f, VORBIS_seek_failed); - // calculate the number of samples returned by the next frame - frame_samples = right_start - left_start; - if (f->current_loc + frame_samples > sample_number) { - return 1; // the next frame will contain the sample - } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) { - // there's a chance the frame after this could contain the sample - vorbis_pump_first_frame(f); - } else { - // this frame is too early to be relevant - f->current_loc += frame_samples; - f->previous_length = 0; - maybe_start_packet(f); - flush_packet(f); - } - } - // the next frame will start with the sample - assert(f->current_loc == sample_number); - return 1; + // linear search for the relevant packet + max_frame_samples = (f->blocksize_1 * 3 - f->blocksize_0) >> 2; + while (f->current_loc < sample_number) + { + int left_start, left_end, right_start, right_end, mode, frame_samples; + if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) + return error(f, VORBIS_seek_failed); + // calculate the number of samples returned by the next frame + frame_samples = right_start - left_start; + if (f->current_loc + frame_samples > sample_number) + { + return 1; // the next frame will contain the sample + } + else if (f->current_loc + frame_samples + max_frame_samples > sample_number) + { + // there's a chance the frame after this could contain the sample + vorbis_pump_first_frame(f); + } + else + { + // this frame is too early to be relevant + f->current_loc += frame_samples; + f->previous_length = 0; + maybe_start_packet(f); + flush_packet(f); + } + } + // the next frame will start with the sample + assert(f->current_loc == sample_number); + return 1; } -int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) +int stb_vorbis_seek(stb_vorbis* f, unsigned int sample_number) { - if (!stb_vorbis_seek_frame(f, sample_number)) - return 0; + if (!stb_vorbis_seek_frame(f, sample_number)) + return 0; - if (sample_number != f->current_loc) { - int n; - uint32 frame_start = f->current_loc; - stb_vorbis_get_frame_float(f, &n, NULL); - assert(sample_number > frame_start); - assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end); - f->channel_buffer_start += (sample_number - frame_start); - } + if (sample_number != f->current_loc) + { + int n; + uint32 frame_start = f->current_loc; + stb_vorbis_get_frame_float(f, &n, NULL); + assert(sample_number > frame_start); + assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end); + f->channel_buffer_start += (sample_number - frame_start); + } - return 1; + return 1; } -int stb_vorbis_seek_start(stb_vorbis *f) +int stb_vorbis_seek_start(stb_vorbis* f) { - if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); } - set_file_offset(f, f->first_audio_page_offset); - f->previous_length = 0; - f->first_decode = TRUE; - f->next_seg = -1; - return vorbis_pump_first_frame(f); + if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); } + set_file_offset(f, f->first_audio_page_offset); + f->previous_length = 0; + f->first_decode = TRUE; + f->next_seg = -1; + return vorbis_pump_first_frame(f); } -unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) +unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis* f) { - unsigned int restore_offset, previous_safe; - unsigned int end, last_page_loc; + unsigned int restore_offset, previous_safe; + unsigned int end, last_page_loc; - if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); - if (!f->total_samples) { - unsigned int last; - uint32 lo,hi; - char header[6]; + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (!f->total_samples) + { + unsigned int last; + uint32 lo, hi; + char header[6]; - // first, store the current decode position so we can restore it - restore_offset = stb_vorbis_get_file_offset(f); + // first, store the current decode position so we can restore it + restore_offset = stb_vorbis_get_file_offset(f); - // now we want to seek back 64K from the end (the last page must - // be at most a little less than 64K, but let's allow a little slop) - if (f->stream_len >= 65536 && f->stream_len-65536 >= f->first_audio_page_offset) - previous_safe = f->stream_len - 65536; - else - previous_safe = f->first_audio_page_offset; + // now we want to seek back 64K from the end (the last page must + // be at most a little less than 64K, but let's allow a little slop) + if (f->stream_len >= 65536 && f->stream_len - 65536 >= f->first_audio_page_offset) + previous_safe = f->stream_len - 65536; + else + previous_safe = f->first_audio_page_offset; - set_file_offset(f, previous_safe); - // previous_safe is now our candidate 'earliest known place that seeking - // to will lead to the final page' + set_file_offset(f, previous_safe); + // previous_safe is now our candidate 'earliest known place that seeking + // to will lead to the final page' - if (!vorbis_find_page(f, &end, &last)) { - // if we can't find a page, we're hosed! - f->error = VORBIS_cant_find_last_page; - f->total_samples = 0xffffffff; - goto done; - } + if (!vorbis_find_page(f, &end, &last)) + { + // if we can't find a page, we're hosed! + f->error = VORBIS_cant_find_last_page; + f->total_samples = 0xffffffff; + goto done; + } - // check if there are more pages - last_page_loc = stb_vorbis_get_file_offset(f); + // check if there are more pages + last_page_loc = stb_vorbis_get_file_offset(f); - // stop when the last_page flag is set, not when we reach eof; - // this allows us to stop short of a 'file_section' end without - // explicitly checking the length of the section - while (!last) { - set_file_offset(f, end); - if (!vorbis_find_page(f, &end, &last)) { - // the last page we found didn't have the 'last page' flag - // set. whoops! - break; - } - previous_safe = last_page_loc+1; - last_page_loc = stb_vorbis_get_file_offset(f); - } + // stop when the last_page flag is set, not when we reach eof; + // this allows us to stop short of a 'file_section' end without + // explicitly checking the length of the section + while (!last) + { + set_file_offset(f, end); + if (!vorbis_find_page(f, &end, &last)) + { + // the last page we found didn't have the 'last page' flag + // set. whoops! + break; + } + previous_safe = last_page_loc + 1; + last_page_loc = stb_vorbis_get_file_offset(f); + } - set_file_offset(f, last_page_loc); + set_file_offset(f, last_page_loc); - // parse the header - getn(f, (unsigned char *)header, 6); - // extract the absolute granule position - lo = get32(f); - hi = get32(f); - if (lo == 0xffffffff && hi == 0xffffffff) { - f->error = VORBIS_cant_find_last_page; - f->total_samples = SAMPLE_unknown; - goto done; - } - if (hi) - lo = 0xfffffffe; // saturate - f->total_samples = lo; + // parse the header + getn(f, (unsigned char*)header, 6); + // extract the absolute granule position + lo = get32(f); + hi = get32(f); + if (lo == 0xffffffff && hi == 0xffffffff) + { + f->error = VORBIS_cant_find_last_page; + f->total_samples = SAMPLE_unknown; + goto done; + } + if (hi) + lo = 0xfffffffe; // saturate + f->total_samples = lo; - f->p_last.page_start = last_page_loc; - f->p_last.page_end = end; - f->p_last.last_decoded_sample = lo; + f->p_last.page_start = last_page_loc; + f->p_last.page_end = end; + f->p_last.last_decoded_sample = lo; - done: - set_file_offset(f, restore_offset); - } - return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples; + done: + set_file_offset(f, restore_offset); + } + return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples; } -float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) +float stb_vorbis_stream_length_in_seconds(stb_vorbis* f) { - return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate; + return stb_vorbis_stream_length_in_samples(f) / (float)f->sample_rate; } - -int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) +int stb_vorbis_get_frame_float(stb_vorbis* f, int* channels, float*** output) { - int len, right,left,i; - if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + int len, right, left, i; + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); - if (!vorbis_decode_packet(f, &len, &left, &right)) { - f->channel_buffer_start = f->channel_buffer_end = 0; - return 0; - } + if (!vorbis_decode_packet(f, &len, &left, &right)) + { + f->channel_buffer_start = f->channel_buffer_end = 0; + return 0; + } - len = vorbis_finish_frame(f, len, left, right); - for (i=0; i < f->channels; ++i) - f->outputs[i] = f->channel_buffers[i] + left; + len = vorbis_finish_frame(f, len, left, right); + for (i = 0; i < f->channels; ++i) + f->outputs[i] = f->channel_buffers[i] + left; - f->channel_buffer_start = left; - f->channel_buffer_end = left+len; + f->channel_buffer_start = left; + f->channel_buffer_end = left + len; - if (channels) *channels = f->channels; - if (output) *output = f->outputs; - return len; + if (channels) *channels = f->channels; + if (output) *output = f->outputs; + return len; } #ifndef STB_VORBIS_NO_STDIO -stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) +stb_vorbis* stb_vorbis_open_file_section(FILE* file, int close_on_free, int* error, const stb_vorbis_alloc* alloc, + unsigned int length) { - stb_vorbis *f, p; - vorbis_init(&p, alloc); - p.f = file; - p.f_start = (uint32) ftell(file); - p.stream_len = length; - p.close_on_free = close_on_free; - if (start_decoder(&p)) { - f = vorbis_alloc(&p); - if (f) { - *f = p; - vorbis_pump_first_frame(f); - return f; - } - } - if (error) *error = p.error; - vorbis_deinit(&p); - return NULL; + stb_vorbis *f, p; + vorbis_init(&p, alloc); + p.f = file; + p.f_start = (uint32)ftell(file); + p.stream_len = length; + p.close_on_free = close_on_free; + if (start_decoder(&p)) + { + f = vorbis_alloc(&p); + if (f) + { + *f = p; + vorbis_pump_first_frame(f); + return f; + } + } + if (error) *error = p.error; + vorbis_deinit(&p); + return NULL; } -stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) +stb_vorbis* stb_vorbis_open_file(FILE* file, int close_on_free, int* error, const stb_vorbis_alloc* alloc) { - unsigned int len, start; - start = (unsigned int) ftell(file); - fseek(file, 0, SEEK_END); - len = (unsigned int) (ftell(file) - start); - fseek(file, start, SEEK_SET); - return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); + unsigned int len, start; + start = (unsigned int)ftell(file); + fseek(file, 0, SEEK_END); + len = (unsigned int)(ftell(file) - start); + fseek(file, start, SEEK_SET); + return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); } -stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) +stb_vorbis* stb_vorbis_open_filename(const char* filename, int* error, const stb_vorbis_alloc* alloc) { - FILE *f; + FILE* f; #if defined(_MSC_VER) || defined(__MINGW64__) - fopen_s(&f, filename, "rb"); + fopen_s(&f, filename, "rb"); #else f = fopen(filename, "rb"); #endif - if (f) - return stb_vorbis_open_file(f, TRUE, error, alloc); - if (error) *error = VORBIS_file_open_failure; - return NULL; + if (f) + return stb_vorbis_open_file(f, TRUE, error, alloc); + if (error) *error = VORBIS_file_open_failure; + return NULL; } #endif // STB_VORBIS_NO_STDIO -stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) +stb_vorbis* stb_vorbis_open_memory(const unsigned char* data, int len, int* error, const stb_vorbis_alloc* alloc) { - stb_vorbis *f, p; - if (data == NULL) return NULL; - vorbis_init(&p, alloc); - p.stream = (uint8 *) data; - p.stream_end = (uint8 *) data + len; - p.stream_start = (uint8 *) p.stream; - p.stream_len = len; - p.push_mode = FALSE; - if (start_decoder(&p)) { - f = vorbis_alloc(&p); - if (f) { - *f = p; - vorbis_pump_first_frame(f); - if (error) *error = VORBIS__no_error; - return f; - } - } - if (error) *error = p.error; - vorbis_deinit(&p); - return NULL; + stb_vorbis *f, p; + if (data == NULL) return NULL; + vorbis_init(&p, alloc); + p.stream = (uint8*)data; + p.stream_end = (uint8*)data + len; + p.stream_start = (uint8*)p.stream; + p.stream_len = len; + p.push_mode = FALSE; + if (start_decoder(&p)) + { + f = vorbis_alloc(&p); + if (f) + { + *f = p; + vorbis_pump_first_frame(f); + if (error) *error = VORBIS__no_error; + return f; + } + } + if (error) *error = p.error; + vorbis_deinit(&p); + return NULL; } #ifndef STB_VORBIS_NO_INTEGER_CONVERSION @@ -4671,348 +5080,392 @@ stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *err static int8 channel_position[7][6] = { - { 0 }, - { C }, - { L, R }, - { L, C, R }, - { L, R, L, R }, - { L, C, R, L, R }, - { L, C, R, L, R, C }, + {0}, + {C}, + {L, R}, + {L, C, R}, + {L, R, L, R}, + {L, C, R, L, R}, + {L, C, R, L, R, C}, }; #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT - typedef union { - float f; - int i; - } float_conv; - typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4]; - #define FASTDEF(x) float_conv x - // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round - #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) - #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) - #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s)) - #define check_endianness() +typedef union +{ + float f; + int i; +} float_conv; + +typedef char stb_vorbis_float_size_test[sizeof(float) == 4 && sizeof(int) == 4]; +#define FASTDEF(x) float_conv x +// add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round +#define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) +#define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) +#define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s)) +#define check_endianness() #else #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) #define check_endianness() #define FASTDEF(x) #endif -static void copy_samples(short *dest, float *src, int len) +static void copy_samples(short* dest, float* src, int len) { - int i; - check_endianness(); - for (i=0; i < len; ++i) { - FASTDEF(temp); - int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); - if ((unsigned int) (v + 32768) > 65535) - v = v < 0 ? -32768 : 32767; - dest[i] = v; - } + int i; + check_endianness(); + for (i = 0; i < len; ++i) + { + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i], 15); + if ((unsigned int)(v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + dest[i] = v; + } } -static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) +static void compute_samples(int mask, short* output, int num_c, float** data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE; - check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE) { - memset(buffer, 0, sizeof(buffer)); - if (o + n > len) n = len - o; - for (j=0; j < num_c; ++j) { - if (channel_position[num_c][j] & mask) { - for (i=0; i < n; ++i) - buffer[i] += data[j][d_offset+o+i]; - } - } - for (i=0; i < n; ++i) { - FASTDEF(temp); - int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); - if ((unsigned int) (v + 32768) > 65535) - v = v < 0 ? -32768 : 32767; - output[o+i] = v; - } - } +#define BUFFER_SIZE 32 + float buffer[BUFFER_SIZE]; + int i, j, o, n = BUFFER_SIZE; + check_endianness(); + for (o = 0; o < len; o += BUFFER_SIZE) + { + memset(buffer, 0, sizeof(buffer)); + if (o + n > len) n = len - o; + for (j = 0; j < num_c; ++j) + { + if (channel_position[num_c][j] & mask) + { + for (i = 0; i < n; ++i) + buffer[i] += data[j][d_offset + o + i]; + } + } + for (i = 0; i < n; ++i) + { + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp, buffer[i], 15); + if ((unsigned int)(v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + output[o + i] = v; + } + } } -static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) +static void compute_stereo_samples(short* output, int num_c, float** data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE >> 1; - // o is the offset in the source data - check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE >> 1) { - // o2 is the offset in the output data - int o2 = o << 1; - memset(buffer, 0, sizeof(buffer)); - if (o + n > len) n = len - o; - for (j=0; j < num_c; ++j) { - int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT); - if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) { - for (i=0; i < n; ++i) { - buffer[i*2+0] += data[j][d_offset+o+i]; - buffer[i*2+1] += data[j][d_offset+o+i]; - } - } else if (m == PLAYBACK_LEFT) { - for (i=0; i < n; ++i) { - buffer[i*2+0] += data[j][d_offset+o+i]; - } - } else if (m == PLAYBACK_RIGHT) { - for (i=0; i < n; ++i) { - buffer[i*2+1] += data[j][d_offset+o+i]; - } - } - } - for (i=0; i < (n<<1); ++i) { - FASTDEF(temp); - int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); - if ((unsigned int) (v + 32768) > 65535) - v = v < 0 ? -32768 : 32767; - output[o2+i] = v; - } - } +#define BUFFER_SIZE 32 + float buffer[BUFFER_SIZE]; + int i, j, o, n = BUFFER_SIZE >> 1; + // o is the offset in the source data + check_endianness(); + for (o = 0; o < len; o += BUFFER_SIZE >> 1) + { + // o2 is the offset in the output data + int o2 = o << 1; + memset(buffer, 0, sizeof(buffer)); + if (o + n > len) n = len - o; + for (j = 0; j < num_c; ++j) + { + int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT); + if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) + { + for (i = 0; i < n; ++i) + { + buffer[i * 2 + 0] += data[j][d_offset + o + i]; + buffer[i * 2 + 1] += data[j][d_offset + o + i]; + } + } + else if (m == PLAYBACK_LEFT) + { + for (i = 0; i < n; ++i) + { + buffer[i * 2 + 0] += data[j][d_offset + o + i]; + } + } + else if (m == PLAYBACK_RIGHT) + { + for (i = 0; i < n; ++i) + { + buffer[i * 2 + 1] += data[j][d_offset + o + i]; + } + } + } + for (i = 0; i < (n << 1); ++i) + { + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp, buffer[i], 15); + if ((unsigned int)(v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + output[o2 + i] = v; + } + } } -static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) +static void convert_samples_short(int buf_c, short** buffer, int b_offset, int data_c, float** data, int d_offset, + int samples) { - int i; - if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { - static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} }; - for (i=0; i < buf_c; ++i) - compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); - } else { - int limit = buf_c < data_c ? buf_c : data_c; - for (i=0; i < limit; ++i) - copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples); - for ( ; i < buf_c; ++i) - memset(buffer[i]+b_offset, 0, sizeof(short) * samples); - } + int i; + if (buf_c != data_c && buf_c <= 2 && data_c <= 6) + { + static int channel_selector[3][2] = {{0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT}}; + for (i = 0; i < buf_c; ++i) + compute_samples(channel_selector[buf_c][i], buffer[i] + b_offset, data_c, data, d_offset, samples); + } + else + { + int limit = buf_c < data_c ? buf_c : data_c; + for (i = 0; i < limit; ++i) + copy_samples(buffer[i] + b_offset, data[i] + d_offset, samples); + for (; i < buf_c; ++i) + memset(buffer[i] + b_offset, 0, sizeof(short) * samples); + } } -int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) +int stb_vorbis_get_frame_short(stb_vorbis* f, int num_c, short** buffer, int num_samples) { - float **output = nullptr; - int len = stb_vorbis_get_frame_float(f, NULL, &output); - if (len > num_samples) len = num_samples; - if (len) - convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); - return len; + float** output = nullptr; + int len = stb_vorbis_get_frame_float(f, NULL, &output); + if (len > num_samples) len = num_samples; + if (len) + convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); + return len; } -static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) +static void convert_channels_short_interleaved(int buf_c, short* buffer, int data_c, float** data, int d_offset, + int len) { - int i; - check_endianness(); - if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { - assert(buf_c == 2); - for (i=0; i < buf_c; ++i) - compute_stereo_samples(buffer, data_c, data, d_offset, len); - } else { - int limit = buf_c < data_c ? buf_c : data_c; - int j; - for (j=0; j < len; ++j) { - for (i=0; i < limit; ++i) { - FASTDEF(temp); - float f = data[i][d_offset+j]; - int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); - if ((unsigned int) (v + 32768) > 65535) - v = v < 0 ? -32768 : 32767; - *buffer++ = v; - } - for ( ; i < buf_c; ++i) - *buffer++ = 0; - } - } + int i; + check_endianness(); + if (buf_c != data_c && buf_c <= 2 && data_c <= 6) + { + assert(buf_c == 2); + for (i = 0; i < buf_c; ++i) + compute_stereo_samples(buffer, data_c, data, d_offset, len); + } + else + { + int limit = buf_c < data_c ? buf_c : data_c; + int j; + for (j = 0; j < len; ++j) + { + for (i = 0; i < limit; ++i) + { + FASTDEF(temp); + float f = data[i][d_offset + j]; + int v = FAST_SCALED_FLOAT_TO_INT(temp, f, 15); //data[i][d_offset+j],15); + if ((unsigned int)(v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + *buffer++ = v; + } + for (; i < buf_c; ++i) + *buffer++ = 0; + } + } } -int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) +int stb_vorbis_get_frame_short_interleaved(stb_vorbis* f, int num_c, short* buffer, int num_shorts) { - float **output; - int len; - if (num_c == 1) return stb_vorbis_get_frame_short(f,num_c,&buffer, num_shorts); - len = stb_vorbis_get_frame_float(f, NULL, &output); - if (len) { - if (len*num_c > num_shorts) len = num_shorts / num_c; - convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); - } - return len; + float** output; + int len; + if (num_c == 1) return stb_vorbis_get_frame_short(f, num_c, &buffer, num_shorts); + len = stb_vorbis_get_frame_float(f, NULL, &output); + if (len) + { + if (len * num_c > num_shorts) len = num_shorts / num_c; + convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); + } + return len; } -int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) +int stb_vorbis_get_samples_short_interleaved(stb_vorbis* f, int channels, short* buffer, int num_shorts) { - float **outputs; - int len = num_shorts / channels; - int n=0; - int z = f->channels; - if (z > channels) z = channels; - while (n < len) { - int k = f->channel_buffer_end - f->channel_buffer_start; - if (n+k >= len) k = len - n; - if (k) - convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); - buffer += k*channels; - n += k; - f->channel_buffer_start += k; - if (n == len) break; - if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; - } - return n; + float** outputs; + int len = num_shorts / channels; + int n = 0; + int z = f->channels; + if (z > channels) z = channels; + while (n < len) + { + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n + k >= len) k = len - n; + if (k) + convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, + k); + buffer += k * channels; + n += k; + f->channel_buffer_start += k; + if (n == len) break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; + } + return n; } -int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) +int stb_vorbis_get_samples_short(stb_vorbis* f, int channels, short** buffer, int len) { - float **outputs; - int n=0; - int z = f->channels; - if (z > channels) z = channels; - while (n < len) { - int k = f->channel_buffer_end - f->channel_buffer_start; - if (n+k >= len) k = len - n; - if (k) - convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); - n += k; - f->channel_buffer_start += k; - if (n == len) break; - if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; - } - return n; + float** outputs; + int n = 0; + int z = f->channels; + if (z > channels) z = channels; + while (n < len) + { + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n + k >= len) k = len - n; + if (k) + convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); + n += k; + f->channel_buffer_start += k; + if (n == len) break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; + } + return n; } #ifndef STB_VORBIS_NO_STDIO -int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output) +int stb_vorbis_decode_filename(const char* filename, int* channels, int* sample_rate, short** output) { - int data_len, offset, total, limit, error; - short *data; - stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL); - if (v == NULL) return -1; - limit = v->channels * 4096; - *channels = v->channels; - if (sample_rate) - *sample_rate = v->sample_rate; - offset = data_len = 0; - total = limit; - data = (short *) malloc(total * sizeof(*data)); - if (data == NULL) { - stb_vorbis_close(v); - return -2; - } - for (;;) { - int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset); - if (n == 0) break; - data_len += n; - offset += n * v->channels; - if (offset + limit > total) { - short *data2; - total *= 2; - data2 = (short *) realloc(data, total * sizeof(*data)); - if (data2 == NULL) { - free(data); - stb_vorbis_close(v); - return -2; - } - data = data2; - } - } - *output = data; - stb_vorbis_close(v); - return data_len; + int data_len, offset, total, limit, error; + short* data; + stb_vorbis* v = stb_vorbis_open_filename(filename, &error, NULL); + if (v == NULL) return -1; + limit = v->channels * 4096; + *channels = v->channels; + if (sample_rate) + *sample_rate = v->sample_rate; + offset = data_len = 0; + total = limit; + data = (short*)malloc(total * sizeof(*data)); + if (data == NULL) + { + stb_vorbis_close(v); + return -2; + } + for (;;) + { + int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data + offset, total - offset); + if (n == 0) break; + data_len += n; + offset += n * v->channels; + if (offset + limit > total) + { + short* data2; + total *= 2; + data2 = (short*)realloc(data, total * sizeof(*data)); + if (data2 == NULL) + { + free(data); + stb_vorbis_close(v); + return -2; + } + data = data2; + } + } + *output = data; + stb_vorbis_close(v); + return data_len; } #endif // NO_STDIO -int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output) +int stb_vorbis_decode_memory(const uint8* mem, int len, int* channels, int* sample_rate, short** output) { - int data_len, offset, total, limit, error; - short *data; - stb_vorbis *v = stb_vorbis_open_memory(mem, len, &error, NULL); - if (v == NULL) return -1; - limit = v->channels * 4096; - *channels = v->channels; - if (sample_rate) - *sample_rate = v->sample_rate; - offset = data_len = 0; - total = limit; - data = (short *) malloc(total * sizeof(*data)); - if (data == NULL) { - stb_vorbis_close(v); - return -2; - } - for (;;) { - int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset); - if (n == 0) break; - data_len += n; - offset += n * v->channels; - if (offset + limit > total) { - short *data2; - total *= 2; - data2 = (short *) realloc(data, total * sizeof(*data)); - if (data2 == NULL) { - free(data); - stb_vorbis_close(v); - return -2; - } - data = data2; - } - } - *output = data; - stb_vorbis_close(v); - return data_len; + int data_len, offset, total, limit, error; + short* data; + stb_vorbis* v = stb_vorbis_open_memory(mem, len, &error, NULL); + if (v == NULL) return -1; + limit = v->channels * 4096; + *channels = v->channels; + if (sample_rate) + *sample_rate = v->sample_rate; + offset = data_len = 0; + total = limit; + data = (short*)malloc(total * sizeof(*data)); + if (data == NULL) + { + stb_vorbis_close(v); + return -2; + } + for (;;) + { + int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data + offset, total - offset); + if (n == 0) break; + data_len += n; + offset += n * v->channels; + if (offset + limit > total) + { + short* data2; + total *= 2; + data2 = (short*)realloc(data, total * sizeof(*data)); + if (data2 == NULL) + { + free(data); + stb_vorbis_close(v); + return -2; + } + data = data2; + } + } + *output = data; + stb_vorbis_close(v); + return data_len; } #endif // STB_VORBIS_NO_INTEGER_CONVERSION -int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) +int stb_vorbis_get_samples_float_interleaved(stb_vorbis* f, int channels, float* buffer, int num_floats) { - float **outputs; - int len = num_floats / channels; - int n=0; - int z = f->channels; - if (z > channels) z = channels; - while (n < len) { - int i,j; - int k = f->channel_buffer_end - f->channel_buffer_start; - if (n+k >= len) k = len - n; - for (j=0; j < k; ++j) { - for (i=0; i < z; ++i) - *buffer++ = f->channel_buffers[i][f->channel_buffer_start+j]; - for ( ; i < channels; ++i) - *buffer++ = 0; - } - n += k; - f->channel_buffer_start += k; - if (n == len) - break; - if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) - break; - } - return n; + float** outputs; + int len = num_floats / channels; + int n = 0; + int z = f->channels; + if (z > channels) z = channels; + while (n < len) + { + int i, j; + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n + k >= len) k = len - n; + for (j = 0; j < k; ++j) + { + for (i = 0; i < z; ++i) + *buffer++ = f->channel_buffers[i][f->channel_buffer_start + j]; + for (; i < channels; ++i) + *buffer++ = 0; + } + n += k; + f->channel_buffer_start += k; + if (n == len) + break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) + break; + } + return n; } -int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) +int stb_vorbis_get_samples_float(stb_vorbis* f, int channels, float** buffer, int num_samples) { - float **outputs; - int n=0; - int z = f->channels; - if (z > channels) z = channels; - while (n < num_samples) { - int i; - int k = f->channel_buffer_end - f->channel_buffer_start; - if (n+k >= num_samples) k = num_samples - n; - if (k) { - for (i=0; i < z; ++i) - memcpy(buffer[i]+n, f->channel_buffers[i]+f->channel_buffer_start, sizeof(float)*k); - for ( ; i < channels; ++i) - memset(buffer[i]+n, 0, sizeof(float) * k); - } - n += k; - f->channel_buffer_start += k; - if (n == num_samples) - break; - if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) - break; - } - return n; + float** outputs; + int n = 0; + int z = f->channels; + if (z > channels) z = channels; + while (n < num_samples) + { + int i; + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n + k >= num_samples) k = num_samples - n; + if (k) + { + for (i = 0; i < z; ++i) + memcpy(buffer[i] + n, f->channel_buffers[i] + f->channel_buffer_start, sizeof(float) * k); + for (; i < channels; ++i) + memset(buffer[i] + n, 0, sizeof(float) * k); + } + n += k; + f->channel_buffer_start += k; + if (n == num_samples) + break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) + break; + } + return n; } #endif // STB_VORBIS_NO_PULLDATA_API diff --git a/Utilities/stb_vorbis.h b/Utilities/stb_vorbis.h index a7dcb07..c3c0085 100644 --- a/Utilities/stb_vorbis.h +++ b/Utilities/stb_vorbis.h @@ -18,307 +18,316 @@ extern "C" { #endif - /////////// THREAD SAFETY +/////////// THREAD SAFETY - // Individual stb_vorbis* handles are not thread-safe; you cannot decode from - // them from multiple threads at the same time. However, you can have multiple - // stb_vorbis* handles and decode from them independently in multiple thrads. +// Individual stb_vorbis* handles are not thread-safe; you cannot decode from +// them from multiple threads at the same time. However, you can have multiple +// stb_vorbis* handles and decode from them independently in multiple thrads. - /////////// MEMORY ALLOCATION +/////////// MEMORY ALLOCATION - // normally stb_vorbis uses malloc() to allocate memory at startup, - // and alloca() to allocate temporary memory during a frame on the - // stack. (Memory consumption will depend on the amount of setup - // data in the file and how you set the compile flags for speed - // vs. size. In my test files the maximal-size usage is ~150KB.) - // - // You can modify the wrapper functions in the source (setup_malloc, - // setup_temp_malloc, temp_malloc) to change this behavior, or you - // can use a simpler allocation model: you pass in a buffer from - // which stb_vorbis will allocate _all_ its memory (including the - // temp memory). "open" may fail with a VORBIS_outofmem if you - // do not pass in enough data; there is no way to determine how - // much you do need except to succeed (at which point you can - // query get_info to find the exact amount required. yes I know - // this is lame). - // - // If you pass in a non-NULL buffer of the type below, allocation - // will occur from it as described above. Otherwise just pass NULL - // to use malloc()/alloca() +// normally stb_vorbis uses malloc() to allocate memory at startup, +// and alloca() to allocate temporary memory during a frame on the +// stack. (Memory consumption will depend on the amount of setup +// data in the file and how you set the compile flags for speed +// vs. size. In my test files the maximal-size usage is ~150KB.) +// +// You can modify the wrapper functions in the source (setup_malloc, +// setup_temp_malloc, temp_malloc) to change this behavior, or you +// can use a simpler allocation model: you pass in a buffer from +// which stb_vorbis will allocate _all_ its memory (including the +// temp memory). "open" may fail with a VORBIS_outofmem if you +// do not pass in enough data; there is no way to determine how +// much you do need except to succeed (at which point you can +// query get_info to find the exact amount required. yes I know +// this is lame). +// +// If you pass in a non-NULL buffer of the type below, allocation +// will occur from it as described above. Otherwise just pass NULL +// to use malloc()/alloca() - typedef struct - { - char *alloc_buffer; - int alloc_buffer_length_in_bytes; - } stb_vorbis_alloc; +typedef struct +{ + char* alloc_buffer; + int alloc_buffer_length_in_bytes; +} stb_vorbis_alloc; - /////////// FUNCTIONS USEABLE WITH ALL INPUT MODES +/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES - typedef struct stb_vorbis stb_vorbis; +typedef struct stb_vorbis stb_vorbis; - typedef struct - { - unsigned int sample_rate; - int channels; +typedef struct +{ + unsigned int sample_rate; + int channels; - unsigned int setup_memory_required; - unsigned int setup_temp_memory_required; - unsigned int temp_memory_required; + unsigned int setup_memory_required; + unsigned int setup_temp_memory_required; + unsigned int temp_memory_required; - int max_frame_size; - } stb_vorbis_info; + int max_frame_size; +} stb_vorbis_info; - // get general information about the file - extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); +// get general information about the file +extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis* f); - // get the last error detected (clears it, too) - extern int stb_vorbis_get_error(stb_vorbis *f); +// get the last error detected (clears it, too) +extern int stb_vorbis_get_error(stb_vorbis* f); - // close an ogg vorbis file and free all memory in use - extern void stb_vorbis_close(stb_vorbis *f); +// close an ogg vorbis file and free all memory in use +extern void stb_vorbis_close(stb_vorbis* f); - // this function returns the offset (in samples) from the beginning of the - // file that will be returned by the next decode, if it is known, or -1 - // otherwise. after a flush_pushdata() call, this may take a while before - // it becomes valid again. - // NOT WORKING YET after a seek with PULLDATA API - extern int stb_vorbis_get_sample_offset(stb_vorbis *f); +// this function returns the offset (in samples) from the beginning of the +// file that will be returned by the next decode, if it is known, or -1 +// otherwise. after a flush_pushdata() call, this may take a while before +// it becomes valid again. +// NOT WORKING YET after a seek with PULLDATA API +extern int stb_vorbis_get_sample_offset(stb_vorbis* f); - // returns the current seek point within the file, or offset from the beginning - // of the memory buffer. In pushdata mode it returns 0. - extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); +// returns the current seek point within the file, or offset from the beginning +// of the memory buffer. In pushdata mode it returns 0. +extern unsigned int stb_vorbis_get_file_offset(stb_vorbis* f); - /////////// PUSHDATA API +/////////// PUSHDATA API #ifndef STB_VORBIS_NO_PUSHDATA_API - // this API allows you to get blocks of data from any source and hand - // them to stb_vorbis. you have to buffer them; stb_vorbis will tell - // you how much it used, and you have to give it the rest next time; - // and stb_vorbis may not have enough data to work with and you will - // need to give it the same data again PLUS more. Note that the Vorbis - // specification does not bound the size of an individual frame. +// this API allows you to get blocks of data from any source and hand +// them to stb_vorbis. you have to buffer them; stb_vorbis will tell +// you how much it used, and you have to give it the rest next time; +// and stb_vorbis may not have enough data to work with and you will +// need to give it the same data again PLUS more. Note that the Vorbis +// specification does not bound the size of an individual frame. - extern stb_vorbis *stb_vorbis_open_pushdata( - const unsigned char * datablock, int datablock_length_in_bytes, - int *datablock_memory_consumed_in_bytes, - int *error, - const stb_vorbis_alloc *alloc_buffer); - // create a vorbis decoder by passing in the initial data block containing - // the ogg&vorbis headers (you don't need to do parse them, just provide - // the first N bytes of the file--you're told if it's not enough, see below) - // on success, returns an stb_vorbis *, does not set error, returns the amount of - // data parsed/consumed on this call in *datablock_memory_consumed_in_bytes; - // on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed - // if returns NULL and *error is VORBIS_need_more_data, then the input block was - // incomplete and you need to pass in a larger block from the start of the file +extern stb_vorbis* stb_vorbis_open_pushdata( + const unsigned char* datablock, int datablock_length_in_bytes, + int* datablock_memory_consumed_in_bytes, + int* error, + const stb_vorbis_alloc* alloc_buffer); +// create a vorbis decoder by passing in the initial data block containing +// the ogg&vorbis headers (you don't need to do parse them, just provide +// the first N bytes of the file--you're told if it's not enough, see below) +// on success, returns an stb_vorbis *, does not set error, returns the amount of +// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes; +// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed +// if returns NULL and *error is VORBIS_need_more_data, then the input block was +// incomplete and you need to pass in a larger block from the start of the file - extern int stb_vorbis_decode_frame_pushdata( - stb_vorbis *f, - const unsigned char *datablock, int datablock_length_in_bytes, - int *channels, // place to write number of float * buffers - float ***output, // place to write float ** array of float * buffers - int *samples // place to write number of output samples - ); - // decode a frame of audio sample data if possible from the passed-in data block - // - // return value: number of bytes we used from datablock - // - // possible cases: - // 0 bytes used, 0 samples output (need more data) - // N bytes used, 0 samples output (resynching the stream, keep going) - // N bytes used, M samples output (one frame of data) - // note that after opening a file, you will ALWAYS get one N-bytes,0-sample - // frame, because Vorbis always "discards" the first frame. - // - // Note that on resynch, stb_vorbis will rarely consume all of the buffer, - // instead only datablock_length_in_bytes-3 or less. This is because it wants - // to avoid missing parts of a page header if they cross a datablock boundary, - // without writing state-machiney code to record a partial detection. - // - // The number of channels returned are stored in *channels (which can be - // NULL--it is always the same as the number of channels reported by - // get_info). *output will contain an array of float* buffers, one per - // channel. In other words, (*output)[0][0] contains the first sample from - // the first channel, and (*output)[1][0] contains the first sample from - // the second channel. +extern int stb_vorbis_decode_frame_pushdata( + stb_vorbis* f, + const unsigned char* datablock, int datablock_length_in_bytes, + int* channels, // place to write number of float * buffers + float*** output, // place to write float ** array of float * buffers + int* samples // place to write number of output samples +); +// decode a frame of audio sample data if possible from the passed-in data block +// +// return value: number of bytes we used from datablock +// +// possible cases: +// 0 bytes used, 0 samples output (need more data) +// N bytes used, 0 samples output (resynching the stream, keep going) +// N bytes used, M samples output (one frame of data) +// note that after opening a file, you will ALWAYS get one N-bytes,0-sample +// frame, because Vorbis always "discards" the first frame. +// +// Note that on resynch, stb_vorbis will rarely consume all of the buffer, +// instead only datablock_length_in_bytes-3 or less. This is because it wants +// to avoid missing parts of a page header if they cross a datablock boundary, +// without writing state-machiney code to record a partial detection. +// +// The number of channels returned are stored in *channels (which can be +// NULL--it is always the same as the number of channels reported by +// get_info). *output will contain an array of float* buffers, one per +// channel. In other words, (*output)[0][0] contains the first sample from +// the first channel, and (*output)[1][0] contains the first sample from +// the second channel. - extern void stb_vorbis_flush_pushdata(stb_vorbis *f); - // inform stb_vorbis that your next datablock will not be contiguous with - // previous ones (e.g. you've seeked in the data); future attempts to decode - // frames will cause stb_vorbis to resynchronize (as noted above), and - // once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it - // will begin decoding the _next_ frame. - // - // if you want to seek using pushdata, you need to seek in your file, then - // call stb_vorbis_flush_pushdata(), then start calling decoding, then once - // decoding is returning you data, call stb_vorbis_get_sample_offset, and - // if you don't like the result, seek your file again and repeat. +extern void stb_vorbis_flush_pushdata(stb_vorbis* f); +// inform stb_vorbis that your next datablock will not be contiguous with +// previous ones (e.g. you've seeked in the data); future attempts to decode +// frames will cause stb_vorbis to resynchronize (as noted above), and +// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it +// will begin decoding the _next_ frame. +// +// if you want to seek using pushdata, you need to seek in your file, then +// call stb_vorbis_flush_pushdata(), then start calling decoding, then once +// decoding is returning you data, call stb_vorbis_get_sample_offset, and +// if you don't like the result, seek your file again and repeat. #endif - ////////// PULLING INPUT API +////////// PULLING INPUT API #ifndef STB_VORBIS_NO_PULLDATA_API - // This API assumes stb_vorbis is allowed to pull data from a source-- - // either a block of memory containing the _entire_ vorbis stream, or a - // FILE * that you or it create, or possibly some other reading mechanism - // if you go modify the source to replace the FILE * case with some kind - // of callback to your code. (But if you don't support seeking, you may - // just want to go ahead and use pushdata.) +// This API assumes stb_vorbis is allowed to pull data from a source-- +// either a block of memory containing the _entire_ vorbis stream, or a +// FILE * that you or it create, or possibly some other reading mechanism +// if you go modify the source to replace the FILE * case with some kind +// of callback to your code. (But if you don't support seeking, you may +// just want to go ahead and use pushdata.) #if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION) - extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output); +extern int stb_vorbis_decode_filename(const char* filename, int* channels, int* sample_rate, short** output); #endif #if !defined(STB_VORBIS_NO_INTEGER_CONVERSION) - extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output); +extern int stb_vorbis_decode_memory(const unsigned char* mem, int len, int* channels, int* sample_rate, short** output); #endif - // decode an entire file and output the data interleaved into a malloc()ed - // buffer stored in *output. The return value is the number of samples - // decoded, or -1 if the file could not be opened or was not an ogg vorbis file. - // When you're done with it, just free() the pointer returned in *output. +// decode an entire file and output the data interleaved into a malloc()ed +// buffer stored in *output. The return value is the number of samples +// decoded, or -1 if the file could not be opened or was not an ogg vorbis file. +// When you're done with it, just free() the pointer returned in *output. - extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, - int *error, const stb_vorbis_alloc *alloc_buffer); - // create an ogg vorbis decoder from an ogg vorbis stream in memory (note - // this must be the entire stream!). on failure, returns NULL and sets *error +extern stb_vorbis* stb_vorbis_open_memory(const unsigned char* data, int len, + int* error, const stb_vorbis_alloc* alloc_buffer); +// create an ogg vorbis decoder from an ogg vorbis stream in memory (note +// this must be the entire stream!). on failure, returns NULL and sets *error #ifndef STB_VORBIS_NO_STDIO - extern stb_vorbis * stb_vorbis_open_filename(const char *filename, - int *error, const stb_vorbis_alloc *alloc_buffer); - // create an ogg vorbis decoder from a filename via fopen(). on failure, - // returns NULL and sets *error (possibly to VORBIS_file_open_failure). +extern stb_vorbis* stb_vorbis_open_filename(const char* filename, + int* error, const stb_vorbis_alloc* alloc_buffer); +// create an ogg vorbis decoder from a filename via fopen(). on failure, +// returns NULL and sets *error (possibly to VORBIS_file_open_failure). - extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, - int *error, const stb_vorbis_alloc *alloc_buffer); - // create an ogg vorbis decoder from an open FILE *, looking for a stream at - // the _current_ seek point (ftell). on failure, returns NULL and sets *error. - // note that stb_vorbis must "own" this stream; if you seek it in between - // calls to stb_vorbis, it will become confused. Morever, if you attempt to - // perform stb_vorbis_seek_*() operations on this file, it will assume it - // owns the _entire_ rest of the file after the start point. Use the next - // function, stb_vorbis_open_file_section(), to limit it. +extern stb_vorbis* stb_vorbis_open_file(FILE* f, int close_handle_on_close, + int* error, const stb_vorbis_alloc* alloc_buffer); +// create an ogg vorbis decoder from an open FILE *, looking for a stream at +// the _current_ seek point (ftell). on failure, returns NULL and sets *error. +// note that stb_vorbis must "own" this stream; if you seek it in between +// calls to stb_vorbis, it will become confused. Morever, if you attempt to +// perform stb_vorbis_seek_*() operations on this file, it will assume it +// owns the _entire_ rest of the file after the start point. Use the next +// function, stb_vorbis_open_file_section(), to limit it. - extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, - int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len); - // create an ogg vorbis decoder from an open FILE *, looking for a stream at - // the _current_ seek point (ftell); the stream will be of length 'len' bytes. - // on failure, returns NULL and sets *error. note that stb_vorbis must "own" - // this stream; if you seek it in between calls to stb_vorbis, it will become - // confused. +extern stb_vorbis* stb_vorbis_open_file_section(FILE* f, int close_handle_on_close, + int* error, const stb_vorbis_alloc* alloc_buffer, unsigned int len); +// create an ogg vorbis decoder from an open FILE *, looking for a stream at +// the _current_ seek point (ftell); the stream will be of length 'len' bytes. +// on failure, returns NULL and sets *error. note that stb_vorbis must "own" +// this stream; if you seek it in between calls to stb_vorbis, it will become +// confused. #endif - extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); - extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); - // these functions seek in the Vorbis file to (approximately) 'sample_number'. - // after calling seek_frame(), the next call to get_frame_*() will include - // the specified sample. after calling stb_vorbis_seek(), the next call to - // stb_vorbis_get_samples_* will start with the specified sample. If you - // do not need to seek to EXACTLY the target sample when using get_samples_*, - // you can also use seek_frame(). +extern int stb_vorbis_seek_frame(stb_vorbis* f, unsigned int sample_number); +extern int stb_vorbis_seek(stb_vorbis* f, unsigned int sample_number); +// these functions seek in the Vorbis file to (approximately) 'sample_number'. +// after calling seek_frame(), the next call to get_frame_*() will include +// the specified sample. after calling stb_vorbis_seek(), the next call to +// stb_vorbis_get_samples_* will start with the specified sample. If you +// do not need to seek to EXACTLY the target sample when using get_samples_*, +// you can also use seek_frame(). - extern int stb_vorbis_seek_start(stb_vorbis *f); - // this function is equivalent to stb_vorbis_seek(f,0) +extern int stb_vorbis_seek_start(stb_vorbis* f); +// this function is equivalent to stb_vorbis_seek(f,0) - extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); - extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); - // these functions return the total length of the vorbis stream +extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis* f); +extern float stb_vorbis_stream_length_in_seconds(stb_vorbis* f); +// these functions return the total length of the vorbis stream - extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); - // decode the next frame and return the number of samples. the number of - // channels returned are stored in *channels (which can be NULL--it is always - // the same as the number of channels reported by get_info). *output will - // contain an array of float* buffers, one per channel. These outputs will - // be overwritten on the next call to stb_vorbis_get_frame_*. - // - // You generally should not intermix calls to stb_vorbis_get_frame_*() - // and stb_vorbis_get_samples_*(), since the latter calls the former. +extern int stb_vorbis_get_frame_float(stb_vorbis* f, int* channels, float*** output); +// decode the next frame and return the number of samples. the number of +// channels returned are stored in *channels (which can be NULL--it is always +// the same as the number of channels reported by get_info). *output will +// contain an array of float* buffers, one per channel. These outputs will +// be overwritten on the next call to stb_vorbis_get_frame_*. +// +// You generally should not intermix calls to stb_vorbis_get_frame_*() +// and stb_vorbis_get_samples_*(), since the latter calls the former. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION - extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); - extern int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples); +extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis* f, int num_c, short* buffer, int num_shorts); +extern int stb_vorbis_get_frame_short(stb_vorbis* f, int num_c, short** buffer, int num_samples); #endif - // decode the next frame and return the number of *samples* per channel. - // Note that for interleaved data, you pass in the number of shorts (the - // size of your array), but the return value is the number of samples per - // channel, not the total number of samples. - // - // The data is coerced to the number of channels you request according to the - // channel coercion rules (see below). You must pass in the size of your - // buffer(s) so that stb_vorbis will not overwrite the end of the buffer. - // The maximum buffer size needed can be gotten from get_info(); however, - // the Vorbis I specification implies an absolute maximum of 4096 samples - // per channel. +// decode the next frame and return the number of *samples* per channel. +// Note that for interleaved data, you pass in the number of shorts (the +// size of your array), but the return value is the number of samples per +// channel, not the total number of samples. +// +// The data is coerced to the number of channels you request according to the +// channel coercion rules (see below). You must pass in the size of your +// buffer(s) so that stb_vorbis will not overwrite the end of the buffer. +// The maximum buffer size needed can be gotten from get_info(); however, +// the Vorbis I specification implies an absolute maximum of 4096 samples +// per channel. - // Channel coercion rules: - // Let M be the number of channels requested, and N the number of channels present, - // and Cn be the nth channel; let stereo L be the sum of all L and center channels, - // and stereo R be the sum of all R and center channels (channel assignment from the - // vorbis spec). - // M N output - // 1 k sum(Ck) for all k - // 2 * stereo L, stereo R - // k l k > l, the first l channels, then 0s - // k l k <= l, the first k channels - // Note that this is not _good_ surround etc. mixing at all! It's just so - // you get something useful. +// Channel coercion rules: +// Let M be the number of channels requested, and N the number of channels present, +// and Cn be the nth channel; let stereo L be the sum of all L and center channels, +// and stereo R be the sum of all R and center channels (channel assignment from the +// vorbis spec). +// M N output +// 1 k sum(Ck) for all k +// 2 * stereo L, stereo R +// k l k > l, the first l channels, then 0s +// k l k <= l, the first k channels +// Note that this is not _good_ surround etc. mixing at all! It's just so +// you get something useful. - extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); - extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); - // gets num_samples samples, not necessarily on a frame boundary--this requires - // buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES. - // Returns the number of samples stored per channel; it may be less than requested - // at the end of the file. If there are no more samples in the file, returns 0. +extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis* f, int channels, float* buffer, int num_floats); +extern int stb_vorbis_get_samples_float(stb_vorbis* f, int channels, float** buffer, int num_samples); +// gets num_samples samples, not necessarily on a frame boundary--this requires +// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES. +// Returns the number of samples stored per channel; it may be less than requested +// at the end of the file. If there are no more samples in the file, returns 0. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION - extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); - extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); +extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis* f, int channels, short* buffer, int num_shorts); +extern int stb_vorbis_get_samples_short(stb_vorbis* f, int channels, short** buffer, int num_samples); #endif - // gets num_samples samples, not necessarily on a frame boundary--this requires - // buffering so you have to supply the buffers. Applies the coercion rules above - // to produce 'channels' channels. Returns the number of samples stored per channel; - // it may be less than requested at the end of the file. If there are no more - // samples in the file, returns 0. +// gets num_samples samples, not necessarily on a frame boundary--this requires +// buffering so you have to supply the buffers. Applies the coercion rules above +// to produce 'channels' channels. Returns the number of samples stored per channel; +// it may be less than requested at the end of the file. If there are no more +// samples in the file, returns 0. #endif - //////// ERROR CODES +//////// ERROR CODES - enum STBVorbisError - { - VORBIS__no_error, +enum STBVorbisError +{ + VORBIS__no_error, - VORBIS_need_more_data = 1, // not a real error + VORBIS_need_more_data = 1, + // not a real error - VORBIS_invalid_api_mixing, // can't mix API modes - VORBIS_outofmem, // not enough memory - VORBIS_feature_not_supported, // uses floor 0 - VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small - VORBIS_file_open_failure, // fopen() failed - VORBIS_seek_without_length, // can't seek in unknown-length file + VORBIS_invalid_api_mixing, + // can't mix API modes + VORBIS_outofmem, + // not enough memory + VORBIS_feature_not_supported, + // uses floor 0 + VORBIS_too_many_channels, + // STB_VORBIS_MAX_CHANNELS is too small + VORBIS_file_open_failure, + // fopen() failed + VORBIS_seek_without_length, + // can't seek in unknown-length file - VORBIS_unexpected_eof = 10, // file is truncated? - VORBIS_seek_invalid, // seek past EOF + VORBIS_unexpected_eof = 10, + // file is truncated? + VORBIS_seek_invalid, + // seek past EOF - // decoding errors (corrupt/invalid stream) -- you probably - // don't care about the exact details of these + // decoding errors (corrupt/invalid stream) -- you probably + // don't care about the exact details of these - // vorbis errors: - VORBIS_invalid_setup = 20, - VORBIS_invalid_stream, + // vorbis errors: + VORBIS_invalid_setup = 20, + VORBIS_invalid_stream, - // ogg errors: - VORBIS_missing_capture_pattern = 30, - VORBIS_invalid_stream_structure_version, - VORBIS_continued_packet_flag_invalid, - VORBIS_incorrect_stream_serial_number, - VORBIS_invalid_first_page, - VORBIS_bad_packet_type, - VORBIS_cant_find_last_page, - VORBIS_seek_failed - }; + // ogg errors: + VORBIS_missing_capture_pattern = 30, + VORBIS_invalid_stream_structure_version, + VORBIS_continued_packet_flag_invalid, + VORBIS_incorrect_stream_serial_number, + VORBIS_invalid_first_page, + VORBIS_bad_packet_type, + VORBIS_cant_find_last_page, + VORBIS_seek_failed +}; #ifdef __cplusplus @@ -330,4 +339,3 @@ extern "C" { // HEADER ENDS HERE // ////////////////////////////////////////////////////////////////////////////// - diff --git a/Utilities/stdafx.h b/Utilities/stdafx.h index fcaaeee..749020f 100644 --- a/Utilities/stdafx.h +++ b/Utilities/stdafx.h @@ -24,11 +24,11 @@ using std::atomic; using std::atomic_flag; #ifndef __MINGW32__ - #ifdef __clang__ +#ifdef __clang__ #define __forceinline __attribute__((always_inline)) inline - #else - #ifdef __GNUC__ +#else +#ifdef __GNUC__ #define __forceinline __attribute__((always_inline)) inline - #endif - #endif -#endif \ No newline at end of file +#endif +#endif +#endif diff --git a/Utilities/xBRZ/config.h b/Utilities/xBRZ/config.h index 49a6790..64e18c6 100644 --- a/Utilities/xBRZ/config.h +++ b/Utilities/xBRZ/config.h @@ -20,14 +20,14 @@ namespace xbrz { -struct ScalerCfg -{ - double luminanceWeight = 1; - double equalColorTolerance = 30; - double dominantDirectionThreshold = 3.6; - double steepDirectionThreshold = 2.2; - double newTestAttribute = 0; //unused; test new parameters -}; + struct ScalerCfg + { + double luminanceWeight = 1; + double equalColorTolerance = 30; + double dominantDirectionThreshold = 3.6; + double steepDirectionThreshold = 2.2; + double newTestAttribute = 0; //unused; test new parameters + }; } #endif diff --git a/Utilities/xBRZ/xbrz.cpp b/Utilities/xBRZ/xbrz.cpp index c8f4f47..036e7a5 100644 --- a/Utilities/xBRZ/xbrz.cpp +++ b/Utilities/xBRZ/xbrz.cpp @@ -22,88 +22,107 @@ namespace { -template inline -unsigned char getByte(uint32_t val) { return static_cast((val >> (8 * N)) & 0xff); } + template + inline + unsigned char getByte(uint32_t val) { return static_cast((val >> (8 * N)) & 0xff); } -inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); } -inline unsigned char getRed (uint32_t pix) { return getByte<2>(pix); } -inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); } -inline unsigned char getBlue (uint32_t pix) { return getByte<0>(pix); } + inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); } + inline unsigned char getRed(uint32_t pix) { return getByte<2>(pix); } + inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); } + inline unsigned char getBlue(uint32_t pix) { return getByte<0>(pix); } -inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return (r << 16) | (g << 8) | b; } -inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (r << 16) | (g << 8) | b; } + inline uint32_t makePixel(unsigned char r, unsigned char g, unsigned char b) { return (r << 16) | (g << 8) | b; } + + inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) + { + return (a << 24) | (r << 16) | (g << 8) | b; + } -template inline -uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending -{ - static_assert(0 < M && M < N && N <= 1000, ""); + template + inline + uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) + //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending + { + static_assert(0 < M && M < N && N <= 1000, ""); - auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { return (colFront * M + colBack * (N - M)) / N; }; + auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char + { + return (colFront * M + colBack * (N - M)) / N; + }; - return makePixel(calcColor(getRed (pixFront), getRed (pixBack)), - calcColor(getGreen(pixFront), getGreen(pixBack)), - calcColor(getBlue (pixFront), getBlue (pixBack))); -} + return makePixel(calcColor(getRed(pixFront), getRed(pixBack)), + calcColor(getGreen(pixFront), getGreen(pixBack)), + calcColor(getBlue(pixFront), getBlue(pixBack))); + } -template inline -uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!) -{ - static_assert(0 < M && M < N && N <= 1000, ""); + template + inline + uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) + //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!) + { + static_assert(0 < M && M < N && N <= 1000, ""); - const unsigned int weightFront = getAlpha(pixFront) * M; - const unsigned int weightBack = getAlpha(pixBack) * (N - M); - const unsigned int weightSum = weightFront + weightBack; - if (weightSum == 0) - return 0; + const unsigned int weightFront = getAlpha(pixFront) * M; + const unsigned int weightBack = getAlpha(pixBack) * (N - M); + const unsigned int weightSum = weightFront + weightBack; + if (weightSum == 0) + return 0; - auto calcColor = [=](unsigned char colFront, unsigned char colBack) - { - return static_cast((colFront * weightFront + colBack * weightBack) / weightSum); - }; + auto calcColor = [=](unsigned char colFront, unsigned char colBack) + { + return static_cast((colFront * weightFront + colBack * weightBack) / weightSum); + }; - return makePixel(static_cast(weightSum / N), - calcColor(getRed (pixFront), getRed (pixBack)), - calcColor(getGreen(pixFront), getGreen(pixBack)), - calcColor(getBlue (pixFront), getBlue (pixBack))); -} + return makePixel(static_cast(weightSum / N), + calcColor(getRed(pixFront), getRed(pixBack)), + calcColor(getGreen(pixFront), getGreen(pixBack)), + calcColor(getBlue(pixFront), getBlue(pixBack))); + } -//inline -//double fastSqrt(double n) -//{ -// __asm //speeds up xBRZ by about 9% compared to std::sqrt which internally uses the same assembler instructions but adds some "fluff" -// { -// fld n -// fsqrt -// } -//} -// + //inline + //double fastSqrt(double n) + //{ + // __asm //speeds up xBRZ by about 9% compared to std::sqrt which internally uses the same assembler instructions but adds some "fluff" + // { + // fld n + // fsqrt + // } + //} + // -uint32_t* byteAdvance( uint32_t* ptr, int bytes) { return reinterpret_cast< uint32_t*>(reinterpret_cast< char*>(ptr) + bytes); } -const uint32_t* byteAdvance(const uint32_t* ptr, int bytes) { return reinterpret_cast(reinterpret_cast(ptr) + bytes); } + uint32_t* byteAdvance(uint32_t* ptr, int bytes) + { + return reinterpret_cast(reinterpret_cast(ptr) + bytes); + } + + const uint32_t* byteAdvance(const uint32_t* ptr, int bytes) + { + return reinterpret_cast(reinterpret_cast(ptr) + bytes); + } -//fill block with the given color -inline -void fillBlock(uint32_t* trg, int pitch, uint32_t col, int blockWidth, int blockHeight) -{ - //for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) - // std::fill(trg, trg + blockWidth, col); + //fill block with the given color + inline + void fillBlock(uint32_t* trg, int pitch, uint32_t col, int blockWidth, int blockHeight) + { + //for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) + // std::fill(trg, trg + blockWidth, col); - for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) - for (int x = 0; x < blockWidth; ++x) - trg[x] = col; -} + for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) + for (int x = 0; x < blockWidth; ++x) + trg[x] = col; + } -inline -void fillBlock(uint32_t* trg, int pitch, uint32_t col, int n) { fillBlock(trg, pitch, col, n, n); } + inline + void fillBlock(uint32_t* trg, int pitch, uint32_t col, int n) { fillBlock(trg, pitch, col, n, n); } #ifdef _MSC_VER - #define FORCE_INLINE __forceinline +#define FORCE_INLINE __forceinline #elif defined __GNUC__ #define FORCE_INLINE __attribute__((always_inline)) inline #else @@ -111,260 +130,301 @@ void fillBlock(uint32_t* trg, int pitch, uint32_t col, int n) { fillBlock(trg, p #endif -enum RotationDegree //clock-wise -{ - ROT_0, - ROT_90, - ROT_180, - ROT_270 -}; + enum RotationDegree //clock-wise + { + ROT_0, + ROT_90, + ROT_180, + ROT_270 + }; -//calculate input matrix coordinates after rotation at compile time -template -struct MatrixRotation; + //calculate input matrix coordinates after rotation at compile time + template + struct MatrixRotation; -template -struct MatrixRotation -{ - static const size_t I_old = I; - static const size_t J_old = J; -}; + template + struct MatrixRotation + { + static const size_t I_old = I; + static const size_t J_old = J; + }; -template //(i, j) = (row, col) indices, N = size of (square) matrix -struct MatrixRotation -{ - static const size_t I_old = N - 1 - MatrixRotation(rotDeg - 1), I, J, N>::J_old; //old coordinates before rotation! - static const size_t J_old = MatrixRotation(rotDeg - 1), I, J, N>::I_old; // -}; + template + //(i, j) = (row, col) indices, N = size of (square) matrix + struct MatrixRotation + { + static const size_t I_old = N - 1 - MatrixRotation(rotDeg - 1), I, J, N>::J_old; + //old coordinates before rotation! + static const size_t J_old = MatrixRotation(rotDeg - 1), I, J, N>::I_old; // + }; -template -class OutputMatrix -{ -public: - OutputMatrix(uint32_t* out, int outWidth) : //access matrix area, top-left at position "out" for image with given width - out_(out), - outWidth_(outWidth) {} + template + class OutputMatrix + { + public: + OutputMatrix(uint32_t* out, int outWidth) : + //access matrix area, top-left at position "out" for image with given width + out_(out), + outWidth_(outWidth) + { + } - template - uint32_t& ref() const - { - static const size_t I_old = MatrixRotation::I_old; - static const size_t J_old = MatrixRotation::J_old; - return *(out_ + J_old + I_old * outWidth_); - } + template + uint32_t& ref() const + { + static const size_t I_old = MatrixRotation::I_old; + static const size_t J_old = MatrixRotation::J_old; + return *(out_ + J_old + I_old * outWidth_); + } -private: - uint32_t* out_; - const int outWidth_; -}; + private: + uint32_t* out_; + const int outWidth_; + }; -template inline -T square(T value) { return value * value; } + template + inline + T square(T value) { return value * value; } -struct DistYCbCrBuffer //30% perf boost compared to distYCbCr()! -{ -public: - static double dist(uint32_t pix1, uint32_t pix2) - { + struct DistYCbCrBuffer //30% perf boost compared to distYCbCr()! + { + public: + static double dist(uint32_t pix1, uint32_t pix2) + { #if defined _MSC_VER && _MSC_VER < 1900 #error function scope static initialization is not yet thread-safe! #endif - static const DistYCbCrBuffer inst; - return inst.distImpl(pix1, pix2); - } + static const DistYCbCrBuffer inst; + return inst.distImpl(pix1, pix2); + } -private: - DistYCbCrBuffer() : buffer(256 * 256 * 256) - { - for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores) - { - const int r_diff = getByte<2>(i) * 2 - 255; - const int g_diff = getByte<1>(i) * 2 - 255; - const int b_diff = getByte<0>(i) * 2 - 255; + private: + DistYCbCrBuffer() : buffer(256 * 256 * 256) + { + for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores) + { + const int r_diff = getByte<2>(i) * 2 - 255; + const int g_diff = getByte<1>(i) * 2 - 255; + const int b_diff = getByte<0>(i) * 2 - 255; - const double k_b = 0.0593; //ITU-R BT.2020 conversion - const double k_r = 0.2627; // - const double k_g = 1 - k_b - k_r; + const double k_b = 0.0593; //ITU-R BT.2020 conversion + const double k_r = 0.2627; // + const double k_g = 1 - k_b - k_r; - const double scale_b = 0.5 / (1 - k_b); - const double scale_r = 0.5 / (1 - k_r); + const double scale_b = 0.5 / (1 - k_b); + const double scale_r = 0.5 / (1 - k_r); - const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff; //[!], analog YCbCr! - const double c_b = scale_b * (b_diff - y); - const double c_r = scale_r * (r_diff - y); + const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff; //[!], analog YCbCr! + const double c_b = scale_b * (b_diff - y); + const double c_r = scale_r * (r_diff - y); - buffer[i] = static_cast(std::sqrt(square(y) + square(c_b) + square(c_r))); - } - } + buffer[i] = static_cast(std::sqrt(square(y) + square(c_b) + square(c_r))); + } + } - double distImpl(uint32_t pix1, uint32_t pix2) const - { - //if (pix1 == pix2) -> 8% perf degradation! - // return 0; - //if (pix1 > pix2) - // std::swap(pix1, pix2); -> 30% perf degradation!!! + double distImpl(uint32_t pix1, uint32_t pix2) const + { + //if (pix1 == pix2) -> 8% perf degradation! + // return 0; + //if (pix1 > pix2) + // std::swap(pix1, pix2); -> 30% perf degradation!!! - const int r_diff = static_cast(getRed (pix1)) - getRed (pix2); - const int g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); - const int b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); + const int r_diff = static_cast(getRed(pix1)) - getRed(pix2); + const int g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); + const int b_diff = static_cast(getBlue(pix1)) - getBlue(pix2); - return buffer[(((r_diff + 255) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte - (((g_diff + 255) / 2) << 8) | - (( b_diff + 255) / 2)]; - } + return buffer[(((r_diff + 255) / 2) << 16) | + //slightly reduce precision (division by 2) to squeeze value into single byte + (((g_diff + 255) / 2) << 8) | + ((b_diff + 255) / 2)]; + } - std::vector buffer; //consumes 64 MB memory; using double is only 2% faster, but takes 128 MB -}; + std::vector buffer; //consumes 64 MB memory; using double is only 2% faster, but takes 128 MB + }; -enum BlendType -{ - BLEND_NONE = 0, - BLEND_NORMAL, //a normal indication to blend - BLEND_DOMINANT, //a strong indication to blend - //attention: BlendType must fit into the value range of 2 bit!!! -}; + enum BlendType + { + BLEND_NONE = 0, + BLEND_NORMAL, + //a normal indication to blend + BLEND_DOMINANT, + //a strong indication to blend + //attention: BlendType must fit into the value range of 2 bit!!! + }; -struct BlendResult -{ - BlendType - /**/blend_f, blend_g, - /**/blend_j, blend_k; -}; + struct BlendResult + { + BlendType + /**/blend_f, blend_g, + /**/blend_j, blend_k; + }; -struct Kernel_4x4 //kernel for preprocessing step -{ - uint32_t - /**/a, b, c, d, - /**/e, f, g, h, - /**/i, j, k, l, - /**/m, n, o, p; -}; + struct Kernel_4x4 //kernel for preprocessing step + { + uint32_t + /**/a, b, c, d, + /**/e, f, g, h, + /**/i, j, k, l, + /**/m, n, o, p; + }; -/* -input kernel area naming convention: ------------------ -| A | B | C | D | -----|---|---|---| -| E | F | G | H | //evaluate the four corners between F, G, J, K -----|---|---|---| //input pixel is at position F -| I | J | K | L | -----|---|---|---| -| M | N | O | P | ------------------ -*/ -template -FORCE_INLINE //detect blend direction -BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType" -{ - BlendResult result = {}; + /* + input kernel area naming convention: + ----------------- + | A | B | C | D | + ----|---|---|---| + | E | F | G | H | //evaluate the four corners between F, G, J, K + ----|---|---|---| //input pixel is at position F + | I | J | K | L | + ----|---|---|---| + | M | N | O | P | + ----------------- + */ + template + FORCE_INLINE //detect blend direction + BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) + //result: F, G, J, K corners of "GradientType" + { + BlendResult result = {}; - if ((ker.f == ker.g && - ker.j == ker.k) || - (ker.f == ker.j && - ker.g == ker.k)) - return result; + if ((ker.f == ker.g && + ker.j == ker.k) || + (ker.f == ker.j && + ker.g == ker.k)) + return result; - auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; + auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; - const int weight = 4; - double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g); - double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k); + const int weight = 4; + double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * + dist(ker.j, ker.g); + double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * + dist(ker.f, ker.k); - if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8 - { - const bool dominantGradient = cfg.dominantDirectionThreshold * jg < fk; - if (ker.f != ker.g && ker.f != ker.j) - result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8 + { + const bool dominantGradient = cfg.dominantDirectionThreshold * jg < fk; + if (ker.f != ker.g && ker.f != ker.j) + result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; - if (ker.k != ker.j && ker.k != ker.g) - result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; - } - else if (fk < jg) - { - const bool dominantGradient = cfg.dominantDirectionThreshold * fk < jg; - if (ker.j != ker.f && ker.j != ker.k) - result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + if (ker.k != ker.j && ker.k != ker.g) + result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + } + else if (fk < jg) + { + const bool dominantGradient = cfg.dominantDirectionThreshold * fk < jg; + if (ker.j != ker.f && ker.j != ker.k) + result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; - if (ker.g != ker.f && ker.g != ker.k) - result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; - } - return result; -} + if (ker.g != ker.f && ker.g != ker.k) + result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + } + return result; + } -struct Kernel_3x3 -{ - uint32_t - /**/a, b, c, - /**/d, e, f, - /**/g, h, i; -}; + struct Kernel_3x3 + { + uint32_t + /**/a, b, c, + /**/d, e, f, + /**/g, h, i; + }; #define DEF_GETTER(x) template uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; } -//we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token -DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c) -DEF_GETTER(d) DEF_GETTER(e) DEF_GETTER(f) -DEF_GETTER(g) DEF_GETTER(h) DEF_GETTER(i) + //we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token + DEF_GETTER(a) + DEF_GETTER(b) + DEF_GETTER(c) + DEF_GETTER(d) + DEF_GETTER(e) + DEF_GETTER(f) + DEF_GETTER(g) + DEF_GETTER(h) + DEF_GETTER(i) #undef DEF_GETTER #define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } -DEF_GETTER(b, d) DEF_GETTER(c, a) -DEF_GETTER(d, h) DEF_GETTER(e, e) DEF_GETTER(f, b) -DEF_GETTER(g, i) DEF_GETTER(h, f) DEF_GETTER(i, c) + DEF_GETTER(b, d) + DEF_GETTER(c, a) + DEF_GETTER(d, h) + DEF_GETTER(e, e) + DEF_GETTER(f, b) + DEF_GETTER(g, i) + DEF_GETTER(h, f) + DEF_GETTER(i, c) #undef DEF_GETTER #define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } -DEF_GETTER(b, h) DEF_GETTER(c, g) -DEF_GETTER(d, f) DEF_GETTER(e, e) DEF_GETTER(f, d) -DEF_GETTER(g, c) DEF_GETTER(h, b) DEF_GETTER(i, a) + DEF_GETTER(b, h) + DEF_GETTER(c, g) + DEF_GETTER(d, f) + DEF_GETTER(e, e) + DEF_GETTER(f, d) + DEF_GETTER(g, c) + DEF_GETTER(h, b) + DEF_GETTER(i, a) #undef DEF_GETTER #define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } -DEF_GETTER(b, f) DEF_GETTER(c, i) -DEF_GETTER(d, b) DEF_GETTER(e, e) DEF_GETTER(f, h) -DEF_GETTER(g, a) DEF_GETTER(h, d) DEF_GETTER(i, g) + DEF_GETTER(b, f) + DEF_GETTER(c, i) + DEF_GETTER(d, b) + DEF_GETTER(e, e) + DEF_GETTER(f, h) + DEF_GETTER(g, a) + DEF_GETTER(h, d) + DEF_GETTER(i, g) #undef DEF_GETTER -//compress four blend types into a single byte -inline BlendType getTopR (unsigned char b) { return static_cast(0x3 & (b >> 2)); } -inline BlendType getBottomR(unsigned char b) { return static_cast(0x3 & (b >> 4)); } -inline BlendType getBottomL(unsigned char b) { return static_cast(0x3 & (b >> 6)); } + //compress four blend types into a single byte + inline BlendType getTopR(unsigned char b) { return static_cast(0x3 & (b >> 2)); } + inline BlendType getBottomR(unsigned char b) { return static_cast(0x3 & (b >> 4)); } + inline BlendType getBottomL(unsigned char b) { return static_cast(0x3 & (b >> 6)); } -inline void setTopL (unsigned char& b, BlendType bt) { b |= bt; } //buffer is assumed to be initialized before preprocessing! -inline void setTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } -inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); } -inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); } + inline void setTopL(unsigned char& b, BlendType bt) { b |= bt; } + //buffer is assumed to be initialized before preprocessing! + inline void setTopR(unsigned char& b, BlendType bt) { b |= (bt << 2); } + inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); } + inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); } -inline bool blendingNeeded(unsigned char b) { return b != 0; } + inline bool blendingNeeded(unsigned char b) { return b != 0; } -template inline -unsigned char rotateBlendInfo(unsigned char b) { return b; } -template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 2) | (b >> 6)) & 0xff; } -template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 4) | (b >> 4)) & 0xff; } -template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; } + template + inline + unsigned char rotateBlendInfo(unsigned char b) { return b; } + + template <> + inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 2) | (b >> 6)) & 0xff; } + + template <> + inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 4) | (b >> 4)) & 0xff; } + + template <> + inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; } -/* -input kernel area naming convention: -------------- -| A | B | C | -----|---|---| -| D | E | F | //input pixel is at position E -----|---|---| -| G | H | I | -------------- -*/ -template -FORCE_INLINE //perf: quite worth it! -void blendPixel(const Kernel_3x3& ker, - uint32_t* target, int trgWidth, - unsigned char blendInfo, //result of preprocessing all four corners of pixel "e" - const xbrz::ScalerCfg& cfg) -{ + /* + input kernel area naming convention: + ------------- + | A | B | C | + ----|---|---| + | D | E | F | //input pixel is at position E + ----|---|---| + | G | H | I | + ------------- + */ + template + FORCE_INLINE //perf: quite worth it! + void blendPixel(const Kernel_3x3& ker, + uint32_t* target, int trgWidth, + unsigned char blendInfo, //result of preprocessing all four corners of pixel "e" + const xbrz::ScalerCfg& cfg) + { #define a get_a(ker) #define b get_b(ker) #define c get_c(ker) @@ -376,61 +436,65 @@ void blendPixel(const Kernel_3x3& ker, #define i get_i(ker) - const unsigned char blend = rotateBlendInfo(blendInfo); + const unsigned char blend = rotateBlendInfo(blendInfo); - if (getBottomR(blend) >= BLEND_NORMAL) - { - auto eq = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight) < cfg.equalColorTolerance; }; - auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; + if (getBottomR(blend) >= BLEND_NORMAL) + { + auto eq = [&](uint32_t pix1, uint32_t pix2) + { + return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight) < cfg.equalColorTolerance; + }; + auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; - const bool doLineBlend = [&]() -> bool - { - if (getBottomR(blend) >= BLEND_DOMINANT) - return true; + const bool doLineBlend = [&]() -> bool + { + if (getBottomR(blend) >= BLEND_DOMINANT) + return true; - //make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes - if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90 corners - return false; - if (getBottomL(blend) != BLEND_NONE && !eq(e, c)) - return false; + //make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes + if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90 corners + return false; + if (getBottomL(blend) != BLEND_NONE && !eq(e, c)) + return false; - //no full blending for L-shapes; blend corner only (handles "mario mushroom eyes") - if (!eq(e, i) && eq(g, h) && eq(h , i) && eq(i, f) && eq(f, c)) - return false; + //no full blending for L-shapes; blend corner only (handles "mario mushroom eyes") + if (!eq(e, i) && eq(g, h) && eq(h, i) && eq(i, f) && eq(f, c)) + return false; - return true; - }(); + return true; + }(); - const uint32_t px = dist(e, f) <= dist(e, h) ? f : h; //choose most similar color + const uint32_t px = dist(e, f) <= dist(e, h) ? f : h; //choose most similar color - OutputMatrix out(target, trgWidth); + OutputMatrix out(target, trgWidth); - if (doLineBlend) - { - const double fg = dist(f, g); //test sample: 70% of values max(fg, hc) / min(fg, hc) are between 1.1 and 3.7 with median being 1.9 - const double hc = dist(h, c); // + if (doLineBlend) + { + const double fg = dist(f, g); + //test sample: 70% of values max(fg, hc) / min(fg, hc) are between 1.1 and 3.7 with median being 1.9 + const double hc = dist(h, c); // - const bool haveShallowLine = cfg.steepDirectionThreshold * fg <= hc && e != g && d != g; - const bool haveSteepLine = cfg.steepDirectionThreshold * hc <= fg && e != c && b != c; + const bool haveShallowLine = cfg.steepDirectionThreshold * fg <= hc && e != g && d != g; + const bool haveSteepLine = cfg.steepDirectionThreshold * hc <= fg && e != c && b != c; - if (haveShallowLine) - { - if (haveSteepLine) - Scaler::blendLineSteepAndShallow(px, out); - else - Scaler::blendLineShallow(px, out); - } - else - { - if (haveSteepLine) - Scaler::blendLineSteep(px, out); - else - Scaler::blendLineDiagonal(px,out); - } - } - else - Scaler::blendCorner(px, out); - } + if (haveShallowLine) + { + if (haveSteepLine) + Scaler::blendLineSteepAndShallow(px, out); + else + Scaler::blendLineShallow(px, out); + } + else + { + if (haveSteepLine) + Scaler::blendLineSteep(px, out); + else + Scaler::blendLineDiagonal(px, out); + } + } + else + Scaler::blendCorner(px, out); + } #undef a #undef b @@ -441,649 +505,682 @@ void blendPixel(const Kernel_3x3& ker, #undef g #undef h #undef i + } + + + template //scaler policy: see "Scaler2x" reference implementation + void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, + int yFirst, int yLast) + { + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, srcHeight); + if (yFirst >= yLast || srcWidth <= 0) + return; + + const int trgWidth = srcWidth * Scaler::scale; + + //"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of + //"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing + const int bufferSize = srcWidth; + unsigned char* preProcBuffer = reinterpret_cast(trg + yLast * Scaler::scale * trgWidth) - + bufferSize; + std::fill(preProcBuffer, preProcBuffer + bufferSize, 0); + static_assert(BLEND_NONE == 0, ""); + + //initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending + //this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition! + if (yFirst > 0) + { + const int y = yFirst - 1; + + const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); + const uint32_t* s_0 = src + srcWidth * y; //center line + const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); + const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + + for (int x = 0; x < srcWidth; ++x) + { + const int x_m1 = std::max(x - 1, 0); + const int x_p1 = std::min(x + 1, srcWidth - 1); + const int x_p2 = std::min(x + 2, srcWidth - 1); + + Kernel_4x4 ker = {}; //perf: initialization is negligible + ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible + ker.b = s_m1[x]; + ker.c = s_m1[x_p1]; + ker.d = s_m1[x_p2]; + + ker.e = s_0[x_m1]; + ker.f = s_0[x]; + ker.g = s_0[x_p1]; + ker.h = s_0[x_p2]; + + ker.i = s_p1[x_m1]; + ker.j = s_p1[x]; + ker.k = s_p1[x_p1]; + ker.l = s_p1[x_p2]; + + ker.m = s_p2[x_m1]; + ker.n = s_p2[x]; + ker.o = s_p2[x_p1]; + ker.p = s_p2[x_p2]; + + const BlendResult res = preProcessCorners(ker, cfg); + /* + preprocessing blend result: + --------- + | F | G | //evalute corner between F, G, J, K + ----|---| //input pixel is at position F + | J | K | + --------- + */ + setTopR(preProcBuffer[x], res.blend_j); + + if (x + 1 < bufferSize) + setTopL(preProcBuffer[x + 1], res.blend_k); + } + } + //------------------------------------------------------------------------------------ + + for (int y = yFirst; y < yLast; ++y) + { + uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access + + const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); + const uint32_t* s_0 = src + srcWidth * y; //center line + const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); + const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + + unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position + + for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) + { + //all those bounds checks have only insignificant impact on performance! + const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers! + const int x_p1 = std::min(x + 1, srcWidth - 1); + const int x_p2 = std::min(x + 2, srcWidth - 1); + + Kernel_4x4 ker4 = {}; //perf: initialization is negligible + + ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible + ker4.b = s_m1[x]; + ker4.c = s_m1[x_p1]; + ker4.d = s_m1[x_p2]; + + ker4.e = s_0[x_m1]; + ker4.f = s_0[x]; + ker4.g = s_0[x_p1]; + ker4.h = s_0[x_p2]; + + ker4.i = s_p1[x_m1]; + ker4.j = s_p1[x]; + ker4.k = s_p1[x_p1]; + ker4.l = s_p1[x_p2]; + + ker4.m = s_p2[x_m1]; + ker4.n = s_p2[x]; + ker4.o = s_p2[x_p1]; + ker4.p = s_p2[x_p2]; + + //evaluate the four corners on bottom-right of current pixel + unsigned char blend_xy = 0; //for current (x, y) position + { + const BlendResult res = preProcessCorners(ker4, cfg); + /* + preprocessing blend result: + --------- + | F | G | //evalute corner between F, G, J, K + ----|---| //current input pixel is at position F + | J | K | + --------- + */ + blend_xy = preProcBuffer[x]; + setBottomR(blend_xy, res.blend_f); + //all four corners of (x, y) have been determined at this point due to processing sequence! + + setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) + preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row + + blend_xy1 = 0; + setTopL(blend_xy1, res.blend_k); + //set 1st known corner for (x + 1, y + 1) and buffer for use on next column + + if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y) + setBottomL(preProcBuffer[x + 1], res.blend_g); + } + + //fill block of size scale * scale with the given color + fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale); + //place *after* preprocessing step, to not overwrite the results while processing the the last pixel! + + //blend four corners of current pixel + if (blendingNeeded(blend_xy)) //good 5% perf-improvement + { + Kernel_3x3 ker3 = {}; //perf: initialization is negligible + + ker3.a = ker4.a; + ker3.b = ker4.b; + ker3.c = ker4.c; + + ker3.d = ker4.e; + ker3.e = ker4.f; + ker3.f = ker4.g; + + ker3.g = ker4.i; + ker3.h = ker4.j; + ker3.i = ker4.k; + + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + } + } + } + } + + //------------------------------------------------------------------------------------ + + template + struct Scaler2x : public ColorGradient + { + static const int scale = 2; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + ColorGradient::template alphaGrad(pixBack, pixFront); + } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<1, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 1>(), col); + alphaGrad<5, 6>(out.template ref<1, 1>(), col); //[!] fixes 7/8 used in xBR + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref<1, 1>(), col); + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<21, 100>(out.template ref<1, 1>(), col); //exact: 1 - pi/4 = 0.2146018366 + } + }; + + + template + struct Scaler3x : public ColorGradient + { + static const int scale = 3; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + ColorGradient::template alphaGrad(pixBack, pixFront); + } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + out.template ref<2, scale - 1>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<2, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 2>(), col); + alphaGrad<3, 4>(out.template ref<2, 1>(), col); + alphaGrad<3, 4>(out.template ref<1, 2>(), col); + out.template ref<2, 2>() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 8>(out.template ref<1, 2>(), col); //conflict with other rotations for this odd scale + alphaGrad<1, 8>(out.template ref<2, 1>(), col); + alphaGrad<7, 8>(out.template ref<2, 2>(), col); // + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<45, 100>(out.template ref<2, 2>(), col); //exact: 0.4545939598 + //alphaGrad<7, 256>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid conflicts with other rotations for this odd scale + //alphaGrad<7, 256>(out.template ref<1, 2>(), col); //0.02826017254 + } + }; + + + template + struct Scaler4x : public ColorGradient + { + static const int scale = 4; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + ColorGradient::template alphaGrad(pixBack, pixFront); + } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<3, 4>(out.template ref<3, 1>(), col); + alphaGrad<3, 4>(out.template ref<1, 3>(), col); + alphaGrad<1, 4>(out.template ref<3, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 3>(), col); + + alphaGrad<1, 3>(out.template ref<2, 2>(), col); //[!] fixes 1/4 used in xBR + + out.template ref<3, 3>() = col; + out.template ref<3, 2>() = col; + out.template ref<2, 3>() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + out.template ref() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<68, 100>(out.template ref<3, 3>(), col); //exact: 0.6848532563 + alphaGrad<9, 100>(out.template ref<3, 2>(), col); //0.08677704501 + alphaGrad<9, 100>(out.template ref<2, 3>(), col); //0.08677704501 + } + }; + + + template + struct Scaler5x : public ColorGradient + { + static const int scale = 5; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + ColorGradient::template alphaGrad(pixBack, pixFront); + } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<4, scale - 2>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + alphaGrad<2, 3>(out.template ref<3, 3>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 8>(out.template ref(), col); + //conflict with other rotations for this odd scale + alphaGrad<1, 8>(out.template ref(), col); + alphaGrad<1, 8>(out.template ref(), col); // + + alphaGrad<7, 8>(out.template ref<4, 3>(), col); + alphaGrad<7, 8>(out.template ref<3, 4>(), col); + + out.template ref<4, 4>() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<86, 100>(out.template ref<4, 4>(), col); //exact: 0.8631434088 + alphaGrad<23, 100>(out.template ref<4, 3>(), col); //0.2306749731 + alphaGrad<23, 100>(out.template ref<3, 4>(), col); //0.2306749731 + //alphaGrad<1, 64>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid conflicts with other rotations for this odd scale + //alphaGrad<1, 64>(out.template ref<2, 4>(), col); //0.01676812367 + } + }; + + + template + struct Scaler6x : public ColorGradient + { + static const int scale = 6; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + ColorGradient::template alphaGrad(pixBack, pixFront); + } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<5, scale - 1>() = col; + + out.template ref<4, scale - 2>() = col; + out.template ref<5, scale - 2>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<5, scale - 1>() = col; + + out.template ref<4, scale - 2>() = col; + out.template ref<5, scale - 2>() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<97, 100>(out.template ref<5, 5>(), col); //exact: 0.9711013910 + alphaGrad<42, 100>(out.template ref<4, 5>(), col); //0.4236372243 + alphaGrad<42, 100>(out.template ref<5, 4>(), col); //0.4236372243 + alphaGrad<6, 100>(out.template ref<5, 3>(), col); //0.05652034508 + alphaGrad<6, 100>(out.template ref<3, 5>(), col); //0.05652034508 + } + }; + + //------------------------------------------------------------------------------------ + + struct ColorDistanceRGB + { + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + return DistYCbCrBuffer::dist(pix1, pix2); + + //if (pix1 == pix2) //about 4% perf boost + // return 0; + //return distYCbCr(pix1, pix2, luminanceWeight); + } + }; + + struct ColorDistanceARGB + { + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + const double a1 = getAlpha(pix1) / 255.0; + const double a2 = getAlpha(pix2) / 255.0; + /* + Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1] + + 1. if a1 = a2, distance should be: a1 * distYCbCr() + 2. if a1 = 0, distance should be: a2 * distYCbCr(black, white) = a2 * 255 + 3. if a1 = 1, ??? maybe: 255 * (1 - a2) + a2 * distYCbCr() + */ + + //return std::min(a1, a2) * DistYCbCrBuffer::dist(pix1, pix2) + 255 * abs(a1 - a2); + //=> following code is 15% faster: + const double d = DistYCbCrBuffer::dist(pix1, pix2); + if (a1 < a2) + return a1 * d + 255 * (a2 - a1); + else + return a2 * d + 255 * (a1 - a2); + + //alternative? return std::sqrt(a1 * a2 * square(DistYCbCrBuffer::dist(pix1, pix2)) + square(255 * (a1 - a2))); + } + }; + + + struct ColorGradientRGB + { + template + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + pixBack = gradientRGB(pixFront, pixBack); + } + }; + + struct ColorGradientARGB + { + template + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + pixBack = gradientARGB(pixFront, pixBack); + } + }; } -template //scaler policy: see "Scaler2x" reference implementation -void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, + const xbrz::ScalerCfg& cfg, int yFirst, int yLast) { - yFirst = std::max(yFirst, 0); - yLast = std::min(yLast, srcHeight); - if (yFirst >= yLast || srcWidth <= 0) - return; - - const int trgWidth = srcWidth * Scaler::scale; - - //"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of - //"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing - const int bufferSize = srcWidth; - unsigned char* preProcBuffer = reinterpret_cast(trg + yLast * Scaler::scale * trgWidth) - bufferSize; - std::fill(preProcBuffer, preProcBuffer + bufferSize, 0); - static_assert(BLEND_NONE == 0, ""); - - //initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending - //this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition! - if (yFirst > 0) - { - const int y = yFirst - 1; - - const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); - const uint32_t* s_0 = src + srcWidth * y; //center line - const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); - const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); - - for (int x = 0; x < srcWidth; ++x) - { - const int x_m1 = std::max(x - 1, 0); - const int x_p1 = std::min(x + 1, srcWidth - 1); - const int x_p2 = std::min(x + 2, srcWidth - 1); - - Kernel_4x4 ker = {}; //perf: initialization is negligible - ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible - ker.b = s_m1[x]; - ker.c = s_m1[x_p1]; - ker.d = s_m1[x_p2]; - - ker.e = s_0[x_m1]; - ker.f = s_0[x]; - ker.g = s_0[x_p1]; - ker.h = s_0[x_p2]; - - ker.i = s_p1[x_m1]; - ker.j = s_p1[x]; - ker.k = s_p1[x_p1]; - ker.l = s_p1[x_p2]; - - ker.m = s_p2[x_m1]; - ker.n = s_p2[x]; - ker.o = s_p2[x_p1]; - ker.p = s_p2[x_p2]; - - const BlendResult res = preProcessCorners(ker, cfg); - /* - preprocessing blend result: - --------- - | F | G | //evalute corner between F, G, J, K - ----|---| //input pixel is at position F - | J | K | - --------- - */ - setTopR(preProcBuffer[x], res.blend_j); - - if (x + 1 < bufferSize) - setTopL(preProcBuffer[x + 1], res.blend_k); - } - } - //------------------------------------------------------------------------------------ - - for (int y = yFirst; y < yLast; ++y) - { - uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access - - const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); - const uint32_t* s_0 = src + srcWidth * y; //center line - const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); - const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); - - unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position - - for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) - { - //all those bounds checks have only insignificant impact on performance! - const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers! - const int x_p1 = std::min(x + 1, srcWidth - 1); - const int x_p2 = std::min(x + 2, srcWidth - 1); - - Kernel_4x4 ker4 = {}; //perf: initialization is negligible - - ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible - ker4.b = s_m1[x]; - ker4.c = s_m1[x_p1]; - ker4.d = s_m1[x_p2]; - - ker4.e = s_0[x_m1]; - ker4.f = s_0[x]; - ker4.g = s_0[x_p1]; - ker4.h = s_0[x_p2]; - - ker4.i = s_p1[x_m1]; - ker4.j = s_p1[x]; - ker4.k = s_p1[x_p1]; - ker4.l = s_p1[x_p2]; - - ker4.m = s_p2[x_m1]; - ker4.n = s_p2[x]; - ker4.o = s_p2[x_p1]; - ker4.p = s_p2[x_p2]; - - //evaluate the four corners on bottom-right of current pixel - unsigned char blend_xy = 0; //for current (x, y) position - { - const BlendResult res = preProcessCorners(ker4, cfg); - /* - preprocessing blend result: - --------- - | F | G | //evalute corner between F, G, J, K - ----|---| //current input pixel is at position F - | J | K | - --------- - */ - blend_xy = preProcBuffer[x]; - setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence! - - setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) - preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row - - blend_xy1 = 0; - setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column - - if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y) - setBottomL(preProcBuffer[x + 1], res.blend_g); - } - - //fill block of size scale * scale with the given color - fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale); //place *after* preprocessing step, to not overwrite the results while processing the the last pixel! - - //blend four corners of current pixel - if (blendingNeeded(blend_xy)) //good 5% perf-improvement - { - Kernel_3x3 ker3 = {}; //perf: initialization is negligible - - ker3.a = ker4.a; - ker3.b = ker4.b; - ker3.c = ker4.c; - - ker3.d = ker4.e; - ker3.e = ker4.f; - ker3.f = ker4.g; - - ker3.g = ker4.i; - ker3.h = ker4.j; - ker3.i = ker4.k; - - blendPixel(ker3, out, trgWidth, blend_xy, cfg); - blendPixel(ker3, out, trgWidth, blend_xy, cfg); - blendPixel(ker3, out, trgWidth, blend_xy, cfg); - blendPixel(ker3, out, trgWidth, blend_xy, cfg); - } - } - } -} - -//------------------------------------------------------------------------------------ - -template -struct Scaler2x : public ColorGradient -{ - static const int scale = 2; - - template //bring template function into scope for GCC - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } - - - template - static void blendLineShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - } - - template - static void blendLineSteep(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - } - - template - static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<1, 0>(), col); - alphaGrad<1, 4>(out.template ref<0, 1>(), col); - alphaGrad<5, 6>(out.template ref<1, 1>(), col); //[!] fixes 7/8 used in xBR - } - - template - static void blendLineDiagonal(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 2>(out.template ref<1, 1>(), col); - } - - template - static void blendCorner(uint32_t col, OutputMatrix& out) - { - //model a round corner - alphaGrad<21, 100>(out.template ref<1, 1>(), col); //exact: 1 - pi/4 = 0.2146018366 - } -}; - - -template -struct Scaler3x : public ColorGradient -{ - static const int scale = 3; - - template //bring template function into scope for GCC - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } - - - template - static void blendLineShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - - alphaGrad<3, 4>(out.template ref(), col); - out.template ref() = col; - } - - template - static void blendLineSteep(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); - - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - out.template ref<2, scale - 1>() = col; - } - - template - static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<2, 0>(), col); - alphaGrad<1, 4>(out.template ref<0, 2>(), col); - alphaGrad<3, 4>(out.template ref<2, 1>(), col); - alphaGrad<3, 4>(out.template ref<1, 2>(), col); - out.template ref<2, 2>() = col; - } - - template - static void blendLineDiagonal(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 8>(out.template ref<1, 2>(), col); //conflict with other rotations for this odd scale - alphaGrad<1, 8>(out.template ref<2, 1>(), col); - alphaGrad<7, 8>(out.template ref<2, 2>(), col); // - } - - template - static void blendCorner(uint32_t col, OutputMatrix& out) - { - //model a round corner - alphaGrad<45, 100>(out.template ref<2, 2>(), col); //exact: 0.4545939598 - //alphaGrad<7, 256>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid conflicts with other rotations for this odd scale - //alphaGrad<7, 256>(out.template ref<1, 2>(), col); //0.02826017254 - } -}; - - -template -struct Scaler4x : public ColorGradient -{ - static const int scale = 4; - - template //bring template function into scope for GCC - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } - - - template - static void blendLineShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - - alphaGrad<3, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - - out.template ref() = col; - out.template ref() = col; - } - - template - static void blendLineSteep(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); - - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); - - out.template ref<2, scale - 1>() = col; - out.template ref<3, scale - 1>() = col; - } - - template - static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<3, 4>(out.template ref<3, 1>(), col); - alphaGrad<3, 4>(out.template ref<1, 3>(), col); - alphaGrad<1, 4>(out.template ref<3, 0>(), col); - alphaGrad<1, 4>(out.template ref<0, 3>(), col); - - alphaGrad<1, 3>(out.template ref<2, 2>(), col); //[!] fixes 1/4 used in xBR - - out.template ref<3, 3>() = col; - out.template ref<3, 2>() = col; - out.template ref<2, 3>() = col; - } - - template - static void blendLineDiagonal(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 2>(out.template ref(), col); - alphaGrad<1, 2>(out.template ref(), col); - out.template ref() = col; - } - - template - static void blendCorner(uint32_t col, OutputMatrix& out) - { - //model a round corner - alphaGrad<68, 100>(out.template ref<3, 3>(), col); //exact: 0.6848532563 - alphaGrad< 9, 100>(out.template ref<3, 2>(), col); //0.08677704501 - alphaGrad< 9, 100>(out.template ref<2, 3>(), col); //0.08677704501 - } -}; - - -template -struct Scaler5x : public ColorGradient -{ - static const int scale = 5; - - template //bring template function into scope for GCC - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } - - - template - static void blendLineShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - - alphaGrad<3, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - - out.template ref() = col; - out.template ref() = col; - out.template ref() = col; - out.template ref() = col; - } - - template - static void blendLineSteep(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); - alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); - - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); - - out.template ref<2, scale - 1>() = col; - out.template ref<3, scale - 1>() = col; - out.template ref<4, scale - 1>() = col; - out.template ref<4, scale - 2>() = col; - } - - template - static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - - alphaGrad<2, 3>(out.template ref<3, 3>(), col); - - out.template ref<2, scale - 1>() = col; - out.template ref<3, scale - 1>() = col; - out.template ref<4, scale - 1>() = col; - - out.template ref() = col; - out.template ref() = col; - } - - template - static void blendLineDiagonal(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 8>(out.template ref(), col); //conflict with other rotations for this odd scale - alphaGrad<1, 8>(out.template ref(), col); - alphaGrad<1, 8>(out.template ref(), col); // - - alphaGrad<7, 8>(out.template ref<4, 3>(), col); - alphaGrad<7, 8>(out.template ref<3, 4>(), col); - - out.template ref<4, 4>() = col; - } - - template - static void blendCorner(uint32_t col, OutputMatrix& out) - { - //model a round corner - alphaGrad<86, 100>(out.template ref<4, 4>(), col); //exact: 0.8631434088 - alphaGrad<23, 100>(out.template ref<4, 3>(), col); //0.2306749731 - alphaGrad<23, 100>(out.template ref<3, 4>(), col); //0.2306749731 - //alphaGrad<1, 64>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid conflicts with other rotations for this odd scale - //alphaGrad<1, 64>(out.template ref<2, 4>(), col); //0.01676812367 - } -}; - - -template -struct Scaler6x : public ColorGradient -{ - static const int scale = 6; - - template //bring template function into scope for GCC - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } - - - template - static void blendLineShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - - alphaGrad<3, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - - out.template ref() = col; - out.template ref() = col; - out.template ref() = col; - out.template ref() = col; - - out.template ref() = col; - out.template ref() = col; - } - - template - static void blendLineSteep(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); - alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); - - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); - alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col); - - out.template ref<2, scale - 1>() = col; - out.template ref<3, scale - 1>() = col; - out.template ref<4, scale - 1>() = col; - out.template ref<5, scale - 1>() = col; - - out.template ref<4, scale - 2>() = col; - out.template ref<5, scale - 2>() = col; - } - - template - static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); - alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); - alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); - alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); - - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<1, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - alphaGrad<3, 4>(out.template ref(), col); - - out.template ref<2, scale - 1>() = col; - out.template ref<3, scale - 1>() = col; - out.template ref<4, scale - 1>() = col; - out.template ref<5, scale - 1>() = col; - - out.template ref<4, scale - 2>() = col; - out.template ref<5, scale - 2>() = col; - - out.template ref() = col; - out.template ref() = col; - } - - template - static void blendLineDiagonal(uint32_t col, OutputMatrix& out) - { - alphaGrad<1, 2>(out.template ref(), col); - alphaGrad<1, 2>(out.template ref(), col); - alphaGrad<1, 2>(out.template ref(), col); - - out.template ref() = col; - out.template ref() = col; - out.template ref() = col; - } - - template - static void blendCorner(uint32_t col, OutputMatrix& out) - { - //model a round corner - alphaGrad<97, 100>(out.template ref<5, 5>(), col); //exact: 0.9711013910 - alphaGrad<42, 100>(out.template ref<4, 5>(), col); //0.4236372243 - alphaGrad<42, 100>(out.template ref<5, 4>(), col); //0.4236372243 - alphaGrad< 6, 100>(out.template ref<5, 3>(), col); //0.05652034508 - alphaGrad< 6, 100>(out.template ref<3, 5>(), col); //0.05652034508 - } -}; - -//------------------------------------------------------------------------------------ - -struct ColorDistanceRGB -{ - static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) - { - return DistYCbCrBuffer::dist(pix1, pix2); - - //if (pix1 == pix2) //about 4% perf boost - // return 0; - //return distYCbCr(pix1, pix2, luminanceWeight); - } -}; - -struct ColorDistanceARGB -{ - static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) - { - const double a1 = getAlpha(pix1) / 255.0 ; - const double a2 = getAlpha(pix2) / 255.0 ; - /* - Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1] - - 1. if a1 = a2, distance should be: a1 * distYCbCr() - 2. if a1 = 0, distance should be: a2 * distYCbCr(black, white) = a2 * 255 - 3. if a1 = 1, ??? maybe: 255 * (1 - a2) + a2 * distYCbCr() - */ - - //return std::min(a1, a2) * DistYCbCrBuffer::dist(pix1, pix2) + 255 * abs(a1 - a2); - //=> following code is 15% faster: - const double d = DistYCbCrBuffer::dist(pix1, pix2); - if (a1 < a2) - return a1 * d + 255 * (a2 - a1); - else - return a2 * d + 255 * (a1 - a2); - - //alternative? return std::sqrt(a1 * a2 * square(DistYCbCrBuffer::dist(pix1, pix2)) + square(255 * (a1 - a2))); - } -}; - - -struct ColorGradientRGB -{ - template - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) - { - pixBack = gradientRGB(pixFront, pixBack); - } -}; - -struct ColorGradientARGB -{ - template - static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) - { - pixBack = gradientARGB(pixFront, pixBack); - } -}; + switch (colFmt) + { + case ColorFormat::ARGB: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceARGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceARGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceARGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceARGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceARGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + + case ColorFormat::RGB: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceRGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceRGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceRGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceRGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceRGB>( + src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + } + assert(false); } -void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, + double equalColorTolerance) { - switch (colFmt) - { - case ColorFormat::ARGB: - switch (factor) - { - case 2: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 3: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 4: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 5: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 6: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - } - break; + switch (colFmt) + { + case ColorFormat::ARGB: + return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; - case ColorFormat::RGB: - switch (factor) - { - case 2: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 3: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 4: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 5: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - case 6: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); - } - break; - } - assert(false); -} - - -bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance) -{ - switch (colFmt) - { - case ColorFormat::ARGB: - return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; - - case ColorFormat::RGB: - return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; - } - assert(false); - return false; + case ColorFormat::RGB: + return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; + } + assert(false); + return false; } @@ -1091,69 +1188,70 @@ void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight uint32_t* trg, int trgWidth, int trgHeight, int trgPitch, SliceType st, int yFirst, int yLast) { - if (srcPitch < srcWidth * static_cast(sizeof(uint32_t)) || - trgPitch < trgWidth * static_cast(sizeof(uint32_t))) - { - assert(false); - return; - } + if (srcPitch < srcWidth * static_cast(sizeof(uint32_t)) || + trgPitch < trgWidth * static_cast(sizeof(uint32_t))) + { + assert(false); + return; + } - switch (st) - { - case NN_SCALE_SLICE_SOURCE: - //nearest-neighbor (going over source image - fast for upscaling, since source is read only once - yFirst = std::max(yFirst, 0); - yLast = std::min(yLast, srcHeight); - if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return; + switch (st) + { + case NN_SCALE_SLICE_SOURCE: + //nearest-neighbor (going over source image - fast for upscaling, since source is read only once + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, srcHeight); + if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return; - for (int y = yFirst; y < yLast; ++y) - { - //mathematically: ySrc = floor(srcHeight * yTrg / trgHeight) - // => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight + for (int y = yFirst; y < yLast; ++y) + { + //mathematically: ySrc = floor(srcHeight * yTrg / trgHeight) + // => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight - //keep within for loop to support MT input slices! - const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight) - const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight) - const int blockHeight = yTrg_last - yTrg_first; + //keep within for loop to support MT input slices! + const int yTrg_first = (y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight) + const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; + //=ceil(((y + 1) * trgHeight) / srcHeight) + const int blockHeight = yTrg_last - yTrg_first; - if (blockHeight > 0) - { - const uint32_t* srcLine = byteAdvance(src, y * srcPitch); - uint32_t* trgLine = byteAdvance(trg, yTrg_first * trgPitch); - int xTrg_first = 0; + if (blockHeight > 0) + { + const uint32_t* srcLine = byteAdvance(src, y * srcPitch); + uint32_t* trgLine = byteAdvance(trg, yTrg_first * trgPitch); + int xTrg_first = 0; - for (int x = 0; x < srcWidth; ++x) - { - int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth; - const int blockWidth = xTrg_last - xTrg_first; - if (blockWidth > 0) - { - xTrg_first = xTrg_last; - fillBlock(trgLine, trgPitch, srcLine[x], blockWidth, blockHeight); - trgLine += blockWidth; - } - } - } - } - break; + for (int x = 0; x < srcWidth; ++x) + { + int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth; + const int blockWidth = xTrg_last - xTrg_first; + if (blockWidth > 0) + { + xTrg_first = xTrg_last; + fillBlock(trgLine, trgPitch, srcLine[x], blockWidth, blockHeight); + trgLine += blockWidth; + } + } + } + } + break; - case NN_SCALE_SLICE_TARGET: - //nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!) - yFirst = std::max(yFirst, 0); - yLast = std::min(yLast, trgHeight); - if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return; + case NN_SCALE_SLICE_TARGET: + //nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!) + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, trgHeight); + if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return; - for (int y = yFirst; y < yLast; ++y) - { - uint32_t* trgLine = byteAdvance(trg, y * trgPitch); - const int ySrc = srcHeight * y / trgHeight; - const uint32_t* srcLine = byteAdvance(src, ySrc * srcPitch); - for (int x = 0; x < trgWidth; ++x) - { - const int xSrc = srcWidth * x / trgWidth; - trgLine[x] = srcLine[xSrc]; - } - } - break; - } + for (int y = yFirst; y < yLast; ++y) + { + uint32_t* trgLine = byteAdvance(trg, y * trgPitch); + const int ySrc = srcHeight * y / trgHeight; + const uint32_t* srcLine = byteAdvance(src, ySrc * srcPitch); + for (int x = 0; x < trgWidth; ++x) + { + const int xSrc = srcWidth * x / trgWidth; + trgLine[x] = srcLine[xSrc]; + } + } + break; + } } diff --git a/Utilities/xBRZ/xbrz.h b/Utilities/xBRZ/xbrz.h index 40dd410..bb86fe0 100644 --- a/Utilities/xBRZ/xbrz.h +++ b/Utilities/xBRZ/xbrz.h @@ -23,72 +23,73 @@ namespace xbrz { -/* -------------------------------------------------------------------------- -| xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju | -------------------------------------------------------------------------- -using a modified approach of xBR: -http://board.byuu.org/viewtopic.php?f=10&t=2248 -- new rule set preserving small image features -- highly optimized for performance -- support alpha channel -- support multithreading -- support 64-bit architectures -- support processing image slices -- support scaling up to 6xBRZ -*/ + /* + ------------------------------------------------------------------------- + | xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju | + ------------------------------------------------------------------------- + using a modified approach of xBR: + http://board.byuu.org/viewtopic.php?f=10&t=2248 + - new rule set preserving small image features + - highly optimized for performance + - support alpha channel + - support multithreading + - support 64-bit architectures + - support processing image slices + - support scaling up to 6xBRZ + */ -enum class ColorFormat //from high bits -> low bits, 8 bit per channel -{ - RGB, //8 bit for each red, green, blue, upper 8 bits unused - ARGB, //including alpha channel, BGRA byte order on little-endian machines -}; + enum class ColorFormat //from high bits -> low bits, 8 bit per channel + { + RGB, + //8 bit for each red, green, blue, upper 8 bits unused + ARGB, + //including alpha channel, BGRA byte order on little-endian machines + }; -/* --> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only --> support for source/target pitch in bytes! --> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image: - Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis) - Caveat: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition - in the target image data if you are using multiple threads for processing each enlarged slice! + /* + -> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only + -> support for source/target pitch in bytes! + -> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image: + Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis) + Caveat: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition + in the target image data if you are using multiple threads for processing each enlarged slice! + + THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap! + - there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process 8-16 rows at least + */ + void scale(size_t factor, //valid range: 2 - 6 + const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, + ColorFormat colFmt, + const ScalerCfg& cfg = ScalerCfg(), + int yFirst = 0, int yLast = std::numeric_limits::max()); //slice of source image -THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap! - - there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process 8-16 rows at least -*/ -void scale(size_t factor, //valid range: 2 - 6 - const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, - ColorFormat colFmt, - const ScalerCfg& cfg = ScalerCfg(), - int yFirst = 0, int yLast = std::numeric_limits::max()); //slice of source image + void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, + uint32_t* trg, int trgWidth, int trgHeight); -void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, - uint32_t* trg, int trgWidth, int trgHeight); + enum SliceType + { + NN_SCALE_SLICE_SOURCE, + NN_SCALE_SLICE_TARGET, + }; -enum SliceType -{ - NN_SCALE_SLICE_SOURCE, - NN_SCALE_SLICE_TARGET, -}; -void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, //pitch in bytes! - uint32_t* trg, int trgWidth, int trgHeight, int trgPitch, - SliceType st, int yFirst, int yLast); + void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, //pitch in bytes! + uint32_t* trg, int trgWidth, int trgHeight, int trgPitch, + SliceType st, int yFirst, int yLast); -//parameter tuning -bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance); + //parameter tuning + bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, + double equalColorTolerance); - - - -//########################### implementation ########################### -inline -void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, - uint32_t* trg, int trgWidth, int trgHeight) -{ - nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), - trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), - NN_SCALE_SLICE_TARGET, 0, trgHeight); -} + //########################### implementation ########################### + inline + void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, + uint32_t* trg, int trgWidth, int trgHeight) + { + nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), + trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), + NN_SCALE_SLICE_TARGET, 0, trgHeight); + } } #endif diff --git a/Windows/DirectInputManager.cpp b/Windows/DirectInputManager.cpp index 3793ce2..aedb873 100644 --- a/Windows/DirectInputManager.cpp +++ b/Windows/DirectInputManager.cpp @@ -26,18 +26,23 @@ void DirectInputManager::Initialize() // Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use. // Create a DInput object - if(FAILED(hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&_directInput, nullptr))) { + if (FAILED( + hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&_directInput, + nullptr))) + { MessageManager::Log("[DInput] DirectInput8Create failed: " + std::to_string(hr)); return; } IDirectInputJoyConfig8* pJoyConfig = nullptr; - if(FAILED(hr = _directInput->QueryInterface(IID_IDirectInputJoyConfig8, (void**)&pJoyConfig))) { + if (FAILED(hr = _directInput->QueryInterface(IID_IDirectInputJoyConfig8, (void**)&pJoyConfig))) + { MessageManager::Log("[DInput] QueryInterface failed: " + std::to_string(hr)); return; } - if(pJoyConfig) { + if (pJoyConfig) + { pJoyConfig->Release(); } @@ -48,19 +53,25 @@ bool DirectInputManager::ProcessDevice(const DIDEVICEINSTANCE* pdidInstance) { const GUID* deviceGuid = &pdidInstance->guidInstance; - auto comp = [=](GUID guid) { + auto comp = [=](GUID guid) + { return guid.Data1 == deviceGuid->Data1 && guid.Data2 == deviceGuid->Data2 && guid.Data3 == deviceGuid->Data3 && memcmp(guid.Data4, deviceGuid->Data4, sizeof(guid.Data4)) == 0; }; - bool wasProcessedBefore = std::find_if(_processedGuids.begin(), _processedGuids.end(), comp) != _processedGuids.end(); - if(wasProcessedBefore) { + bool wasProcessedBefore = std::find_if(_processedGuids.begin(), _processedGuids.end(), comp) != _processedGuids. + end(); + if (wasProcessedBefore) + { return false; - } else { + } + else + { bool isXInput = IsXInputDevice(&pdidInstance->guidProduct); - if(isXInput) { + if (isXInput) + { _xinputDeviceGuids.push_back(*deviceGuid); _processedGuids.push_back(*deviceGuid); } @@ -75,76 +86,89 @@ bool DirectInputManager::ProcessDevice(const DIDEVICEINSTANCE* pdidInstance) //----------------------------------------------------------------------------- bool DirectInputManager::IsXInputDevice(const GUID* pGuidProductFromDirectInput) { - IWbemLocator* pIWbemLocator = NULL; - IEnumWbemClassObject* pEnumDevices = NULL; - IWbemClassObject* pDevices[20] = { 0 }; - IWbemServices* pIWbemServices = NULL; - BSTR bstrNamespace = NULL; - BSTR bstrDeviceID = NULL; - BSTR bstrClassName = NULL; - DWORD uReturned = 0; - bool bIsXinputDevice = false; - UINT iDevice = 0; - VARIANT var; - HRESULT hr; + IWbemLocator* pIWbemLocator = NULL; + IEnumWbemClassObject* pEnumDevices = NULL; + IWbemClassObject* pDevices[20] = {0}; + IWbemServices* pIWbemServices = NULL; + BSTR bstrNamespace = NULL; + BSTR bstrDeviceID = NULL; + BSTR bstrClassName = NULL; + DWORD uReturned = 0; + bool bIsXinputDevice = false; + UINT iDevice = 0; + VARIANT var; + HRESULT hr; // CoInit if needed hr = CoInitialize(NULL); bool bCleanupCOM = SUCCEEDED(hr); // Create WMI - hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator); - if(FAILED(hr) || pIWbemLocator == NULL) { + hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), + (LPVOID*)&pIWbemLocator); + if (FAILED(hr) || pIWbemLocator == NULL) + { goto LCleanup; } - bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); + bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); bstrClassName = SysAllocString(L"Win32_PNPEntity"); bstrDeviceID = SysAllocString(L"DeviceID"); // Connect to WMI hr = pIWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices); - if(FAILED(hr) || pIWbemServices == NULL) { + if (FAILED(hr) || pIWbemServices == NULL) + { goto LCleanup; } // Switch security level to IMPERSONATE. - CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, NULL, &pEnumDevices); - if(FAILED(hr) || pEnumDevices == NULL) { + if (FAILED(hr) || pEnumDevices == NULL) + { goto LCleanup; } // Loop over all devices - for(;; ) { + for (;;) + { // Get 20 at a time hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned); - if(FAILED(hr) || uReturned == 0 || bIsXinputDevice) { + if (FAILED(hr) || uReturned == 0 || bIsXinputDevice) + { break; } - for(iDevice = 0; iDevice < uReturned; iDevice++) { + for (iDevice = 0; iDevice < uReturned; iDevice++) + { // For each device, get its device ID hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL); - if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) { + if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) + { // Check if the device ID contains "IG_". If it does, then it's an XInput device // This information can not be found from DirectInput - if(wcsstr(var.bstrVal, L"IG_")) { + if (wcsstr(var.bstrVal, L"IG_")) + { // If it does, then get the VID/PID from var.bstrVal DWORD dwPid = 0, dwVid = 0; WCHAR* strVid = wcsstr(var.bstrVal, L"VID_"); - if(strVid && swscanf_s(strVid, L"VID_%4X", &dwVid) != 1) { + if (strVid && swscanf_s(strVid, L"VID_%4X", &dwVid) != 1) + { dwVid = 0; } WCHAR* strPid = wcsstr(var.bstrVal, L"PID_"); - if(strPid && swscanf_s(strPid, L"PID_%4X", &dwPid) != 1) { + if (strPid && swscanf_s(strPid, L"PID_%4X", &dwPid) != 1) + { dwPid = 0; } // Compare the VID/PID to the DInput device DWORD dwVidPid = MAKELONG(dwVid, dwPid); - if(dwVidPid == pGuidProductFromDirectInput->Data1) { + if (dwVidPid == pGuidProductFromDirectInput->Data1) + { bIsXinputDevice = true; pDevices[iDevice]->Release(); pDevices[iDevice] = nullptr; @@ -159,31 +183,40 @@ bool DirectInputManager::IsXInputDevice(const GUID* pGuidProductFromDirectInput) } LCleanup: - if(bstrNamespace) { + if (bstrNamespace) + { SysFreeString(bstrNamespace); } - if(bstrDeviceID) { + if (bstrDeviceID) + { SysFreeString(bstrDeviceID); } - if(bstrClassName) { + if (bstrClassName) + { SysFreeString(bstrClassName); } - for(iDevice = 0; iDevice < 20; iDevice++) { - if(pDevices[iDevice]) { + for (iDevice = 0; iDevice < 20; iDevice++) + { + if (pDevices[iDevice]) + { pDevices[iDevice]->Release(); } } - if(pEnumDevices) { + if (pEnumDevices) + { pEnumDevices->Release(); } - if(pIWbemLocator) { + if (pIWbemLocator) + { pIWbemLocator->Release(); } - if(pIWbemServices) { + if (pIWbemServices) + { pIWbemServices->Release(); } - if(bCleanupCOM) { + if (bCleanupCOM) + { CoUninitialize(); } @@ -192,7 +225,8 @@ LCleanup: void DirectInputManager::UpdateDeviceList() { - if(_needToUpdate) { + if (_needToUpdate) + { //An update is already pending, skip return; } @@ -200,15 +234,20 @@ void DirectInputManager::UpdateDeviceList() HRESULT hr; // Enumerate devices - if(SUCCEEDED(hr = _directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, nullptr, DIEDFL_ALLDEVICES))) { - if(!_joysticksToAdd.empty()) { + if (SUCCEEDED( + hr = _directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, nullptr, DIEDFL_ALLDEVICES))) + { + if (!_joysticksToAdd.empty()) + { //Sleeping apparently lets us read accurate "default" values, otherwise a PS4 controller returns all 0s, despite not doing so normally - for(DirectInputData &joystick : _joysticksToAdd) { + for (DirectInputData& joystick : _joysticksToAdd) + { UpdateInputState(joystick); } std::this_thread::sleep_for(std::chrono::duration(100)); - for(DirectInputData &joystick : _joysticksToAdd) { + for (DirectInputData& joystick : _joysticksToAdd) + { UpdateInputState(joystick); joystick.defaultState = joystick.state; } @@ -216,7 +255,8 @@ void DirectInputManager::UpdateDeviceList() } } - if(_requestUpdate) { + if (_requestUpdate) + { _requestUpdate = false; _needToUpdate = true; } @@ -231,38 +271,51 @@ int DirectInputManager::EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstan { HRESULT hr; - if(ProcessDevice(pdidInstance)) { + if (ProcessDevice(pdidInstance)) + { _processedGuids.push_back(pdidInstance->guidInstance); // Obtain an interface to the enumerated joystick. LPDIRECTINPUTDEVICE8 pJoystick = nullptr; hr = _directInput->CreateDevice(pdidInstance->guidInstance, &pJoystick, nullptr); - if(SUCCEEDED(hr)) { + if (SUCCEEDED(hr)) + { DIJOYSTATE2 state; memset(&state, 0, sizeof(state)); - DirectInputData data{ pJoystick, state, state, false }; + DirectInputData data{pJoystick, state, state, false}; memcpy(&data.instanceInfo, pdidInstance, sizeof(DIDEVICEINSTANCE)); // Set the data format to "simple joystick" - a predefined data format // A data format specifies which controls on a device we are interested in, and how they should be reported. // This tells DInput that we will be passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState(). - if(SUCCEEDED(hr = data.joystick->SetDataFormat(&c_dfDIJoystick2))) { + if (SUCCEEDED(hr = data.joystick->SetDataFormat(&c_dfDIJoystick2))) + { // Set the cooperative level to let DInput know how this device should interact with the system and with other DInput applications. - if(SUCCEEDED(hr = data.joystick->SetCooperativeLevel(_hWnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) { + if (SUCCEEDED(hr = data.joystick->SetCooperativeLevel(_hWnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + { // Enumerate the joystick objects. The callback function enabled user interface elements for objects that are found, and sets the min/max values property for discovered axes. - if(SUCCEEDED(hr = data.joystick->EnumObjects(EnumObjectsCallback, data.joystick, DIDFT_ALL))) { + if (SUCCEEDED(hr = data.joystick->EnumObjects(EnumObjectsCallback, data.joystick, DIDFT_ALL))) + { _joysticksToAdd.push_back(data); - } else { + } + else + { MessageManager::Log("[DInput] Failed to enumerate objects: " + std::to_string(hr)); } - } else { + } + else + { MessageManager::Log("[DInput] Failed to set cooperative level: " + std::to_string(hr)); } - } else { + } + else + { MessageManager::Log("[DInput] Failed to set data format: " + std::to_string(hr)); } - } else { + } + else + { MessageManager::Log("[DInput] Failed to create directinput device" + std::to_string(hr)); } } @@ -280,7 +333,8 @@ int DirectInputManager::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi LPDIRECTINPUTDEVICE8 joystick = (LPDIRECTINPUTDEVICE8)pContext; // For axes that are returned, set the DIPROP_RANGE property for the enumerated axis in order to scale min/max values. - if(pdidoi->dwType & DIDFT_AXIS) { + if (pdidoi->dwType & DIDFT_AXIS) + { DIPROPRANGE diprg; diprg.diph.dwSize = sizeof(DIPROPRANGE); diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); @@ -290,7 +344,8 @@ int DirectInputManager::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi diprg.lMax = +1000; // Set the range for the axis - if(FAILED(joystick->SetProperty(DIPROP_RANGE, &diprg.diph))) { + if (FAILED(joystick->SetProperty(DIPROP_RANGE, &diprg.diph))) + { return DIENUM_STOP; } } @@ -301,25 +356,32 @@ int DirectInputManager::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi void DirectInputManager::RefreshState() { - if(_needToUpdate) { + if (_needToUpdate) + { vector joysticks; //Keep exisiting joysticks, if they still work, otherwise remove them from the list - for(DirectInputData &joystick : _joysticks) { - if(joystick.stateValid) { + for (DirectInputData& joystick : _joysticks) + { + if (joystick.stateValid) + { joysticks.push_back(joystick); - } else { + } + else + { MessageManager::Log("[DInput] Device lost, trying to reacquire..."); - + //Release the joystick, we'll try to initialize it again if it still exists const GUID* deviceGuid = &joystick.instanceInfo.guidInstance; - auto comp = [=](GUID guid) { + auto comp = [=](GUID guid) + { return guid.Data1 == deviceGuid->Data1 && guid.Data2 == deviceGuid->Data2 && guid.Data3 == deviceGuid->Data3 && memcmp(guid.Data4, deviceGuid->Data4, sizeof(guid.Data4)) == 0; }; - _processedGuids.erase(std::remove_if(_processedGuids.begin(), _processedGuids.end(), comp), _processedGuids.end()); + _processedGuids.erase(std::remove_if(_processedGuids.begin(), _processedGuids.end(), comp), + _processedGuids.end()); joystick.joystick->Unacquire(); joystick.joystick->Release(); @@ -327,7 +389,8 @@ void DirectInputManager::RefreshState() } //Add the newly-found joysticks - for(DirectInputData &joystick : _joysticksToAdd) { + for (DirectInputData& joystick : _joysticksToAdd) + { joysticks.push_back(joystick); } @@ -336,7 +399,8 @@ void DirectInputManager::RefreshState() _needToUpdate = false; } - for(DirectInputData &joystick : _joysticks) { + for (DirectInputData& joystick : _joysticks) + { UpdateInputState(joystick); } } @@ -348,7 +412,8 @@ int DirectInputManager::GetJoystickCount() bool DirectInputManager::IsPressed(int port, int button) { - if(port >= (int)_joysticks.size() || !_joysticks[port].stateValid) { + if (port >= (int)_joysticks.size() || !_joysticks[port].stateValid) + { return false; } @@ -359,47 +424,51 @@ bool DirectInputManager::IsPressed(int port, int button) int povDirection = state.rgdwPOV[0] / 4500; bool povCentered = (LOWORD(state.rgdwPOV[0]) == 0xFFFF) || povDirection >= 8; - switch(button) { - case 0x00: return state.lY - defaultState.lY < -deadRange; - case 0x01: return state.lY - defaultState.lY > deadRange; - case 0x02: return state.lX - defaultState.lX < -deadRange; - case 0x03: return state.lX - defaultState.lX > deadRange; - case 0x04: return state.lRy - defaultState.lRy < -deadRange; - case 0x05: return state.lRy - defaultState.lRy > deadRange; - case 0x06: return state.lRx - defaultState.lRx < -deadRange; - case 0x07: return state.lRx - defaultState.lRx > deadRange; - case 0x08: return state.lZ - defaultState.lZ < -deadRange; - case 0x09: return state.lZ - defaultState.lZ > deadRange; - case 0x0A: return state.lRz - defaultState.lRz < -deadRange; - case 0x0B: return state.lRz - defaultState.lRz > deadRange; - case 0x0C: return !povCentered && (povDirection == 7 || povDirection == 0 || povDirection == 1); - case 0x0D: return !povCentered && (povDirection >= 3 && povDirection <= 5); - case 0x0E: return !povCentered && (povDirection >= 1 && povDirection <= 3); - case 0x0F: return !povCentered && (povDirection >= 5 && povDirection <= 7); - default: return state.rgbButtons[button - 0x10] != 0; + switch (button) + { + case 0x00: return state.lY - defaultState.lY < -deadRange; + case 0x01: return state.lY - defaultState.lY > deadRange; + case 0x02: return state.lX - defaultState.lX < -deadRange; + case 0x03: return state.lX - defaultState.lX > deadRange; + case 0x04: return state.lRy - defaultState.lRy < -deadRange; + case 0x05: return state.lRy - defaultState.lRy > deadRange; + case 0x06: return state.lRx - defaultState.lRx < -deadRange; + case 0x07: return state.lRx - defaultState.lRx > deadRange; + case 0x08: return state.lZ - defaultState.lZ < -deadRange; + case 0x09: return state.lZ - defaultState.lZ > deadRange; + case 0x0A: return state.lRz - defaultState.lRz < -deadRange; + case 0x0B: return state.lRz - defaultState.lRz > deadRange; + case 0x0C: return !povCentered && (povDirection == 7 || povDirection == 0 || povDirection == 1); + case 0x0D: return !povCentered && (povDirection >= 3 && povDirection <= 5); + case 0x0E: return !povCentered && (povDirection >= 1 && povDirection <= 3); + case 0x0F: return !povCentered && (povDirection >= 5 && povDirection <= 7); + default: return state.rgbButtons[button - 0x10] != 0; } return false; } -void DirectInputManager::UpdateInputState(DirectInputData &data) +void DirectInputManager::UpdateInputState(DirectInputData& data) { DIJOYSTATE2 newState; HRESULT hr; // Poll the device to read the current state hr = data.joystick->Poll(); - if(FAILED(hr)) { + if (FAILED(hr)) + { // DInput is telling us that the input stream has been interrupted. We aren't tracking any state between polls, so // we don't have any special reset that needs to be done. We just re-acquire and try again. hr = data.joystick->Acquire(); - while(hr == DIERR_INPUTLOST) { + while (hr == DIERR_INPUTLOST) + { hr = data.joystick->Acquire(); } // hr may be DIERR_OTHERAPPHASPRIO or other errors. This may occur when the app is minimized or in the process of // switching, so just try again later - if(FAILED(hr)) { + if (FAILED(hr)) + { data.stateValid = false; _requestUpdate = true; return; @@ -407,7 +476,8 @@ void DirectInputManager::UpdateInputState(DirectInputData &data) } // Get the input's device state - if(FAILED(hr = data.joystick->GetDeviceState(sizeof(DIJOYSTATE2), &newState))) { + if (FAILED(hr = data.joystick->GetDeviceState(sizeof(DIJOYSTATE2), &newState))) + { MessageManager::Log("[DInput] Failed to get device state: " + std::to_string(hr)); data.stateValid = false; _requestUpdate = true; @@ -428,7 +498,8 @@ DirectInputManager::DirectInputManager(shared_ptr console, HWND hWnd) DirectInputManager::~DirectInputManager() { - for(DirectInputData &data: _joysticks) { + for (DirectInputData& data : _joysticks) + { data.joystick->Unacquire(); data.joystick->Release(); } @@ -439,7 +510,8 @@ DirectInputManager::~DirectInputManager() _processedGuids.clear(); _xinputDeviceGuids.clear(); - if(_directInput) { + if (_directInput) + { _directInput->Release(); _directInput = nullptr; } diff --git a/Windows/DirectXTK/Audio.h b/Windows/DirectXTK/Audio.h index a05bdd7..a6fd63c 100644 --- a/Windows/DirectXTK/Audio.h +++ b/Windows/DirectXTK/Audio.h @@ -93,626 +93,656 @@ namespace DirectX { - #if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) +#if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) #define XM_CALLCONV __fastcall typedef const XMVECTOR& HXMVECTOR; typedef const XMMATRIX& FXMMATRIX; - #endif +#endif - class SoundEffectInstance; + class SoundEffectInstance; - //---------------------------------------------------------------------------------- - struct AudioStatistics - { - size_t playingOneShots; // Number of one-shot sounds currently playing - size_t playingInstances; // Number of sound effect instances currently playing - size_t allocatedInstances; // Number of SoundEffectInstance allocated - size_t allocatedVoices; // Number of XAudio2 voices allocated (standard, 3D, one-shots, and idle one-shots) - size_t allocatedVoices3d; // Number of XAudio2 voices allocated for 3D - size_t allocatedVoicesOneShot; // Number of XAudio2 voices allocated for one-shot sounds - size_t allocatedVoicesIdle; // Number of XAudio2 voices allocated for one-shot sounds but not currently in use - size_t audioBytes; // Total wave data (in bytes) in SoundEffects and in-memory WaveBanks + //---------------------------------------------------------------------------------- + struct AudioStatistics + { + size_t playingOneShots; // Number of one-shot sounds currently playing + size_t playingInstances; // Number of sound effect instances currently playing + size_t allocatedInstances; // Number of SoundEffectInstance allocated + size_t allocatedVoices; // Number of XAudio2 voices allocated (standard, 3D, one-shots, and idle one-shots) + size_t allocatedVoices3d; // Number of XAudio2 voices allocated for 3D + size_t allocatedVoicesOneShot; // Number of XAudio2 voices allocated for one-shot sounds + size_t allocatedVoicesIdle; // Number of XAudio2 voices allocated for one-shot sounds but not currently in use + size_t audioBytes; // Total wave data (in bytes) in SoundEffects and in-memory WaveBanks #if defined(_XBOX_ONE) && defined(_TITLE) size_t xmaAudioBytes; // Total wave data (in bytes) in SoundEffects and in-memory WaveBanks allocated with ApuAlloc #endif - }; + }; - //---------------------------------------------------------------------------------- - class IVoiceNotify - { - public: - virtual void __cdecl OnBufferEnd() = 0; - // Notfication that a voice buffer has finished - // Note this is called from XAudio2's worker thread, so it should perform very minimal and thread-safe operations + //---------------------------------------------------------------------------------- + class IVoiceNotify + { + public: + virtual void __cdecl OnBufferEnd() = 0; + // Notfication that a voice buffer has finished + // Note this is called from XAudio2's worker thread, so it should perform very minimal and thread-safe operations - virtual void __cdecl OnCriticalError() = 0; - // Notification that the audio engine encountered a critical error + virtual void __cdecl OnCriticalError() = 0; + // Notification that the audio engine encountered a critical error - virtual void __cdecl OnReset() = 0; - // Notification of an audio engine reset + virtual void __cdecl OnReset() = 0; + // Notification of an audio engine reset - virtual void __cdecl OnUpdate() = 0; - // Notification of an audio engine per-frame update (opt-in) + virtual void __cdecl OnUpdate() = 0; + // Notification of an audio engine per-frame update (opt-in) - virtual void __cdecl OnDestroyEngine() = 0; - // Notification that the audio engine is being destroyed + virtual void __cdecl OnDestroyEngine() = 0; + // Notification that the audio engine is being destroyed - virtual void __cdecl OnTrim() = 0; - // Notification of a request to trim the voice pool + virtual void __cdecl OnTrim() = 0; + // Notification of a request to trim the voice pool - virtual void __cdecl GatherStatistics( AudioStatistics& stats ) const = 0; - // Contribute to statistics request - }; + virtual void __cdecl GatherStatistics(AudioStatistics& stats) const = 0; + // Contribute to statistics request + }; - //---------------------------------------------------------------------------------- - enum AUDIO_ENGINE_FLAGS - { - AudioEngine_Default = 0x0, + //---------------------------------------------------------------------------------- + enum AUDIO_ENGINE_FLAGS + { + AudioEngine_Default = 0x0, - AudioEngine_EnvironmentalReverb = 0x1, - AudioEngine_ReverbUseFilters = 0x2, - AudioEngine_UseMasteringLimiter = 0x4, + AudioEngine_EnvironmentalReverb = 0x1, + AudioEngine_ReverbUseFilters = 0x2, + AudioEngine_UseMasteringLimiter = 0x4, - AudioEngine_Debug = 0x10000, - AudioEngine_ThrowOnNoAudioHW = 0x20000, - AudioEngine_DisableVoiceReuse = 0x40000, - }; + AudioEngine_Debug = 0x10000, + AudioEngine_ThrowOnNoAudioHW = 0x20000, + AudioEngine_DisableVoiceReuse = 0x40000, + }; - inline AUDIO_ENGINE_FLAGS operator|(AUDIO_ENGINE_FLAGS a, AUDIO_ENGINE_FLAGS b) { return static_cast( static_cast(a) | static_cast(b) ); } + inline AUDIO_ENGINE_FLAGS operator|(AUDIO_ENGINE_FLAGS a, AUDIO_ENGINE_FLAGS b) + { + return static_cast(static_cast(a) | static_cast(b)); + } - enum SOUND_EFFECT_INSTANCE_FLAGS - { - SoundEffectInstance_Default = 0x0, + enum SOUND_EFFECT_INSTANCE_FLAGS + { + SoundEffectInstance_Default = 0x0, - SoundEffectInstance_Use3D = 0x1, - SoundEffectInstance_ReverbUseFilters = 0x2, - SoundEffectInstance_NoSetPitch = 0x4, + SoundEffectInstance_Use3D = 0x1, + SoundEffectInstance_ReverbUseFilters = 0x2, + SoundEffectInstance_NoSetPitch = 0x4, - SoundEffectInstance_UseRedirectLFE = 0x10000, - }; + SoundEffectInstance_UseRedirectLFE = 0x10000, + }; - inline SOUND_EFFECT_INSTANCE_FLAGS operator|(SOUND_EFFECT_INSTANCE_FLAGS a, SOUND_EFFECT_INSTANCE_FLAGS b) { return static_cast( static_cast(a) | static_cast(b) ); } + inline SOUND_EFFECT_INSTANCE_FLAGS operator|(SOUND_EFFECT_INSTANCE_FLAGS a, SOUND_EFFECT_INSTANCE_FLAGS b) + { + return static_cast(static_cast(a) | static_cast(b)); + } - enum AUDIO_ENGINE_REVERB - { - Reverb_Off, - Reverb_Default, - Reverb_Generic, - Reverb_Forest, - Reverb_PaddedCell, - Reverb_Room, - Reverb_Bathroom, - Reverb_LivingRoom, - Reverb_StoneRoom, - Reverb_Auditorium, - Reverb_ConcertHall, - Reverb_Cave, - Reverb_Arena, - Reverb_Hangar, - Reverb_CarpetedHallway, - Reverb_Hallway, - Reverb_StoneCorridor, - Reverb_Alley, - Reverb_City, - Reverb_Mountains, - Reverb_Quarry, - Reverb_Plain, - Reverb_ParkingLot, - Reverb_SewerPipe, - Reverb_Underwater, - Reverb_SmallRoom, - Reverb_MediumRoom, - Reverb_LargeRoom, - Reverb_MediumHall, - Reverb_LargeHall, - Reverb_Plate, - Reverb_MAX - }; + enum AUDIO_ENGINE_REVERB + { + Reverb_Off, + Reverb_Default, + Reverb_Generic, + Reverb_Forest, + Reverb_PaddedCell, + Reverb_Room, + Reverb_Bathroom, + Reverb_LivingRoom, + Reverb_StoneRoom, + Reverb_Auditorium, + Reverb_ConcertHall, + Reverb_Cave, + Reverb_Arena, + Reverb_Hangar, + Reverb_CarpetedHallway, + Reverb_Hallway, + Reverb_StoneCorridor, + Reverb_Alley, + Reverb_City, + Reverb_Mountains, + Reverb_Quarry, + Reverb_Plain, + Reverb_ParkingLot, + Reverb_SewerPipe, + Reverb_Underwater, + Reverb_SmallRoom, + Reverb_MediumRoom, + Reverb_LargeRoom, + Reverb_MediumHall, + Reverb_LargeHall, + Reverb_Plate, + Reverb_MAX + }; - enum SoundState - { - STOPPED = 0, - PLAYING, - PAUSED - }; + enum SoundState + { + STOPPED = 0, + PLAYING, + PAUSED + }; - //---------------------------------------------------------------------------------- - class AudioEngine - { - public: - explicit AudioEngine( AUDIO_ENGINE_FLAGS flags = AudioEngine_Default, _In_opt_ const WAVEFORMATEX* wfx = nullptr, _In_opt_z_ const wchar_t* deviceId = nullptr, - AUDIO_STREAM_CATEGORY category = AudioCategory_GameEffects ); + //---------------------------------------------------------------------------------- + class AudioEngine + { + public: + explicit AudioEngine(AUDIO_ENGINE_FLAGS flags = AudioEngine_Default, _In_opt_ const WAVEFORMATEX* wfx = nullptr, + _In_opt_z_ const wchar_t* deviceId = nullptr, + AUDIO_STREAM_CATEGORY category = AudioCategory_GameEffects); - AudioEngine(AudioEngine&& moveFrom); - AudioEngine& operator= (AudioEngine&& moveFrom); - virtual ~AudioEngine(); + AudioEngine(AudioEngine&& moveFrom); + AudioEngine& operator=(AudioEngine&& moveFrom); + virtual ~AudioEngine(); - bool __cdecl Update(); - // Performs per-frame processing for the audio engine, returns false if in 'silent mode' + bool __cdecl Update(); + // Performs per-frame processing for the audio engine, returns false if in 'silent mode' - bool __cdecl Reset( _In_opt_ const WAVEFORMATEX* wfx = nullptr, _In_opt_z_ const wchar_t* deviceId = nullptr ); - // Reset audio engine from critical error/silent mode using a new device; can also 'migrate' the graph - // Returns true if succesfully reset, false if in 'silent mode' due to no default device - // Note: One shots are lost, all SoundEffectInstances are in the STOPPED state after successful reset + bool __cdecl Reset(_In_opt_ const WAVEFORMATEX* wfx = nullptr, _In_opt_z_ const wchar_t* deviceId = nullptr); + // Reset audio engine from critical error/silent mode using a new device; can also 'migrate' the graph + // Returns true if succesfully reset, false if in 'silent mode' due to no default device + // Note: One shots are lost, all SoundEffectInstances are in the STOPPED state after successful reset - void __cdecl Suspend(); - void __cdecl Resume(); - // Suspend/resumes audio processing (i.e. global pause/resume) + void __cdecl Suspend(); + void __cdecl Resume(); + // Suspend/resumes audio processing (i.e. global pause/resume) - float __cdecl GetMasterVolume() const; - void __cdecl SetMasterVolume( float volume ); - // Master volume property for all sounds + float __cdecl GetMasterVolume() const; + void __cdecl SetMasterVolume(float volume); + // Master volume property for all sounds - void __cdecl SetReverb( AUDIO_ENGINE_REVERB reverb ); - void __cdecl SetReverb( _In_opt_ const XAUDIO2FX_REVERB_PARAMETERS* native ); - // Sets environmental reverb for 3D positional audio (if active) + void __cdecl SetReverb(AUDIO_ENGINE_REVERB reverb); + void __cdecl SetReverb(_In_opt_ const XAUDIO2FX_REVERB_PARAMETERS* native); + // Sets environmental reverb for 3D positional audio (if active) - void __cdecl SetMasteringLimit( int release, int loudness ); - // Sets the mastering volume limiter properties (if active) + void __cdecl SetMasteringLimit(int release, int loudness); + // Sets the mastering volume limiter properties (if active) - AudioStatistics __cdecl GetStatistics() const; - // Gathers audio engine statistics + AudioStatistics __cdecl GetStatistics() const; + // Gathers audio engine statistics - WAVEFORMATEXTENSIBLE __cdecl GetOutputFormat() const; - // Returns the format consumed by the mastering voice (which is the same as the device output if defaults are used) + WAVEFORMATEXTENSIBLE __cdecl GetOutputFormat() const; + // Returns the format consumed by the mastering voice (which is the same as the device output if defaults are used) - uint32_t __cdecl GetChannelMask() const; - // Returns the output channel mask + uint32_t __cdecl GetChannelMask() const; + // Returns the output channel mask - int __cdecl GetOutputChannels() const; - // Returns the number of output channels + int __cdecl GetOutputChannels() const; + // Returns the number of output channels - bool __cdecl IsAudioDevicePresent() const; - // Returns true if the audio graph is operating normally, false if in 'silent mode' + bool __cdecl IsAudioDevicePresent() const; + // Returns true if the audio graph is operating normally, false if in 'silent mode' - bool __cdecl IsCriticalError() const; - // Returns true if the audio graph is halted due to a critical error (which also places the engine into 'silent mode') + bool __cdecl IsCriticalError() const; + // Returns true if the audio graph is halted due to a critical error (which also places the engine into 'silent mode') - // Voice pool management. - void __cdecl SetDefaultSampleRate( int sampleRate ); - // Sample rate for voices in the reuse pool (defaults to 44100) + // Voice pool management. + void __cdecl SetDefaultSampleRate(int sampleRate); + // Sample rate for voices in the reuse pool (defaults to 44100) - void __cdecl SetMaxVoicePool( size_t maxOneShots, size_t maxInstances ); - // Maximum number of voices to allocate for one-shots and instances - // Note: one-shots over this limit are ignored; too many instance voices throws an exception + void __cdecl SetMaxVoicePool(size_t maxOneShots, size_t maxInstances); + // Maximum number of voices to allocate for one-shots and instances + // Note: one-shots over this limit are ignored; too many instance voices throws an exception - void __cdecl TrimVoicePool(); - // Releases any currently unused voices + void __cdecl TrimVoicePool(); + // Releases any currently unused voices - // Internal-use functions - void __cdecl AllocateVoice( _In_ const WAVEFORMATEX* wfx, SOUND_EFFECT_INSTANCE_FLAGS flags, bool oneshot, _Outptr_result_maybenull_ IXAudio2SourceVoice** voice ); + // Internal-use functions + void __cdecl AllocateVoice(_In_ const WAVEFORMATEX* wfx, SOUND_EFFECT_INSTANCE_FLAGS flags, bool oneshot, + _Outptr_result_maybenull_ IXAudio2SourceVoice** voice); - void __cdecl DestroyVoice( _In_ IXAudio2SourceVoice* voice ); - // Should only be called for instance voices, not one-shots + void __cdecl DestroyVoice(_In_ IXAudio2SourceVoice* voice); + // Should only be called for instance voices, not one-shots - void __cdecl RegisterNotify( _In_ IVoiceNotify* notify, bool usesUpdate ); - void __cdecl UnregisterNotify( _In_ IVoiceNotify* notify, bool usesOneShots, bool usesUpdate ); + void __cdecl RegisterNotify(_In_ IVoiceNotify* notify, bool usesUpdate); + void __cdecl UnregisterNotify(_In_ IVoiceNotify* notify, bool usesOneShots, bool usesUpdate); - // XAudio2 interface access - IXAudio2* __cdecl GetInterface() const; - IXAudio2MasteringVoice* __cdecl GetMasterVoice() const; - IXAudio2SubmixVoice* __cdecl GetReverbVoice() const; - X3DAUDIO_HANDLE& __cdecl Get3DHandle() const; + // XAudio2 interface access + IXAudio2* __cdecl GetInterface() const; + IXAudio2MasteringVoice* __cdecl GetMasterVoice() const; + IXAudio2SubmixVoice* __cdecl GetReverbVoice() const; + X3DAUDIO_HANDLE& __cdecl Get3DHandle() const; - // Static functions - struct RendererDetail - { - std::wstring deviceId; - std::wstring description; - }; + // Static functions + struct RendererDetail + { + std::wstring deviceId; + std::wstring description; + }; - static std::vector __cdecl GetRendererDetails(); - // Returns a list of valid audio endpoint devices + static std::vector __cdecl GetRendererDetails(); + // Returns a list of valid audio endpoint devices - private: - // Private implementation. - class Impl; - std::unique_ptr pImpl; + private: + // Private implementation. + class Impl; + std::unique_ptr pImpl; - // Prevent copying. - AudioEngine(AudioEngine const&) DIRECTX_CTOR_DELETE - AudioEngine& operator= (AudioEngine const&) DIRECTX_CTOR_DELETE - }; + // Prevent copying. + AudioEngine(AudioEngine const&) DIRECTX_CTOR_DELETE + AudioEngine& operator=(AudioEngine const&) DIRECTX_CTOR_DELETE + }; - //---------------------------------------------------------------------------------- - class WaveBank - { - public: - WaveBank( _In_ AudioEngine* engine, _In_z_ const wchar_t* wbFileName ); + //---------------------------------------------------------------------------------- + class WaveBank + { + public: + WaveBank(_In_ AudioEngine* engine, _In_z_ const wchar_t* wbFileName); - WaveBank(WaveBank&& moveFrom); - WaveBank& operator= (WaveBank&& moveFrom); - virtual ~WaveBank(); + WaveBank(WaveBank&& moveFrom); + WaveBank& operator=(WaveBank&& moveFrom); + virtual ~WaveBank(); - void __cdecl Play( int index ); - void __cdecl Play( int index, float volume, float pitch, float pan ); + void __cdecl Play(int index); + void __cdecl Play(int index, float volume, float pitch, float pan); - void __cdecl Play( _In_z_ const char* name ); - void __cdecl Play( _In_z_ const char* name, float volume, float pitch, float pan ); + void __cdecl Play(_In_z_ const char* name); + void __cdecl Play(_In_z_ const char* name, float volume, float pitch, float pan); - std::unique_ptr __cdecl CreateInstance( int index, SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default ); - std::unique_ptr __cdecl CreateInstance( _In_z_ const char* name, SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default ); + std::unique_ptr __cdecl CreateInstance( + int index, SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default); + std::unique_ptr __cdecl CreateInstance( + _In_z_ const char* name, SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default); - bool __cdecl IsPrepared() const; - bool __cdecl IsInUse() const; - bool __cdecl IsStreamingBank() const; + bool __cdecl IsPrepared() const; + bool __cdecl IsInUse() const; + bool __cdecl IsStreamingBank() const; - size_t __cdecl GetSampleSizeInBytes( int index ) const; - // Returns size of wave audio data + size_t __cdecl GetSampleSizeInBytes(int index) const; + // Returns size of wave audio data - size_t __cdecl GetSampleDuration( int index ) const; - // Returns the duration in samples + size_t __cdecl GetSampleDuration(int index) const; + // Returns the duration in samples - size_t __cdecl GetSampleDurationMS( int index ) const; - // Returns the duration in milliseconds + size_t __cdecl GetSampleDurationMS(int index) const; + // Returns the duration in milliseconds - const WAVEFORMATEX* __cdecl GetFormat( int index, _Out_writes_bytes_(maxsize) WAVEFORMATEX* wfx, size_t maxsize ) const; + const WAVEFORMATEX* __cdecl GetFormat(int index, _Out_writes_bytes_(maxsize) WAVEFORMATEX* wfx, + size_t maxsize) const; - int __cdecl Find( _In_z_ const char* name ) const; + int __cdecl Find(_In_z_ const char* name) const; #if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/ ) - bool __cdecl FillSubmitBuffer( int index, _Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer ) const; + bool __cdecl FillSubmitBuffer(int index, _Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer) const; #else void __cdecl FillSubmitBuffer( int index, _Out_ XAUDIO2_BUFFER& buffer ) const; #endif - private: - // Private implementation. - class Impl; + private: + // Private implementation. + class Impl; - std::unique_ptr pImpl; + std::unique_ptr pImpl; - // Prevent copying. - WaveBank(WaveBank const&) DIRECTX_CTOR_DELETE - WaveBank& operator= (WaveBank const&) DIRECTX_CTOR_DELETE + // Prevent copying. + WaveBank(WaveBank const&) DIRECTX_CTOR_DELETE + WaveBank& operator=(WaveBank const&) DIRECTX_CTOR_DELETE - // Private interface - void __cdecl UnregisterInstance( _In_ SoundEffectInstance* instance ); + // Private interface + void __cdecl UnregisterInstance(_In_ SoundEffectInstance* instance); - friend class SoundEffectInstance; - }; + friend class SoundEffectInstance; + }; - //---------------------------------------------------------------------------------- - class SoundEffect - { - public: - SoundEffect( _In_ AudioEngine* engine, _In_z_ const wchar_t* waveFileName ); + //---------------------------------------------------------------------------------- + class SoundEffect + { + public: + SoundEffect(_In_ AudioEngine* engine, _In_z_ const wchar_t* waveFileName); - SoundEffect( _In_ AudioEngine* engine, _Inout_ std::unique_ptr& wavData, - _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes ); + SoundEffect(_In_ AudioEngine* engine, _Inout_ std::unique_ptr& wavData, + _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, + size_t audioBytes); - SoundEffect( _In_ AudioEngine* engine, _Inout_ std::unique_ptr& wavData, - _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes, - uint32_t loopStart, uint32_t loopLength ); + SoundEffect(_In_ AudioEngine* engine, _Inout_ std::unique_ptr& wavData, + _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, + size_t audioBytes, + uint32_t loopStart, uint32_t loopLength); #if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/) - SoundEffect( _In_ AudioEngine* engine, _Inout_ std::unique_ptr& wavData, - _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes, - _In_reads_(seekCount) const uint32_t* seekTable, size_t seekCount ); + SoundEffect(_In_ AudioEngine* engine, _Inout_ std::unique_ptr& wavData, + _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, + size_t audioBytes, + _In_reads_(seekCount) const uint32_t* seekTable, size_t seekCount); #endif - SoundEffect(SoundEffect&& moveFrom); - SoundEffect& operator= (SoundEffect&& moveFrom); - virtual ~SoundEffect(); + SoundEffect(SoundEffect&& moveFrom); + SoundEffect& operator=(SoundEffect&& moveFrom); + virtual ~SoundEffect(); - void __cdecl Play(); - void __cdecl Play(float volume, float pitch, float pan); + void __cdecl Play(); + void __cdecl Play(float volume, float pitch, float pan); - std::unique_ptr __cdecl CreateInstance( SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default ); + std::unique_ptr __cdecl CreateInstance( + SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default); - bool __cdecl IsInUse() const; + bool __cdecl IsInUse() const; - size_t __cdecl GetSampleSizeInBytes() const; - // Returns size of wave audio data + size_t __cdecl GetSampleSizeInBytes() const; + // Returns size of wave audio data - size_t __cdecl GetSampleDuration() const; - // Returns the duration in samples + size_t __cdecl GetSampleDuration() const; + // Returns the duration in samples - size_t __cdecl GetSampleDurationMS() const; - // Returns the duration in milliseconds + size_t __cdecl GetSampleDurationMS() const; + // Returns the duration in milliseconds - const WAVEFORMATEX* __cdecl GetFormat() const; + const WAVEFORMATEX* __cdecl GetFormat() const; #if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/) - bool __cdecl FillSubmitBuffer( _Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer ) const; + bool __cdecl FillSubmitBuffer(_Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer) const; #else void __cdecl FillSubmitBuffer( _Out_ XAUDIO2_BUFFER& buffer ) const; #endif - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Prevent copying. - SoundEffect(SoundEffect const&) DIRECTX_CTOR_DELETE - SoundEffect& operator= (SoundEffect const&) DIRECTX_CTOR_DELETE - - // Private interface - void __cdecl UnregisterInstance( _In_ SoundEffectInstance* instance ); - - friend class SoundEffectInstance; - }; - - - //---------------------------------------------------------------------------------- - struct AudioListener : public X3DAUDIO_LISTENER - { - AudioListener() - { - memset( this, 0, sizeof(X3DAUDIO_LISTENER) ); - - OrientFront.z = -1.f; - - OrientTop.y = 1.f; - } - - void XM_CALLCONV SetPosition( FXMVECTOR v ) - { - XMStoreFloat3( reinterpret_cast( &Position ), v ); - } - void __cdecl SetPosition( const XMFLOAT3& pos ) - { - Position.x = pos.x; - Position.y = pos.y; - Position.z = pos.z; - } - - void XM_CALLCONV SetVelocity( FXMVECTOR v ) - { - XMStoreFloat3( reinterpret_cast( &Velocity ), v ); - } - void __cdecl SetVelocity( const XMFLOAT3& vel ) - { - Velocity.x = vel.x; - Velocity.y = vel.y; - Velocity.z = vel.z; - } - - void XM_CALLCONV SetOrientation( FXMVECTOR forward, FXMVECTOR up ) - { - XMStoreFloat3( reinterpret_cast( &OrientFront ), forward ); - XMStoreFloat3( reinterpret_cast( &OrientTop ), up ); - } - void __cdecl SetOrientation( const XMFLOAT3& forward, const XMFLOAT3& up ) - { - OrientFront.x = forward.x; OrientTop.x = up.x; - OrientFront.y = forward.y; OrientTop.y = up.y; - OrientFront.z = forward.z; OrientTop.z = up.z; - } - - void XM_CALLCONV SetOrientationFromQuaternion( FXMVECTOR quat ) - { - XMVECTOR forward = XMVector3Rotate( g_XMIdentityR2, quat ); - XMStoreFloat3( reinterpret_cast( &OrientFront ), forward ); - - XMVECTOR up = XMVector3Rotate( g_XMIdentityR1, quat ); - XMStoreFloat3( reinterpret_cast( &OrientTop ), up ); - } - - void XM_CALLCONV Update( FXMVECTOR newPos, XMVECTOR upDir, float dt ) - // Updates velocity and orientation by tracking changes in position over time... - { - if ( dt > 0.f ) - { - XMVECTOR lastPos = XMLoadFloat3( reinterpret_cast( &Position ) ); - - XMVECTOR vDelta = ( newPos - lastPos ); - XMVECTOR v = vDelta / dt; - XMStoreFloat3( reinterpret_cast( &Velocity ), v ); - - vDelta = XMVector3Normalize( vDelta ); - XMStoreFloat3( reinterpret_cast( &OrientFront ), vDelta ); - - v = XMVector3Cross( upDir, vDelta ); - v = XMVector3Normalize( v ); - - v = XMVector3Cross( vDelta, v ); - v = XMVector3Normalize( v ); - XMStoreFloat3( reinterpret_cast( &OrientTop ), v ); - - XMStoreFloat3( reinterpret_cast( &Position ), newPos ); - } - } - }; - - - //---------------------------------------------------------------------------------- - struct AudioEmitter : public X3DAUDIO_EMITTER - { - float EmitterAzimuths[XAUDIO2_MAX_AUDIO_CHANNELS]; - - AudioEmitter() - { - memset( this, 0, sizeof(X3DAUDIO_EMITTER) ); - memset( EmitterAzimuths, 0, sizeof(EmitterAzimuths) ); - - OrientFront.z = -1.f; - - OrientTop.y = - ChannelRadius = - CurveDistanceScaler = - DopplerScaler = 1.f; - - ChannelCount = 1; - pChannelAzimuths = EmitterAzimuths; - - InnerRadiusAngle = X3DAUDIO_PI / 4.0f; - } - - void XM_CALLCONV SetPosition( FXMVECTOR v ) - { - XMStoreFloat3( reinterpret_cast( &Position ), v ); - } - void __cdecl SetPosition( const XMFLOAT3& pos ) - { - Position.x = pos.x; - Position.y = pos.y; - Position.z = pos.z; - } - - void XM_CALLCONV SetVelocity( FXMVECTOR v ) - { - XMStoreFloat3( reinterpret_cast( &Velocity ), v ); - } - void __cdecl SetVelocity( const XMFLOAT3& vel ) - { - Velocity.x = vel.x; - Velocity.y = vel.y; - Velocity.z = vel.z; - } - - void XM_CALLCONV SetOrientation( FXMVECTOR forward, FXMVECTOR up ) - { - XMStoreFloat3( reinterpret_cast( &OrientFront ), forward ); - XMStoreFloat3( reinterpret_cast( &OrientTop ), up ); - } - void __cdecl SetOrientation( const XMFLOAT3& forward, const XMFLOAT3& up ) - { - OrientFront.x = forward.x; OrientTop.x = up.x; - OrientFront.y = forward.y; OrientTop.y = up.y; - OrientFront.z = forward.z; OrientTop.z = up.z; - } - - void XM_CALLCONV SetOrientationFromQuaternion( FXMVECTOR quat ) - { - XMVECTOR forward = XMVector3Rotate( g_XMIdentityR2, quat ); - XMStoreFloat3( reinterpret_cast( &OrientFront ), forward ); - - XMVECTOR up = XMVector3Rotate( g_XMIdentityR1, quat ); - XMStoreFloat3( reinterpret_cast( &OrientTop ), up ); - } - - void XM_CALLCONV Update( FXMVECTOR newPos, XMVECTOR upDir, float dt ) - // Updates velocity and orientation by tracking changes in position over time... - { - if ( dt > 0.f ) - { - XMVECTOR lastPos = XMLoadFloat3( reinterpret_cast( &Position ) ); - - XMVECTOR vDelta = ( newPos - lastPos ); - XMVECTOR v = vDelta / dt; - XMStoreFloat3( reinterpret_cast( &Velocity ), v ); - - vDelta = XMVector3Normalize( vDelta ); - XMStoreFloat3( reinterpret_cast( &OrientFront ), vDelta ); - - v = XMVector3Cross( upDir, vDelta ); - v = XMVector3Normalize( v ); - - v = XMVector3Cross( vDelta, v ); - v = XMVector3Normalize( v ); - XMStoreFloat3( reinterpret_cast( &OrientTop ), v ); - - XMStoreFloat3( reinterpret_cast( &Position ), newPos ); - } - } - }; - - - //---------------------------------------------------------------------------------- - class SoundEffectInstance - { - public: - SoundEffectInstance(SoundEffectInstance&& moveFrom); - SoundEffectInstance& operator= (SoundEffectInstance&& moveFrom); - virtual ~SoundEffectInstance(); - - void __cdecl Play( bool loop = false ); - void __cdecl Stop( bool immediate = true ); - void __cdecl Pause(); - void __cdecl Resume(); - - void __cdecl SetVolume( float volume ); - void __cdecl SetPitch( float pitch ); - void __cdecl SetPan( float pan ); - - void __cdecl Apply3D( const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true ); - - bool __cdecl IsLooped() const; - - SoundState __cdecl GetState(); - - // Notifications. - void __cdecl OnDestroyParent(); - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Private constructors - SoundEffectInstance( _In_ AudioEngine* engine, _In_ SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags ); - SoundEffectInstance( _In_ AudioEngine* engine, _In_ WaveBank* effect, int index, SOUND_EFFECT_INSTANCE_FLAGS flags ); - - friend std::unique_ptr __cdecl SoundEffect::CreateInstance( SOUND_EFFECT_INSTANCE_FLAGS ); - friend std::unique_ptr __cdecl WaveBank::CreateInstance( int, SOUND_EFFECT_INSTANCE_FLAGS ); - - // Prevent copying. - SoundEffectInstance(SoundEffectInstance const&) DIRECTX_CTOR_DELETE - SoundEffectInstance& operator= (SoundEffectInstance const&) DIRECTX_CTOR_DELETE - }; - - - //---------------------------------------------------------------------------------- - class DynamicSoundEffectInstance - { - public: - DynamicSoundEffectInstance( _In_ AudioEngine* engine, - _In_opt_ std::function bufferNeeded, - int sampleRate, int channels, int sampleBits = 16, - SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default ); - DynamicSoundEffectInstance(DynamicSoundEffectInstance&& moveFrom); - DynamicSoundEffectInstance& operator= (DynamicSoundEffectInstance&& moveFrom); - virtual ~DynamicSoundEffectInstance(); + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Prevent copying. + SoundEffect(SoundEffect const&) DIRECTX_CTOR_DELETE + SoundEffect& operator=(SoundEffect const&) DIRECTX_CTOR_DELETE + + // Private interface + void __cdecl UnregisterInstance(_In_ SoundEffectInstance* instance); + + friend class SoundEffectInstance; + }; + + + //---------------------------------------------------------------------------------- + struct AudioListener : public X3DAUDIO_LISTENER + { + AudioListener() + { + memset(this, 0, sizeof(X3DAUDIO_LISTENER)); + + OrientFront.z = -1.f; + + OrientTop.y = 1.f; + } + + void XM_CALLCONV SetPosition(FXMVECTOR v) + { + XMStoreFloat3(reinterpret_cast(&Position), v); + } + + void __cdecl SetPosition(const XMFLOAT3& pos) + { + Position.x = pos.x; + Position.y = pos.y; + Position.z = pos.z; + } + + void XM_CALLCONV SetVelocity(FXMVECTOR v) + { + XMStoreFloat3(reinterpret_cast(&Velocity), v); + } + + void __cdecl SetVelocity(const XMFLOAT3& vel) + { + Velocity.x = vel.x; + Velocity.y = vel.y; + Velocity.z = vel.z; + } + + void XM_CALLCONV SetOrientation(FXMVECTOR forward, FXMVECTOR up) + { + XMStoreFloat3(reinterpret_cast(&OrientFront), forward); + XMStoreFloat3(reinterpret_cast(&OrientTop), up); + } + + void __cdecl SetOrientation(const XMFLOAT3& forward, const XMFLOAT3& up) + { + OrientFront.x = forward.x; + OrientTop.x = up.x; + OrientFront.y = forward.y; + OrientTop.y = up.y; + OrientFront.z = forward.z; + OrientTop.z = up.z; + } + + void XM_CALLCONV SetOrientationFromQuaternion(FXMVECTOR quat) + { + XMVECTOR forward = XMVector3Rotate(g_XMIdentityR2, quat); + XMStoreFloat3(reinterpret_cast(&OrientFront), forward); + + XMVECTOR up = XMVector3Rotate(g_XMIdentityR1, quat); + XMStoreFloat3(reinterpret_cast(&OrientTop), up); + } + + void XM_CALLCONV Update(FXMVECTOR newPos, XMVECTOR upDir, float dt) + // Updates velocity and orientation by tracking changes in position over time... + { + if (dt > 0.f) + { + XMVECTOR lastPos = XMLoadFloat3(reinterpret_cast(&Position)); + + XMVECTOR vDelta = (newPos - lastPos); + XMVECTOR v = vDelta / dt; + XMStoreFloat3(reinterpret_cast(&Velocity), v); + + vDelta = XMVector3Normalize(vDelta); + XMStoreFloat3(reinterpret_cast(&OrientFront), vDelta); + + v = XMVector3Cross(upDir, vDelta); + v = XMVector3Normalize(v); + + v = XMVector3Cross(vDelta, v); + v = XMVector3Normalize(v); + XMStoreFloat3(reinterpret_cast(&OrientTop), v); + + XMStoreFloat3(reinterpret_cast(&Position), newPos); + } + } + }; + + + //---------------------------------------------------------------------------------- + struct AudioEmitter : public X3DAUDIO_EMITTER + { + float EmitterAzimuths[XAUDIO2_MAX_AUDIO_CHANNELS]; + + AudioEmitter() + { + memset(this, 0, sizeof(X3DAUDIO_EMITTER)); + memset(EmitterAzimuths, 0, sizeof(EmitterAzimuths)); + + OrientFront.z = -1.f; + + OrientTop.y = + ChannelRadius = + CurveDistanceScaler = + DopplerScaler = 1.f; + + ChannelCount = 1; + pChannelAzimuths = EmitterAzimuths; + + InnerRadiusAngle = X3DAUDIO_PI / 4.0f; + } + + void XM_CALLCONV SetPosition(FXMVECTOR v) + { + XMStoreFloat3(reinterpret_cast(&Position), v); + } + + void __cdecl SetPosition(const XMFLOAT3& pos) + { + Position.x = pos.x; + Position.y = pos.y; + Position.z = pos.z; + } + + void XM_CALLCONV SetVelocity(FXMVECTOR v) + { + XMStoreFloat3(reinterpret_cast(&Velocity), v); + } + + void __cdecl SetVelocity(const XMFLOAT3& vel) + { + Velocity.x = vel.x; + Velocity.y = vel.y; + Velocity.z = vel.z; + } + + void XM_CALLCONV SetOrientation(FXMVECTOR forward, FXMVECTOR up) + { + XMStoreFloat3(reinterpret_cast(&OrientFront), forward); + XMStoreFloat3(reinterpret_cast(&OrientTop), up); + } + + void __cdecl SetOrientation(const XMFLOAT3& forward, const XMFLOAT3& up) + { + OrientFront.x = forward.x; + OrientTop.x = up.x; + OrientFront.y = forward.y; + OrientTop.y = up.y; + OrientFront.z = forward.z; + OrientTop.z = up.z; + } + + void XM_CALLCONV SetOrientationFromQuaternion(FXMVECTOR quat) + { + XMVECTOR forward = XMVector3Rotate(g_XMIdentityR2, quat); + XMStoreFloat3(reinterpret_cast(&OrientFront), forward); + + XMVECTOR up = XMVector3Rotate(g_XMIdentityR1, quat); + XMStoreFloat3(reinterpret_cast(&OrientTop), up); + } + + void XM_CALLCONV Update(FXMVECTOR newPos, XMVECTOR upDir, float dt) + // Updates velocity and orientation by tracking changes in position over time... + { + if (dt > 0.f) + { + XMVECTOR lastPos = XMLoadFloat3(reinterpret_cast(&Position)); + + XMVECTOR vDelta = (newPos - lastPos); + XMVECTOR v = vDelta / dt; + XMStoreFloat3(reinterpret_cast(&Velocity), v); + + vDelta = XMVector3Normalize(vDelta); + XMStoreFloat3(reinterpret_cast(&OrientFront), vDelta); + + v = XMVector3Cross(upDir, vDelta); + v = XMVector3Normalize(v); + + v = XMVector3Cross(vDelta, v); + v = XMVector3Normalize(v); + XMStoreFloat3(reinterpret_cast(&OrientTop), v); + + XMStoreFloat3(reinterpret_cast(&Position), newPos); + } + } + }; + + + //---------------------------------------------------------------------------------- + class SoundEffectInstance + { + public: + SoundEffectInstance(SoundEffectInstance&& moveFrom); + SoundEffectInstance& operator=(SoundEffectInstance&& moveFrom); + virtual ~SoundEffectInstance(); + + void __cdecl Play(bool loop = false); + void __cdecl Stop(bool immediate = true); + void __cdecl Pause(); + void __cdecl Resume(); + + void __cdecl SetVolume(float volume); + void __cdecl SetPitch(float pitch); + void __cdecl SetPan(float pan); + + void __cdecl Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true); + + bool __cdecl IsLooped() const; + + SoundState __cdecl GetState(); + + // Notifications. + void __cdecl OnDestroyParent(); + + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Private constructors + SoundEffectInstance(_In_ AudioEngine* engine, _In_ SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags); + SoundEffectInstance(_In_ AudioEngine* engine, _In_ WaveBank* effect, int index, + SOUND_EFFECT_INSTANCE_FLAGS flags); + + friend std::unique_ptr __cdecl SoundEffect::CreateInstance(SOUND_EFFECT_INSTANCE_FLAGS); + friend std::unique_ptr __cdecl WaveBank::CreateInstance(int, SOUND_EFFECT_INSTANCE_FLAGS); + + // Prevent copying. + SoundEffectInstance(SoundEffectInstance const&) DIRECTX_CTOR_DELETE + SoundEffectInstance& operator=(SoundEffectInstance const&) DIRECTX_CTOR_DELETE + }; - void __cdecl Play(); - void __cdecl Stop( bool immediate = true ); - void __cdecl Pause(); - void __cdecl Resume(); - void __cdecl SetVolume( float volume ); - void __cdecl SetPitch( float pitch ); - void __cdecl SetPan( float pan ); + //---------------------------------------------------------------------------------- + class DynamicSoundEffectInstance + { + public: + DynamicSoundEffectInstance(_In_ AudioEngine* engine, + _In_opt_ std::function + bufferNeeded, + int sampleRate, int channels, int sampleBits = 16, + SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default); + DynamicSoundEffectInstance(DynamicSoundEffectInstance&& moveFrom); + DynamicSoundEffectInstance& operator=(DynamicSoundEffectInstance&& moveFrom); + virtual ~DynamicSoundEffectInstance(); - void __cdecl Apply3D( const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true ); + void __cdecl Play(); + void __cdecl Stop(bool immediate = true); + void __cdecl Pause(); + void __cdecl Resume(); - void __cdecl SubmitBuffer( _In_reads_bytes_(audioBytes) const uint8_t* pAudioData, size_t audioBytes ); - void __cdecl SubmitBuffer( _In_reads_bytes_(audioBytes) const uint8_t* pAudioData, uint32_t offset, size_t audioBytes ); + void __cdecl SetVolume(float volume); + void __cdecl SetPitch(float pitch); + void __cdecl SetPan(float pan); - SoundState __cdecl GetState(); + void __cdecl Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true); - size_t __cdecl GetSampleDuration( size_t bytes ) const; - // Returns duration in samples of a buffer of a given size + void __cdecl SubmitBuffer(_In_reads_bytes_(audioBytes) const uint8_t* pAudioData, size_t audioBytes); + void __cdecl SubmitBuffer(_In_reads_bytes_(audioBytes) const uint8_t* pAudioData, uint32_t offset, + size_t audioBytes); - size_t __cdecl GetSampleDurationMS( size_t bytes ) const; - // Returns duration in milliseconds of a buffer of a given size + SoundState __cdecl GetState(); - size_t __cdecl GetSampleSizeInBytes( uint64_t duration ) const; - // Returns size of a buffer for a duration given in milliseconds + size_t __cdecl GetSampleDuration(size_t bytes) const; + // Returns duration in samples of a buffer of a given size - int __cdecl GetPendingBufferCount() const; + size_t __cdecl GetSampleDurationMS(size_t bytes) const; + // Returns duration in milliseconds of a buffer of a given size - const WAVEFORMATEX* __cdecl GetFormat() const; + size_t __cdecl GetSampleSizeInBytes(uint64_t duration) const; + // Returns size of a buffer for a duration given in milliseconds - private: - // Private implementation. - class Impl; + int __cdecl GetPendingBufferCount() const; - std::unique_ptr pImpl; + const WAVEFORMATEX* __cdecl GetFormat() const; - // Prevent copying. - DynamicSoundEffectInstance(DynamicSoundEffectInstance const&) DIRECTX_CTOR_DELETE - DynamicSoundEffectInstance& operator= (DynamicSoundEffectInstance const&) DIRECTX_CTOR_DELETE - }; + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Prevent copying. + DynamicSoundEffectInstance(DynamicSoundEffectInstance const&) DIRECTX_CTOR_DELETE + DynamicSoundEffectInstance& operator=(DynamicSoundEffectInstance const&) DIRECTX_CTOR_DELETE + }; } -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) diff --git a/Windows/DirectXTK/CommonStates.h b/Windows/DirectXTK/CommonStates.h index cfeb436..77c85b9 100644 --- a/Windows/DirectXTK/CommonStates.h +++ b/Windows/DirectXTK/CommonStates.h @@ -35,47 +35,47 @@ namespace DirectX { - class CommonStates - { - public: - explicit CommonStates(_In_ ID3D11Device* device); - CommonStates(CommonStates&& moveFrom); - CommonStates& operator= (CommonStates&& moveFrom); - virtual ~CommonStates(); + class CommonStates + { + public: + explicit CommonStates(_In_ ID3D11Device* device); + CommonStates(CommonStates&& moveFrom); + CommonStates& operator=(CommonStates&& moveFrom); + virtual ~CommonStates(); - // Blend states. - ID3D11BlendState* __cdecl Opaque() const; - ID3D11BlendState* __cdecl AlphaBlend() const; - ID3D11BlendState* __cdecl Additive() const; - ID3D11BlendState* __cdecl NonPremultiplied() const; + // Blend states. + ID3D11BlendState* __cdecl Opaque() const; + ID3D11BlendState* __cdecl AlphaBlend() const; + ID3D11BlendState* __cdecl Additive() const; + ID3D11BlendState* __cdecl NonPremultiplied() const; - // Depth stencil states. - ID3D11DepthStencilState* __cdecl DepthNone() const; - ID3D11DepthStencilState* __cdecl DepthDefault() const; - ID3D11DepthStencilState* __cdecl DepthRead() const; + // Depth stencil states. + ID3D11DepthStencilState* __cdecl DepthNone() const; + ID3D11DepthStencilState* __cdecl DepthDefault() const; + ID3D11DepthStencilState* __cdecl DepthRead() const; - // Rasterizer states. - ID3D11RasterizerState* __cdecl CullNone() const; - ID3D11RasterizerState* __cdecl CullClockwise() const; - ID3D11RasterizerState* __cdecl CullCounterClockwise() const; - ID3D11RasterizerState* __cdecl Wireframe() const; + // Rasterizer states. + ID3D11RasterizerState* __cdecl CullNone() const; + ID3D11RasterizerState* __cdecl CullClockwise() const; + ID3D11RasterizerState* __cdecl CullCounterClockwise() const; + ID3D11RasterizerState* __cdecl Wireframe() const; - // Sampler states. - ID3D11SamplerState* __cdecl PointWrap() const; - ID3D11SamplerState* __cdecl PointClamp() const; - ID3D11SamplerState* __cdecl LinearWrap() const; - ID3D11SamplerState* __cdecl LinearClamp() const; - ID3D11SamplerState* __cdecl AnisotropicWrap() const; - ID3D11SamplerState* __cdecl AnisotropicClamp() const; + // Sampler states. + ID3D11SamplerState* __cdecl PointWrap() const; + ID3D11SamplerState* __cdecl PointClamp() const; + ID3D11SamplerState* __cdecl LinearWrap() const; + ID3D11SamplerState* __cdecl LinearClamp() const; + ID3D11SamplerState* __cdecl AnisotropicWrap() const; + ID3D11SamplerState* __cdecl AnisotropicClamp() const; - private: - // Private implementation. - class Impl; + private: + // Private implementation. + class Impl; - std::shared_ptr pImpl; + std::shared_ptr pImpl; - // Prevent copying. - CommonStates(CommonStates const&) DIRECTX_CTOR_DELETE - CommonStates& operator= (CommonStates const&) DIRECTX_CTOR_DELETE - }; + // Prevent copying. + CommonStates(CommonStates const&) DIRECTX_CTOR_DELETE + CommonStates& operator=(CommonStates const&) DIRECTX_CTOR_DELETE + }; } diff --git a/Windows/DirectXTK/DDSTextureLoader.h b/Windows/DirectXTK/DDSTextureLoader.h index e2a40d2..7ed9f3a 100644 --- a/Windows/DirectXTK/DDSTextureLoader.h +++ b/Windows/DirectXTK/DDSTextureLoader.h @@ -33,128 +33,128 @@ namespace DirectX { - enum DDS_ALPHA_MODE - { - DDS_ALPHA_MODE_UNKNOWN = 0, - DDS_ALPHA_MODE_STRAIGHT = 1, - DDS_ALPHA_MODE_PREMULTIPLIED = 2, - DDS_ALPHA_MODE_OPAQUE = 3, - DDS_ALPHA_MODE_CUSTOM = 4, - }; + enum DDS_ALPHA_MODE + { + DDS_ALPHA_MODE_UNKNOWN = 0, + DDS_ALPHA_MODE_STRAIGHT = 1, + DDS_ALPHA_MODE_PREMULTIPLIED = 2, + DDS_ALPHA_MODE_OPAQUE = 3, + DDS_ALPHA_MODE_CUSTOM = 4, + }; - // Standard version - HRESULT __cdecl CreateDDSTextureFromMemory( _In_ ID3D11Device* d3dDevice, - _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, - _In_ size_t ddsDataSize, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); + // Standard version + HRESULT __cdecl CreateDDSTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - HRESULT __cdecl CreateDDSTextureFromFile( _In_ ID3D11Device* d3dDevice, - _In_z_ const wchar_t* szFileName, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); + HRESULT __cdecl CreateDDSTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - // Standard version with optional auto-gen mipmap support - #if defined(_XBOX_ONE) && defined(_TITLE) + // Standard version with optional auto-gen mipmap support +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateDDSTextureFromMemory( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateDDSTextureFromMemory( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, - _In_ size_t ddsDataSize, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); +#else + HRESULT __cdecl CreateDDSTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - #if defined(_XBOX_ONE) && defined(_TITLE) +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateDDSTextureFromFile( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateDDSTextureFromFile( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_z_ const wchar_t* szFileName, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); +#else + HRESULT __cdecl CreateDDSTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_z_ const wchar_t* szFileName, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - // Extended version - HRESULT __cdecl CreateDDSTextureFromMemoryEx( _In_ ID3D11Device* d3dDevice, - _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, - _In_ size_t ddsDataSize, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); + // Extended version + HRESULT __cdecl CreateDDSTextureFromMemoryEx(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - HRESULT __cdecl CreateDDSTextureFromFileEx( _In_ ID3D11Device* d3dDevice, - _In_z_ const wchar_t* szFileName, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); + HRESULT __cdecl CreateDDSTextureFromFileEx(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - // Extended version with optional auto-gen mipmap support - #if defined(_XBOX_ONE) && defined(_TITLE) + // Extended version with optional auto-gen mipmap support +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateDDSTextureFromMemoryEx( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateDDSTextureFromMemoryEx( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, - _In_ size_t ddsDataSize, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); +#else + HRESULT __cdecl CreateDDSTextureFromMemoryEx(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); - #if defined(_XBOX_ONE) && defined(_TITLE) +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateDDSTextureFromFileEx( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateDDSTextureFromFileEx( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_z_ const wchar_t* szFileName, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr - ); -} \ No newline at end of file +#else + HRESULT __cdecl CreateDDSTextureFromFileEx(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_z_ const wchar_t* szFileName, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr + ); +} diff --git a/Windows/DirectXTK/DirectXHelpers.h b/Windows/DirectXTK/DirectXHelpers.h index 40ce645..e0e481a 100644 --- a/Windows/DirectXTK/DirectXHelpers.h +++ b/Windows/DirectXTK/DirectXHelpers.h @@ -56,95 +56,97 @@ namespace DirectX { - // simliar to std::lock_guard for exception-safe Direct3D 11 resource locking - class MapGuard : public D3D11_MAPPED_SUBRESOURCE - { - public: - MapGuard( _In_ ID3D11DeviceContext* context, - _In_ ID3D11Resource *resource, - _In_ UINT subresource, - _In_ D3D11_MAP mapType, - _In_ UINT mapFlags ) - : mContext(context), mResource(resource), mSubresource(subresource) - { - HRESULT hr = mContext->Map( resource, subresource, mapType, mapFlags, this ); - if (FAILED(hr)) - { - throw std::exception(); - } - } + // simliar to std::lock_guard for exception-safe Direct3D 11 resource locking + class MapGuard : public D3D11_MAPPED_SUBRESOURCE + { + public: + MapGuard(_In_ ID3D11DeviceContext* context, + _In_ ID3D11Resource* resource, + _In_ UINT subresource, + _In_ D3D11_MAP mapType, + _In_ UINT mapFlags) + : mContext(context), mResource(resource), mSubresource(subresource) + { + HRESULT hr = mContext->Map(resource, subresource, mapType, mapFlags, this); + if (FAILED(hr)) + { + throw std::exception(); + } + } - ~MapGuard() - { - mContext->Unmap( mResource, mSubresource ); - } + ~MapGuard() + { + mContext->Unmap(mResource, mSubresource); + } - uint8_t* get() const - { - return reinterpret_cast( pData ); - } - uint8_t* get(size_t slice) const - { - return reinterpret_cast( pData ) + ( slice * DepthPitch ); - } + uint8_t* get() const + { + return reinterpret_cast(pData); + } - uint8_t* scanline(size_t row) const - { - return reinterpret_cast( pData ) + ( row * RowPitch ); - } - uint8_t* scanline(size_t slice, size_t row) const - { - return reinterpret_cast( pData ) + ( slice * DepthPitch ) + ( row * RowPitch ); - } + uint8_t* get(size_t slice) const + { + return reinterpret_cast(pData) + (slice * DepthPitch); + } - private: - ID3D11DeviceContext* mContext; - ID3D11Resource* mResource; - UINT mSubresource; + uint8_t* scanline(size_t row) const + { + return reinterpret_cast(pData) + (row * RowPitch); + } - MapGuard(MapGuard const&); - MapGuard& operator= (MapGuard const&); - }; + uint8_t* scanline(size_t slice, size_t row) const + { + return reinterpret_cast(pData) + (slice * DepthPitch) + (row * RowPitch); + } + + private: + ID3D11DeviceContext* mContext; + ID3D11Resource* mResource; + UINT mSubresource; + + MapGuard(MapGuard const&); + MapGuard& operator=(MapGuard const&); + }; - // Helper sets a D3D resource name string (used by PIX and debug layer leak reporting). - template - inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_z_ const char (&name)[TNameLength]) - { - #if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) ) - #if defined(_XBOX_ONE) && defined(_TITLE) + // Helper sets a D3D resource name string (used by PIX and debug layer leak reporting). + template + inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_z_ const char (&name)[TNameLength]) + { +#if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) ) +#if defined(_XBOX_ONE) && defined(_TITLE) WCHAR wname[MAX_PATH]; int result = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, TNameLength, wname, MAX_PATH ); if ( result > 0 ) { resource->SetName( wname ); } - #else - resource->SetPrivateData(WKPDID_D3DDebugObjectName, TNameLength - 1, name); - #endif - #else +#else + resource->SetPrivateData(WKPDID_D3DDebugObjectName, TNameLength - 1, name); +#endif +#else UNREFERENCED_PARAMETER(resource); UNREFERENCED_PARAMETER(name); - #endif - } +#endif + } - template - inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_z_ const wchar_t (&name)[TNameLength]) - { - #if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) ) - #if defined(_XBOX_ONE) && defined(_TITLE) + template + inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_z_ const wchar_t (&name)[TNameLength]) + { +#if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) ) +#if defined(_XBOX_ONE) && defined(_TITLE) resource->SetName( name ); - #else - char aname[MAX_PATH]; - int result = WideCharToMultiByte( CP_ACP, 0, name, TNameLength, aname, MAX_PATH, nullptr, nullptr ); - if ( result > 0 ) - { - resource->SetPrivateData(WKPDID_D3DDebugObjectName, TNameLength - 1, aname); - } - #endif - #else +#else + char aname[MAX_PATH]; + int result = WideCharToMultiByte(CP_ACP, 0, name, TNameLength, aname, MAX_PATH, nullptr, nullptr); + if (result > 0) + { + resource->SetPrivateData(WKPDID_D3DDebugObjectName, TNameLength - 1, aname); + } +#endif +#else UNREFERENCED_PARAMETER(resource); UNREFERENCED_PARAMETER(name); - #endif - } -} \ No newline at end of file +#endif + } +} diff --git a/Windows/DirectXTK/Effects.h b/Windows/DirectXTK/Effects.h index 5c594f2..92d785b 100644 --- a/Windows/DirectXTK/Effects.h +++ b/Windows/DirectXTK/Effects.h @@ -39,574 +39,588 @@ namespace DirectX { - #if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) +#if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) #define XM_CALLCONV __fastcall typedef const XMVECTOR& HXMVECTOR; typedef const XMMATRIX& FXMMATRIX; - #endif - - //---------------------------------------------------------------------------------- - // Abstract interface representing any effect which can be applied onto a D3D device context. - class IEffect - { - public: - virtual ~IEffect() { } - - virtual void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) = 0; - - virtual void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) = 0; - }; +#endif + + //---------------------------------------------------------------------------------- + // Abstract interface representing any effect which can be applied onto a D3D device context. + class IEffect + { + public: + virtual ~IEffect() + { + } + + virtual void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) = 0; + + virtual void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) = + 0; + }; + + + // Abstract interface for effects with world, view, and projection matrices. + class IEffectMatrices + { + public: + virtual ~IEffectMatrices() + { + } + + virtual void XM_CALLCONV SetWorld(FXMMATRIX value) = 0; + virtual void XM_CALLCONV SetView(FXMMATRIX value) = 0; + virtual void XM_CALLCONV SetProjection(FXMMATRIX value) = 0; + }; + + + // Abstract interface for effects which support directional lighting. + class IEffectLights + { + public: + virtual ~IEffectLights() + { + } + + virtual void __cdecl SetLightingEnabled(bool value) = 0; + virtual void __cdecl SetPerPixelLighting(bool value) = 0; + virtual void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) = 0; + + virtual void __cdecl SetLightEnabled(int whichLight, bool value) = 0; + virtual void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) = 0; + virtual void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) = 0; + virtual void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) = 0; + + virtual void __cdecl EnableDefaultLighting() = 0; + + static const int MaxDirectionalLights = 3; + }; + + + // Abstract interface for effects which support fog. + class IEffectFog + { + public: + virtual ~IEffectFog() + { + } + + virtual void __cdecl SetFogEnabled(bool value) = 0; + virtual void __cdecl SetFogStart(float value) = 0; + virtual void __cdecl SetFogEnd(float value) = 0; + virtual void XM_CALLCONV SetFogColor(FXMVECTOR value) = 0; + }; + + + // Abstract interface for effects which support skinning + class IEffectSkinning + { + public: + virtual ~IEffectSkinning() + { + } + + virtual void __cdecl SetWeightsPerVertex(int value) = 0; + virtual void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) = 0; + virtual void __cdecl ResetBoneTransforms() = 0; + + static const int MaxBones = 72; + }; + + + //---------------------------------------------------------------------------------- + // Built-in shader supports optional texture mapping, vertex coloring, directional lighting, and fog. + class BasicEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog + { + public: + explicit BasicEffect(_In_ ID3D11Device* device); + BasicEffect(BasicEffect&& moveFrom); + BasicEffect& operator=(BasicEffect&& moveFrom); + virtual ~BasicEffect(); + + // IEffect methods. + void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; + + void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; + + // Camera settings. + void XM_CALLCONV SetWorld(FXMMATRIX value) override; + void XM_CALLCONV SetView(FXMMATRIX value) override; + void XM_CALLCONV SetProjection(FXMMATRIX value) override; + + // Material settings. + void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); + void XM_CALLCONV SetSpecularColor(FXMVECTOR value); + void __cdecl SetSpecularPower(float value); + void __cdecl DisableSpecular(); + void __cdecl SetAlpha(float value); + + // Light settings. + void __cdecl SetLightingEnabled(bool value) override; + void __cdecl SetPerPixelLighting(bool value) override; + void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; + + void __cdecl SetLightEnabled(int whichLight, bool value) override; + void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; + + void __cdecl EnableDefaultLighting() override; + + // Fog settings. + void __cdecl SetFogEnabled(bool value) override; + void __cdecl SetFogStart(float value) override; + void __cdecl SetFogEnd(float value) override; + void XM_CALLCONV SetFogColor(FXMVECTOR value) override; + + // Vertex color setting. + void __cdecl SetVertexColorEnabled(bool value); + + // Texture setting. + void __cdecl SetTextureEnabled(bool value); + void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); + + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Prevent copying. + BasicEffect(BasicEffect const&) DIRECTX_CTOR_DELETE + BasicEffect& operator=(BasicEffect const&) DIRECTX_CTOR_DELETE + }; - // Abstract interface for effects with world, view, and projection matrices. - class IEffectMatrices - { - public: - virtual ~IEffectMatrices() { } - - virtual void XM_CALLCONV SetWorld(FXMMATRIX value) = 0; - virtual void XM_CALLCONV SetView(FXMMATRIX value) = 0; - virtual void XM_CALLCONV SetProjection(FXMMATRIX value) = 0; - }; - - - // Abstract interface for effects which support directional lighting. - class IEffectLights - { - public: - virtual ~IEffectLights() { } - - virtual void __cdecl SetLightingEnabled(bool value) = 0; - virtual void __cdecl SetPerPixelLighting(bool value) = 0; - virtual void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) = 0; - - virtual void __cdecl SetLightEnabled(int whichLight, bool value) = 0; - virtual void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) = 0; - virtual void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) = 0; - virtual void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) = 0; + // Built-in shader supports per-pixel alpha testing. + class AlphaTestEffect : public IEffect, public IEffectMatrices, public IEffectFog + { + public: + explicit AlphaTestEffect(_In_ ID3D11Device* device); + AlphaTestEffect(AlphaTestEffect&& moveFrom); + AlphaTestEffect& operator=(AlphaTestEffect&& moveFrom); + virtual ~AlphaTestEffect(); + + // IEffect methods. + void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; + + void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; + + // Camera settings. + void XM_CALLCONV SetWorld(FXMMATRIX value) override; + void XM_CALLCONV SetView(FXMMATRIX value) override; + void XM_CALLCONV SetProjection(FXMMATRIX value) override; + + // Material settings. + void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + void __cdecl SetAlpha(float value); + + // Fog settings. + void __cdecl SetFogEnabled(bool value) override; + void __cdecl SetFogStart(float value) override; + void __cdecl SetFogEnd(float value) override; + void XM_CALLCONV SetFogColor(FXMVECTOR value) override; + + // Vertex color setting. + void __cdecl SetVertexColorEnabled(bool value); - virtual void __cdecl EnableDefaultLighting() = 0; - - static const int MaxDirectionalLights = 3; - }; - - - // Abstract interface for effects which support fog. - class IEffectFog - { - public: - virtual ~IEffectFog() { } - - virtual void __cdecl SetFogEnabled(bool value) = 0; - virtual void __cdecl SetFogStart(float value) = 0; - virtual void __cdecl SetFogEnd(float value) = 0; - virtual void XM_CALLCONV SetFogColor(FXMVECTOR value) = 0; - }; - - - // Abstract interface for effects which support skinning - class IEffectSkinning - { - public: - virtual ~IEffectSkinning() { } - - virtual void __cdecl SetWeightsPerVertex(int value) = 0; - virtual void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) = 0; - virtual void __cdecl ResetBoneTransforms() = 0; - - static const int MaxBones = 72; - }; - - - //---------------------------------------------------------------------------------- - // Built-in shader supports optional texture mapping, vertex coloring, directional lighting, and fog. - class BasicEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog - { - public: - explicit BasicEffect(_In_ ID3D11Device* device); - BasicEffect(BasicEffect&& moveFrom); - BasicEffect& operator= (BasicEffect&& moveFrom); - virtual ~BasicEffect(); - - // IEffect methods. - void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - - void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - - // Camera settings. - void XM_CALLCONV SetWorld(FXMMATRIX value) override; - void XM_CALLCONV SetView(FXMMATRIX value) override; - void XM_CALLCONV SetProjection(FXMMATRIX value) override; - - // Material settings. - void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); - void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); - void XM_CALLCONV SetSpecularColor(FXMVECTOR value); - void __cdecl SetSpecularPower(float value); - void __cdecl DisableSpecular(); - void __cdecl SetAlpha(float value); - - // Light settings. - void __cdecl SetLightingEnabled(bool value) override; - void __cdecl SetPerPixelLighting(bool value) override; - void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; - - void __cdecl SetLightEnabled(int whichLight, bool value) override; - void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; - - void __cdecl EnableDefaultLighting() override; - - // Fog settings. - void __cdecl SetFogEnabled(bool value) override; - void __cdecl SetFogStart(float value) override; - void __cdecl SetFogEnd(float value) override; - void XM_CALLCONV SetFogColor(FXMVECTOR value) override; - - // Vertex color setting. - void __cdecl SetVertexColorEnabled(bool value); - - // Texture setting. - void __cdecl SetTextureEnabled(bool value); - void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Prevent copying. - BasicEffect(BasicEffect const&) DIRECTX_CTOR_DELETE - BasicEffect& operator= (BasicEffect const&) DIRECTX_CTOR_DELETE - }; - - - - // Built-in shader supports per-pixel alpha testing. - class AlphaTestEffect : public IEffect, public IEffectMatrices, public IEffectFog - { - public: - explicit AlphaTestEffect(_In_ ID3D11Device* device); - AlphaTestEffect(AlphaTestEffect&& moveFrom); - AlphaTestEffect& operator= (AlphaTestEffect&& moveFrom); - virtual ~AlphaTestEffect(); - - // IEffect methods. - void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - - void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - - // Camera settings. - void XM_CALLCONV SetWorld(FXMMATRIX value) override; - void XM_CALLCONV SetView(FXMMATRIX value) override; - void XM_CALLCONV SetProjection(FXMMATRIX value) override; - - // Material settings. - void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); - void __cdecl SetAlpha(float value); - - // Fog settings. - void __cdecl SetFogEnabled(bool value) override; - void __cdecl SetFogStart(float value) override; - void __cdecl SetFogEnd(float value) override; - void XM_CALLCONV SetFogColor(FXMVECTOR value) override; - - // Vertex color setting. - void __cdecl SetVertexColorEnabled(bool value); - - // Texture setting. - void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); - - // Alpha test settings. - void __cdecl SetAlphaFunction(D3D11_COMPARISON_FUNC value); - void __cdecl SetReferenceAlpha(int value); - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Prevent copying. - AlphaTestEffect(AlphaTestEffect const&) DIRECTX_CTOR_DELETE - AlphaTestEffect& operator= (AlphaTestEffect const&) DIRECTX_CTOR_DELETE - }; - - - - // Built-in shader supports two layer multitexturing (eg. for lightmaps or detail textures). - class DualTextureEffect : public IEffect, public IEffectMatrices, public IEffectFog - { - public: - explicit DualTextureEffect(_In_ ID3D11Device* device); - DualTextureEffect(DualTextureEffect&& moveFrom); - DualTextureEffect& operator= (DualTextureEffect&& moveFrom); - ~DualTextureEffect(); - - // IEffect methods. - void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - - void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - - // Camera settings. - void XM_CALLCONV SetWorld(FXMMATRIX value) override; - void XM_CALLCONV SetView(FXMMATRIX value) override; - void XM_CALLCONV SetProjection(FXMMATRIX value) override; - - // Material settings. - void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); - void __cdecl SetAlpha(float value); - - // Fog settings. - void __cdecl SetFogEnabled(bool value) override; - void __cdecl SetFogStart(float value) override; - void __cdecl SetFogEnd(float value) override; - void XM_CALLCONV SetFogColor(FXMVECTOR value) override; - - // Vertex color setting. - void __cdecl SetVertexColorEnabled(bool value); - - // Texture settings. - void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); - void __cdecl SetTexture2(_In_opt_ ID3D11ShaderResourceView* value); - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Prevent copying. - DualTextureEffect(DualTextureEffect const&) DIRECTX_CTOR_DELETE - DualTextureEffect& operator= (DualTextureEffect const&) DIRECTX_CTOR_DELETE - }; - - - - // Built-in shader supports cubic environment mapping. - class EnvironmentMapEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog - { - public: - explicit EnvironmentMapEffect(_In_ ID3D11Device* device); - EnvironmentMapEffect(EnvironmentMapEffect&& moveFrom); - EnvironmentMapEffect& operator= (EnvironmentMapEffect&& moveFrom); - virtual ~EnvironmentMapEffect(); - - // IEffect methods. - void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - - void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - - // Camera settings. - void XM_CALLCONV SetWorld(FXMMATRIX value) override; - void XM_CALLCONV SetView(FXMMATRIX value) override; - void XM_CALLCONV SetProjection(FXMMATRIX value) override; - - // Material settings. - void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); - void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); - void __cdecl SetAlpha(float value); - - // Light settings. - void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; - - void __cdecl SetLightEnabled(int whichLight, bool value) override; - void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; - - void __cdecl EnableDefaultLighting() override; - - // Fog settings. - void __cdecl SetFogEnabled(bool value) override; - void __cdecl SetFogStart(float value) override; - void __cdecl SetFogEnd(float value) override; - void XM_CALLCONV SetFogColor(FXMVECTOR value) override; - - // Texture setting. - void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); - - // Environment map settings. - void __cdecl SetEnvironmentMap(_In_opt_ ID3D11ShaderResourceView* value); - void __cdecl SetEnvironmentMapAmount(float value); - void XM_CALLCONV SetEnvironmentMapSpecular(FXMVECTOR value); - void __cdecl SetFresnelFactor(float value); - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Unsupported interface methods. - void __cdecl SetLightingEnabled(bool value) override; - void __cdecl SetPerPixelLighting(bool value) override; - void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; - - // Prevent copying. - EnvironmentMapEffect(EnvironmentMapEffect const&) DIRECTX_CTOR_DELETE - EnvironmentMapEffect& operator= (EnvironmentMapEffect const&) DIRECTX_CTOR_DELETE - }; - - - - // Built-in shader supports skinned animation. - class SkinnedEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog, public IEffectSkinning - { - public: - explicit SkinnedEffect(_In_ ID3D11Device* device); - SkinnedEffect(SkinnedEffect&& moveFrom); - SkinnedEffect& operator= (SkinnedEffect&& moveFrom); - virtual ~SkinnedEffect(); - - // IEffect methods. - void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - - void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - - // Camera settings. - void XM_CALLCONV SetWorld(FXMMATRIX value) override; - void XM_CALLCONV SetView(FXMMATRIX value) override; - void XM_CALLCONV SetProjection(FXMMATRIX value) override; - - // Material settings. - void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); - void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); - void XM_CALLCONV SetSpecularColor(FXMVECTOR value); - void __cdecl SetSpecularPower(float value); - void __cdecl DisableSpecular(); - void __cdecl SetAlpha(float value); - - // Light settings. - void __cdecl SetPerPixelLighting(bool value) override; - void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; - - void __cdecl SetLightEnabled(int whichLight, bool value) override; - void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; - - void __cdecl EnableDefaultLighting() override; - - // Fog settings. - void __cdecl SetFogEnabled(bool value) override; - void __cdecl SetFogStart(float value) override; - void __cdecl SetFogEnd(float value) override; - void XM_CALLCONV SetFogColor(FXMVECTOR value) override; - - // Texture setting. - void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); - - // Animation settings. - void __cdecl SetWeightsPerVertex(int value) override; - void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override; - void __cdecl ResetBoneTransforms() override; - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Unsupported interface method. - void __cdecl SetLightingEnabled(bool value) override; - - // Prevent copying. - SkinnedEffect(SkinnedEffect const&) DIRECTX_CTOR_DELETE - SkinnedEffect& operator= (SkinnedEffect const&) DIRECTX_CTOR_DELETE - }; - - - - //---------------------------------------------------------------------------------- - // Built-in effect for Visual Studio Shader Designer (DGSL) shaders - class DGSLEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectSkinning - { - public: - explicit DGSLEffect( _In_ ID3D11Device* device, _In_opt_ ID3D11PixelShader* pixelShader = nullptr, - _In_ bool enableSkinning = false ); - DGSLEffect(DGSLEffect&& moveFrom); - DGSLEffect& operator= (DGSLEffect&& moveFrom); - virtual ~DGSLEffect(); - - // IEffect methods. - void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - - void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - - // Camera settings. - void XM_CALLCONV SetWorld(FXMMATRIX value) override; - void XM_CALLCONV SetView(FXMMATRIX value) override; - void XM_CALLCONV SetProjection(FXMMATRIX value) override; - - // Material settings. - void XM_CALLCONV SetAmbientColor(FXMVECTOR value); - void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); - void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); - void XM_CALLCONV SetSpecularColor(FXMVECTOR value); - void __cdecl SetSpecularPower(float value); - void __cdecl DisableSpecular(); - void __cdecl SetAlpha(float value); - - // Additional settings. - void XM_CALLCONV SetUVTransform(FXMMATRIX value); - void __cdecl SetViewport( float width, float height ); - void __cdecl SetTime( float time ); - void __cdecl SetAlphaDiscardEnable(bool value); - - // Light settings. - void __cdecl SetLightingEnabled(bool value) override; - void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; - - void __cdecl SetLightEnabled(int whichLight, bool value) override; - void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; - void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; - - void __cdecl EnableDefaultLighting() override; - - static const int MaxDirectionalLights = 4; - - // Vertex color setting. - void __cdecl SetVertexColorEnabled(bool value); - - // Texture settings. - void __cdecl SetTextureEnabled(bool value); - void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); - void __cdecl SetTexture2(_In_opt_ ID3D11ShaderResourceView* value); - void __cdecl SetTexture(int whichTexture, _In_opt_ ID3D11ShaderResourceView* value); - - static const int MaxTextures = 8; - - // Animation setting. - void __cdecl SetWeightsPerVertex(int value) override; - void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override; - void __cdecl ResetBoneTransforms() override; - - private: - // Private implementation. - class Impl; - - std::unique_ptr pImpl; - - // Unsupported interface methods. - void __cdecl SetPerPixelLighting(bool value) override; - - // Prevent copying. - DGSLEffect(DGSLEffect const&) DIRECTX_CTOR_DELETE - DGSLEffect& operator= (DGSLEffect const&) DIRECTX_CTOR_DELETE - }; + // Texture setting. + void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); + + // Alpha test settings. + void __cdecl SetAlphaFunction(D3D11_COMPARISON_FUNC value); + void __cdecl SetReferenceAlpha(int value); + + private: + // Private implementation. + class Impl; + std::unique_ptr pImpl; + // Prevent copying. + AlphaTestEffect(AlphaTestEffect const&) DIRECTX_CTOR_DELETE + AlphaTestEffect& operator=(AlphaTestEffect const&) DIRECTX_CTOR_DELETE + }; + + + // Built-in shader supports two layer multitexturing (eg. for lightmaps or detail textures). + class DualTextureEffect : public IEffect, public IEffectMatrices, public IEffectFog + { + public: + explicit DualTextureEffect(_In_ ID3D11Device* device); + DualTextureEffect(DualTextureEffect&& moveFrom); + DualTextureEffect& operator=(DualTextureEffect&& moveFrom); + ~DualTextureEffect(); - //---------------------------------------------------------------------------------- - // Abstract interface to factory for sharing effects and texture resources - class IEffectFactory - { - public: - virtual ~IEffectFactory() {} + // IEffect methods. + void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; - struct EffectInfo - { - const WCHAR* name; - bool perVertexColor; - bool enableSkinning; - bool enableDualTexture; - float specularPower; - float alpha; - DirectX::XMFLOAT3 ambientColor; - DirectX::XMFLOAT3 diffuseColor; - DirectX::XMFLOAT3 specularColor; - DirectX::XMFLOAT3 emissiveColor; - const WCHAR* texture; - const WCHAR* texture2; + void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; - EffectInfo() { memset( this, 0, sizeof(EffectInfo) ); }; - }; + // Camera settings. + void XM_CALLCONV SetWorld(FXMMATRIX value) override; + void XM_CALLCONV SetView(FXMMATRIX value) override; + void XM_CALLCONV SetProjection(FXMMATRIX value) override; - virtual std::shared_ptr __cdecl CreateEffect( _In_ const EffectInfo& info, _In_opt_ ID3D11DeviceContext* deviceContext ) = 0; + // Material settings. + void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + void __cdecl SetAlpha(float value); - virtual void __cdecl CreateTexture( _In_z_ const WCHAR* name, _In_opt_ ID3D11DeviceContext* deviceContext, _Outptr_ ID3D11ShaderResourceView** textureView ) = 0; - }; + // Fog settings. + void __cdecl SetFogEnabled(bool value) override; + void __cdecl SetFogStart(float value) override; + void __cdecl SetFogEnd(float value) override; + void XM_CALLCONV SetFogColor(FXMVECTOR value) override; + // Vertex color setting. + void __cdecl SetVertexColorEnabled(bool value); - // Factory for sharing effects and texture resources - class EffectFactory : public IEffectFactory - { - public: - explicit EffectFactory(_In_ ID3D11Device* device); - EffectFactory(EffectFactory&& moveFrom); - EffectFactory& operator= (EffectFactory&& moveFrom); - virtual ~EffectFactory(); + // Texture settings. + void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); + void __cdecl SetTexture2(_In_opt_ ID3D11ShaderResourceView* value); - // IEffectFactory methods. - virtual std::shared_ptr __cdecl CreateEffect( _In_ const EffectInfo& info, _In_opt_ ID3D11DeviceContext* deviceContext ) override; - virtual void __cdecl CreateTexture( _In_z_ const WCHAR* name, _In_opt_ ID3D11DeviceContext* deviceContext, _Outptr_ ID3D11ShaderResourceView** textureView ) override; + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Prevent copying. + DualTextureEffect(DualTextureEffect const&) DIRECTX_CTOR_DELETE + DualTextureEffect& operator=(DualTextureEffect const&) DIRECTX_CTOR_DELETE + }; + + + // Built-in shader supports cubic environment mapping. + class EnvironmentMapEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog + { + public: + explicit EnvironmentMapEffect(_In_ ID3D11Device* device); + EnvironmentMapEffect(EnvironmentMapEffect&& moveFrom); + EnvironmentMapEffect& operator=(EnvironmentMapEffect&& moveFrom); + virtual ~EnvironmentMapEffect(); + + // IEffect methods. + void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; + + void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; + + // Camera settings. + void XM_CALLCONV SetWorld(FXMMATRIX value) override; + void XM_CALLCONV SetView(FXMMATRIX value) override; + void XM_CALLCONV SetProjection(FXMMATRIX value) override; + + // Material settings. + void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); + void __cdecl SetAlpha(float value); - // Settings. - void __cdecl ReleaseCache(); + // Light settings. + void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; - void __cdecl SetSharing( bool enabled ); + void __cdecl SetLightEnabled(int whichLight, bool value) override; + void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; + + void __cdecl EnableDefaultLighting() override; - void __cdecl SetDirectory( _In_opt_z_ const WCHAR* path ); + // Fog settings. + void __cdecl SetFogEnabled(bool value) override; + void __cdecl SetFogStart(float value) override; + void __cdecl SetFogEnd(float value) override; + void XM_CALLCONV SetFogColor(FXMVECTOR value) override; + + // Texture setting. + void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); + + // Environment map settings. + void __cdecl SetEnvironmentMap(_In_opt_ ID3D11ShaderResourceView* value); + void __cdecl SetEnvironmentMapAmount(float value); + void XM_CALLCONV SetEnvironmentMapSpecular(FXMVECTOR value); + void __cdecl SetFresnelFactor(float value); + + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Unsupported interface methods. + void __cdecl SetLightingEnabled(bool value) override; + void __cdecl SetPerPixelLighting(bool value) override; + void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; + + // Prevent copying. + EnvironmentMapEffect(EnvironmentMapEffect const&) DIRECTX_CTOR_DELETE + EnvironmentMapEffect& operator=(EnvironmentMapEffect const&) DIRECTX_CTOR_DELETE + }; + + + // Built-in shader supports skinned animation. + class SkinnedEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog, + public IEffectSkinning + { + public: + explicit SkinnedEffect(_In_ ID3D11Device* device); + SkinnedEffect(SkinnedEffect&& moveFrom); + SkinnedEffect& operator=(SkinnedEffect&& moveFrom); + virtual ~SkinnedEffect(); + + // IEffect methods. + void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; + + void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; + + // Camera settings. + void XM_CALLCONV SetWorld(FXMMATRIX value) override; + void XM_CALLCONV SetView(FXMMATRIX value) override; + void XM_CALLCONV SetProjection(FXMMATRIX value) override; + + // Material settings. + void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); + void XM_CALLCONV SetSpecularColor(FXMVECTOR value); + void __cdecl SetSpecularPower(float value); + void __cdecl DisableSpecular(); + void __cdecl SetAlpha(float value); + + // Light settings. + void __cdecl SetPerPixelLighting(bool value) override; + void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; + + void __cdecl SetLightEnabled(int whichLight, bool value) override; + void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; + + void __cdecl EnableDefaultLighting() override; + + // Fog settings. + void __cdecl SetFogEnabled(bool value) override; + void __cdecl SetFogStart(float value) override; + void __cdecl SetFogEnd(float value) override; + void XM_CALLCONV SetFogColor(FXMVECTOR value) override; + + // Texture setting. + void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); + + // Animation settings. + void __cdecl SetWeightsPerVertex(int value) override; + void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override; + void __cdecl ResetBoneTransforms() override; + + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Unsupported interface method. + void __cdecl SetLightingEnabled(bool value) override; + + // Prevent copying. + SkinnedEffect(SkinnedEffect const&) DIRECTX_CTOR_DELETE + SkinnedEffect& operator=(SkinnedEffect const&) DIRECTX_CTOR_DELETE + }; + + + //---------------------------------------------------------------------------------- + // Built-in effect for Visual Studio Shader Designer (DGSL) shaders + class DGSLEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectSkinning + { + public: + explicit DGSLEffect(_In_ ID3D11Device* device, _In_opt_ ID3D11PixelShader* pixelShader = nullptr, + _In_ bool enableSkinning = false); + DGSLEffect(DGSLEffect&& moveFrom); + DGSLEffect& operator=(DGSLEffect&& moveFrom); + virtual ~DGSLEffect(); + + // IEffect methods. + void __cdecl Apply(_In_ ID3D11DeviceContext* deviceContext) override; + + void __cdecl GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override; + + // Camera settings. + void XM_CALLCONV SetWorld(FXMMATRIX value) override; + void XM_CALLCONV SetView(FXMMATRIX value) override; + void XM_CALLCONV SetProjection(FXMMATRIX value) override; + + // Material settings. + void XM_CALLCONV SetAmbientColor(FXMVECTOR value); + void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + void XM_CALLCONV SetEmissiveColor(FXMVECTOR value); + void XM_CALLCONV SetSpecularColor(FXMVECTOR value); + void __cdecl SetSpecularPower(float value); + void __cdecl DisableSpecular(); + void __cdecl SetAlpha(float value); + + // Additional settings. + void XM_CALLCONV SetUVTransform(FXMMATRIX value); + void __cdecl SetViewport(float width, float height); + void __cdecl SetTime(float time); + void __cdecl SetAlphaDiscardEnable(bool value); + + // Light settings. + void __cdecl SetLightingEnabled(bool value) override; + void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; + + void __cdecl SetLightEnabled(int whichLight, bool value) override; + void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; + void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; + + void __cdecl EnableDefaultLighting() override; + + static const int MaxDirectionalLights = 4; + + // Vertex color setting. + void __cdecl SetVertexColorEnabled(bool value); + + // Texture settings. + void __cdecl SetTextureEnabled(bool value); + void __cdecl SetTexture(_In_opt_ ID3D11ShaderResourceView* value); + void __cdecl SetTexture2(_In_opt_ ID3D11ShaderResourceView* value); + void __cdecl SetTexture(int whichTexture, _In_opt_ ID3D11ShaderResourceView* value); + + static const int MaxTextures = 8; + + // Animation setting. + void __cdecl SetWeightsPerVertex(int value) override; + void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override; + void __cdecl ResetBoneTransforms() override; + + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Unsupported interface methods. + void __cdecl SetPerPixelLighting(bool value) override; + + // Prevent copying. + DGSLEffect(DGSLEffect const&) DIRECTX_CTOR_DELETE + DGSLEffect& operator=(DGSLEffect const&) DIRECTX_CTOR_DELETE + }; + + + //---------------------------------------------------------------------------------- + // Abstract interface to factory for sharing effects and texture resources + class IEffectFactory + { + public: + virtual ~IEffectFactory() + { + } + + struct EffectInfo + { + const WCHAR* name; + bool perVertexColor; + bool enableSkinning; + bool enableDualTexture; + float specularPower; + float alpha; + DirectX::XMFLOAT3 ambientColor; + DirectX::XMFLOAT3 diffuseColor; + DirectX::XMFLOAT3 specularColor; + DirectX::XMFLOAT3 emissiveColor; + const WCHAR* texture; + const WCHAR* texture2; + + EffectInfo() { memset(this, 0, sizeof(EffectInfo)); }; + }; + + virtual std::shared_ptr __cdecl CreateEffect(_In_ const EffectInfo& info, + _In_opt_ ID3D11DeviceContext* deviceContext) = 0; + + virtual void __cdecl CreateTexture(_In_z_ const WCHAR* name, _In_opt_ ID3D11DeviceContext* deviceContext, + _Outptr_ ID3D11ShaderResourceView** textureView) = 0; + }; + + + // Factory for sharing effects and texture resources + class EffectFactory : public IEffectFactory + { + public: + explicit EffectFactory(_In_ ID3D11Device* device); + EffectFactory(EffectFactory&& moveFrom); + EffectFactory& operator=(EffectFactory&& moveFrom); + virtual ~EffectFactory(); + + // IEffectFactory methods. + virtual std::shared_ptr __cdecl CreateEffect(_In_ const EffectInfo& info, + _In_opt_ ID3D11DeviceContext* deviceContext) override; + virtual void __cdecl CreateTexture(_In_z_ const WCHAR* name, _In_opt_ ID3D11DeviceContext* deviceContext, + _Outptr_ ID3D11ShaderResourceView** textureView) override; - private: - // Private implementation. - class Impl; + // Settings. + void __cdecl ReleaseCache(); - std::shared_ptr pImpl; + void __cdecl SetSharing(bool enabled); - // Prevent copying. - EffectFactory(EffectFactory const&) DIRECTX_CTOR_DELETE - EffectFactory& operator= (EffectFactory const&) DIRECTX_CTOR_DELETE - }; + void __cdecl SetDirectory(_In_opt_z_ const WCHAR* path); + private: + // Private implementation. + class Impl; - // Factory for sharing Visual Studio Shader Designer (DGSL) shaders and texture resources - class DGSLEffectFactory : public IEffectFactory - { - public: - explicit DGSLEffectFactory(_In_ ID3D11Device* device); - DGSLEffectFactory(DGSLEffectFactory&& moveFrom); - DGSLEffectFactory& operator= (DGSLEffectFactory&& moveFrom); - virtual ~DGSLEffectFactory(); + std::shared_ptr pImpl; + + // Prevent copying. + EffectFactory(EffectFactory const&) DIRECTX_CTOR_DELETE + EffectFactory& operator=(EffectFactory const&) DIRECTX_CTOR_DELETE + }; - // IEffectFactory methods. - virtual std::shared_ptr __cdecl CreateEffect( _In_ const EffectInfo& info, _In_opt_ ID3D11DeviceContext* deviceContext ) override; - virtual void __cdecl CreateTexture( _In_z_ const WCHAR* name, _In_opt_ ID3D11DeviceContext* deviceContext, _Outptr_ ID3D11ShaderResourceView** textureView ) override; - // DGSL methods. - struct DGSLEffectInfo : public EffectInfo - { - const WCHAR* textures[6]; - const WCHAR* pixelShader; + // Factory for sharing Visual Studio Shader Designer (DGSL) shaders and texture resources + class DGSLEffectFactory : public IEffectFactory + { + public: + explicit DGSLEffectFactory(_In_ ID3D11Device* device); + DGSLEffectFactory(DGSLEffectFactory&& moveFrom); + DGSLEffectFactory& operator=(DGSLEffectFactory&& moveFrom); + virtual ~DGSLEffectFactory(); - DGSLEffectInfo() { memset( this, 0, sizeof(DGSLEffectInfo) ); }; - }; - - virtual std::shared_ptr __cdecl CreateDGSLEffect( _In_ const DGSLEffectInfo& info, _In_opt_ ID3D11DeviceContext* deviceContext ); - - virtual void __cdecl CreatePixelShader( _In_z_ const WCHAR* shader, _Outptr_ ID3D11PixelShader** pixelShader ); - - // Settings. - void __cdecl ReleaseCache(); - - void __cdecl SetSharing( bool enabled ); - - void __cdecl SetDirectory( _In_opt_z_ const WCHAR* path ); - - private: - // Private implementation. - class Impl; - - std::shared_ptr pImpl; - - // Prevent copying. - DGSLEffectFactory(DGSLEffectFactory const&) DIRECTX_CTOR_DELETE - DGSLEffectFactory& operator= (DGSLEffectFactory const&) DIRECTX_CTOR_DELETE - }; + // IEffectFactory methods. + virtual std::shared_ptr __cdecl CreateEffect(_In_ const EffectInfo& info, + _In_opt_ ID3D11DeviceContext* deviceContext) override; + virtual void __cdecl CreateTexture(_In_z_ const WCHAR* name, _In_opt_ ID3D11DeviceContext* deviceContext, + _Outptr_ ID3D11ShaderResourceView** textureView) override; + + // DGSL methods. + struct DGSLEffectInfo : public EffectInfo + { + const WCHAR* textures[6]; + const WCHAR* pixelShader; + + DGSLEffectInfo() { memset(this, 0, sizeof(DGSLEffectInfo)); }; + }; + + virtual std::shared_ptr __cdecl CreateDGSLEffect(_In_ const DGSLEffectInfo& info, + _In_opt_ ID3D11DeviceContext* deviceContext); + + virtual void __cdecl CreatePixelShader(_In_z_ const WCHAR* shader, _Outptr_ ID3D11PixelShader** pixelShader); + + // Settings. + void __cdecl ReleaseCache(); + + void __cdecl SetSharing(bool enabled); + + void __cdecl SetDirectory(_In_opt_z_ const WCHAR* path); + + private: + // Private implementation. + class Impl; + std::shared_ptr pImpl; + + // Prevent copying. + DGSLEffectFactory(DGSLEffectFactory const&) DIRECTX_CTOR_DELETE + DGSLEffectFactory& operator=(DGSLEffectFactory const&) DIRECTX_CTOR_DELETE + }; } #pragma warning(pop) diff --git a/Windows/DirectXTK/GeometricPrimitive.h b/Windows/DirectXTK/GeometricPrimitive.h index 6e0584e..0637a50 100644 --- a/Windows/DirectXTK/GeometricPrimitive.h +++ b/Windows/DirectXTK/GeometricPrimitive.h @@ -43,68 +43,107 @@ namespace DirectX { - #if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) +#if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) #define XM_CALLCONV __fastcall typedef const XMVECTOR& HXMVECTOR; typedef const XMMATRIX& FXMMATRIX; - #endif +#endif - class IEffect; + class IEffect; - class GeometricPrimitive - { - public: - virtual ~GeometricPrimitive(); - - // Factory methods. - static std::unique_ptr __cdecl CreateCube (_In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); - static std::unique_ptr __cdecl CreateBox (_In_ ID3D11DeviceContext* deviceContext, const XMFLOAT3& size, bool rhcoords = true, bool invertn = false); - static std::unique_ptr __cdecl CreateSphere (_In_ ID3D11DeviceContext* deviceContext, float diameter = 1, size_t tessellation = 16, bool rhcoords = true, bool invertn = false); - static std::unique_ptr __cdecl CreateGeoSphere (_In_ ID3D11DeviceContext* deviceContext, float diameter = 1, size_t tessellation = 3, bool rhcoords = true); - static std::unique_ptr __cdecl CreateCylinder (_In_ ID3D11DeviceContext* deviceContext, float height = 1, float diameter = 1, size_t tessellation = 32, bool rhcoords = true); - static std::unique_ptr __cdecl CreateCone (_In_ ID3D11DeviceContext* deviceContext, float diameter = 1, float height = 1, size_t tessellation = 32, bool rhcoords = true); - static std::unique_ptr __cdecl CreateTorus (_In_ ID3D11DeviceContext* deviceContext, float diameter = 1, float thickness = 0.333f, size_t tessellation = 32, bool rhcoords = true); - static std::unique_ptr __cdecl CreateTetrahedron (_In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); - static std::unique_ptr __cdecl CreateOctahedron (_In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); - static std::unique_ptr __cdecl CreateDodecahedron (_In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); - static std::unique_ptr __cdecl CreateIcosahedron (_In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); - static std::unique_ptr __cdecl CreateTeapot (_In_ ID3D11DeviceContext* deviceContext, float size = 1, size_t tessellation = 8, bool rhcoords = true); - static std::unique_ptr __cdecl CreateCustom (_In_ ID3D11DeviceContext* deviceContext, const std::vector& vertices, const std::vector& indices); + class GeometricPrimitive + { + public: + virtual ~GeometricPrimitive(); - static void __cdecl CreateCube (std::vector& vertices, std::vector& indices, float size = 1, bool rhcoords = true); - static void __cdecl CreateBox (std::vector& vertices, std::vector& indices, const XMFLOAT3& size, bool rhcoords = true, bool invertn = false); - static void __cdecl CreateSphere (std::vector& vertices, std::vector& indices, float diameter = 1, size_t tessellation = 16, bool rhcoords = true, bool invertn = false); - static void __cdecl CreateGeoSphere (std::vector& vertices, std::vector& indices, float diameter = 1, size_t tessellation = 3, bool rhcoords = true); - static void __cdecl CreateCylinder (std::vector& vertices, std::vector& indices, float height = 1, float diameter = 1, size_t tessellation = 32, bool rhcoords = true); - static void __cdecl CreateCone (std::vector& vertices, std::vector& indices, float diameter = 1, float height = 1, size_t tessellation = 32, bool rhcoords = true); - static void __cdecl CreateTorus (std::vector& vertices, std::vector& indices, float diameter = 1, float thickness = 0.333f, size_t tessellation = 32, bool rhcoords = true); - static void __cdecl CreateTetrahedron (std::vector& vertices, std::vector& indices, float size = 1, bool rhcoords = true); - static void __cdecl CreateOctahedron (std::vector& vertices, std::vector& indices, float size = 1, bool rhcoords = true); - static void __cdecl CreateDodecahedron (std::vector& vertices, std::vector& indices, float size = 1, bool rhcoords = true); - static void __cdecl CreateIcosahedron (std::vector& vertices, std::vector& indices, float size = 1, bool rhcoords = true); - static void __cdecl CreateTeapot (std::vector& vertices, std::vector& indices, float size = 1, size_t tessellation = 8, bool rhcoords = true); + // Factory methods. + static std::unique_ptr __cdecl CreateCube( + _In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); + static std::unique_ptr __cdecl CreateBox(_In_ ID3D11DeviceContext* deviceContext, + const XMFLOAT3& size, bool rhcoords = true, + bool invertn = false); + static std::unique_ptr __cdecl CreateSphere( + _In_ ID3D11DeviceContext* deviceContext, float diameter = 1, size_t tessellation = 16, bool rhcoords = true, + bool invertn = false); + static std::unique_ptr __cdecl CreateGeoSphere( + _In_ ID3D11DeviceContext* deviceContext, float diameter = 1, size_t tessellation = 3, bool rhcoords = true); + static std::unique_ptr __cdecl CreateCylinder( + _In_ ID3D11DeviceContext* deviceContext, float height = 1, float diameter = 1, size_t tessellation = 32, + bool rhcoords = true); + static std::unique_ptr __cdecl CreateCone( + _In_ ID3D11DeviceContext* deviceContext, float diameter = 1, float height = 1, size_t tessellation = 32, + bool rhcoords = true); + static std::unique_ptr __cdecl CreateTorus( + _In_ ID3D11DeviceContext* deviceContext, float diameter = 1, float thickness = 0.333f, + size_t tessellation = 32, bool rhcoords = true); + static std::unique_ptr __cdecl CreateTetrahedron( + _In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); + static std::unique_ptr __cdecl CreateOctahedron( + _In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); + static std::unique_ptr __cdecl CreateDodecahedron( + _In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); + static std::unique_ptr __cdecl CreateIcosahedron( + _In_ ID3D11DeviceContext* deviceContext, float size = 1, bool rhcoords = true); + static std::unique_ptr __cdecl CreateTeapot( + _In_ ID3D11DeviceContext* deviceContext, float size = 1, size_t tessellation = 8, bool rhcoords = true); + static std::unique_ptr __cdecl CreateCustom( + _In_ ID3D11DeviceContext* deviceContext, const std::vector& vertices, + const std::vector& indices); - // Draw the primitive. - void XM_CALLCONV Draw(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, FXMVECTOR color = Colors::White, _In_opt_ ID3D11ShaderResourceView* texture = nullptr, bool wireframe = false, - _In_opt_ std::function setCustomState = nullptr ); + static void __cdecl CreateCube(std::vector& vertices, std::vector& indices, + float size = 1, bool rhcoords = true); + static void __cdecl CreateBox(std::vector& vertices, std::vector& indices, + const XMFLOAT3& size, bool rhcoords = true, bool invertn = false); + static void __cdecl CreateSphere(std::vector& vertices, + std::vector& indices, float diameter = 1, size_t tessellation = 16, + bool rhcoords = true, bool invertn = false); + static void __cdecl CreateGeoSphere(std::vector& vertices, + std::vector& indices, float diameter = 1, size_t tessellation = 3, + bool rhcoords = true); + static void __cdecl CreateCylinder(std::vector& vertices, + std::vector& indices, float height = 1, float diameter = 1, + size_t tessellation = 32, bool rhcoords = true); + static void __cdecl CreateCone(std::vector& vertices, std::vector& indices, + float diameter = 1, float height = 1, size_t tessellation = 32, + bool rhcoords = true); + static void __cdecl CreateTorus(std::vector& vertices, + std::vector& indices, float diameter = 1, float thickness = 0.333f, + size_t tessellation = 32, bool rhcoords = true); + static void __cdecl CreateTetrahedron(std::vector& vertices, + std::vector& indices, float size = 1, bool rhcoords = true); + static void __cdecl CreateOctahedron(std::vector& vertices, + std::vector& indices, float size = 1, bool rhcoords = true); + static void __cdecl CreateDodecahedron(std::vector& vertices, + std::vector& indices, float size = 1, bool rhcoords = true); + static void __cdecl CreateIcosahedron(std::vector& vertices, + std::vector& indices, float size = 1, bool rhcoords = true); + static void __cdecl CreateTeapot(std::vector& vertices, + std::vector& indices, float size = 1, size_t tessellation = 8, + bool rhcoords = true); - // Draw the primitive using a custom effect. - void __cdecl Draw( _In_ IEffect* effect, _In_ ID3D11InputLayout* inputLayout, bool alpha = false, bool wireframe = false, - _In_opt_ std::function setCustomState = nullptr ); + // Draw the primitive. + void XM_CALLCONV Draw(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, FXMVECTOR color = Colors::White, + _In_opt_ ID3D11ShaderResourceView* texture = nullptr, bool wireframe = false, + _In_opt_ std::function setCustomState = nullptr); - // Create input layout for drawing with a custom effect. - void __cdecl CreateInputLayout( _In_ IEffect* effect, _Outptr_ ID3D11InputLayout** inputLayout ); - - private: - GeometricPrimitive(); + // Draw the primitive using a custom effect. + void __cdecl Draw(_In_ IEffect* effect, _In_ ID3D11InputLayout* inputLayout, bool alpha = false, + bool wireframe = false, + _In_opt_ std::function setCustomState = nullptr); - // Private implementation. - class Impl; + // Create input layout for drawing with a custom effect. + void __cdecl CreateInputLayout(_In_ IEffect* effect, _Outptr_ ID3D11InputLayout** inputLayout); - std::unique_ptr pImpl; + private: + GeometricPrimitive(); - // Prevent copying. - GeometricPrimitive(GeometricPrimitive const&) DIRECTX_CTOR_DELETE - GeometricPrimitive& operator= (GeometricPrimitive const&) DIRECTX_CTOR_DELETE - }; + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Prevent copying. + GeometricPrimitive(GeometricPrimitive const&) DIRECTX_CTOR_DELETE + GeometricPrimitive& operator=(GeometricPrimitive const&) DIRECTX_CTOR_DELETE + }; } diff --git a/Windows/DirectXTK/Model.h b/Windows/DirectXTK/Model.h index 75fd90f..153cbcd 100644 --- a/Windows/DirectXTK/Model.h +++ b/Windows/DirectXTK/Model.h @@ -47,117 +47,140 @@ namespace DirectX { - #if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) +#if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) #define XM_CALLCONV __fastcall typedef const XMVECTOR& HXMVECTOR; typedef const XMMATRIX& FXMMATRIX; - #endif +#endif - class IEffect; - class IEffectFactory; - class CommonStates; - class ModelMesh; + class IEffect; + class IEffectFactory; + class CommonStates; + class ModelMesh; - //---------------------------------------------------------------------------------- - // Each mesh part is a submesh with a single effect - class ModelMeshPart - { - public: - ModelMeshPart(); - virtual ~ModelMeshPart(); + //---------------------------------------------------------------------------------- + // Each mesh part is a submesh with a single effect + class ModelMeshPart + { + public: + ModelMeshPart(); + virtual ~ModelMeshPart(); - uint32_t indexCount; - uint32_t startIndex; - uint32_t vertexOffset; - uint32_t vertexStride; - D3D_PRIMITIVE_TOPOLOGY primitiveType; - DXGI_FORMAT indexFormat; - Microsoft::WRL::ComPtr inputLayout; - Microsoft::WRL::ComPtr indexBuffer; - Microsoft::WRL::ComPtr vertexBuffer; - std::shared_ptr effect; - std::shared_ptr> vbDecl; - bool isAlpha; + uint32_t indexCount; + uint32_t startIndex; + uint32_t vertexOffset; + uint32_t vertexStride; + D3D_PRIMITIVE_TOPOLOGY primitiveType; + DXGI_FORMAT indexFormat; + Microsoft::WRL::ComPtr inputLayout; + Microsoft::WRL::ComPtr indexBuffer; + Microsoft::WRL::ComPtr vertexBuffer; + std::shared_ptr effect; + std::shared_ptr> vbDecl; + bool isAlpha; - typedef std::vector> Collection; + typedef std::vector> Collection; - // Draw mesh part with custom effect - void __cdecl Draw( _In_ ID3D11DeviceContext* deviceContext, _In_ IEffect* ieffect, _In_ ID3D11InputLayout* iinputLayout, - _In_opt_ std::function setCustomState = nullptr ) const; + // Draw mesh part with custom effect + void __cdecl Draw(_In_ ID3D11DeviceContext* deviceContext, _In_ IEffect* ieffect, + _In_ ID3D11InputLayout* iinputLayout, + _In_opt_ std::function setCustomState = nullptr) const; - // Create input layout for drawing with a custom effect. - void __cdecl CreateInputLayout( _In_ ID3D11Device* d3dDevice, _In_ IEffect* ieffect, _Outptr_ ID3D11InputLayout** iinputLayout ); + // Create input layout for drawing with a custom effect. + void __cdecl CreateInputLayout(_In_ ID3D11Device* d3dDevice, _In_ IEffect* ieffect, + _Outptr_ ID3D11InputLayout** iinputLayout); - // Change effect used by part and regenerate input layout (be sure to call Model::Modified as well) - void __cdecl ModifyEffect( _In_ ID3D11Device* d3dDevice, _In_ std::shared_ptr& ieffect, bool isalpha = false ); - }; + // Change effect used by part and regenerate input layout (be sure to call Model::Modified as well) + void __cdecl ModifyEffect(_In_ ID3D11Device* d3dDevice, _In_ std::shared_ptr& ieffect, + bool isalpha = false); + }; - //---------------------------------------------------------------------------------- - // A mesh consists of one or more model mesh parts - class ModelMesh - { - public: - ModelMesh(); - virtual ~ModelMesh(); + //---------------------------------------------------------------------------------- + // A mesh consists of one or more model mesh parts + class ModelMesh + { + public: + ModelMesh(); + virtual ~ModelMesh(); - BoundingSphere boundingSphere; - BoundingBox boundingBox; - ModelMeshPart::Collection meshParts; - std::wstring name; - bool ccw; - bool pmalpha; + BoundingSphere boundingSphere; + BoundingBox boundingBox; + ModelMeshPart::Collection meshParts; + std::wstring name; + bool ccw; + bool pmalpha; - typedef std::vector> Collection; + typedef std::vector> Collection; - // Setup states for drawing mesh - void __cdecl PrepareForRendering( _In_ ID3D11DeviceContext* deviceContext, CommonStates& states, bool alpha = false, bool wireframe = false ) const; + // Setup states for drawing mesh + void __cdecl PrepareForRendering(_In_ ID3D11DeviceContext* deviceContext, CommonStates& states, + bool alpha = false, bool wireframe = false) const; - // Draw the mesh - void XM_CALLCONV Draw( _In_ ID3D11DeviceContext* deviceContext, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, - bool alpha = false, _In_opt_ std::function setCustomState = nullptr ) const; - }; + // Draw the mesh + void XM_CALLCONV Draw(_In_ ID3D11DeviceContext* deviceContext, FXMMATRIX world, CXMMATRIX view, + CXMMATRIX projection, + bool alpha = false, + _In_opt_ std::function setCustomState = nullptr) const; + }; - //---------------------------------------------------------------------------------- - // A model consists of one or more meshes - class Model - { - public: - virtual ~Model(); + //---------------------------------------------------------------------------------- + // A model consists of one or more meshes + class Model + { + public: + virtual ~Model(); - ModelMesh::Collection meshes; - std::wstring name; + ModelMesh::Collection meshes; + std::wstring name; - // Draw all the meshes in the model - void XM_CALLCONV Draw( _In_ ID3D11DeviceContext* deviceContext, CommonStates& states, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, - bool wireframe = false, _In_opt_ std::function setCustomState = nullptr ) const; + // Draw all the meshes in the model + void XM_CALLCONV Draw(_In_ ID3D11DeviceContext* deviceContext, CommonStates& states, FXMMATRIX world, + CXMMATRIX view, CXMMATRIX projection, + bool wireframe = false, + _In_opt_ std::function setCustomState = nullptr) const; - // Notify model that effects, parts list, or mesh list has changed - void __cdecl Modified() { mEffectCache.clear(); } + // Notify model that effects, parts list, or mesh list has changed + void __cdecl Modified() { mEffectCache.clear(); } - // Update all effects used by the model - void __cdecl UpdateEffects( _In_ std::function setEffect ); + // Update all effects used by the model + void __cdecl UpdateEffects(_In_ std::function setEffect); - // Loads a model from a Visual Studio Starter Kit .CMO file - static std::unique_ptr __cdecl CreateFromCMO( _In_ ID3D11Device* d3dDevice, _In_reads_bytes_(dataSize) const uint8_t* meshData, size_t dataSize, - _In_ IEffectFactory& fxFactory, bool ccw = true, bool pmalpha = false ); - static std::unique_ptr __cdecl CreateFromCMO( _In_ ID3D11Device* d3dDevice, _In_z_ const wchar_t* szFileName, - _In_ IEffectFactory& fxFactory, bool ccw = true, bool pmalpha = false ); + // Loads a model from a Visual Studio Starter Kit .CMO file + static std::unique_ptr __cdecl CreateFromCMO(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(dataSize) const uint8_t* meshData, + size_t dataSize, + _In_ IEffectFactory& fxFactory, bool ccw = true, + bool pmalpha = false); + static std::unique_ptr __cdecl CreateFromCMO(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _In_ IEffectFactory& fxFactory, bool ccw = true, + bool pmalpha = false); - // Loads a model from a DirectX SDK .SDKMESH file - static std::unique_ptr __cdecl CreateFromSDKMESH( _In_ ID3D11Device* d3dDevice, _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize, - _In_ IEffectFactory& fxFactory, bool ccw = false, bool pmalpha = false ); - static std::unique_ptr __cdecl CreateFromSDKMESH( _In_ ID3D11Device* d3dDevice, _In_z_ const wchar_t* szFileName, - _In_ IEffectFactory& fxFactory, bool ccw = false, bool pmalpha = false ); + // Loads a model from a DirectX SDK .SDKMESH file + static std::unique_ptr __cdecl CreateFromSDKMESH(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(dataSize) const uint8_t* meshData, + _In_ size_t dataSize, + _In_ IEffectFactory& fxFactory, bool ccw = false, + bool pmalpha = false); + static std::unique_ptr __cdecl CreateFromSDKMESH(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _In_ IEffectFactory& fxFactory, bool ccw = false, + bool pmalpha = false); - // Loads a model from a .VBO file - static std::unique_ptr __cdecl CreateFromVBO( _In_ ID3D11Device* d3dDevice, _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize, - _In_opt_ std::shared_ptr ieffect = nullptr, bool ccw = false, bool pmalpha = false ); - static std::unique_ptr __cdecl CreateFromVBO( _In_ ID3D11Device* d3dDevice, _In_z_ const wchar_t* szFileName, - _In_opt_ std::shared_ptr ieffect = nullptr, bool ccw = false, bool pmalpha = false ); + // Loads a model from a .VBO file + static std::unique_ptr __cdecl CreateFromVBO(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(dataSize) const uint8_t* meshData, + _In_ size_t dataSize, + _In_opt_ std::shared_ptr ieffect = nullptr, + bool ccw = false, bool pmalpha = false); + static std::unique_ptr __cdecl CreateFromVBO(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _In_opt_ std::shared_ptr ieffect = nullptr, + bool ccw = false, bool pmalpha = false); - private: - std::set mEffectCache; - }; - } \ No newline at end of file + private: + std::set mEffectCache; + }; +} diff --git a/Windows/DirectXTK/PrimitiveBatch.h b/Windows/DirectXTK/PrimitiveBatch.h index c2e7965..b870c05 100644 --- a/Windows/DirectXTK/PrimitiveBatch.h +++ b/Windows/DirectXTK/PrimitiveBatch.h @@ -41,118 +41,129 @@ namespace DirectX { - namespace Internal - { - // Base class, not to be used directly: clients should access this via the derived PrimitiveBatch. - class PrimitiveBatchBase - { - protected: - PrimitiveBatchBase(_In_ ID3D11DeviceContext* deviceContext, size_t maxIndices, size_t maxVertices, size_t vertexSize); - PrimitiveBatchBase(PrimitiveBatchBase&& moveFrom); - PrimitiveBatchBase& operator= (PrimitiveBatchBase&& moveFrom); - virtual ~PrimitiveBatchBase(); + namespace Internal + { + // Base class, not to be used directly: clients should access this via the derived PrimitiveBatch. + class PrimitiveBatchBase + { + protected: + PrimitiveBatchBase(_In_ ID3D11DeviceContext* deviceContext, size_t maxIndices, size_t maxVertices, + size_t vertexSize); + PrimitiveBatchBase(PrimitiveBatchBase&& moveFrom); + PrimitiveBatchBase& operator=(PrimitiveBatchBase&& moveFrom); + virtual ~PrimitiveBatchBase(); - public: - // Begin/End a batch of primitive drawing operations. - void __cdecl Begin(); - void __cdecl End(); + public: + // Begin/End a batch of primitive drawing operations. + void __cdecl Begin(); + void __cdecl End(); - protected: - // Internal, untyped drawing method. - void __cdecl Draw(D3D11_PRIMITIVE_TOPOLOGY topology, bool isIndexed, _In_opt_count_(indexCount) uint16_t const* indices, size_t indexCount, size_t vertexCount, _Out_ void** pMappedVertices); + protected: + // Internal, untyped drawing method. + void __cdecl Draw(D3D11_PRIMITIVE_TOPOLOGY topology, bool isIndexed, + _In_opt_count_(indexCount) uint16_t const* indices, size_t indexCount, size_t vertexCount, + _Out_ void** pMappedVertices); - private: - // Private implementation. - class Impl; + private: + // Private implementation. + class Impl; - std::unique_ptr pImpl; + std::unique_ptr pImpl; - // Prevent copying. - PrimitiveBatchBase(PrimitiveBatchBase const&) DIRECTX_CTOR_DELETE - PrimitiveBatchBase& operator= (PrimitiveBatchBase const&) DIRECTX_CTOR_DELETE - }; - } + // Prevent copying. + PrimitiveBatchBase(PrimitiveBatchBase const&) DIRECTX_CTOR_DELETE + PrimitiveBatchBase& operator=(PrimitiveBatchBase const&) DIRECTX_CTOR_DELETE + }; + } - // Template makes the API typesafe, eg. PrimitiveBatch. - template - class PrimitiveBatch : public Internal::PrimitiveBatchBase - { - static const size_t DefaultBatchSize = 2048; + // Template makes the API typesafe, eg. PrimitiveBatch. + template + class PrimitiveBatch : public Internal::PrimitiveBatchBase + { + static const size_t DefaultBatchSize = 2048; - public: - PrimitiveBatch(_In_ ID3D11DeviceContext* deviceContext, size_t maxIndices = DefaultBatchSize * 3, size_t maxVertices = DefaultBatchSize) - : PrimitiveBatchBase(deviceContext, maxIndices, maxVertices, sizeof(TVertex)) - { } + public: + PrimitiveBatch(_In_ ID3D11DeviceContext* deviceContext, size_t maxIndices = DefaultBatchSize * 3, + size_t maxVertices = DefaultBatchSize) + : PrimitiveBatchBase(deviceContext, maxIndices, maxVertices, sizeof(TVertex)) + { + } - PrimitiveBatch(PrimitiveBatch&& moveFrom) - : PrimitiveBatchBase(std::move(moveFrom)) - { } + PrimitiveBatch(PrimitiveBatch&& moveFrom) + : PrimitiveBatchBase(std::move(moveFrom)) + { + } - PrimitiveBatch& __cdecl operator= (PrimitiveBatch&& moveFrom) - { - PrimitiveBatchBase::operator=(std::move(moveFrom)); - return *this; - } + PrimitiveBatch& __cdecl operator=(PrimitiveBatch&& moveFrom) + { + PrimitiveBatchBase::operator=(std::move(moveFrom)); + return *this; + } - // Similar to the D3D9 API DrawPrimitiveUP. - void __cdecl Draw(D3D11_PRIMITIVE_TOPOLOGY topology, _In_reads_(vertexCount) TVertex const* vertices, size_t vertexCount) - { - void* mappedVertices; + // Similar to the D3D9 API DrawPrimitiveUP. + void __cdecl Draw(D3D11_PRIMITIVE_TOPOLOGY topology, _In_reads_(vertexCount) TVertex const* vertices, + size_t vertexCount) + { + void* mappedVertices; - PrimitiveBatchBase::Draw(topology, false, nullptr, 0, vertexCount, &mappedVertices); + PrimitiveBatchBase::Draw(topology, false, nullptr, 0, vertexCount, &mappedVertices); - memcpy(mappedVertices, vertices, vertexCount * sizeof(TVertex)); - } + memcpy(mappedVertices, vertices, vertexCount * sizeof(TVertex)); + } - // Similar to the D3D9 API DrawIndexedPrimitiveUP. - void __cdecl DrawIndexed(D3D11_PRIMITIVE_TOPOLOGY topology, _In_reads_(indexCount) uint16_t const* indices, size_t indexCount, _In_reads_(vertexCount) TVertex const* vertices, size_t vertexCount) - { - void* mappedVertices; + // Similar to the D3D9 API DrawIndexedPrimitiveUP. + void __cdecl DrawIndexed(D3D11_PRIMITIVE_TOPOLOGY topology, _In_reads_(indexCount) uint16_t const* indices, + size_t indexCount, _In_reads_(vertexCount) TVertex const* vertices, size_t vertexCount) + { + void* mappedVertices; - PrimitiveBatchBase::Draw(topology, true, indices, indexCount, vertexCount, &mappedVertices); + PrimitiveBatchBase::Draw(topology, true, indices, indexCount, vertexCount, &mappedVertices); - memcpy(mappedVertices, vertices, vertexCount * sizeof(TVertex)); - } + memcpy(mappedVertices, vertices, vertexCount * sizeof(TVertex)); + } - void __cdecl DrawLine(TVertex const& v1, TVertex const& v2) - { - TVertex* mappedVertices; + void __cdecl DrawLine(TVertex const& v1, TVertex const& v2) + { + TVertex* mappedVertices; - PrimitiveBatchBase::Draw(D3D11_PRIMITIVE_TOPOLOGY_LINELIST, false, nullptr, 0, 2, reinterpret_cast(&mappedVertices)); + PrimitiveBatchBase::Draw(D3D11_PRIMITIVE_TOPOLOGY_LINELIST, false, nullptr, 0, 2, + reinterpret_cast(&mappedVertices)); - mappedVertices[0] = v1; - mappedVertices[1] = v2; - } + mappedVertices[0] = v1; + mappedVertices[1] = v2; + } - void __cdecl DrawTriangle(TVertex const& v1, TVertex const& v2, TVertex const& v3) - { - TVertex* mappedVertices; + void __cdecl DrawTriangle(TVertex const& v1, TVertex const& v2, TVertex const& v3) + { + TVertex* mappedVertices; - PrimitiveBatchBase::Draw(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, false, nullptr, 0, 3, reinterpret_cast(&mappedVertices)); + PrimitiveBatchBase::Draw(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, false, nullptr, 0, 3, + reinterpret_cast(&mappedVertices)); - mappedVertices[0] = v1; - mappedVertices[1] = v2; - mappedVertices[2] = v3; - } + mappedVertices[0] = v1; + mappedVertices[1] = v2; + mappedVertices[2] = v3; + } - void __cdecl DrawQuad(TVertex const& v1, TVertex const& v2, TVertex const& v3, TVertex const& v4) - { - static const uint16_t quadIndices[] = { 0, 1, 2, 0, 2, 3 }; + void __cdecl DrawQuad(TVertex const& v1, TVertex const& v2, TVertex const& v3, TVertex const& v4) + { + static const uint16_t quadIndices[] = {0, 1, 2, 0, 2, 3}; - TVertex* mappedVertices; + TVertex* mappedVertices; - PrimitiveBatchBase::Draw(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, true, quadIndices, 6, 4, reinterpret_cast(&mappedVertices)); + PrimitiveBatchBase::Draw(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, true, quadIndices, 6, 4, + reinterpret_cast(&mappedVertices)); - mappedVertices[0] = v1; - mappedVertices[1] = v2; - mappedVertices[2] = v3; - mappedVertices[3] = v4; - } - }; + mappedVertices[0] = v1; + mappedVertices[1] = v2; + mappedVertices[2] = v3; + mappedVertices[3] = v4; + } + }; } diff --git a/Windows/DirectXTK/ScreenGrab.h b/Windows/DirectXTK/ScreenGrab.h index 2a1b661..62e2e6b 100644 --- a/Windows/DirectXTK/ScreenGrab.h +++ b/Windows/DirectXTK/ScreenGrab.h @@ -47,18 +47,19 @@ namespace DirectX { - HRESULT __cdecl SaveDDSTextureToFile( _In_ ID3D11DeviceContext* pContext, - _In_ ID3D11Resource* pSource, - _In_z_ LPCWSTR fileName ); + HRESULT __cdecl SaveDDSTextureToFile(_In_ ID3D11DeviceContext* pContext, + _In_ ID3D11Resource* pSource, + _In_z_ LPCWSTR fileName); #if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (_WIN32_WINNT > _WIN32_WINNT_WIN8) - HRESULT __cdecl SaveWICTextureToFile( _In_ ID3D11DeviceContext* pContext, - _In_ ID3D11Resource* pSource, - _In_ REFGUID guidContainerFormat, - _In_z_ LPCWSTR fileName, - _In_opt_ const GUID* targetFormat = nullptr, - _In_opt_ std::function setCustomProps = nullptr ); + HRESULT __cdecl SaveWICTextureToFile(_In_ ID3D11DeviceContext* pContext, + _In_ ID3D11Resource* pSource, + _In_ REFGUID guidContainerFormat, + _In_z_ LPCWSTR fileName, + _In_opt_ const GUID* targetFormat = nullptr, + _In_opt_ std::function setCustomProps + = nullptr); #endif -} \ No newline at end of file +} diff --git a/Windows/DirectXTK/SimpleMath.h b/Windows/DirectXTK/SimpleMath.h index c0cf1c8..dbab2dd 100644 --- a/Windows/DirectXTK/SimpleMath.h +++ b/Windows/DirectXTK/SimpleMath.h @@ -28,900 +28,1230 @@ namespace DirectX { + namespace SimpleMath + { + struct Vector4; + struct Matrix; + struct Quaternion; + struct Plane; + + //------------------------------------------------------------------------------ + // 2D vector + struct Vector2 : public XMFLOAT2 + { + Vector2() : XMFLOAT2(0.f, 0.f) + { + } + + explicit Vector2(float x) : XMFLOAT2(x, x) + { + } -namespace SimpleMath -{ - -struct Vector4; -struct Matrix; -struct Quaternion; -struct Plane; - -//------------------------------------------------------------------------------ -// 2D vector -struct Vector2 : public XMFLOAT2 -{ - Vector2() : XMFLOAT2(0.f, 0.f) {} - explicit Vector2(float x) : XMFLOAT2( x, x ) {} - Vector2(float _x, float _y) : XMFLOAT2(_x, _y) {} - explicit Vector2(_In_reads_(2) const float *pArray) : XMFLOAT2(pArray) {} - Vector2(FXMVECTOR V) { XMStoreFloat2( this, V ); } - Vector2(const XMFLOAT2& V) { this->x = V.x; this->y = V.y; } - - operator XMVECTOR() const { return XMLoadFloat2( this ); } - - // Comparison operators - bool operator == ( const Vector2& V ) const; - bool operator != ( const Vector2& V ) const; - - // Assignment operators - Vector2& operator= (const Vector2& V) { x = V.x; y = V.y; return *this; } - Vector2& operator= (const XMFLOAT2& V) { x = V.x; y = V.y; return *this; } - Vector2& operator+= (const Vector2& V); - Vector2& operator-= (const Vector2& V); - Vector2& operator*= (const Vector2& V); - Vector2& operator*= (float S); - Vector2& operator/= (float S); - - // Unary operators - Vector2 operator+ () const { return *this; } - Vector2 operator- () const { return Vector2(-x, -y); } - - // Vector operations - bool InBounds( const Vector2& Bounds ) const; - - float Length() const; - float LengthSquared() const; - - float Dot( const Vector2& V ) const; - void Cross( const Vector2& V, Vector2& result ) const; - Vector2 Cross( const Vector2& V ) const; - - void Normalize(); - void Normalize( Vector2& result ) const; - - void Clamp( const Vector2& vmin, const Vector2& vmax ); - void Clamp( const Vector2& vmin, const Vector2& vmax, Vector2& result ) const; - - // Static functions - static float Distance( const Vector2& v1, const Vector2& v2 ); - static float DistanceSquared( const Vector2& v1, const Vector2& v2 ); - - static void Min( const Vector2& v1, const Vector2& v2, Vector2& result ); - static Vector2 Min( const Vector2& v1, const Vector2& v2 ); - - static void Max( const Vector2& v1, const Vector2& v2, Vector2& result ); - static Vector2 Max( const Vector2& v1, const Vector2& v2 ); - - static void Lerp( const Vector2& v1, const Vector2& v2, float t, Vector2& result ); - static Vector2 Lerp( const Vector2& v1, const Vector2& v2, float t ); - - static void SmoothStep( const Vector2& v1, const Vector2& v2, float t, Vector2& result ); - static Vector2 SmoothStep( const Vector2& v1, const Vector2& v2, float t ); - - static void Barycentric( const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result ); - static Vector2 Barycentric( const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g ); - - static void CatmullRom( const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result ); - static Vector2 CatmullRom( const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t ); - - static void Hermite( const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result ); - static Vector2 Hermite( const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t ); - - static void Reflect( const Vector2& ivec, const Vector2& nvec, Vector2& result ); - static Vector2 Reflect( const Vector2& ivec, const Vector2& nvec ); - - static void Refract( const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result ); - static Vector2 Refract( const Vector2& ivec, const Vector2& nvec, float refractionIndex ); - - static void Transform( const Vector2& v, const Quaternion& quat, Vector2& result ); - static Vector2 Transform( const Vector2& v, const Quaternion& quat ); - - static void Transform( const Vector2& v, const Matrix& m, Vector2& result ); - static Vector2 Transform( const Vector2& v, const Matrix& m ); - static void Transform( _In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray ); - - static void Transform( const Vector2& v, const Matrix& m, Vector4& result ); - static void Transform( _In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray ); - - static void TransformNormal( const Vector2& v, const Matrix& m, Vector2& result ); - static Vector2 TransformNormal( const Vector2& v, const Matrix& m ); - static void TransformNormal( _In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray ); - - // Constants - static const Vector2 Zero; - static const Vector2 One; - static const Vector2 UnitX; - static const Vector2 UnitY; -}; + Vector2(float _x, float _y) : XMFLOAT2(_x, _y) + { + } + + explicit Vector2(_In_reads_(2) const float* pArray) : XMFLOAT2(pArray) + { + } + + Vector2(FXMVECTOR V) { XMStoreFloat2(this, V); } + + Vector2(const XMFLOAT2& V) + { + this->x = V.x; + this->y = V.y; + } + + operator XMVECTOR() const { return XMLoadFloat2(this); } + + // Comparison operators + bool operator ==(const Vector2& V) const; + bool operator !=(const Vector2& V) const; + + // Assignment operators + Vector2& operator=(const Vector2& V) + { + x = V.x; + y = V.y; + return *this; + } + + Vector2& operator=(const XMFLOAT2& V) + { + x = V.x; + y = V.y; + return *this; + } + + Vector2& operator+=(const Vector2& V); + Vector2& operator-=(const Vector2& V); + Vector2& operator*=(const Vector2& V); + Vector2& operator*=(float S); + Vector2& operator/=(float S); + + // Unary operators + Vector2 operator+() const { return *this; } + Vector2 operator-() const { return Vector2(-x, -y); } + + // Vector operations + bool InBounds(const Vector2& Bounds) const; + + float Length() const; + float LengthSquared() const; + + float Dot(const Vector2& V) const; + void Cross(const Vector2& V, Vector2& result) const; + Vector2 Cross(const Vector2& V) const; + + void Normalize(); + void Normalize(Vector2& result) const; + + void Clamp(const Vector2& vmin, const Vector2& vmax); + void Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const; + + // Static functions + static float Distance(const Vector2& v1, const Vector2& v2); + static float DistanceSquared(const Vector2& v1, const Vector2& v2); + + static void Min(const Vector2& v1, const Vector2& v2, Vector2& result); + static Vector2 Min(const Vector2& v1, const Vector2& v2); + + static void Max(const Vector2& v1, const Vector2& v2, Vector2& result); + static Vector2 Max(const Vector2& v1, const Vector2& v2); + + static void Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result); + static Vector2 Lerp(const Vector2& v1, const Vector2& v2, float t); + + static void SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result); + static Vector2 SmoothStep(const Vector2& v1, const Vector2& v2, float t); + + static void Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, + Vector2& result); + static Vector2 Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g); + + static void CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, + Vector2& result); + static Vector2 CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t); + + static void Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, + Vector2& result); + static Vector2 Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t); + + static void Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result); + static Vector2 Reflect(const Vector2& ivec, const Vector2& nvec); + + static void Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result); + static Vector2 Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex); + + static void Transform(const Vector2& v, const Quaternion& quat, Vector2& result); + static Vector2 Transform(const Vector2& v, const Quaternion& quat); + + static void Transform(const Vector2& v, const Matrix& m, Vector2& result); + static Vector2 Transform(const Vector2& v, const Matrix& m); + static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector2* resultArray); + + static void Transform(const Vector2& v, const Matrix& m, Vector4& result); + static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector4* resultArray); + + static void TransformNormal(const Vector2& v, const Matrix& m, Vector2& result); + static Vector2 TransformNormal(const Vector2& v, const Matrix& m); + static void TransformNormal(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector2* resultArray); + + // Constants + static const Vector2 Zero; + static const Vector2 One; + static const Vector2 UnitX; + static const Vector2 UnitY; + }; + + // Binary operators + Vector2 operator+(const Vector2& V1, const Vector2& V2); + Vector2 operator-(const Vector2& V1, const Vector2& V2); + Vector2 operator*(const Vector2& V1, const Vector2& V2); + Vector2 operator*(const Vector2& V, float S); + Vector2 operator/(const Vector2& V1, const Vector2& V2); + Vector2 operator*(float S, const Vector2& V); + + //------------------------------------------------------------------------------ + // 3D vector + struct Vector3 : public XMFLOAT3 + { + Vector3() : XMFLOAT3(0.f, 0.f, 0.f) + { + } + + explicit Vector3(float x) : XMFLOAT3(x, x, x) + { + } -// Binary operators -Vector2 operator+ (const Vector2& V1, const Vector2& V2); -Vector2 operator- (const Vector2& V1, const Vector2& V2); -Vector2 operator* (const Vector2& V1, const Vector2& V2); -Vector2 operator* (const Vector2& V, float S); -Vector2 operator/ (const Vector2& V1, const Vector2& V2); -Vector2 operator* (float S, const Vector2& V); - -//------------------------------------------------------------------------------ -// 3D vector -struct Vector3 : public XMFLOAT3 -{ - Vector3() : XMFLOAT3(0.f, 0.f, 0.f) {} - explicit Vector3(float x) : XMFLOAT3( x, x, x ) {} - Vector3(float _x, float _y, float _z) : XMFLOAT3(_x, _y, _z) {} - explicit Vector3(_In_reads_(3) const float *pArray) : XMFLOAT3(pArray) {} - Vector3(FXMVECTOR V) { XMStoreFloat3( this, V ); } - Vector3(const XMFLOAT3& V) { this->x = V.x; this->y = V.y; this->z = V.z; } - - operator XMVECTOR() const { return XMLoadFloat3( this ); } - - // Comparison operators - bool operator == ( const Vector3& V ) const; - bool operator != ( const Vector3& V ) const; - - // Assignment operators - Vector3& operator= (const Vector3& V) { x = V.x; y = V.y; z = V.z; return *this; } - Vector3& operator= (const XMFLOAT3& V) { x = V.x; y = V.y; z = V.z; return *this; } - Vector3& operator+= (const Vector3& V); - Vector3& operator-= (const Vector3& V); - Vector3& operator*= (const Vector3& V); - Vector3& operator*= (float S); - Vector3& operator/= (float S); - - // Unary operators - Vector3 operator+ () const { return *this; } - Vector3 operator- () const; - - // Vector operations - bool InBounds( const Vector3& Bounds ) const; - - float Length() const; - float LengthSquared() const; - - float Dot( const Vector3& V ) const; - void Cross( const Vector3& V, Vector3& result ) const; - Vector3 Cross( const Vector3& V ) const; - - void Normalize(); - void Normalize( Vector3& result ) const; - - void Clamp( const Vector3& vmin, const Vector3& vmax ); - void Clamp( const Vector3& vmin, const Vector3& vmax, Vector3& result ) const; - - // Static functions - static float Distance( const Vector3& v1, const Vector3& v2 ); - static float DistanceSquared( const Vector3& v1, const Vector3& v2 ); - - static void Min( const Vector3& v1, const Vector3& v2, Vector3& result ); - static Vector3 Min( const Vector3& v1, const Vector3& v2 ); - - static void Max( const Vector3& v1, const Vector3& v2, Vector3& result ); - static Vector3 Max( const Vector3& v1, const Vector3& v2 ); - - static void Lerp( const Vector3& v1, const Vector3& v2, float t, Vector3& result ); - static Vector3 Lerp( const Vector3& v1, const Vector3& v2, float t ); - - static void SmoothStep( const Vector3& v1, const Vector3& v2, float t, Vector3& result ); - static Vector3 SmoothStep( const Vector3& v1, const Vector3& v2, float t ); - - static void Barycentric( const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, Vector3& result ); - static Vector3 Barycentric( const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g ); - - static void CatmullRom( const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, Vector3& result ); - static Vector3 CatmullRom( const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t ); - - static void Hermite( const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, Vector3& result ); - static Vector3 Hermite( const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t ); - - static void Reflect( const Vector3& ivec, const Vector3& nvec, Vector3& result ); - static Vector3 Reflect( const Vector3& ivec, const Vector3& nvec ); - - static void Refract( const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result ); - static Vector3 Refract( const Vector3& ivec, const Vector3& nvec, float refractionIndex ); - - static void Transform( const Vector3& v, const Quaternion& quat, Vector3& result ); - static Vector3 Transform( const Vector3& v, const Quaternion& quat ); - - static void Transform( const Vector3& v, const Matrix& m, Vector3& result ); - static Vector3 Transform( const Vector3& v, const Matrix& m ); - static void Transform( _In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector3* resultArray ); - - static void Transform( const Vector3& v, const Matrix& m, Vector4& result ); - static void Transform( _In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray ); - - static void TransformNormal( const Vector3& v, const Matrix& m, Vector3& result ); - static Vector3 TransformNormal( const Vector3& v, const Matrix& m ); - static void TransformNormal( _In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector3* resultArray ); - - // Constants - static const Vector3 Zero; - static const Vector3 One; - static const Vector3 UnitX; - static const Vector3 UnitY; - static const Vector3 UnitZ; - static const Vector3 Up; - static const Vector3 Down; - static const Vector3 Right; - static const Vector3 Left; - static const Vector3 Forward; - static const Vector3 Backward; -}; + Vector3(float _x, float _y, float _z) : XMFLOAT3(_x, _y, _z) + { + } -// Binary operators -Vector3 operator+ (const Vector3& V1, const Vector3& V2); -Vector3 operator- (const Vector3& V1, const Vector3& V2); -Vector3 operator* (const Vector3& V1, const Vector3& V2); -Vector3 operator* (const Vector3& V, float S); -Vector3 operator/ (const Vector3& V1, const Vector3& V2); -Vector3 operator* (float S, const Vector3& V); + explicit Vector3(_In_reads_(3) const float* pArray) : XMFLOAT3(pArray) + { + } -//------------------------------------------------------------------------------ -// 4D vector -struct Vector4 : public XMFLOAT4 -{ - Vector4() : XMFLOAT4(0.f, 0.f, 0.f, 0.f) {} - explicit Vector4(float x) : XMFLOAT4( x, x, x, x ) {} - Vector4(float _x, float _y, float _z, float _w) : XMFLOAT4(_x, _y, _z, _w) {} - explicit Vector4(_In_reads_(4) const float *pArray) : XMFLOAT4(pArray) {} - Vector4(FXMVECTOR V) { XMStoreFloat4( this, V ); } - Vector4(const XMFLOAT4& V) { this->x = V.x; this->y = V.y; this->z = V.z; this->w = V.w; } - - operator XMVECTOR() const { return XMLoadFloat4( this ); } - - // Comparison operators - bool operator == ( const Vector4& V ) const; - bool operator != ( const Vector4& V ) const; - - // Assignment operators - Vector4& operator= (const Vector4& V) { x = V.x; y = V.y; z = V.z; w = V.w; return *this; } - Vector4& operator= (const XMFLOAT4& V) { x = V.x; y = V.y; z = V.z; w = V.w; return *this; } - Vector4& operator+= (const Vector4& V); - Vector4& operator-= (const Vector4& V); - Vector4& operator*= (const Vector4& V); - Vector4& operator*= (float S); - Vector4& operator/= (float S); - - // Unary operators - Vector4 operator+ () const { return *this; } - Vector4 operator- () const; - - // Vector operations - bool InBounds( const Vector4& Bounds ) const; - - float Length() const; - float LengthSquared() const; - - float Dot( const Vector4& V ) const; - void Cross( const Vector4& v1, const Vector4& v2, Vector4& result ) const; - Vector4 Cross( const Vector4& v1, const Vector4& v2 ) const; - - void Normalize(); - void Normalize( Vector4& result ) const; - - void Clamp( const Vector4& vmin, const Vector4& vmax ); - void Clamp( const Vector4& vmin, const Vector4& vmax, Vector4& result ) const; - - // Static functions - static float Distance( const Vector4& v1, const Vector4& v2 ); - static float DistanceSquared( const Vector4& v1, const Vector4& v2 ); - - static void Min( const Vector4& v1, const Vector4& v2, Vector4& result ); - static Vector4 Min( const Vector4& v1, const Vector4& v2 ); - - static void Max( const Vector4& v1, const Vector4& v2, Vector4& result ); - static Vector4 Max( const Vector4& v1, const Vector4& v2 ); - - static void Lerp( const Vector4& v1, const Vector4& v2, float t, Vector4& result ); - static Vector4 Lerp( const Vector4& v1, const Vector4& v2, float t ); - - static void SmoothStep( const Vector4& v1, const Vector4& v2, float t, Vector4& result ); - static Vector4 SmoothStep( const Vector4& v1, const Vector4& v2, float t ); - - static void Barycentric( const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, Vector4& result ); - static Vector4 Barycentric( const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g ); - - static void CatmullRom( const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, Vector4& result ); - static Vector4 CatmullRom( const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t ); - - static void Hermite( const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, Vector4& result ); - static Vector4 Hermite( const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t ); - - static void Reflect( const Vector4& ivec, const Vector4& nvec, Vector4& result ); - static Vector4 Reflect( const Vector4& ivec, const Vector4& nvec ); - - static void Refract( const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result ); - static Vector4 Refract( const Vector4& ivec, const Vector4& nvec, float refractionIndex ); - - static void Transform( const Vector2& v, const Quaternion& quat, Vector4& result ); - static Vector4 Transform( const Vector2& v, const Quaternion& quat ); - - static void Transform( const Vector3& v, const Quaternion& quat, Vector4& result ); - static Vector4 Transform( const Vector3& v, const Quaternion& quat ); - - static void Transform( const Vector4& v, const Quaternion& quat, Vector4& result ); - static Vector4 Transform( const Vector4& v, const Quaternion& quat ); - - static void Transform( const Vector4& v, const Matrix& m, Vector4& result ); - static Vector4 Transform( const Vector4& v, const Matrix& m ); - static void Transform( _In_reads_(count) const Vector4* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray ); - - // Constants - static const Vector4 Zero; - static const Vector4 One; - static const Vector4 UnitX; - static const Vector4 UnitY; - static const Vector4 UnitZ; - static const Vector4 UnitW; -}; - -// Binary operators -Vector4 operator+ (const Vector4& V1, const Vector4& V2); -Vector4 operator- (const Vector4& V1, const Vector4& V2); -Vector4 operator* (const Vector4& V1, const Vector4& V2); -Vector4 operator* (const Vector4& V, float S); -Vector4 operator/ (const Vector4& V1, const Vector4& V2); -Vector4 operator* (float S, const Vector4& V); - -//------------------------------------------------------------------------------ -// 4x4 Matrix (assumes right-handed cooordinates) -struct Matrix : public XMFLOAT4X4 -{ - Matrix() : XMFLOAT4X4( 1.f, 0, 0, 0, - 0, 1.f, 0, 0, - 0, 0, 1.f, 0, - 0, 0, 0, 1.f ) {} - Matrix(float m00, float m01, float m02, float m03, - float m10, float m11, float m12, float m13, - float m20, float m21, float m22, float m23, - float m30, float m31, float m32, float m33) : XMFLOAT4X4(m00, m01, m02, m03, - m10, m11, m12, m13, - m20, m21, m22, m23, - m30, m31, m32, m33) {} - explicit Matrix( const Vector3& r0, const Vector3& r1, const Vector3& r2 ) : XMFLOAT4X4( r0.x, r0.y, r0.z, 0, - r1.x, r1.y, r1.z, 0, - r2.x, r2.y, r2.z, 0, - 0, 0, 0, 1.f ) {} - explicit Matrix( const Vector4& r0, const Vector4& r1, const Vector4& r2, const Vector4& r3 ) : XMFLOAT4X4( r0.x, r0.y, r0.z, r0.w, - r1.x, r1.y, r1.z, r1.w, - r2.x, r2.y, r2.z, r2.w, - r3.x, r3.y, r3.z, r3.w ) {} - Matrix(const XMFLOAT4X4& M) { memcpy_s(this, sizeof(float)*16, &M, sizeof(XMFLOAT4X4)); } - Matrix(const XMFLOAT3X3& M); - Matrix(const XMFLOAT4X3& M); + Vector3(FXMVECTOR V) { XMStoreFloat3(this, V); } + + Vector3(const XMFLOAT3& V) + { + this->x = V.x; + this->y = V.y; + this->z = V.z; + } + + operator XMVECTOR() const { return XMLoadFloat3(this); } + + // Comparison operators + bool operator ==(const Vector3& V) const; + bool operator !=(const Vector3& V) const; + + // Assignment operators + Vector3& operator=(const Vector3& V) + { + x = V.x; + y = V.y; + z = V.z; + return *this; + } + + Vector3& operator=(const XMFLOAT3& V) + { + x = V.x; + y = V.y; + z = V.z; + return *this; + } + + Vector3& operator+=(const Vector3& V); + Vector3& operator-=(const Vector3& V); + Vector3& operator*=(const Vector3& V); + Vector3& operator*=(float S); + Vector3& operator/=(float S); + + // Unary operators + Vector3 operator+() const { return *this; } + Vector3 operator-() const; + + // Vector operations + bool InBounds(const Vector3& Bounds) const; + + float Length() const; + float LengthSquared() const; + + float Dot(const Vector3& V) const; + void Cross(const Vector3& V, Vector3& result) const; + Vector3 Cross(const Vector3& V) const; + + void Normalize(); + void Normalize(Vector3& result) const; + + void Clamp(const Vector3& vmin, const Vector3& vmax); + void Clamp(const Vector3& vmin, const Vector3& vmax, Vector3& result) const; + + // Static functions + static float Distance(const Vector3& v1, const Vector3& v2); + static float DistanceSquared(const Vector3& v1, const Vector3& v2); + + static void Min(const Vector3& v1, const Vector3& v2, Vector3& result); + static Vector3 Min(const Vector3& v1, const Vector3& v2); + + static void Max(const Vector3& v1, const Vector3& v2, Vector3& result); + static Vector3 Max(const Vector3& v1, const Vector3& v2); + + static void Lerp(const Vector3& v1, const Vector3& v2, float t, Vector3& result); + static Vector3 Lerp(const Vector3& v1, const Vector3& v2, float t); + + static void SmoothStep(const Vector3& v1, const Vector3& v2, float t, Vector3& result); + static Vector3 SmoothStep(const Vector3& v1, const Vector3& v2, float t); + + static void Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, + Vector3& result); + static Vector3 Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g); + + static void CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, + Vector3& result); + static Vector3 CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t); + + static void Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, + Vector3& result); + static Vector3 Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t); + + static void Reflect(const Vector3& ivec, const Vector3& nvec, Vector3& result); + static Vector3 Reflect(const Vector3& ivec, const Vector3& nvec); + + static void Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result); + static Vector3 Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex); + + static void Transform(const Vector3& v, const Quaternion& quat, Vector3& result); + static Vector3 Transform(const Vector3& v, const Quaternion& quat); + + static void Transform(const Vector3& v, const Matrix& m, Vector3& result); + static Vector3 Transform(const Vector3& v, const Matrix& m); + static void Transform(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector3* resultArray); + + static void Transform(const Vector3& v, const Matrix& m, Vector4& result); + static void Transform(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector4* resultArray); + + static void TransformNormal(const Vector3& v, const Matrix& m, Vector3& result); + static Vector3 TransformNormal(const Vector3& v, const Matrix& m); + static void TransformNormal(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector3* resultArray); + + // Constants + static const Vector3 Zero; + static const Vector3 One; + static const Vector3 UnitX; + static const Vector3 UnitY; + static const Vector3 UnitZ; + static const Vector3 Up; + static const Vector3 Down; + static const Vector3 Right; + static const Vector3 Left; + static const Vector3 Forward; + static const Vector3 Backward; + }; + + // Binary operators + Vector3 operator+(const Vector3& V1, const Vector3& V2); + Vector3 operator-(const Vector3& V1, const Vector3& V2); + Vector3 operator*(const Vector3& V1, const Vector3& V2); + Vector3 operator*(const Vector3& V, float S); + Vector3 operator/(const Vector3& V1, const Vector3& V2); + Vector3 operator*(float S, const Vector3& V); + + //------------------------------------------------------------------------------ + // 4D vector + struct Vector4 : public XMFLOAT4 + { + Vector4() : XMFLOAT4(0.f, 0.f, 0.f, 0.f) + { + } + + explicit Vector4(float x) : XMFLOAT4(x, x, x, x) + { + } + + Vector4(float _x, float _y, float _z, float _w) : XMFLOAT4(_x, _y, _z, _w) + { + } + + explicit Vector4(_In_reads_(4) const float* pArray) : XMFLOAT4(pArray) + { + } + + Vector4(FXMVECTOR V) { XMStoreFloat4(this, V); } + + Vector4(const XMFLOAT4& V) + { + this->x = V.x; + this->y = V.y; + this->z = V.z; + this->w = V.w; + } + + operator XMVECTOR() const { return XMLoadFloat4(this); } + + // Comparison operators + bool operator ==(const Vector4& V) const; + bool operator !=(const Vector4& V) const; + + // Assignment operators + Vector4& operator=(const Vector4& V) + { + x = V.x; + y = V.y; + z = V.z; + w = V.w; + return *this; + } + + Vector4& operator=(const XMFLOAT4& V) + { + x = V.x; + y = V.y; + z = V.z; + w = V.w; + return *this; + } + + Vector4& operator+=(const Vector4& V); + Vector4& operator-=(const Vector4& V); + Vector4& operator*=(const Vector4& V); + Vector4& operator*=(float S); + Vector4& operator/=(float S); + + // Unary operators + Vector4 operator+() const { return *this; } + Vector4 operator-() const; + + // Vector operations + bool InBounds(const Vector4& Bounds) const; + + float Length() const; + float LengthSquared() const; + + float Dot(const Vector4& V) const; + void Cross(const Vector4& v1, const Vector4& v2, Vector4& result) const; + Vector4 Cross(const Vector4& v1, const Vector4& v2) const; + + void Normalize(); + void Normalize(Vector4& result) const; + + void Clamp(const Vector4& vmin, const Vector4& vmax); + void Clamp(const Vector4& vmin, const Vector4& vmax, Vector4& result) const; + + // Static functions + static float Distance(const Vector4& v1, const Vector4& v2); + static float DistanceSquared(const Vector4& v1, const Vector4& v2); + + static void Min(const Vector4& v1, const Vector4& v2, Vector4& result); + static Vector4 Min(const Vector4& v1, const Vector4& v2); + + static void Max(const Vector4& v1, const Vector4& v2, Vector4& result); + static Vector4 Max(const Vector4& v1, const Vector4& v2); + + static void Lerp(const Vector4& v1, const Vector4& v2, float t, Vector4& result); + static Vector4 Lerp(const Vector4& v1, const Vector4& v2, float t); + + static void SmoothStep(const Vector4& v1, const Vector4& v2, float t, Vector4& result); + static Vector4 SmoothStep(const Vector4& v1, const Vector4& v2, float t); + + static void Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, + Vector4& result); + static Vector4 Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g); + + static void CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, + Vector4& result); + static Vector4 CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t); + + static void Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, + Vector4& result); + static Vector4 Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t); + + static void Reflect(const Vector4& ivec, const Vector4& nvec, Vector4& result); + static Vector4 Reflect(const Vector4& ivec, const Vector4& nvec); + + static void Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result); + static Vector4 Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex); + + static void Transform(const Vector2& v, const Quaternion& quat, Vector4& result); + static Vector4 Transform(const Vector2& v, const Quaternion& quat); + + static void Transform(const Vector3& v, const Quaternion& quat, Vector4& result); + static Vector4 Transform(const Vector3& v, const Quaternion& quat); + + static void Transform(const Vector4& v, const Quaternion& quat, Vector4& result); + static Vector4 Transform(const Vector4& v, const Quaternion& quat); + + static void Transform(const Vector4& v, const Matrix& m, Vector4& result); + static Vector4 Transform(const Vector4& v, const Matrix& m); + static void Transform(_In_reads_(count) const Vector4* varray, size_t count, const Matrix& m, + _Out_writes_(count) Vector4* resultArray); + + // Constants + static const Vector4 Zero; + static const Vector4 One; + static const Vector4 UnitX; + static const Vector4 UnitY; + static const Vector4 UnitZ; + static const Vector4 UnitW; + }; + + // Binary operators + Vector4 operator+(const Vector4& V1, const Vector4& V2); + Vector4 operator-(const Vector4& V1, const Vector4& V2); + Vector4 operator*(const Vector4& V1, const Vector4& V2); + Vector4 operator*(const Vector4& V, float S); + Vector4 operator/(const Vector4& V1, const Vector4& V2); + Vector4 operator*(float S, const Vector4& V); + + //------------------------------------------------------------------------------ + // 4x4 Matrix (assumes right-handed cooordinates) + struct Matrix : public XMFLOAT4X4 + { + Matrix() : XMFLOAT4X4(1.f, 0, 0, 0, + 0, 1.f, 0, 0, + 0, 0, 1.f, 0, + 0, 0, 0, 1.f) + { + } + + Matrix(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) : XMFLOAT4X4(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33) + { + } + + explicit Matrix(const Vector3& r0, const Vector3& r1, const Vector3& r2) : XMFLOAT4X4(r0.x, r0.y, r0.z, 0, + r1.x, r1.y, r1.z, 0, + r2.x, r2.y, r2.z, 0, + 0, 0, 0, 1.f) + { + } + + explicit Matrix(const Vector4& r0, const Vector4& r1, const Vector4& r2, const Vector4& r3) : XMFLOAT4X4( + r0.x, r0.y, r0.z, r0.w, + r1.x, r1.y, r1.z, r1.w, + r2.x, r2.y, r2.z, r2.w, + r3.x, r3.y, r3.z, r3.w) + { + } + + Matrix(const XMFLOAT4X4& M) { memcpy_s(this, sizeof(float) * 16, &M, sizeof(XMFLOAT4X4)); } + Matrix(const XMFLOAT3X3& M); + Matrix(const XMFLOAT4X3& M); + + explicit Matrix(_In_reads_(16) const float* pArray) : XMFLOAT4X4(pArray) + { + } + + Matrix(CXMMATRIX M) { XMStoreFloat4x4(this, M); } + + operator XMMATRIX() const { return XMLoadFloat4x4(this); } + + // Comparison operators + bool operator ==(const Matrix& M) const; + bool operator !=(const Matrix& M) const; + + // Assignment operators + Matrix& operator=(const Matrix& M) + { + memcpy_s(this, sizeof(float) * 16, &M, sizeof(float) * 16); + return *this; + } + + Matrix& operator=(const XMFLOAT4X4& M) + { + memcpy_s(this, sizeof(float) * 16, &M, sizeof(XMFLOAT4X4)); + return *this; + } + + Matrix& operator=(const XMFLOAT3X3& M); + Matrix& operator=(const XMFLOAT4X3& M); + Matrix& operator+=(const Matrix& M); + Matrix& operator-=(const Matrix& M); + Matrix& operator*=(const Matrix& M); + Matrix& operator*=(float S); + Matrix& operator/=(float S); + + Matrix& operator/=(const Matrix& M); + // Element-wise divide + + // Unary operators + Matrix operator+() const { return *this; } + Matrix operator-() const; + + // Properties + Vector3 Up() const { return Vector3(_21, _22, _23); } + + void Up(const Vector3& v) + { + _21 = v.x; + _22 = v.y; + _23 = v.z; + } + + Vector3 Down() const { return Vector3(-_21, -_22, -_23); } + + void Down(const Vector3& v) + { + _21 = -v.x; + _22 = -v.y; + _23 = -v.z; + } + + Vector3 Right() const { return Vector3(_11, _12, _13); } + + void Right(const Vector3& v) + { + _11 = v.x; + _12 = v.y; + _13 = v.z; + } + + Vector3 Left() const { return Vector3(-_11, -_12, -_13); } + + void Left(const Vector3& v) + { + _11 = -v.x; + _12 = -v.y; + _13 = -v.z; + } + + Vector3 Forward() const { return Vector3(-_31, -_32, -_33); } + + void Forward(const Vector3& v) + { + _31 = -v.x; + _32 = -v.y; + _33 = -v.z; + } + + Vector3 Backward() const { return Vector3(_31, _32, _33); } + + void Backward(const Vector3& v) + { + _31 = v.x; + _32 = v.y; + _33 = v.z; + } + + Vector3 Translation() const { return Vector3(_41, _42, _43); } + + void Translation(const Vector3& v) + { + _41 = v.x; + _42 = v.y; + _43 = v.z; + } - explicit Matrix(_In_reads_(16) const float *pArray) : XMFLOAT4X4(pArray) {} - Matrix( CXMMATRIX M ) { XMStoreFloat4x4( this, M ); } - - operator XMMATRIX() const { return XMLoadFloat4x4( this ); } - - // Comparison operators - bool operator == ( const Matrix& M ) const; - bool operator != ( const Matrix& M ) const; - - // Assignment operators - Matrix& operator= (const Matrix& M) { memcpy_s( this, sizeof(float)*16, &M, sizeof(float)*16 ); return *this; } - Matrix& operator= (const XMFLOAT4X4& M) { memcpy_s( this, sizeof(float)*16, &M, sizeof(XMFLOAT4X4) ); return *this; } - Matrix& operator= (const XMFLOAT3X3& M); - Matrix& operator= (const XMFLOAT4X3& M); - Matrix& operator+= (const Matrix& M); - Matrix& operator-= (const Matrix& M); - Matrix& operator*= (const Matrix& M); - Matrix& operator*= (float S); - Matrix& operator/= (float S); - - Matrix& operator/= (const Matrix& M); - // Element-wise divide - - // Unary operators - Matrix operator+ () const { return *this; } - Matrix operator- () const; - - // Properties - Vector3 Up() const { return Vector3( _21, _22, _23); } - void Up( const Vector3& v ) { _21 = v.x; _22 = v.y; _23 = v.z; } - - Vector3 Down() const { return Vector3( -_21, -_22, -_23); } - void Down( const Vector3& v ) { _21 = -v.x; _22 = -v.y; _23 = -v.z; } - - Vector3 Right() const { return Vector3( _11, _12, _13 ); } - void Right( const Vector3& v ) { _11 = v.x; _12 = v.y; _13 = v.z; } - - Vector3 Left() const { return Vector3( -_11, -_12, -_13 ); } - void Left( const Vector3& v ) { _11 = -v.x; _12 = -v.y; _13 = -v.z; } - - Vector3 Forward() const { return Vector3( -_31, -_32, -_33 ); } - void Forward( const Vector3& v ) { _31 = -v.x; _32 = -v.y; _33 = -v.z; } - - Vector3 Backward() const { return Vector3( _31, _32, _33 ); } - void Backward( const Vector3& v ) { _31 = v.x; _32 = v.y; _33 = v.z; } - - Vector3 Translation() const { return Vector3( _41, _42, _43 ); } - void Translation( const Vector3& v ) { _41 = v.x; _42 = v.y; _43 = v.z; } - - // Matrix operations - bool Decompose( Vector3& scale, Quaternion& rotation, Vector3& translation ); - - Matrix Transpose() const; - void Transpose( Matrix& result ) const; - - Matrix Invert() const; - void Invert( Matrix& result ) const; - - float Determinant() const; - - // Static functions - static Matrix CreateBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, _In_opt_ const Vector3* cameraForward = nullptr ); - - static Matrix CreateConstrainedBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& rotateAxis, - _In_opt_ const Vector3* cameraForward = nullptr, _In_opt_ const Vector3* objectForward = nullptr); - - static Matrix CreateTranslation( const Vector3& position ); - static Matrix CreateTranslation( float x, float y, float z ); - - static Matrix CreateScale( const Vector3& scales ); - static Matrix CreateScale( float xs, float ys, float zs ); - static Matrix CreateScale( float scale ); - - static Matrix CreateRotationX( float radians ); - static Matrix CreateRotationY( float radians ); - static Matrix CreateRotationZ( float radians ); - - static Matrix CreateFromAxisAngle( const Vector3& axis, float angle ); - - static Matrix CreatePerspectiveFieldOfView( float fov, float aspectRatio, float nearPlane, float farPlane ); - static Matrix CreatePerspective( float width, float height, float nearPlane, float farPlane ); - static Matrix CreatePerspectiveOffCenter( float left, float right, float bottom, float top, float nearPlane, float farPlane ); - static Matrix CreateOrthographic( float width, float height, float zNearPlane, float zFarPlane ); - static Matrix CreateOrthographicOffCenter( float left, float right, float bottom, float top, float zNearPlane, float zFarPlane ); - - static Matrix CreateLookAt( const Vector3& position, const Vector3& target, const Vector3& up ); - static Matrix CreateWorld( const Vector3& position, const Vector3& forward, const Vector3& up ); - - static Matrix CreateFromQuaternion( const Quaternion& quat ); - - static Matrix CreateFromYawPitchRoll( float yaw, float pitch, float roll ); - - static Matrix CreateShadow( const Vector3& lightDir, const Plane& plane ); - - static Matrix CreateReflection( const Plane& plane ); - - static void Lerp( const Matrix& M1, const Matrix& M2, float t, Matrix& result ); - static Matrix Lerp( const Matrix& M1, const Matrix& M2, float t ); - - static void Transform( const Matrix& M, const Quaternion& rotation, Matrix& result ); - static Matrix Transform( const Matrix& M, const Quaternion& rotation ); - - // Constants - static const Matrix Identity; -}; - -// Binary operators -Matrix operator+ (const Matrix& M1, const Matrix& M2); -Matrix operator- (const Matrix& M1, const Matrix& M2); -Matrix operator* (const Matrix& M1, const Matrix& M2); -Matrix operator* (const Matrix& M, float S); -Matrix operator/ (const Matrix& M, float S); -Matrix operator/ (const Matrix& M1, const Matrix& M2); - // Element-wise divide -Matrix operator* (float S, const Matrix& M); - - -//----------------------------------------------------------------------------- -// Plane -struct Plane : public XMFLOAT4 -{ - Plane() : XMFLOAT4(0.f, 1.f, 0.f, 0.f) {} - Plane(float _x, float _y, float _z, float _w) : XMFLOAT4(_x, _y, _z, _w) {} - Plane(const Vector3& normal, float d) : XMFLOAT4(normal.x, normal.y, normal.z, d) {} - Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3 ); - Plane(const Vector3& point, const Vector3& normal); - explicit Plane(const Vector4& v) : XMFLOAT4(v.x, v.y, v.z, v.w) {} - explicit Plane(_In_reads_(4) const float *pArray) : XMFLOAT4(pArray) {} - Plane(FXMVECTOR V) { XMStoreFloat4( this, V ); } - Plane(const XMFLOAT4& p) { this->x = p.x; this->y = p.y; this->z = p.z; this->w = p.w; } - - operator XMVECTOR() const { return XMLoadFloat4( this ); } - - // Comparison operators - bool operator == ( const Plane& p ) const; - bool operator != ( const Plane& p ) const; - - // Assignment operators - Plane& operator= (const Plane& p) { x = p.x; y = p.y; z = p.z; w = p.w; return *this; } - Plane& operator= (const XMFLOAT4& p) { x = p.x; y = p.y; z = p.z; w = p.w; return *this; } - - // Properties - Vector3 Normal() const { return Vector3( x, y, z ); } - void Normal( const Vector3& normal ) { x = normal.x; y = normal.y; z = normal.z; } - - float D() const { return w; } - void D(float d) { w = d; } - - // Plane operations - void Normalize(); - void Normalize( Plane& result ) const; - - float Dot( const Vector4& v ) const; - float DotCoordinate( const Vector3& position ) const; - float DotNormal( const Vector3& normal ) const; - - // Static functions - static void Transform( const Plane& plane, const Matrix& M, Plane& result ); - static Plane Transform( const Plane& plane, const Matrix& M ); - - static void Transform( const Plane& plane, const Quaternion& rotation, Plane& result ); - static Plane Transform( const Plane& plane, const Quaternion& rotation ); - // Input quaternion must be the inverse transpose of the transformation -}; - -//------------------------------------------------------------------------------ -// Quaternion -struct Quaternion : public XMFLOAT4 -{ - Quaternion() : XMFLOAT4(0, 0, 0, 1.f) {} - Quaternion( float _x, float _y, float _z, float _w ) : XMFLOAT4(_x, _y, _z, _w) {} - Quaternion( const Vector3& v, float scalar ) : XMFLOAT4( v.x, v.y, v.z, scalar ) {} - explicit Quaternion( const Vector4& v ) : XMFLOAT4( v.x, v.y, v.z, v.w ) {} - explicit Quaternion(_In_reads_(4) const float *pArray) : XMFLOAT4(pArray) {} - Quaternion(FXMVECTOR V) { XMStoreFloat4( this, V ); } - Quaternion(const XMFLOAT4& q) { this->x = q.x; this->y = q.y; this->z = q.z; this->w = q.w; } - - operator XMVECTOR() const { return XMLoadFloat4( this ); } - - // Comparison operators - bool operator == ( const Quaternion& q ) const; - bool operator != ( const Quaternion& q ) const; - - // Assignment operators - Quaternion& operator= (const Quaternion& q) { x = q.x; y = q.y; z = q.z; w = q.w; return *this; } - Quaternion& operator= (const XMFLOAT4& q) { x = q.x; y = q.y; z = q.z; w = q.w; return *this; } - Quaternion& operator+= (const Quaternion& q); - Quaternion& operator-= (const Quaternion& q); - Quaternion& operator*= (const Quaternion& q); - Quaternion& operator*= (float S); - Quaternion& operator/= (const Quaternion& q); - - // Unary operators - Quaternion operator+ () const { return *this; } - Quaternion operator- () const; - - // Quaternion operations - float Length() const; - float LengthSquared() const; - - void Normalize(); - void Normalize( Quaternion& result ) const; - - void Conjugate(); - void Conjugate( Quaternion& result ) const; - - void Inverse( Quaternion& result ) const; - - float Dot( const Quaternion& Q ) const; - - // Static functions - static Quaternion CreateFromAxisAngle( const Vector3& axis, float angle ); - static Quaternion CreateFromYawPitchRoll( float yaw, float pitch, float roll ); - static Quaternion CreateFromRotationMatrix( const Matrix& M ); - - static void Lerp( const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result ); - static Quaternion Lerp( const Quaternion& q1, const Quaternion& q2, float t ); - - static void Slerp( const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result ); - static Quaternion Slerp( const Quaternion& q1, const Quaternion& q2, float t ); - - static void Concatenate( const Quaternion& q1, const Quaternion& q2, Quaternion& result ); - static Quaternion Concatenate( const Quaternion& q1, const Quaternion& q2 ); - - // Constants - static const Quaternion Identity; -}; - -// Binary operators -Quaternion operator+ (const Quaternion& Q1, const Quaternion& Q2); -Quaternion operator- (const Quaternion& Q1, const Quaternion& Q2); -Quaternion operator* (const Quaternion& Q1, const Quaternion& Q2); -Quaternion operator* (const Quaternion& Q, float S); -Quaternion operator/ (const Quaternion& Q1, const Quaternion& Q2); -Quaternion operator* (float S, const Quaternion& Q); - -//------------------------------------------------------------------------------ -// Color -struct Color : public XMFLOAT4 -{ - Color() : XMFLOAT4(0, 0, 0, 1.f) {} - Color( float _r, float _g, float _b ) : XMFLOAT4(_r, _g, _b, 1.f) {} - Color( float _r, float _g, float _b, float _a ) : XMFLOAT4(_r, _g, _b, _a) {} - explicit Color( const Vector3& clr ) : XMFLOAT4( clr.x, clr.y, clr.z, 1.f ) {} - explicit Color( const Vector4& clr ) : XMFLOAT4( clr.x, clr.y, clr.z, clr.w ) {} - explicit Color(_In_reads_(4) const float *pArray) : XMFLOAT4(pArray) {} - Color(FXMVECTOR V) { XMStoreFloat4( this, V ); } - Color(const XMFLOAT4& c) { this->x = c.x; this->y = c.y; this->z = c.z; this->w = c.w; } - - explicit Color( const DirectX::PackedVector::XMCOLOR& Packed ); - // BGRA Direct3D 9 D3DCOLOR packed color - - explicit Color( const DirectX::PackedVector::XMUBYTEN4& Packed ); - // RGBA XNA Game Studio packed color - - operator XMVECTOR() const { return XMLoadFloat4( this ); } - operator const float*() const { return reinterpret_cast(this); } - - // Comparison operators - bool operator == ( const Color& c ) const; - bool operator != ( const Color& c ) const; - - // Assignment operators - Color& operator= (const Color& c) { x = c.x; y = c.y; z = c.z; w = c.w; return *this; } - Color& operator= (const XMFLOAT4& c) { x = c.x; y = c.y; z = c.z; w = c.w; return *this; } - Color& operator= (const DirectX::PackedVector::XMCOLOR& Packed); - Color& operator= (const DirectX::PackedVector::XMUBYTEN4& Packed); - Color& operator+= (const Color& c); - Color& operator-= (const Color& c); - Color& operator*= (const Color& c); - Color& operator*= (float S); - Color& operator/= (const Color& c); - - // Unary operators - Color operator+ () const { return *this; } - Color operator- () const; - - // Properties - float R() const { return x; } - void R(float r) { x = r; } - - float G() const { return y; } - void G(float g) { y = g; } - - float B() const { return z; } - void B(float b) { z = b; } - - float A() const { return w; } - void A(float a) { w = a; } - - // Color operations - DirectX::PackedVector::XMCOLOR BGRA() const; - DirectX::PackedVector::XMUBYTEN4 RGBA() const; - - Vector3 ToVector3() const; - Vector4 ToVector4() const; - - void Negate(); - void Negate( Color& result ) const; - - void Saturate(); - void Saturate( Color& result ) const; - - void Premultiply(); - void Premultiply( Color& result ) const; - - void AdjustSaturation( float sat ); - void AdjustSaturation( float sat, Color& result ) const; - - void AdjustContrast( float contrast ); - void AdjustContrast( float contrast, Color& result ) const; - - // Static functions - static void Modulate( const Color& c1, const Color& c2, Color& result ); - static Color Modulate( const Color& c1, const Color& c2 ); - - static void Lerp( const Color& c1, const Color& c2, float t, Color& result ); - static Color Lerp( const Color& c1, const Color& c2, float t ); -}; - -// Binary operators -Color operator+ (const Color& C1, const Color& C2); -Color operator- (const Color& C1, const Color& C2); -Color operator* (const Color& C1, const Color& C2); -Color operator* (const Color& C, float S); -Color operator/ (const Color& C1, const Color& C2); -Color operator* (float S, const Color& C); - -//------------------------------------------------------------------------------ -// Ray -class Ray -{ -public: - Vector3 position; - Vector3 direction; - - Ray() : position(0,0,0), direction(0,0,1) {} - Ray( const Vector3& pos, const Vector3& dir ) : position(pos), direction(dir) {} - - // Comparison operators - bool operator == ( const Ray& r ) const; - bool operator != ( const Ray& r ) const; - - // Ray operations - bool Intersects( const BoundingSphere& sphere, _Out_ float& Dist ) const; - bool Intersects( const BoundingBox& box, _Out_ float& Dist ) const; - bool Intersects( const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist ) const; - bool Intersects( const Plane& plane, _Out_ float& Dist ) const; -}; - -//------------------------------------------------------------------------------ -// Viewport -class Viewport -{ -public: - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; - - Viewport() : - x(0.f), y(0.f), width(0.f), height(0.f), minDepth(0.f), maxDepth(1.f) {} - Viewport( float ix, float iy, float iw, float ih, float iminz = 0.f, float imaxz = 1.f ) : - x(ix), y(iy), width(iw), height(ih), minDepth(iminz), maxDepth(imaxz) {} - explicit Viewport(const RECT& rct) : - x(float(rct.left)), y(float(rct.top)), - width(float(rct.right - rct.left)), - height(float(rct.bottom - rct.top)), - minDepth(0.f), maxDepth(1.f) {} - explicit Viewport(const D3D11_VIEWPORT& vp) : - x(vp.TopLeftX), y(vp.TopLeftY), - width(vp.Width), height(vp.Height), - minDepth(vp.MinDepth), maxDepth(vp.MaxDepth) {} - - // Direct3D 11 interop - operator D3D11_VIEWPORT() { return *reinterpret_cast(this); } - const D3D11_VIEWPORT* Get11() const { return reinterpret_cast(this); } - - // Comparison operators - bool operator == ( const Viewport& vp ) const; - bool operator != ( const Viewport& vp ) const; - - // Assignment operators - Viewport& operator= (const Viewport& vp); - Viewport& operator= (const RECT& rct); - Viewport& operator= (const D3D11_VIEWPORT& vp); - - // Viewport operations - float AspectRatio() const; - - Vector3 Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world ) const; - void Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result ) const; - - Vector3 Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world ) const; - void Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result ) const; - - // Static methods - static RECT __cdecl ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, int outputWidth, int outputHeight); - static RECT __cdecl ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight); -}; + // Matrix operations + bool Decompose(Vector3& scale, Quaternion& rotation, Vector3& translation); + + Matrix Transpose() const; + void Transpose(Matrix& result) const; + + Matrix Invert() const; + void Invert(Matrix& result) const; + + float Determinant() const; + + // Static functions + static Matrix CreateBillboard(const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, + _In_opt_ const Vector3* cameraForward = nullptr); + + static Matrix CreateConstrainedBillboard(const Vector3& object, const Vector3& cameraPosition, + const Vector3& rotateAxis, + _In_opt_ const Vector3* cameraForward = nullptr, + _In_opt_ const Vector3* objectForward = nullptr); + + static Matrix CreateTranslation(const Vector3& position); + static Matrix CreateTranslation(float x, float y, float z); + + static Matrix CreateScale(const Vector3& scales); + static Matrix CreateScale(float xs, float ys, float zs); + static Matrix CreateScale(float scale); + + static Matrix CreateRotationX(float radians); + static Matrix CreateRotationY(float radians); + static Matrix CreateRotationZ(float radians); + + static Matrix CreateFromAxisAngle(const Vector3& axis, float angle); + + static Matrix CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane, float farPlane); + static Matrix CreatePerspective(float width, float height, float nearPlane, float farPlane); + static Matrix CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlane, + float farPlane); + static Matrix CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane); + static Matrix CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, + float zFarPlane); + + static Matrix CreateLookAt(const Vector3& position, const Vector3& target, const Vector3& up); + static Matrix CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up); + + static Matrix CreateFromQuaternion(const Quaternion& quat); + + static Matrix CreateFromYawPitchRoll(float yaw, float pitch, float roll); + + static Matrix CreateShadow(const Vector3& lightDir, const Plane& plane); + + static Matrix CreateReflection(const Plane& plane); + + static void Lerp(const Matrix& M1, const Matrix& M2, float t, Matrix& result); + static Matrix Lerp(const Matrix& M1, const Matrix& M2, float t); + + static void Transform(const Matrix& M, const Quaternion& rotation, Matrix& result); + static Matrix Transform(const Matrix& M, const Quaternion& rotation); + + // Constants + static const Matrix Identity; + }; + + // Binary operators + Matrix operator+(const Matrix& M1, const Matrix& M2); + Matrix operator-(const Matrix& M1, const Matrix& M2); + Matrix operator*(const Matrix& M1, const Matrix& M2); + Matrix operator*(const Matrix& M, float S); + Matrix operator/(const Matrix& M, float S); + Matrix operator/(const Matrix& M1, const Matrix& M2); + // Element-wise divide + Matrix operator*(float S, const Matrix& M); + + + //----------------------------------------------------------------------------- + // Plane + struct Plane : public XMFLOAT4 + { + Plane() : XMFLOAT4(0.f, 1.f, 0.f, 0.f) + { + } + + Plane(float _x, float _y, float _z, float _w) : XMFLOAT4(_x, _y, _z, _w) + { + } + + Plane(const Vector3& normal, float d) : XMFLOAT4(normal.x, normal.y, normal.z, d) + { + } + + Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3); + Plane(const Vector3& point, const Vector3& normal); + + explicit Plane(const Vector4& v) : XMFLOAT4(v.x, v.y, v.z, v.w) + { + } + + explicit Plane(_In_reads_(4) const float* pArray) : XMFLOAT4(pArray) + { + } + + Plane(FXMVECTOR V) { XMStoreFloat4(this, V); } + + Plane(const XMFLOAT4& p) + { + this->x = p.x; + this->y = p.y; + this->z = p.z; + this->w = p.w; + } + + operator XMVECTOR() const { return XMLoadFloat4(this); } + + // Comparison operators + bool operator ==(const Plane& p) const; + bool operator !=(const Plane& p) const; + + // Assignment operators + Plane& operator=(const Plane& p) + { + x = p.x; + y = p.y; + z = p.z; + w = p.w; + return *this; + } + + Plane& operator=(const XMFLOAT4& p) + { + x = p.x; + y = p.y; + z = p.z; + w = p.w; + return *this; + } + + // Properties + Vector3 Normal() const { return Vector3(x, y, z); } + + void Normal(const Vector3& normal) + { + x = normal.x; + y = normal.y; + z = normal.z; + } + + float D() const { return w; } + void D(float d) { w = d; } + + // Plane operations + void Normalize(); + void Normalize(Plane& result) const; + + float Dot(const Vector4& v) const; + float DotCoordinate(const Vector3& position) const; + float DotNormal(const Vector3& normal) const; + + // Static functions + static void Transform(const Plane& plane, const Matrix& M, Plane& result); + static Plane Transform(const Plane& plane, const Matrix& M); + + static void Transform(const Plane& plane, const Quaternion& rotation, Plane& result); + static Plane Transform(const Plane& plane, const Quaternion& rotation); + // Input quaternion must be the inverse transpose of the transformation + }; + + //------------------------------------------------------------------------------ + // Quaternion + struct Quaternion : public XMFLOAT4 + { + Quaternion() : XMFLOAT4(0, 0, 0, 1.f) + { + } + + Quaternion(float _x, float _y, float _z, float _w) : XMFLOAT4(_x, _y, _z, _w) + { + } + + Quaternion(const Vector3& v, float scalar) : XMFLOAT4(v.x, v.y, v.z, scalar) + { + } + + explicit Quaternion(const Vector4& v) : XMFLOAT4(v.x, v.y, v.z, v.w) + { + } + + explicit Quaternion(_In_reads_(4) const float* pArray) : XMFLOAT4(pArray) + { + } + + Quaternion(FXMVECTOR V) { XMStoreFloat4(this, V); } + + Quaternion(const XMFLOAT4& q) + { + this->x = q.x; + this->y = q.y; + this->z = q.z; + this->w = q.w; + } + + operator XMVECTOR() const { return XMLoadFloat4(this); } + + // Comparison operators + bool operator ==(const Quaternion& q) const; + bool operator !=(const Quaternion& q) const; + + // Assignment operators + Quaternion& operator=(const Quaternion& q) + { + x = q.x; + y = q.y; + z = q.z; + w = q.w; + return *this; + } + + Quaternion& operator=(const XMFLOAT4& q) + { + x = q.x; + y = q.y; + z = q.z; + w = q.w; + return *this; + } + + Quaternion& operator+=(const Quaternion& q); + Quaternion& operator-=(const Quaternion& q); + Quaternion& operator*=(const Quaternion& q); + Quaternion& operator*=(float S); + Quaternion& operator/=(const Quaternion& q); + + // Unary operators + Quaternion operator+() const { return *this; } + Quaternion operator-() const; + + // Quaternion operations + float Length() const; + float LengthSquared() const; + + void Normalize(); + void Normalize(Quaternion& result) const; + + void Conjugate(); + void Conjugate(Quaternion& result) const; + + void Inverse(Quaternion& result) const; + + float Dot(const Quaternion& Q) const; + + // Static functions + static Quaternion CreateFromAxisAngle(const Vector3& axis, float angle); + static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll); + static Quaternion CreateFromRotationMatrix(const Matrix& M); + + static void Lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result); + static Quaternion Lerp(const Quaternion& q1, const Quaternion& q2, float t); + + static void Slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result); + static Quaternion Slerp(const Quaternion& q1, const Quaternion& q2, float t); + + static void Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result); + static Quaternion Concatenate(const Quaternion& q1, const Quaternion& q2); + + // Constants + static const Quaternion Identity; + }; + + // Binary operators + Quaternion operator+(const Quaternion& Q1, const Quaternion& Q2); + Quaternion operator-(const Quaternion& Q1, const Quaternion& Q2); + Quaternion operator*(const Quaternion& Q1, const Quaternion& Q2); + Quaternion operator*(const Quaternion& Q, float S); + Quaternion operator/(const Quaternion& Q1, const Quaternion& Q2); + Quaternion operator*(float S, const Quaternion& Q); + + //------------------------------------------------------------------------------ + // Color + struct Color : public XMFLOAT4 + { + Color() : XMFLOAT4(0, 0, 0, 1.f) + { + } + + Color(float _r, float _g, float _b) : XMFLOAT4(_r, _g, _b, 1.f) + { + } + + Color(float _r, float _g, float _b, float _a) : XMFLOAT4(_r, _g, _b, _a) + { + } + + explicit Color(const Vector3& clr) : XMFLOAT4(clr.x, clr.y, clr.z, 1.f) + { + } + + explicit Color(const Vector4& clr) : XMFLOAT4(clr.x, clr.y, clr.z, clr.w) + { + } + + explicit Color(_In_reads_(4) const float* pArray) : XMFLOAT4(pArray) + { + } + + Color(FXMVECTOR V) { XMStoreFloat4(this, V); } + + Color(const XMFLOAT4& c) + { + this->x = c.x; + this->y = c.y; + this->z = c.z; + this->w = c.w; + } + + explicit Color(const DirectX::PackedVector::XMCOLOR& Packed); + // BGRA Direct3D 9 D3DCOLOR packed color + + explicit Color(const DirectX::PackedVector::XMUBYTEN4& Packed); + // RGBA XNA Game Studio packed color + + operator XMVECTOR() const { return XMLoadFloat4(this); } + operator const float*() const { return reinterpret_cast(this); } + + // Comparison operators + bool operator ==(const Color& c) const; + bool operator !=(const Color& c) const; + + // Assignment operators + Color& operator=(const Color& c) + { + x = c.x; + y = c.y; + z = c.z; + w = c.w; + return *this; + } + + Color& operator=(const XMFLOAT4& c) + { + x = c.x; + y = c.y; + z = c.z; + w = c.w; + return *this; + } + + Color& operator=(const DirectX::PackedVector::XMCOLOR& Packed); + Color& operator=(const DirectX::PackedVector::XMUBYTEN4& Packed); + Color& operator+=(const Color& c); + Color& operator-=(const Color& c); + Color& operator*=(const Color& c); + Color& operator*=(float S); + Color& operator/=(const Color& c); + + // Unary operators + Color operator+() const { return *this; } + Color operator-() const; + + // Properties + float R() const { return x; } + void R(float r) { x = r; } + + float G() const { return y; } + void G(float g) { y = g; } + + float B() const { return z; } + void B(float b) { z = b; } + + float A() const { return w; } + void A(float a) { w = a; } + + // Color operations + DirectX::PackedVector::XMCOLOR BGRA() const; + DirectX::PackedVector::XMUBYTEN4 RGBA() const; + + Vector3 ToVector3() const; + Vector4 ToVector4() const; + + void Negate(); + void Negate(Color& result) const; + + void Saturate(); + void Saturate(Color& result) const; + + void Premultiply(); + void Premultiply(Color& result) const; + + void AdjustSaturation(float sat); + void AdjustSaturation(float sat, Color& result) const; + + void AdjustContrast(float contrast); + void AdjustContrast(float contrast, Color& result) const; + + // Static functions + static void Modulate(const Color& c1, const Color& c2, Color& result); + static Color Modulate(const Color& c1, const Color& c2); + + static void Lerp(const Color& c1, const Color& c2, float t, Color& result); + static Color Lerp(const Color& c1, const Color& c2, float t); + }; + + // Binary operators + Color operator+(const Color& C1, const Color& C2); + Color operator-(const Color& C1, const Color& C2); + Color operator*(const Color& C1, const Color& C2); + Color operator*(const Color& C, float S); + Color operator/(const Color& C1, const Color& C2); + Color operator*(float S, const Color& C); + + //------------------------------------------------------------------------------ + // Ray + class Ray + { + public: + Vector3 position; + Vector3 direction; + + Ray() : position(0, 0, 0), direction(0, 0, 1) + { + } + + Ray(const Vector3& pos, const Vector3& dir) : position(pos), direction(dir) + { + } + + // Comparison operators + bool operator ==(const Ray& r) const; + bool operator !=(const Ray& r) const; + + // Ray operations + bool Intersects(const BoundingSphere& sphere, _Out_ float& Dist) const; + bool Intersects(const BoundingBox& box, _Out_ float& Dist) const; + bool Intersects(const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist) const; + bool Intersects(const Plane& plane, _Out_ float& Dist) const; + }; + + //------------------------------------------------------------------------------ + // Viewport + class Viewport + { + public: + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; + + Viewport() : + x(0.f), y(0.f), width(0.f), height(0.f), minDepth(0.f), maxDepth(1.f) + { + } + + Viewport(float ix, float iy, float iw, float ih, float iminz = 0.f, float imaxz = 1.f) : + x(ix), y(iy), width(iw), height(ih), minDepth(iminz), maxDepth(imaxz) + { + } + + explicit Viewport(const RECT& rct) : + x(float(rct.left)), y(float(rct.top)), + width(float(rct.right - rct.left)), + height(float(rct.bottom - rct.top)), + minDepth(0.f), maxDepth(1.f) + { + } + + explicit Viewport(const D3D11_VIEWPORT& vp) : + x(vp.TopLeftX), y(vp.TopLeftY), + width(vp.Width), height(vp.Height), + minDepth(vp.MinDepth), maxDepth(vp.MaxDepth) + { + } + + // Direct3D 11 interop + operator D3D11_VIEWPORT() { return *reinterpret_cast(this); } + const D3D11_VIEWPORT* Get11() const { return reinterpret_cast(this); } + + // Comparison operators + bool operator ==(const Viewport& vp) const; + bool operator !=(const Viewport& vp) const; + + // Assignment operators + Viewport& operator=(const Viewport& vp); + Viewport& operator=(const RECT& rct); + Viewport& operator=(const D3D11_VIEWPORT& vp); + + // Viewport operations + float AspectRatio() const; + + Vector3 Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const; + void Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, + Vector3& result) const; + + Vector3 Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const; + void Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, + Vector3& result) const; + + // Static methods + static RECT __cdecl ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, + int outputWidth, int outputHeight); + static RECT __cdecl ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight); + }; #include "SimpleMath.inl" - -}; // namespace SimpleMath - + }; // namespace SimpleMath }; // namespace DirectX //------------------------------------------------------------------------------ // Support for SimpleMath and Standard C++ Library containers namespace std { + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Vector2& V1, const DirectX::SimpleMath::Vector2& V2) const + { + return ((V1.x < V2.x) || ((V1.x == V2.x) && (V1.y < V2.y))); + } + }; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Vector2& V1, const DirectX::SimpleMath::Vector2& V2) const - { - return ( (V1.x < V2.x) || ((V1.x == V2.x) && (V1.y < V2.y)) ); - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Vector3& V1, const DirectX::SimpleMath::Vector3& V2) const + { + return ((V1.x < V2.x) + || ((V1.x == V2.x) && (V1.y < V2.y)) + || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z))); + } + }; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Vector3& V1, const DirectX::SimpleMath::Vector3& V2) const - { - return ( (V1.x < V2.x) - || ((V1.x == V2.x) && (V1.y < V2.y)) - || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z)) ); - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Vector4& V1, const DirectX::SimpleMath::Vector4& V2) const + { + return ((V1.x < V2.x) + || ((V1.x == V2.x) && (V1.y < V2.y)) + || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z)) + || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z == V2.z) && (V1.w < V2.w))); + } + }; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Vector4& V1, const DirectX::SimpleMath::Vector4& V2) const - { - return ( (V1.x < V2.x) - || ((V1.x == V2.x) && (V1.y < V2.y)) - || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z)) - || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z == V2.z) && (V1.w < V2.w)) ); - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Matrix& M1, const DirectX::SimpleMath::Matrix& M2) const + { + if (M1._11 != M2._11) return M1._11 < M2._11; + if (M1._12 != M2._12) return M1._12 < M2._12; + if (M1._13 != M2._13) return M1._13 < M2._13; + if (M1._14 != M2._14) return M1._14 < M2._14; + if (M1._21 != M2._21) return M1._21 < M2._21; + if (M1._22 != M2._22) return M1._22 < M2._22; + if (M1._23 != M2._23) return M1._23 < M2._23; + if (M1._24 != M2._24) return M1._24 < M2._24; + if (M1._31 != M2._31) return M1._31 < M2._31; + if (M1._32 != M2._32) return M1._32 < M2._32; + if (M1._33 != M2._33) return M1._33 < M2._33; + if (M1._34 != M2._34) return M1._34 < M2._34; + if (M1._41 != M2._41) return M1._41 < M2._41; + if (M1._42 != M2._42) return M1._42 < M2._42; + if (M1._43 != M2._43) return M1._43 < M2._43; + if (M1._44 != M2._44) return M1._44 < M2._44; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Matrix& M1, const DirectX::SimpleMath::Matrix& M2) const - { - if (M1._11 != M2._11) return M1._11 < M2._11; - if (M1._12 != M2._12) return M1._12 < M2._12; - if (M1._13 != M2._13) return M1._13 < M2._13; - if (M1._14 != M2._14) return M1._14 < M2._14; - if (M1._21 != M2._21) return M1._21 < M2._21; - if (M1._22 != M2._22) return M1._22 < M2._22; - if (M1._23 != M2._23) return M1._23 < M2._23; - if (M1._24 != M2._24) return M1._24 < M2._24; - if (M1._31 != M2._31) return M1._31 < M2._31; - if (M1._32 != M2._32) return M1._32 < M2._32; - if (M1._33 != M2._33) return M1._33 < M2._33; - if (M1._34 != M2._34) return M1._34 < M2._34; - if (M1._41 != M2._41) return M1._41 < M2._41; - if (M1._42 != M2._42) return M1._42 < M2._42; - if (M1._43 != M2._43) return M1._43 < M2._43; - if (M1._44 != M2._44) return M1._44 < M2._44; + return false; + } + }; - return false; - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Plane& P1, const DirectX::SimpleMath::Plane& P2) const + { + return ((P1.x < P2.x) + || ((P1.x == P2.x) && (P1.y < P2.y)) + || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z < P2.z)) + || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z == P2.z) && (P1.w < P2.w))); + } + }; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Plane& P1, const DirectX::SimpleMath::Plane& P2) const - { - return ( (P1.x < P2.x) - || ((P1.x == P2.x) && (P1.y < P2.y)) - || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z < P2.z)) - || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z == P2.z) && (P1.w < P2.w)) ); - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Quaternion& Q1, const DirectX::SimpleMath::Quaternion& Q2) const + { + return ((Q1.x < Q2.x) + || ((Q1.x == Q2.x) && (Q1.y < Q2.y)) + || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z < Q2.z)) + || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z == Q2.z) && (Q1.w < Q2.w))); + } + }; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Quaternion& Q1, const DirectX::SimpleMath::Quaternion& Q2) const - { - return ( (Q1.x < Q2.x) - || ((Q1.x == Q2.x) && (Q1.y < Q2.y)) - || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z < Q2.z)) - || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z == Q2.z) && (Q1.w < Q2.w)) ); - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Color& C1, const DirectX::SimpleMath::Color& C2) const + { + return ((C1.x < C2.x) + || ((C1.x == C2.x) && (C1.y < C2.y)) + || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z < C2.z)) + || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z == C2.z) && (C1.w < C2.w))); + } + }; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Color& C1, const DirectX::SimpleMath::Color& C2) const - { - return ( (C1.x < C2.x) - || ((C1.x == C2.x) && (C1.y < C2.y)) - || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z < C2.z)) - || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z == C2.z) && (C1.w < C2.w)) ); - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Ray& R1, const DirectX::SimpleMath::Ray& R2) const + { + if (R1.position.x != R2.position.x) return R1.position.x < R2.position.x; + if (R1.position.y != R2.position.y) return R1.position.y < R2.position.y; + if (R1.position.z != R2.position.z) return R1.position.z < R2.position.z; - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Ray& R1, const DirectX::SimpleMath::Ray& R2) const - { - if (R1.position.x != R2.position.x) return R1.position.x < R2.position.x; - if (R1.position.y != R2.position.y) return R1.position.y < R2.position.y; - if (R1.position.z != R2.position.z) return R1.position.z < R2.position.z; + if (R1.direction.x != R2.direction.x) return R1.direction.x < R2.direction.x; + if (R1.direction.y != R2.direction.y) return R1.direction.y < R2.direction.y; + if (R1.direction.z != R2.direction.z) return R1.direction.z < R2.direction.z; - if (R1.direction.x != R2.direction.x) return R1.direction.x < R2.direction.x; - if (R1.direction.y != R2.direction.y) return R1.direction.y < R2.direction.y; - if (R1.direction.z != R2.direction.z) return R1.direction.z < R2.direction.z; + return false; + } + }; - return false; - } - }; + template <> + struct less + { + bool operator()(const DirectX::SimpleMath::Viewport& vp1, const DirectX::SimpleMath::Viewport& vp2) const + { + if (vp1.x != vp2.x) return (vp1.x < vp2.x); + if (vp1.y != vp2.y) return (vp1.y < vp2.y); - template<> struct less - { - bool operator()(const DirectX::SimpleMath::Viewport& vp1, const DirectX::SimpleMath::Viewport& vp2) const - { - if (vp1.x != vp2.x) return (vp1.x < vp2.x); - if (vp1.y != vp2.y) return (vp1.y < vp2.y); + if (vp1.width != vp2.width) return (vp1.width < vp2.width); + if (vp1.height != vp2.height) return (vp1.height < vp2.height); - if (vp1.width != vp2.width) return (vp1.width < vp2.width); - if (vp1.height != vp2.height) return (vp1.height < vp2.height); - - if (vp1.minDepth != vp2.minDepth) return (vp1.minDepth < vp2.minDepth); - if (vp1.maxDepth != vp2.maxDepth) return (vp1.maxDepth < vp2.maxDepth); - - return false; - } - }; + if (vp1.minDepth != vp2.minDepth) return (vp1.minDepth < vp2.minDepth); + if (vp1.maxDepth != vp2.maxDepth) return (vp1.maxDepth < vp2.maxDepth); + return false; + } + }; } // namespace std diff --git a/Windows/DirectXTK/SimpleMath.inl b/Windows/DirectXTK/SimpleMath.inl index 0d719ec..9c4e48c 100644 --- a/Windows/DirectXTK/SimpleMath.inl +++ b/Windows/DirectXTK/SimpleMath.inl @@ -23,558 +23,564 @@ // Comparision operators //------------------------------------------------------------------------------ -inline bool Vector2::operator == ( const Vector2& V ) const +inline bool Vector2::operator ==(const Vector2& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - return XMVector2Equal( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + return XMVector2Equal(v1, v2); } -inline bool Vector2::operator != ( const Vector2& V ) const +inline bool Vector2::operator !=(const Vector2& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - return XMVector2NotEqual( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + return XMVector2NotEqual(v1, v2); } //------------------------------------------------------------------------------ // Assignment operators //------------------------------------------------------------------------------ -inline Vector2& Vector2::operator+= (const Vector2& V) +inline Vector2& Vector2::operator+=(const Vector2& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - XMVECTOR X = XMVectorAdd(v1,v2); - XMStoreFloat2( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + XMVECTOR X = XMVectorAdd(v1, v2); + XMStoreFloat2(this, X); + return *this; } -inline Vector2& Vector2::operator-= (const Vector2& V) +inline Vector2& Vector2::operator-=(const Vector2& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - XMVECTOR X = XMVectorSubtract(v1,v2); - XMStoreFloat2( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + XMVECTOR X = XMVectorSubtract(v1, v2); + XMStoreFloat2(this, X); + return *this; } -inline Vector2& Vector2::operator*= (const Vector2& V) +inline Vector2& Vector2::operator*=(const Vector2& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - XMVECTOR X = XMVectorMultiply(v1,v2); - XMStoreFloat2( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + XMVECTOR X = XMVectorMultiply(v1, v2); + XMStoreFloat2(this, X); + return *this; } -inline Vector2& Vector2::operator*= (float S) +inline Vector2& Vector2::operator*=(float S) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR X = XMVectorScale(v1,S); - XMStoreFloat2( this, X ); - return *this; -} + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR X = XMVectorScale(v1, S); + XMStoreFloat2(this, X); + return *this; +} -inline Vector2& Vector2::operator/= (float S) +inline Vector2& Vector2::operator/=(float S) { - using namespace DirectX; - assert( S != 0.0f ); - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR X = XMVectorScale(v1, 1.f/S); - XMStoreFloat2( this, X ); - return *this; -} + using namespace DirectX; + assert(S != 0.0f); + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR X = XMVectorScale(v1, 1.f / S); + XMStoreFloat2(this, X); + return *this; +} //------------------------------------------------------------------------------ // Binary operators //------------------------------------------------------------------------------ -inline Vector2 operator+ (const Vector2& V1, const Vector2& V2) +inline Vector2 operator+(const Vector2& V1, const Vector2& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &V1 ); - XMVECTOR v2 = XMLoadFloat2( &V2 ); - XMVECTOR X = XMVectorAdd(v1,v2); - Vector2 R; - XMStoreFloat2( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&V1); + XMVECTOR v2 = XMLoadFloat2(&V2); + XMVECTOR X = XMVectorAdd(v1, v2); + Vector2 R; + XMStoreFloat2(&R, X); + return R; } -inline Vector2 operator- (const Vector2& V1, const Vector2& V2) +inline Vector2 operator-(const Vector2& V1, const Vector2& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &V1 ); - XMVECTOR v2 = XMLoadFloat2( &V2 ); - XMVECTOR X = XMVectorSubtract(v1,v2); - Vector2 R; - XMStoreFloat2( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&V1); + XMVECTOR v2 = XMLoadFloat2(&V2); + XMVECTOR X = XMVectorSubtract(v1, v2); + Vector2 R; + XMStoreFloat2(&R, X); + return R; } -inline Vector2 operator* (const Vector2& V1, const Vector2& V2) +inline Vector2 operator*(const Vector2& V1, const Vector2& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &V1 ); - XMVECTOR v2 = XMLoadFloat2( &V2 ); - XMVECTOR X = XMVectorMultiply(v1,v2); - Vector2 R; - XMStoreFloat2( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&V1); + XMVECTOR v2 = XMLoadFloat2(&V2); + XMVECTOR X = XMVectorMultiply(v1, v2); + Vector2 R; + XMStoreFloat2(&R, X); + return R; } -inline Vector2 operator* (const Vector2& V, float S) +inline Vector2 operator*(const Vector2& V, float S) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &V ); - XMVECTOR X = XMVectorScale(v1,S); - Vector2 R; - XMStoreFloat2( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&V); + XMVECTOR X = XMVectorScale(v1, S); + Vector2 R; + XMStoreFloat2(&R, X); + return R; } -inline Vector2 operator/ (const Vector2& V1, const Vector2& V2) +inline Vector2 operator/(const Vector2& V1, const Vector2& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &V1 ); - XMVECTOR v2 = XMLoadFloat2( &V2 ); - XMVECTOR X = XMVectorDivide(v1,v2); - Vector2 R; - XMStoreFloat2( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&V1); + XMVECTOR v2 = XMLoadFloat2(&V2); + XMVECTOR X = XMVectorDivide(v1, v2); + Vector2 R; + XMStoreFloat2(&R, X); + return R; } -inline Vector2 operator* (float S, const Vector2& V) +inline Vector2 operator*(float S, const Vector2& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &V ); - XMVECTOR X = XMVectorScale(v1,S); - Vector2 R; - XMStoreFloat2( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&V); + XMVECTOR X = XMVectorScale(v1, S); + Vector2 R; + XMStoreFloat2(&R, X); + return R; } //------------------------------------------------------------------------------ // Vector operations //------------------------------------------------------------------------------ -inline bool Vector2::InBounds( const Vector2& Bounds ) const +inline bool Vector2::InBounds(const Vector2& Bounds) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &Bounds ); - return XMVector2InBounds( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&Bounds); + return XMVector2InBounds(v1, v2); } inline float Vector2::Length() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR X = XMVector2Length( v1 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR X = XMVector2Length(v1); + return XMVectorGetX(X); } inline float Vector2::LengthSquared() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR X = XMVector2LengthSq( v1 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR X = XMVector2LengthSq(v1); + return XMVectorGetX(X); } -inline float Vector2::Dot( const Vector2& V ) const +inline float Vector2::Dot(const Vector2& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - XMVECTOR X = XMVector2Dot( v1, v2 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + XMVECTOR X = XMVector2Dot(v1, v2); + return XMVectorGetX(X); } -inline void Vector2::Cross( const Vector2& V, Vector2& result ) const +inline void Vector2::Cross(const Vector2& V, Vector2& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - XMVECTOR R = XMVector2Cross( v1, v2 ); - XMStoreFloat2( &result, R ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + XMVECTOR R = XMVector2Cross(v1, v2); + XMStoreFloat2(&result, R); } -inline Vector2 Vector2::Cross( const Vector2& V ) const +inline Vector2 Vector2::Cross(const Vector2& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &V ); - XMVECTOR R = XMVector2Cross( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&V); + XMVECTOR R = XMVector2Cross(v1, v2); - Vector2 result; - XMStoreFloat2( &result, R ); - return result; + Vector2 result; + XMStoreFloat2(&result, R); + return result; } inline void Vector2::Normalize() { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR X = XMVector2Normalize( v1 ); - XMStoreFloat2( this, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR X = XMVector2Normalize(v1); + XMStoreFloat2(this, X); } -inline void Vector2::Normalize( Vector2& result ) const +inline void Vector2::Normalize(Vector2& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR X = XMVector2Normalize( v1 ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR X = XMVector2Normalize(v1); + XMStoreFloat2(&result, X); } -inline void Vector2::Clamp( const Vector2& vmin, const Vector2& vmax ) +inline void Vector2::Clamp(const Vector2& vmin, const Vector2& vmax) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &vmin ); - XMVECTOR v3 = XMLoadFloat2( &vmax ); - XMVECTOR X = XMVectorClamp( v1, v2, v3 ); - XMStoreFloat2( this, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&vmin); + XMVECTOR v3 = XMLoadFloat2(&vmax); + XMVECTOR X = XMVectorClamp(v1, v2, v3); + XMStoreFloat2(this, X); } -inline void Vector2::Clamp( const Vector2& vmin, const Vector2& vmax, Vector2& result ) const +inline void Vector2::Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( this ); - XMVECTOR v2 = XMLoadFloat2( &vmin ); - XMVECTOR v3 = XMLoadFloat2( &vmax ); - XMVECTOR X = XMVectorClamp( v1, v2, v3 ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(this); + XMVECTOR v2 = XMLoadFloat2(&vmin); + XMVECTOR v3 = XMLoadFloat2(&vmax); + XMVECTOR X = XMVectorClamp(v1, v2, v3); + XMStoreFloat2(&result, X); } //------------------------------------------------------------------------------ // Static functions //------------------------------------------------------------------------------ -inline float Vector2::Distance( const Vector2& v1, const Vector2& v2 ) +inline float Vector2::Distance(const Vector2& v1, const Vector2& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR V = XMVectorSubtract( x2, x1 ); - XMVECTOR X = XMVector2Length( V ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR V = XMVectorSubtract(x2, x1); + XMVECTOR X = XMVector2Length(V); + return XMVectorGetX(X); } -inline float Vector2::DistanceSquared( const Vector2& v1, const Vector2& v2 ) +inline float Vector2::DistanceSquared(const Vector2& v1, const Vector2& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR V = XMVectorSubtract( x2, x1 ); - XMVECTOR X = XMVector2LengthSq( V ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR V = XMVectorSubtract(x2, x1); + XMVECTOR X = XMVector2LengthSq(V); + return XMVectorGetX(X); } -inline void Vector2::Min( const Vector2& v1, const Vector2& v2, Vector2& result ) +inline void Vector2::Min(const Vector2& v1, const Vector2& v2, Vector2& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorMin( x1, x2 ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorMin(x1, x2); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Min( const Vector2& v1, const Vector2& v2 ) +inline Vector2 Vector2::Min(const Vector2& v1, const Vector2& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorMin( x1, x2 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorMin(x1, x2); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Max( const Vector2& v1, const Vector2& v2, Vector2& result ) +inline void Vector2::Max(const Vector2& v1, const Vector2& v2, Vector2& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorMax( x1, x2 ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorMax(x1, x2); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Max( const Vector2& v1, const Vector2& v2 ) +inline Vector2 Vector2::Max(const Vector2& v1, const Vector2& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorMax( x1, x2 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorMax(x1, x2); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Lerp( const Vector2& v1, const Vector2& v2, float t, Vector2& result ) +inline void Vector2::Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Lerp( const Vector2& v1, const Vector2& v2, float t ) +inline Vector2 Vector2::Lerp(const Vector2& v1, const Vector2& v2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::SmoothStep( const Vector2& v1, const Vector2& v2, float t, Vector2& result ) +inline void Vector2::SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result) { - using namespace DirectX; - t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 - t = t*t*(3.f - 2.f*t); - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 + t = t * t * (3.f - 2.f * t); + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::SmoothStep( const Vector2& v1, const Vector2& v2, float t ) +inline Vector2 Vector2::SmoothStep(const Vector2& v1, const Vector2& v2, float t) { - using namespace DirectX; - t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 - t = t*t*(3.f - 2.f*t); - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); + using namespace DirectX; + t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 + t = t * t * (3.f - 2.f * t); + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Barycentric( const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result ) +inline void Vector2::Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, + Vector2& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR x3 = XMLoadFloat2( &v3 ); - XMVECTOR X = XMVectorBaryCentric( x1, x2, x3, f, g ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR x3 = XMLoadFloat2(&v3); + XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Barycentric( const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g ) +inline Vector2 Vector2::Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR x3 = XMLoadFloat2( &v3 ); - XMVECTOR X = XMVectorBaryCentric( x1, x2, x3, f, g ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR x3 = XMLoadFloat2(&v3); + XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::CatmullRom( const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result ) +inline void Vector2::CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, + Vector2& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR x3 = XMLoadFloat2( &v3 ); - XMVECTOR x4 = XMLoadFloat2( &v4 ); - XMVECTOR X = XMVectorCatmullRom( x1, x2, x3, x4, t ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR x3 = XMLoadFloat2(&v3); + XMVECTOR x4 = XMLoadFloat2(&v4); + XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::CatmullRom( const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t ) +inline Vector2 Vector2::CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &v2 ); - XMVECTOR x3 = XMLoadFloat2( &v3 ); - XMVECTOR x4 = XMLoadFloat2( &v4 ); - XMVECTOR X = XMVectorCatmullRom( x1, x2, x3, x4, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&v2); + XMVECTOR x3 = XMLoadFloat2(&v3); + XMVECTOR x4 = XMLoadFloat2(&v4); + XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Hermite( const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result ) +inline void Vector2::Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, + Vector2& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &t1 ); - XMVECTOR x3 = XMLoadFloat2( &v2 ); - XMVECTOR x4 = XMLoadFloat2( &t2 ); - XMVECTOR X = XMVectorHermite( x1, x2, x3, x4, t ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&t1); + XMVECTOR x3 = XMLoadFloat2(&v2); + XMVECTOR x4 = XMLoadFloat2(&t2); + XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Hermite( const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t ) +inline Vector2 Vector2::Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat2( &v1 ); - XMVECTOR x2 = XMLoadFloat2( &t1 ); - XMVECTOR x3 = XMLoadFloat2( &v2 ); - XMVECTOR x4 = XMLoadFloat2( &t2 ); - XMVECTOR X = XMVectorHermite( x1, x2, x3, x4, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat2(&v1); + XMVECTOR x2 = XMLoadFloat2(&t1); + XMVECTOR x3 = XMLoadFloat2(&v2); + XMVECTOR x4 = XMLoadFloat2(&t2); + XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Reflect( const Vector2& ivec, const Vector2& nvec, Vector2& result ) +inline void Vector2::Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat2( &ivec ); - XMVECTOR n = XMLoadFloat2( &nvec ); - XMVECTOR X = XMVector2Reflect( i, n ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat2(&ivec); + XMVECTOR n = XMLoadFloat2(&nvec); + XMVECTOR X = XMVector2Reflect(i, n); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Reflect( const Vector2& ivec, const Vector2& nvec ) +inline Vector2 Vector2::Reflect(const Vector2& ivec, const Vector2& nvec) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat2( &ivec ); - XMVECTOR n = XMLoadFloat2( &nvec ); - XMVECTOR X = XMVector2Reflect( i, n ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat2(&ivec); + XMVECTOR n = XMLoadFloat2(&nvec); + XMVECTOR X = XMVector2Reflect(i, n); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Refract( const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result ) +inline void Vector2::Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat2( &ivec ); - XMVECTOR n = XMLoadFloat2( &nvec ); - XMVECTOR X = XMVector2Refract( i, n, refractionIndex ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat2(&ivec); + XMVECTOR n = XMLoadFloat2(&nvec); + XMVECTOR X = XMVector2Refract(i, n, refractionIndex); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Refract( const Vector2& ivec, const Vector2& nvec, float refractionIndex ) +inline Vector2 Vector2::Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat2( &ivec ); - XMVECTOR n = XMLoadFloat2( &nvec ); - XMVECTOR X = XMVector2Refract( i, n, refractionIndex ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat2(&ivec); + XMVECTOR n = XMLoadFloat2(&nvec); + XMVECTOR X = XMVector2Refract(i, n, refractionIndex); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Transform( const Vector2& v, const Quaternion& quat, Vector2& result ) +inline void Vector2::Transform(const Vector2& v, const Quaternion& quat, Vector2& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Transform( const Vector2& v, const Quaternion& quat ) +inline Vector2 Vector2::Transform(const Vector2& v, const Quaternion& quat) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } -inline void Vector2::Transform( const Vector2& v, const Matrix& m, Vector2& result ) +inline void Vector2::Transform(const Vector2& v, const Matrix& m, Vector2& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector2TransformCoord( v1, M ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector2TransformCoord(v1, M); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::Transform( const Vector2& v, const Matrix& m ) +inline Vector2 Vector2::Transform(const Vector2& v, const Matrix& m) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector2TransformCoord( v1, M ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector2TransformCoord(v1, M); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } _Use_decl_annotations_ -inline void Vector2::Transform( const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray ) + +inline void Vector2::Transform(const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector2TransformCoordStream( resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector2TransformCoordStream(resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M); } -inline void Vector2::Transform( const Vector2& v, const Matrix& m, Vector4& result ) +inline void Vector2::Transform(const Vector2& v, const Matrix& m, Vector4& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector2Transform( v1, M ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector2Transform(v1, M); + XMStoreFloat4(&result, X); } _Use_decl_annotations_ -inline void Vector2::Transform( const Vector2* varray, size_t count, const Matrix& m, Vector4* resultArray ) + +inline void Vector2::Transform(const Vector2* varray, size_t count, const Matrix& m, Vector4* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector2TransformStream( resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT2), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector2TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT2), count, M); } -inline void Vector2::TransformNormal( const Vector2& v, const Matrix& m, Vector2& result ) +inline void Vector2::TransformNormal(const Vector2& v, const Matrix& m, Vector2& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector2TransformNormal( v1, M ); - XMStoreFloat2( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector2TransformNormal(v1, M); + XMStoreFloat2(&result, X); } -inline Vector2 Vector2::TransformNormal( const Vector2& v, const Matrix& m ) +inline Vector2 Vector2::TransformNormal(const Vector2& v, const Matrix& m) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector2TransformNormal( v1, M ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector2TransformNormal(v1, M); - Vector2 result; - XMStoreFloat2( &result, X ); - return result; + Vector2 result; + XMStoreFloat2(&result, X); + return result; } _Use_decl_annotations_ -inline void Vector2::TransformNormal( const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray ) + +inline void Vector2::TransformNormal(const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector2TransformNormalStream( resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector2TransformNormalStream(resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M); } @@ -588,572 +594,578 @@ inline void Vector2::TransformNormal( const Vector2* varray, size_t count, const // Comparision operators //------------------------------------------------------------------------------ -inline bool Vector3::operator == ( const Vector3& V ) const +inline bool Vector3::operator ==(const Vector3& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - return XMVector3Equal( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + return XMVector3Equal(v1, v2); } -inline bool Vector3::operator != ( const Vector3& V ) const +inline bool Vector3::operator !=(const Vector3& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - return XMVector3NotEqual( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + return XMVector3NotEqual(v1, v2); } //------------------------------------------------------------------------------ // Assignment operators //------------------------------------------------------------------------------ -inline Vector3& Vector3::operator+= (const Vector3& V) +inline Vector3& Vector3::operator+=(const Vector3& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - XMVECTOR X = XMVectorAdd(v1,v2); - XMStoreFloat3( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + XMVECTOR X = XMVectorAdd(v1, v2); + XMStoreFloat3(this, X); + return *this; } -inline Vector3& Vector3::operator-= (const Vector3& V) +inline Vector3& Vector3::operator-=(const Vector3& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - XMVECTOR X = XMVectorSubtract(v1,v2); - XMStoreFloat3( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + XMVECTOR X = XMVectorSubtract(v1, v2); + XMStoreFloat3(this, X); + return *this; } -inline Vector3& Vector3::operator*= (const Vector3& V) +inline Vector3& Vector3::operator*=(const Vector3& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - XMVECTOR X = XMVectorMultiply(v1,v2); - XMStoreFloat3( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + XMVECTOR X = XMVectorMultiply(v1, v2); + XMStoreFloat3(this, X); + return *this; } -inline Vector3& Vector3::operator*= (float S) +inline Vector3& Vector3::operator*=(float S) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVectorScale(v1,S); - XMStoreFloat3( this, X ); - return *this; -} + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVectorScale(v1, S); + XMStoreFloat3(this, X); + return *this; +} -inline Vector3& Vector3::operator/= (float S) +inline Vector3& Vector3::operator/=(float S) { - using namespace DirectX; - assert( S != 0.0f ); - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVectorScale(v1, 1.f/S); - XMStoreFloat3( this, X ); - return *this; -} + using namespace DirectX; + assert(S != 0.0f); + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVectorScale(v1, 1.f / S); + XMStoreFloat3(this, X); + return *this; +} //------------------------------------------------------------------------------ // Urnary operators //------------------------------------------------------------------------------ -inline Vector3 Vector3::operator- () const +inline Vector3 Vector3::operator-() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVectorNegate( v1 ); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVectorNegate(v1); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } //------------------------------------------------------------------------------ // Binary operators //------------------------------------------------------------------------------ -inline Vector3 operator+ (const Vector3& V1, const Vector3& V2) +inline Vector3 operator+(const Vector3& V1, const Vector3& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &V1 ); - XMVECTOR v2 = XMLoadFloat3( &V2 ); - XMVECTOR X = XMVectorAdd(v1,v2); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&V1); + XMVECTOR v2 = XMLoadFloat3(&V2); + XMVECTOR X = XMVectorAdd(v1, v2); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } -inline Vector3 operator- (const Vector3& V1, const Vector3& V2) +inline Vector3 operator-(const Vector3& V1, const Vector3& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &V1 ); - XMVECTOR v2 = XMLoadFloat3( &V2 ); - XMVECTOR X = XMVectorSubtract(v1,v2); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&V1); + XMVECTOR v2 = XMLoadFloat3(&V2); + XMVECTOR X = XMVectorSubtract(v1, v2); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } -inline Vector3 operator* (const Vector3& V1, const Vector3& V2) +inline Vector3 operator*(const Vector3& V1, const Vector3& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &V1 ); - XMVECTOR v2 = XMLoadFloat3( &V2 ); - XMVECTOR X = XMVectorMultiply(v1,v2); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&V1); + XMVECTOR v2 = XMLoadFloat3(&V2); + XMVECTOR X = XMVectorMultiply(v1, v2); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } -inline Vector3 operator* (const Vector3& V, float S) +inline Vector3 operator*(const Vector3& V, float S) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &V ); - XMVECTOR X = XMVectorScale(v1,S); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&V); + XMVECTOR X = XMVectorScale(v1, S); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } -inline Vector3 operator/ (const Vector3& V1, const Vector3& V2) +inline Vector3 operator/(const Vector3& V1, const Vector3& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &V1 ); - XMVECTOR v2 = XMLoadFloat3( &V2 ); - XMVECTOR X = XMVectorDivide(v1,v2); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&V1); + XMVECTOR v2 = XMLoadFloat3(&V2); + XMVECTOR X = XMVectorDivide(v1, v2); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } -inline Vector3 operator* (float S, const Vector3& V) +inline Vector3 operator*(float S, const Vector3& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &V ); - XMVECTOR X = XMVectorScale(v1,S); - Vector3 R; - XMStoreFloat3( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&V); + XMVECTOR X = XMVectorScale(v1, S); + Vector3 R; + XMStoreFloat3(&R, X); + return R; } //------------------------------------------------------------------------------ // Vector operations //------------------------------------------------------------------------------ -inline bool Vector3::InBounds( const Vector3& Bounds ) const +inline bool Vector3::InBounds(const Vector3& Bounds) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &Bounds ); - return XMVector3InBounds( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&Bounds); + return XMVector3InBounds(v1, v2); } inline float Vector3::Length() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVector3Length( v1 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVector3Length(v1); + return XMVectorGetX(X); } inline float Vector3::LengthSquared() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVector3LengthSq( v1 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVector3LengthSq(v1); + return XMVectorGetX(X); } -inline float Vector3::Dot( const Vector3& V ) const +inline float Vector3::Dot(const Vector3& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - XMVECTOR X = XMVector3Dot( v1, v2 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + XMVECTOR X = XMVector3Dot(v1, v2); + return XMVectorGetX(X); } -inline void Vector3::Cross( const Vector3& V, Vector3& result ) const +inline void Vector3::Cross(const Vector3& V, Vector3& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - XMVECTOR R = XMVector3Cross( v1, v2 ); - XMStoreFloat3( &result, R ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + XMVECTOR R = XMVector3Cross(v1, v2); + XMStoreFloat3(&result, R); } -inline Vector3 Vector3::Cross( const Vector3& V ) const +inline Vector3 Vector3::Cross(const Vector3& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &V ); - XMVECTOR R = XMVector3Cross( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&V); + XMVECTOR R = XMVector3Cross(v1, v2); - Vector3 result; - XMStoreFloat3( &result, R ); - return result; + Vector3 result; + XMStoreFloat3(&result, R); + return result; } inline void Vector3::Normalize() { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVector3Normalize( v1 ); - XMStoreFloat3( this, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVector3Normalize(v1); + XMStoreFloat3(this, X); } -inline void Vector3::Normalize( Vector3& result ) const +inline void Vector3::Normalize(Vector3& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR X = XMVector3Normalize( v1 ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR X = XMVector3Normalize(v1); + XMStoreFloat3(&result, X); } -inline void Vector3::Clamp( const Vector3& vmin, const Vector3& vmax ) +inline void Vector3::Clamp(const Vector3& vmin, const Vector3& vmax) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &vmin ); - XMVECTOR v3 = XMLoadFloat3( &vmax ); - XMVECTOR X = XMVectorClamp( v1, v2, v3 ); - XMStoreFloat3( this, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&vmin); + XMVECTOR v3 = XMLoadFloat3(&vmax); + XMVECTOR X = XMVectorClamp(v1, v2, v3); + XMStoreFloat3(this, X); } -inline void Vector3::Clamp( const Vector3& vmin, const Vector3& vmax, Vector3& result ) const +inline void Vector3::Clamp(const Vector3& vmin, const Vector3& vmax, Vector3& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( this ); - XMVECTOR v2 = XMLoadFloat3( &vmin ); - XMVECTOR v3 = XMLoadFloat3( &vmax ); - XMVECTOR X = XMVectorClamp( v1, v2, v3 ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(this); + XMVECTOR v2 = XMLoadFloat3(&vmin); + XMVECTOR v3 = XMLoadFloat3(&vmax); + XMVECTOR X = XMVectorClamp(v1, v2, v3); + XMStoreFloat3(&result, X); } //------------------------------------------------------------------------------ // Static functions //------------------------------------------------------------------------------ -inline float Vector3::Distance( const Vector3& v1, const Vector3& v2 ) +inline float Vector3::Distance(const Vector3& v1, const Vector3& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR V = XMVectorSubtract( x2, x1 ); - XMVECTOR X = XMVector3Length( V ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR V = XMVectorSubtract(x2, x1); + XMVECTOR X = XMVector3Length(V); + return XMVectorGetX(X); } -inline float Vector3::DistanceSquared( const Vector3& v1, const Vector3& v2 ) +inline float Vector3::DistanceSquared(const Vector3& v1, const Vector3& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR V = XMVectorSubtract( x2, x1 ); - XMVECTOR X = XMVector3LengthSq( V ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR V = XMVectorSubtract(x2, x1); + XMVECTOR X = XMVector3LengthSq(V); + return XMVectorGetX(X); } -inline void Vector3::Min( const Vector3& v1, const Vector3& v2, Vector3& result ) +inline void Vector3::Min(const Vector3& v1, const Vector3& v2, Vector3& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorMin( x1, x2 ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorMin(x1, x2); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Min( const Vector3& v1, const Vector3& v2 ) +inline Vector3 Vector3::Min(const Vector3& v1, const Vector3& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorMin( x1, x2 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorMin(x1, x2); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Max( const Vector3& v1, const Vector3& v2, Vector3& result ) +inline void Vector3::Max(const Vector3& v1, const Vector3& v2, Vector3& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorMax( x1, x2 ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorMax(x1, x2); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Max( const Vector3& v1, const Vector3& v2 ) +inline Vector3 Vector3::Max(const Vector3& v1, const Vector3& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorMax( x1, x2 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorMax(x1, x2); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Lerp( const Vector3& v1, const Vector3& v2, float t, Vector3& result ) +inline void Vector3::Lerp(const Vector3& v1, const Vector3& v2, float t, Vector3& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Lerp( const Vector3& v1, const Vector3& v2, float t ) +inline Vector3 Vector3::Lerp(const Vector3& v1, const Vector3& v2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::SmoothStep( const Vector3& v1, const Vector3& v2, float t, Vector3& result ) +inline void Vector3::SmoothStep(const Vector3& v1, const Vector3& v2, float t, Vector3& result) { - using namespace DirectX; - t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 - t = t*t*(3.f - 2.f*t); - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 + t = t * t * (3.f - 2.f * t); + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::SmoothStep( const Vector3& v1, const Vector3& v2, float t ) +inline Vector3 Vector3::SmoothStep(const Vector3& v1, const Vector3& v2, float t) { - using namespace DirectX; - t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 - t = t*t*(3.f - 2.f*t); - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); + using namespace DirectX; + t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 + t = t * t * (3.f - 2.f * t); + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Barycentric( const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, Vector3& result ) +inline void Vector3::Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, + Vector3& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR x3 = XMLoadFloat3( &v3 ); - XMVECTOR X = XMVectorBaryCentric( x1, x2, x3, f, g ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR x3 = XMLoadFloat3(&v3); + XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Barycentric( const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g ) +inline Vector3 Vector3::Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR x3 = XMLoadFloat3( &v3 ); - XMVECTOR X = XMVectorBaryCentric( x1, x2, x3, f, g ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR x3 = XMLoadFloat3(&v3); + XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::CatmullRom( const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, Vector3& result ) +inline void Vector3::CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, + Vector3& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR x3 = XMLoadFloat3( &v3 ); - XMVECTOR x4 = XMLoadFloat3( &v4 ); - XMVECTOR X = XMVectorCatmullRom( x1, x2, x3, x4, t ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR x3 = XMLoadFloat3(&v3); + XMVECTOR x4 = XMLoadFloat3(&v4); + XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::CatmullRom( const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t ) +inline Vector3 Vector3::CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &v2 ); - XMVECTOR x3 = XMLoadFloat3( &v3 ); - XMVECTOR x4 = XMLoadFloat3( &v4 ); - XMVECTOR X = XMVectorCatmullRom( x1, x2, x3, x4, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&v2); + XMVECTOR x3 = XMLoadFloat3(&v3); + XMVECTOR x4 = XMLoadFloat3(&v4); + XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Hermite( const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, Vector3& result ) +inline void Vector3::Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, + Vector3& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &t1 ); - XMVECTOR x3 = XMLoadFloat3( &v2 ); - XMVECTOR x4 = XMLoadFloat3( &t2 ); - XMVECTOR X = XMVectorHermite( x1, x2, x3, x4, t ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&t1); + XMVECTOR x3 = XMLoadFloat3(&v2); + XMVECTOR x4 = XMLoadFloat3(&t2); + XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Hermite( const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t ) +inline Vector3 Vector3::Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat3( &v1 ); - XMVECTOR x2 = XMLoadFloat3( &t1 ); - XMVECTOR x3 = XMLoadFloat3( &v2 ); - XMVECTOR x4 = XMLoadFloat3( &t2 ); - XMVECTOR X = XMVectorHermite( x1, x2, x3, x4, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat3(&v1); + XMVECTOR x2 = XMLoadFloat3(&t1); + XMVECTOR x3 = XMLoadFloat3(&v2); + XMVECTOR x4 = XMLoadFloat3(&t2); + XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Reflect( const Vector3& ivec, const Vector3& nvec, Vector3& result ) +inline void Vector3::Reflect(const Vector3& ivec, const Vector3& nvec, Vector3& result) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat3( &ivec ); - XMVECTOR n = XMLoadFloat3( &nvec ); - XMVECTOR X = XMVector3Reflect( i, n ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat3(&ivec); + XMVECTOR n = XMLoadFloat3(&nvec); + XMVECTOR X = XMVector3Reflect(i, n); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Reflect( const Vector3& ivec, const Vector3& nvec ) +inline Vector3 Vector3::Reflect(const Vector3& ivec, const Vector3& nvec) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat3( &ivec ); - XMVECTOR n = XMLoadFloat3( &nvec ); - XMVECTOR X = XMVector3Reflect( i, n ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat3(&ivec); + XMVECTOR n = XMLoadFloat3(&nvec); + XMVECTOR X = XMVector3Reflect(i, n); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Refract( const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result ) +inline void Vector3::Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat3( &ivec ); - XMVECTOR n = XMLoadFloat3( &nvec ); - XMVECTOR X = XMVector3Refract( i, n, refractionIndex ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat3(&ivec); + XMVECTOR n = XMLoadFloat3(&nvec); + XMVECTOR X = XMVector3Refract(i, n, refractionIndex); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Refract( const Vector3& ivec, const Vector3& nvec, float refractionIndex ) +inline Vector3 Vector3::Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat3( &ivec ); - XMVECTOR n = XMLoadFloat3( &nvec ); - XMVECTOR X = XMVector3Refract( i, n, refractionIndex ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat3(&ivec); + XMVECTOR n = XMLoadFloat3(&nvec); + XMVECTOR X = XMVector3Refract(i, n, refractionIndex); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Transform( const Vector3& v, const Quaternion& quat, Vector3& result ) +inline void Vector3::Transform(const Vector3& v, const Quaternion& quat, Vector3& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Transform( const Vector3& v, const Quaternion& quat ) +inline Vector3 Vector3::Transform(const Vector3& v, const Quaternion& quat) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } -inline void Vector3::Transform( const Vector3& v, const Matrix& m, Vector3& result ) +inline void Vector3::Transform(const Vector3& v, const Matrix& m, Vector3& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector3TransformCoord( v1, M ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector3TransformCoord(v1, M); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::Transform( const Vector3& v, const Matrix& m ) +inline Vector3 Vector3::Transform(const Vector3& v, const Matrix& m) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector3TransformCoord( v1, M ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector3TransformCoord(v1, M); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } _Use_decl_annotations_ -inline void Vector3::Transform( const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray ) + +inline void Vector3::Transform(const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector3TransformCoordStream( resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector3TransformCoordStream(resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M); } -inline void Vector3::Transform( const Vector3& v, const Matrix& m, Vector4& result ) +inline void Vector3::Transform(const Vector3& v, const Matrix& m, Vector4& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector3Transform( v1, M ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector3Transform(v1, M); + XMStoreFloat4(&result, X); } _Use_decl_annotations_ -inline void Vector3::Transform( const Vector3* varray, size_t count, const Matrix& m, Vector4* resultArray ) + +inline void Vector3::Transform(const Vector3* varray, size_t count, const Matrix& m, Vector4* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector3TransformStream( resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT3), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector3TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT3), count, M); } -inline void Vector3::TransformNormal( const Vector3& v, const Matrix& m, Vector3& result ) +inline void Vector3::TransformNormal(const Vector3& v, const Matrix& m, Vector3& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector3TransformNormal( v1, M ); - XMStoreFloat3( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector3TransformNormal(v1, M); + XMStoreFloat3(&result, X); } -inline Vector3 Vector3::TransformNormal( const Vector3& v, const Matrix& m ) +inline Vector3 Vector3::TransformNormal(const Vector3& v, const Matrix& m) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector3TransformNormal( v1, M ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector3TransformNormal(v1, M); - Vector3 result; - XMStoreFloat3( &result, X ); - return result; + Vector3 result; + XMStoreFloat3(&result, X); + return result; } _Use_decl_annotations_ -inline void Vector3::TransformNormal( const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray ) + +inline void Vector3::TransformNormal(const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector3TransformNormalStream( resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector3TransformNormalStream(resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M); } @@ -1167,576 +1179,580 @@ inline void Vector3::TransformNormal( const Vector3* varray, size_t count, const // Comparision operators //------------------------------------------------------------------------------ -inline bool Vector4::operator == ( const Vector4& V ) const +inline bool Vector4::operator ==(const Vector4& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &V ); - return XMVector4Equal( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&V); + return XMVector4Equal(v1, v2); } -inline bool Vector4::operator != ( const Vector4& V ) const +inline bool Vector4::operator !=(const Vector4& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &V ); - return XMVector4NotEqual( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&V); + return XMVector4NotEqual(v1, v2); } //------------------------------------------------------------------------------ // Assignment operators //------------------------------------------------------------------------------ -inline Vector4& Vector4::operator+= (const Vector4& V) +inline Vector4& Vector4::operator+=(const Vector4& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &V ); - XMVECTOR X = XMVectorAdd(v1,v2); - XMStoreFloat4( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&V); + XMVECTOR X = XMVectorAdd(v1, v2); + XMStoreFloat4(this, X); + return *this; } -inline Vector4& Vector4::operator-= (const Vector4& V) +inline Vector4& Vector4::operator-=(const Vector4& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &V ); - XMVECTOR X = XMVectorSubtract(v1,v2); - XMStoreFloat4( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&V); + XMVECTOR X = XMVectorSubtract(v1, v2); + XMStoreFloat4(this, X); + return *this; } -inline Vector4& Vector4::operator*= (const Vector4& V) +inline Vector4& Vector4::operator*=(const Vector4& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &V ); - XMVECTOR X = XMVectorMultiply(v1,v2); - XMStoreFloat4( this, X ); - return *this; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&V); + XMVECTOR X = XMVectorMultiply(v1, v2); + XMStoreFloat4(this, X); + return *this; } -inline Vector4& Vector4::operator*= (float S) +inline Vector4& Vector4::operator*=(float S) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVectorScale(v1,S); - XMStoreFloat4( this, X ); - return *this; -} + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVectorScale(v1, S); + XMStoreFloat4(this, X); + return *this; +} -inline Vector4& Vector4::operator/= (float S) +inline Vector4& Vector4::operator/=(float S) { - using namespace DirectX; - assert( S != 0.0f ); - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVectorScale(v1, 1.f/S); - XMStoreFloat4( this, X ); - return *this; -} + using namespace DirectX; + assert(S != 0.0f); + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVectorScale(v1, 1.f / S); + XMStoreFloat4(this, X); + return *this; +} //------------------------------------------------------------------------------ // Urnary operators //------------------------------------------------------------------------------ -inline Vector4 Vector4::operator- () const +inline Vector4 Vector4::operator-() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVectorNegate( v1 ); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVectorNegate(v1); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } //------------------------------------------------------------------------------ // Binary operators //------------------------------------------------------------------------------ -inline Vector4 operator+ (const Vector4& V1, const Vector4& V2) +inline Vector4 operator+(const Vector4& V1, const Vector4& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &V1 ); - XMVECTOR v2 = XMLoadFloat4( &V2 ); - XMVECTOR X = XMVectorAdd(v1,v2); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&V1); + XMVECTOR v2 = XMLoadFloat4(&V2); + XMVECTOR X = XMVectorAdd(v1, v2); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } -inline Vector4 operator- (const Vector4& V1, const Vector4& V2) +inline Vector4 operator-(const Vector4& V1, const Vector4& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &V1 ); - XMVECTOR v2 = XMLoadFloat4( &V2 ); - XMVECTOR X = XMVectorSubtract(v1,v2); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&V1); + XMVECTOR v2 = XMLoadFloat4(&V2); + XMVECTOR X = XMVectorSubtract(v1, v2); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } -inline Vector4 operator* (const Vector4& V1, const Vector4& V2) +inline Vector4 operator*(const Vector4& V1, const Vector4& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &V1 ); - XMVECTOR v2 = XMLoadFloat4( &V2 ); - XMVECTOR X = XMVectorMultiply(v1,v2); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&V1); + XMVECTOR v2 = XMLoadFloat4(&V2); + XMVECTOR X = XMVectorMultiply(v1, v2); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } -inline Vector4 operator* (const Vector4& V, float S) +inline Vector4 operator*(const Vector4& V, float S) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &V ); - XMVECTOR X = XMVectorScale(v1,S); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&V); + XMVECTOR X = XMVectorScale(v1, S); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } -inline Vector4 operator/ (const Vector4& V1, const Vector4& V2) +inline Vector4 operator/(const Vector4& V1, const Vector4& V2) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &V1 ); - XMVECTOR v2 = XMLoadFloat4( &V2 ); - XMVECTOR X = XMVectorDivide(v1,v2); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&V1); + XMVECTOR v2 = XMLoadFloat4(&V2); + XMVECTOR X = XMVectorDivide(v1, v2); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } -inline Vector4 operator* (float S, const Vector4& V) +inline Vector4 operator*(float S, const Vector4& V) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &V ); - XMVECTOR X = XMVectorScale(v1,S); - Vector4 R; - XMStoreFloat4( &R, X ); - return R; + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&V); + XMVECTOR X = XMVectorScale(v1, S); + Vector4 R; + XMStoreFloat4(&R, X); + return R; } //------------------------------------------------------------------------------ // Vector operations //------------------------------------------------------------------------------ -inline bool Vector4::InBounds( const Vector4& Bounds ) const +inline bool Vector4::InBounds(const Vector4& Bounds) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &Bounds ); - return XMVector4InBounds( v1, v2 ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&Bounds); + return XMVector4InBounds(v1, v2); } inline float Vector4::Length() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVector4Length( v1 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVector4Length(v1); + return XMVectorGetX(X); } inline float Vector4::LengthSquared() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVector4LengthSq( v1 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVector4LengthSq(v1); + return XMVectorGetX(X); } -inline float Vector4::Dot( const Vector4& V ) const +inline float Vector4::Dot(const Vector4& V) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &V ); - XMVECTOR X = XMVector4Dot( v1, v2 ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&V); + XMVECTOR X = XMVector4Dot(v1, v2); + return XMVectorGetX(X); } -inline void Vector4::Cross( const Vector4& v1, const Vector4& v2, Vector4& result ) const +inline void Vector4::Cross(const Vector4& v1, const Vector4& v2, Vector4& result) const { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( this ); - XMVECTOR x2 = XMLoadFloat4( &v1 ); - XMVECTOR x3 = XMLoadFloat4( &v2 ); - XMVECTOR R = XMVector4Cross( x1, x2, x3 ); - XMStoreFloat4( &result, R ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(this); + XMVECTOR x2 = XMLoadFloat4(&v1); + XMVECTOR x3 = XMLoadFloat4(&v2); + XMVECTOR R = XMVector4Cross(x1, x2, x3); + XMStoreFloat4(&result, R); } -inline Vector4 Vector4::Cross( const Vector4& v1, const Vector4& v2 ) const +inline Vector4 Vector4::Cross(const Vector4& v1, const Vector4& v2) const { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( this ); - XMVECTOR x2 = XMLoadFloat4( &v1 ); - XMVECTOR x3 = XMLoadFloat4( &v2 ); - XMVECTOR R = XMVector4Cross( x1, x2, x3 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(this); + XMVECTOR x2 = XMLoadFloat4(&v1); + XMVECTOR x3 = XMLoadFloat4(&v2); + XMVECTOR R = XMVector4Cross(x1, x2, x3); - Vector4 result; - XMStoreFloat4( &result, R ); - return result; + Vector4 result; + XMStoreFloat4(&result, R); + return result; } inline void Vector4::Normalize() { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVector4Normalize( v1 ); - XMStoreFloat4( this, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVector4Normalize(v1); + XMStoreFloat4(this, X); } -inline void Vector4::Normalize( Vector4& result ) const +inline void Vector4::Normalize(Vector4& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR X = XMVector4Normalize( v1 ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR X = XMVector4Normalize(v1); + XMStoreFloat4(&result, X); } -inline void Vector4::Clamp( const Vector4& vmin, const Vector4& vmax ) +inline void Vector4::Clamp(const Vector4& vmin, const Vector4& vmax) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &vmin ); - XMVECTOR v3 = XMLoadFloat4( &vmax ); - XMVECTOR X = XMVectorClamp( v1, v2, v3 ); - XMStoreFloat4( this, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&vmin); + XMVECTOR v3 = XMLoadFloat4(&vmax); + XMVECTOR X = XMVectorClamp(v1, v2, v3); + XMStoreFloat4(this, X); } -inline void Vector4::Clamp( const Vector4& vmin, const Vector4& vmax, Vector4& result ) const +inline void Vector4::Clamp(const Vector4& vmin, const Vector4& vmax, Vector4& result) const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( this ); - XMVECTOR v2 = XMLoadFloat4( &vmin ); - XMVECTOR v3 = XMLoadFloat4( &vmax ); - XMVECTOR X = XMVectorClamp( v1, v2, v3 ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(this); + XMVECTOR v2 = XMLoadFloat4(&vmin); + XMVECTOR v3 = XMLoadFloat4(&vmax); + XMVECTOR X = XMVectorClamp(v1, v2, v3); + XMStoreFloat4(&result, X); } //------------------------------------------------------------------------------ // Static functions //------------------------------------------------------------------------------ -inline float Vector4::Distance( const Vector4& v1, const Vector4& v2 ) +inline float Vector4::Distance(const Vector4& v1, const Vector4& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR V = XMVectorSubtract( x2, x1 ); - XMVECTOR X = XMVector4Length( V ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR V = XMVectorSubtract(x2, x1); + XMVECTOR X = XMVector4Length(V); + return XMVectorGetX(X); } -inline float Vector4::DistanceSquared( const Vector4& v1, const Vector4& v2 ) +inline float Vector4::DistanceSquared(const Vector4& v1, const Vector4& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR V = XMVectorSubtract( x2, x1 ); - XMVECTOR X = XMVector4LengthSq( V ); - return XMVectorGetX( X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR V = XMVectorSubtract(x2, x1); + XMVECTOR X = XMVector4LengthSq(V); + return XMVectorGetX(X); } -inline void Vector4::Min( const Vector4& v1, const Vector4& v2, Vector4& result ) +inline void Vector4::Min(const Vector4& v1, const Vector4& v2, Vector4& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorMin( x1, x2 ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorMin(x1, x2); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Min( const Vector4& v1, const Vector4& v2 ) +inline Vector4 Vector4::Min(const Vector4& v1, const Vector4& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorMin( x1, x2 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorMin(x1, x2); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Max( const Vector4& v1, const Vector4& v2, Vector4& result ) +inline void Vector4::Max(const Vector4& v1, const Vector4& v2, Vector4& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorMax( x1, x2 ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorMax(x1, x2); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Max( const Vector4& v1, const Vector4& v2 ) +inline Vector4 Vector4::Max(const Vector4& v1, const Vector4& v2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorMax( x1, x2 ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorMax(x1, x2); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Lerp( const Vector4& v1, const Vector4& v2, float t, Vector4& result ) +inline void Vector4::Lerp(const Vector4& v1, const Vector4& v2, float t, Vector4& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Lerp( const Vector4& v1, const Vector4& v2, float t ) +inline Vector4 Vector4::Lerp(const Vector4& v1, const Vector4& v2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::SmoothStep( const Vector4& v1, const Vector4& v2, float t, Vector4& result ) +inline void Vector4::SmoothStep(const Vector4& v1, const Vector4& v2, float t, Vector4& result) { - using namespace DirectX; - t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 - t = t*t*(3.f - 2.f*t); - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 + t = t * t * (3.f - 2.f * t); + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::SmoothStep( const Vector4& v1, const Vector4& v2, float t ) +inline Vector4 Vector4::SmoothStep(const Vector4& v1, const Vector4& v2, float t) { - using namespace DirectX; - t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 - t = t*t*(3.f - 2.f*t); - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR X = XMVectorLerp( x1, x2, t ); + using namespace DirectX; + t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t); // Clamp value to 0 to 1 + t = t * t * (3.f - 2.f * t); + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR X = XMVectorLerp(x1, x2, t); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Barycentric( const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, Vector4& result ) +inline void Vector4::Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, + Vector4& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR x3 = XMLoadFloat4( &v3 ); - XMVECTOR X = XMVectorBaryCentric( x1, x2, x3, f, g ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR x3 = XMLoadFloat4(&v3); + XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Barycentric( const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g ) +inline Vector4 Vector4::Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR x3 = XMLoadFloat4( &v3 ); - XMVECTOR X = XMVectorBaryCentric( x1, x2, x3, f, g ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR x3 = XMLoadFloat4(&v3); + XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::CatmullRom( const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, Vector4& result ) +inline void Vector4::CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, + Vector4& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR x3 = XMLoadFloat4( &v3 ); - XMVECTOR x4 = XMLoadFloat4( &v4 ); - XMVECTOR X = XMVectorCatmullRom( x1, x2, x3, x4, t ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR x3 = XMLoadFloat4(&v3); + XMVECTOR x4 = XMLoadFloat4(&v4); + XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::CatmullRom( const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t ) +inline Vector4 Vector4::CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &v2 ); - XMVECTOR x3 = XMLoadFloat4( &v3 ); - XMVECTOR x4 = XMLoadFloat4( &v4 ); - XMVECTOR X = XMVectorCatmullRom( x1, x2, x3, x4, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&v2); + XMVECTOR x3 = XMLoadFloat4(&v3); + XMVECTOR x4 = XMLoadFloat4(&v4); + XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Hermite( const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, Vector4& result ) +inline void Vector4::Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, + Vector4& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &t1 ); - XMVECTOR x3 = XMLoadFloat4( &v2 ); - XMVECTOR x4 = XMLoadFloat4( &t2 ); - XMVECTOR X = XMVectorHermite( x1, x2, x3, x4, t ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&t1); + XMVECTOR x3 = XMLoadFloat4(&v2); + XMVECTOR x4 = XMLoadFloat4(&t2); + XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Hermite( const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t ) +inline Vector4 Vector4::Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( &v1 ); - XMVECTOR x2 = XMLoadFloat4( &t1 ); - XMVECTOR x3 = XMLoadFloat4( &v2 ); - XMVECTOR x4 = XMLoadFloat4( &t2 ); - XMVECTOR X = XMVectorHermite( x1, x2, x3, x4, t ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(&v1); + XMVECTOR x2 = XMLoadFloat4(&t1); + XMVECTOR x3 = XMLoadFloat4(&v2); + XMVECTOR x4 = XMLoadFloat4(&t2); + XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Reflect( const Vector4& ivec, const Vector4& nvec, Vector4& result ) +inline void Vector4::Reflect(const Vector4& ivec, const Vector4& nvec, Vector4& result) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat4( &ivec ); - XMVECTOR n = XMLoadFloat4( &nvec ); - XMVECTOR X = XMVector4Reflect( i, n ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat4(&ivec); + XMVECTOR n = XMLoadFloat4(&nvec); + XMVECTOR X = XMVector4Reflect(i, n); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Reflect( const Vector4& ivec, const Vector4& nvec ) +inline Vector4 Vector4::Reflect(const Vector4& ivec, const Vector4& nvec) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat4( &ivec ); - XMVECTOR n = XMLoadFloat4( &nvec ); - XMVECTOR X = XMVector4Reflect( i, n ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat4(&ivec); + XMVECTOR n = XMLoadFloat4(&nvec); + XMVECTOR X = XMVector4Reflect(i, n); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Refract( const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result ) +inline void Vector4::Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat4( &ivec ); - XMVECTOR n = XMLoadFloat4( &nvec ); - XMVECTOR X = XMVector4Refract( i, n, refractionIndex ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat4(&ivec); + XMVECTOR n = XMLoadFloat4(&nvec); + XMVECTOR X = XMVector4Refract(i, n, refractionIndex); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Refract( const Vector4& ivec, const Vector4& nvec, float refractionIndex ) +inline Vector4 Vector4::Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex) { - using namespace DirectX; - XMVECTOR i = XMLoadFloat4( &ivec ); - XMVECTOR n = XMLoadFloat4( &nvec ); - XMVECTOR X = XMVector4Refract( i, n, refractionIndex ); + using namespace DirectX; + XMVECTOR i = XMLoadFloat4(&ivec); + XMVECTOR n = XMLoadFloat4(&nvec); + XMVECTOR X = XMVector4Refract(i, n, refractionIndex); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Transform( const Vector2& v, const Quaternion& quat, Vector4& result ) +inline void Vector4::Transform(const Vector2& v, const Quaternion& quat, Vector4& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - X = XMVectorSelect( g_XMIdentityR3, X, g_XMSelect1110 ); // result.w = 1.f - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Transform( const Vector2& v, const Quaternion& quat ) +inline Vector4 Vector4::Transform(const Vector2& v, const Quaternion& quat) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat2( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - X = XMVectorSelect( g_XMIdentityR3, X, g_XMSelect1110 ); // result.w = 1.f + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat2(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Transform( const Vector3& v, const Quaternion& quat, Vector4& result ) +inline void Vector4::Transform(const Vector3& v, const Quaternion& quat, Vector4& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - X = XMVectorSelect( g_XMIdentityR3, X, g_XMSelect1110 ); // result.w = 1.f - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Transform( const Vector3& v, const Quaternion& quat ) +inline Vector4 Vector4::Transform(const Vector3& v, const Quaternion& quat) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat3( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - X = XMVectorSelect( g_XMIdentityR3, X, g_XMSelect1110 ); // result.w = 1.f + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat3(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Transform( const Vector4& v, const Quaternion& quat, Vector4& result ) +inline void Vector4::Transform(const Vector4& v, const Quaternion& quat, Vector4& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - X = XMVectorSelect( v1, X, g_XMSelect1110 ); // result.w = v.w - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + X = XMVectorSelect(v1, X, g_XMSelect1110); // result.w = v.w + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Transform( const Vector4& v, const Quaternion& quat ) +inline Vector4 Vector4::Transform(const Vector4& v, const Quaternion& quat) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &v ); - XMVECTOR q = XMLoadFloat4( &quat ); - XMVECTOR X = XMVector3Rotate( v1, q ); - X = XMVectorSelect( v1, X, g_XMSelect1110 ); // result.w = v.w + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&v); + XMVECTOR q = XMLoadFloat4(&quat); + XMVECTOR X = XMVector3Rotate(v1, q); + X = XMVectorSelect(v1, X, g_XMSelect1110); // result.w = v.w - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } -inline void Vector4::Transform( const Vector4& v, const Matrix& m, Vector4& result ) +inline void Vector4::Transform(const Vector4& v, const Matrix& m, Vector4& result) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector4Transform( v1, M ); - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector4Transform(v1, M); + XMStoreFloat4(&result, X); } -inline Vector4 Vector4::Transform( const Vector4& v, const Matrix& m ) +inline Vector4 Vector4::Transform(const Vector4& v, const Matrix& m) { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( &v ); - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVECTOR X = XMVector4Transform( v1, M ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(&v); + XMMATRIX M = XMLoadFloat4x4(&m); + XMVECTOR X = XMVector4Transform(v1, M); - Vector4 result; - XMStoreFloat4( &result, X ); - return result; + Vector4 result; + XMStoreFloat4(&result, X); + return result; } _Use_decl_annotations_ -inline void Vector4::Transform( const Vector4* varray, size_t count, const Matrix& m, Vector4* resultArray ) + +inline void Vector4::Transform(const Vector4* varray, size_t count, const Matrix& m, Vector4* resultArray) { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( &m ); - XMVector4TransformStream( resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT4), count, M ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(&m); + XMVector4TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT4), count, M); } @@ -1750,42 +1766,42 @@ inline void Vector4::Transform( const Vector4* varray, size_t count, const Matri // Comparision operators //------------------------------------------------------------------------------ -inline bool Matrix::operator == ( const Matrix& M ) const +inline bool Matrix::operator ==(const Matrix& M) const { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M._41)); - return ( XMVector4Equal( x1, y1 ) - && XMVector4Equal( x2, y2 ) - && XMVector4Equal( x3, y3 ) - && XMVector4Equal( x4, y4 ) ) != 0; + return (XMVector4Equal(x1, y1) + && XMVector4Equal(x2, y2) + && XMVector4Equal(x3, y3) + && XMVector4Equal(x4, y4)) != 0; } -inline bool Matrix::operator != ( const Matrix& M ) const +inline bool Matrix::operator !=(const Matrix& M) const { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M._41)); - return ( XMVector4NotEqual( x1, y1 ) - || XMVector4NotEqual( x2, y2 ) - || XMVector4NotEqual( x3, y3 ) - || XMVector4NotEqual( x4, y4 ) ) != 0; + return (XMVector4NotEqual(x1, y1) + || XMVector4NotEqual(x2, y2) + || XMVector4NotEqual(x3, y3) + || XMVector4NotEqual(x4, y4)) != 0; } //------------------------------------------------------------------------------ @@ -1794,412 +1810,460 @@ inline bool Matrix::operator != ( const Matrix& M ) const inline Matrix::Matrix(const XMFLOAT3X3& M) { - _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f; - _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f; - _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f; - _41 = 0.f; _42 = 0.f; _43 = 0.f; _44 = 1.f; + _11 = M._11; + _12 = M._12; + _13 = M._13; + _14 = 0.f; + _21 = M._21; + _22 = M._22; + _23 = M._23; + _24 = 0.f; + _31 = M._31; + _32 = M._32; + _33 = M._33; + _34 = 0.f; + _41 = 0.f; + _42 = 0.f; + _43 = 0.f; + _44 = 1.f; } inline Matrix::Matrix(const XMFLOAT4X3& M) { - _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f; - _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f; - _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f; - _41 = M._41; _42 = M._42; _43 = M._43; _44 = 1.f; + _11 = M._11; + _12 = M._12; + _13 = M._13; + _14 = 0.f; + _21 = M._21; + _22 = M._22; + _23 = M._23; + _24 = 0.f; + _31 = M._31; + _32 = M._32; + _33 = M._33; + _34 = 0.f; + _41 = M._41; + _42 = M._42; + _43 = M._43; + _44 = 1.f; } -inline Matrix& Matrix::operator= (const XMFLOAT3X3& M) +inline Matrix& Matrix::operator=(const XMFLOAT3X3& M) { - _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f; - _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f; - _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f; - _41 = 0.f; _42 = 0.f; _43 = 0.f; _44 = 1.f; - return *this; + _11 = M._11; + _12 = M._12; + _13 = M._13; + _14 = 0.f; + _21 = M._21; + _22 = M._22; + _23 = M._23; + _24 = 0.f; + _31 = M._31; + _32 = M._32; + _33 = M._33; + _34 = 0.f; + _41 = 0.f; + _42 = 0.f; + _43 = 0.f; + _44 = 1.f; + return *this; } -inline Matrix& Matrix::operator= (const XMFLOAT4X3& M) +inline Matrix& Matrix::operator=(const XMFLOAT4X3& M) { - _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f; - _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f; - _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f; - _41 = M._41; _42 = M._42; _43 = M._43; _44 = 1.f; - return *this; + _11 = M._11; + _12 = M._12; + _13 = M._13; + _14 = 0.f; + _21 = M._21; + _22 = M._22; + _23 = M._23; + _24 = 0.f; + _31 = M._31; + _32 = M._32; + _33 = M._33; + _34 = 0.f; + _41 = M._41; + _42 = M._42; + _43 = M._43; + _44 = 1.f; + return *this; } -inline Matrix& Matrix::operator+= (const Matrix& M) +inline Matrix& Matrix::operator+=(const Matrix& M) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M._41)); - x1 = XMVectorAdd( x1, y1 ); - x2 = XMVectorAdd( x2, y2 ); - x3 = XMVectorAdd( x3, y3 ); - x4 = XMVectorAdd( x4, y4 ); + x1 = XMVectorAdd(x1, y1); + x2 = XMVectorAdd(x2, y2); + x3 = XMVectorAdd(x3, y3); + x4 = XMVectorAdd(x4, y4); - XMStoreFloat4( reinterpret_cast(&_11), x1 ); - XMStoreFloat4( reinterpret_cast(&_21), x2 ); - XMStoreFloat4( reinterpret_cast(&_31), x3 ); - XMStoreFloat4( reinterpret_cast(&_41), x4 ); - return *this; + XMStoreFloat4(reinterpret_cast(&_11), x1); + XMStoreFloat4(reinterpret_cast(&_21), x2); + XMStoreFloat4(reinterpret_cast(&_31), x3); + XMStoreFloat4(reinterpret_cast(&_41), x4); + return *this; } -inline Matrix& Matrix::operator-= (const Matrix& M) +inline Matrix& Matrix::operator-=(const Matrix& M) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M._41)); - x1 = XMVectorSubtract( x1, y1 ); - x2 = XMVectorSubtract( x2, y2 ); - x3 = XMVectorSubtract( x3, y3 ); - x4 = XMVectorSubtract( x4, y4 ); + x1 = XMVectorSubtract(x1, y1); + x2 = XMVectorSubtract(x2, y2); + x3 = XMVectorSubtract(x3, y3); + x4 = XMVectorSubtract(x4, y4); - XMStoreFloat4( reinterpret_cast(&_11), x1 ); - XMStoreFloat4( reinterpret_cast(&_21), x2 ); - XMStoreFloat4( reinterpret_cast(&_31), x3 ); - XMStoreFloat4( reinterpret_cast(&_41), x4 ); - return *this; + XMStoreFloat4(reinterpret_cast(&_11), x1); + XMStoreFloat4(reinterpret_cast(&_21), x2); + XMStoreFloat4(reinterpret_cast(&_31), x3); + XMStoreFloat4(reinterpret_cast(&_41), x4); + return *this; } -inline Matrix& Matrix::operator*= (const Matrix& M) +inline Matrix& Matrix::operator*=(const Matrix& M) { - using namespace DirectX; - XMMATRIX M1 = XMLoadFloat4x4( this ); - XMMATRIX M2 = XMLoadFloat4x4( &M ); - XMMATRIX X = XMMatrixMultiply( M1, M2 ); - XMStoreFloat4x4( this, X ); - return *this; + using namespace DirectX; + XMMATRIX M1 = XMLoadFloat4x4(this); + XMMATRIX M2 = XMLoadFloat4x4(&M); + XMMATRIX X = XMMatrixMultiply(M1, M2); + XMStoreFloat4x4(this, X); + return *this; } -inline Matrix& Matrix::operator*= (float S) +inline Matrix& Matrix::operator*=(float S) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - x1 = XMVectorScale( x1, S ); - x2 = XMVectorScale( x2, S ); - x3 = XMVectorScale( x3, S ); - x4 = XMVectorScale( x4, S ); + x1 = XMVectorScale(x1, S); + x2 = XMVectorScale(x2, S); + x3 = XMVectorScale(x3, S); + x4 = XMVectorScale(x4, S); - XMStoreFloat4( reinterpret_cast(&_11), x1 ); - XMStoreFloat4( reinterpret_cast(&_21), x2 ); - XMStoreFloat4( reinterpret_cast(&_31), x3 ); - XMStoreFloat4( reinterpret_cast(&_41), x4 ); - return *this; + XMStoreFloat4(reinterpret_cast(&_11), x1); + XMStoreFloat4(reinterpret_cast(&_21), x2); + XMStoreFloat4(reinterpret_cast(&_31), x3); + XMStoreFloat4(reinterpret_cast(&_41), x4); + return *this; } -inline Matrix& Matrix::operator/= (float S) +inline Matrix& Matrix::operator/=(float S) { - using namespace DirectX; - assert( S != 0.f ); - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + assert(S != 0.f); + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - float rs = 1.f / S; + float rs = 1.f / S; - x1 = XMVectorScale( x1, rs ); - x2 = XMVectorScale( x2, rs ); - x3 = XMVectorScale( x3, rs ); - x4 = XMVectorScale( x4, rs ); + x1 = XMVectorScale(x1, rs); + x2 = XMVectorScale(x2, rs); + x3 = XMVectorScale(x3, rs); + x4 = XMVectorScale(x4, rs); - XMStoreFloat4( reinterpret_cast(&_11), x1 ); - XMStoreFloat4( reinterpret_cast(&_21), x2 ); - XMStoreFloat4( reinterpret_cast(&_31), x3 ); - XMStoreFloat4( reinterpret_cast(&_41), x4 ); - return *this; + XMStoreFloat4(reinterpret_cast(&_11), x1); + XMStoreFloat4(reinterpret_cast(&_21), x2); + XMStoreFloat4(reinterpret_cast(&_31), x3); + XMStoreFloat4(reinterpret_cast(&_41), x4); + return *this; } -inline Matrix& Matrix::operator/= (const Matrix& M) +inline Matrix& Matrix::operator/=(const Matrix& M) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&_41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M._41)); - x1 = XMVectorDivide( x1, y1 ); - x2 = XMVectorDivide( x2, y2 ); - x3 = XMVectorDivide( x3, y3 ); - x4 = XMVectorDivide( x4, y4 ); + x1 = XMVectorDivide(x1, y1); + x2 = XMVectorDivide(x2, y2); + x3 = XMVectorDivide(x3, y3); + x4 = XMVectorDivide(x4, y4); - XMStoreFloat4( reinterpret_cast(&_11), x1 ); - XMStoreFloat4( reinterpret_cast(&_21), x2 ); - XMStoreFloat4( reinterpret_cast(&_31), x3 ); - XMStoreFloat4( reinterpret_cast(&_41), x4 ); - return *this; + XMStoreFloat4(reinterpret_cast(&_11), x1); + XMStoreFloat4(reinterpret_cast(&_21), x2); + XMStoreFloat4(reinterpret_cast(&_31), x3); + XMStoreFloat4(reinterpret_cast(&_41), x4); + return *this; } //------------------------------------------------------------------------------ // Urnary operators //------------------------------------------------------------------------------ -inline Matrix Matrix::operator- () const +inline Matrix Matrix::operator-() const { - using namespace DirectX; - XMVECTOR v1 = XMLoadFloat4( reinterpret_cast(&_11) ); - XMVECTOR v2 = XMLoadFloat4( reinterpret_cast(&_21) ); - XMVECTOR v3 = XMLoadFloat4( reinterpret_cast(&_31) ); - XMVECTOR v4 = XMLoadFloat4( reinterpret_cast(&_41) ); + using namespace DirectX; + XMVECTOR v1 = XMLoadFloat4(reinterpret_cast(&_11)); + XMVECTOR v2 = XMLoadFloat4(reinterpret_cast(&_21)); + XMVECTOR v3 = XMLoadFloat4(reinterpret_cast(&_31)); + XMVECTOR v4 = XMLoadFloat4(reinterpret_cast(&_41)); - v1 = XMVectorNegate( v1 ); - v2 = XMVectorNegate( v2 ); - v3 = XMVectorNegate( v3 ); - v4 = XMVectorNegate( v4 ); + v1 = XMVectorNegate(v1); + v2 = XMVectorNegate(v2); + v3 = XMVectorNegate(v3); + v4 = XMVectorNegate(v4); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), v1 ); - XMStoreFloat4( reinterpret_cast(&R._21), v2 ); - XMStoreFloat4( reinterpret_cast(&R._31), v3 ); - XMStoreFloat4( reinterpret_cast(&R._41), v4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), v1); + XMStoreFloat4(reinterpret_cast(&R._21), v2); + XMStoreFloat4(reinterpret_cast(&R._31), v3); + XMStoreFloat4(reinterpret_cast(&R._41), v4); + return R; } //------------------------------------------------------------------------------ // Binary operators //------------------------------------------------------------------------------ -inline Matrix operator+ (const Matrix& M1, const Matrix& M2) +inline Matrix operator+(const Matrix& M1, const Matrix& M2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M1._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M1._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M1._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M1._41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M1._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M1._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M1._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M1._41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M2._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M2._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M2._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M2._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M2._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M2._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M2._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M2._41)); - x1 = XMVectorAdd( x1, y1 ); - x2 = XMVectorAdd( x2, y2 ); - x3 = XMVectorAdd( x3, y3 ); - x4 = XMVectorAdd( x4, y4 ); + x1 = XMVectorAdd(x1, y1); + x2 = XMVectorAdd(x2, y2); + x3 = XMVectorAdd(x3, y3); + x4 = XMVectorAdd(x4, y4); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), x1 ); - XMStoreFloat4( reinterpret_cast(&R._21), x2 ); - XMStoreFloat4( reinterpret_cast(&R._31), x3 ); - XMStoreFloat4( reinterpret_cast(&R._41), x4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), x1); + XMStoreFloat4(reinterpret_cast(&R._21), x2); + XMStoreFloat4(reinterpret_cast(&R._31), x3); + XMStoreFloat4(reinterpret_cast(&R._41), x4); + return R; } -inline Matrix operator- (const Matrix& M1, const Matrix& M2) +inline Matrix operator-(const Matrix& M1, const Matrix& M2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M1._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M1._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M1._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M1._41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M1._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M1._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M1._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M1._41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M2._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M2._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M2._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M2._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M2._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M2._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M2._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M2._41)); - x1 = XMVectorSubtract( x1, y1 ); - x2 = XMVectorSubtract( x2, y2 ); - x3 = XMVectorSubtract( x3, y3 ); - x4 = XMVectorSubtract( x4, y4 ); + x1 = XMVectorSubtract(x1, y1); + x2 = XMVectorSubtract(x2, y2); + x3 = XMVectorSubtract(x3, y3); + x4 = XMVectorSubtract(x4, y4); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), x1 ); - XMStoreFloat4( reinterpret_cast(&R._21), x2 ); - XMStoreFloat4( reinterpret_cast(&R._31), x3 ); - XMStoreFloat4( reinterpret_cast(&R._41), x4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), x1); + XMStoreFloat4(reinterpret_cast(&R._21), x2); + XMStoreFloat4(reinterpret_cast(&R._31), x3); + XMStoreFloat4(reinterpret_cast(&R._41), x4); + return R; } -inline Matrix operator* (const Matrix& M1, const Matrix& M2) +inline Matrix operator*(const Matrix& M1, const Matrix& M2) { - using namespace DirectX; - XMMATRIX m1 = XMLoadFloat4x4( &M1 ); - XMMATRIX m2 = XMLoadFloat4x4( &M2 ); - XMMATRIX X = XMMatrixMultiply( m1, m2 ); + using namespace DirectX; + XMMATRIX m1 = XMLoadFloat4x4(&M1); + XMMATRIX m2 = XMLoadFloat4x4(&M2); + XMMATRIX X = XMMatrixMultiply(m1, m2); - Matrix R; - XMStoreFloat4x4( &R, X ); - return R; + Matrix R; + XMStoreFloat4x4(&R, X); + return R; } -inline Matrix operator* (const Matrix& M, float S) +inline Matrix operator*(const Matrix& M, float S) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M._41)); - x1 = XMVectorScale( x1, S ); - x2 = XMVectorScale( x2, S ); - x3 = XMVectorScale( x3, S ); - x4 = XMVectorScale( x4, S ); + x1 = XMVectorScale(x1, S); + x2 = XMVectorScale(x2, S); + x3 = XMVectorScale(x3, S); + x4 = XMVectorScale(x4, S); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), x1 ); - XMStoreFloat4( reinterpret_cast(&R._21), x2 ); - XMStoreFloat4( reinterpret_cast(&R._31), x3 ); - XMStoreFloat4( reinterpret_cast(&R._41), x4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), x1); + XMStoreFloat4(reinterpret_cast(&R._21), x2); + XMStoreFloat4(reinterpret_cast(&R._31), x3); + XMStoreFloat4(reinterpret_cast(&R._41), x4); + return R; } -inline Matrix operator/ (const Matrix& M, float S) +inline Matrix operator/(const Matrix& M, float S) { - using namespace DirectX; - assert( S != 0.f ); + using namespace DirectX; + assert(S != 0.f); - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M._41)); - float rs = 1.f / S; + float rs = 1.f / S; - x1 = XMVectorScale( x1, rs ); - x2 = XMVectorScale( x2, rs ); - x3 = XMVectorScale( x3, rs ); - x4 = XMVectorScale( x4, rs ); + x1 = XMVectorScale(x1, rs); + x2 = XMVectorScale(x2, rs); + x3 = XMVectorScale(x3, rs); + x4 = XMVectorScale(x4, rs); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), x1 ); - XMStoreFloat4( reinterpret_cast(&R._21), x2 ); - XMStoreFloat4( reinterpret_cast(&R._31), x3 ); - XMStoreFloat4( reinterpret_cast(&R._41), x4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), x1); + XMStoreFloat4(reinterpret_cast(&R._21), x2); + XMStoreFloat4(reinterpret_cast(&R._31), x3); + XMStoreFloat4(reinterpret_cast(&R._41), x4); + return R; } -inline Matrix operator/ (const Matrix& M1, const Matrix& M2) +inline Matrix operator/(const Matrix& M1, const Matrix& M2) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M1._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M1._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M1._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M1._41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M1._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M1._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M1._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M1._41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M2._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M2._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M2._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M2._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M2._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M2._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M2._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M2._41)); - x1 = XMVectorDivide( x1, y1 ); - x2 = XMVectorDivide( x2, y2 ); - x3 = XMVectorDivide( x3, y3 ); - x4 = XMVectorDivide( x4, y4 ); + x1 = XMVectorDivide(x1, y1); + x2 = XMVectorDivide(x2, y2); + x3 = XMVectorDivide(x3, y3); + x4 = XMVectorDivide(x4, y4); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), x1 ); - XMStoreFloat4( reinterpret_cast(&R._21), x2 ); - XMStoreFloat4( reinterpret_cast(&R._31), x3 ); - XMStoreFloat4( reinterpret_cast(&R._41), x4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), x1); + XMStoreFloat4(reinterpret_cast(&R._21), x2); + XMStoreFloat4(reinterpret_cast(&R._31), x3); + XMStoreFloat4(reinterpret_cast(&R._41), x4); + return R; } -inline Matrix operator* (float S, const Matrix& M) +inline Matrix operator*(float S, const Matrix& M) { - using namespace DirectX; + using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M._41) ); + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M._41)); - x1 = XMVectorScale( x1, S ); - x2 = XMVectorScale( x2, S ); - x3 = XMVectorScale( x3, S ); - x4 = XMVectorScale( x4, S ); + x1 = XMVectorScale(x1, S); + x2 = XMVectorScale(x2, S); + x3 = XMVectorScale(x3, S); + x4 = XMVectorScale(x4, S); - Matrix R; - XMStoreFloat4( reinterpret_cast(&R._11), x1 ); - XMStoreFloat4( reinterpret_cast(&R._21), x2 ); - XMStoreFloat4( reinterpret_cast(&R._31), x3 ); - XMStoreFloat4( reinterpret_cast(&R._41), x4 ); - return R; + Matrix R; + XMStoreFloat4(reinterpret_cast(&R._11), x1); + XMStoreFloat4(reinterpret_cast(&R._21), x2); + XMStoreFloat4(reinterpret_cast(&R._31), x3); + XMStoreFloat4(reinterpret_cast(&R._41), x4); + return R; } //------------------------------------------------------------------------------ // Matrix operations //------------------------------------------------------------------------------ -inline bool Matrix::Decompose( Vector3& scale, Quaternion& rotation, Vector3& translation ) +inline bool Matrix::Decompose(Vector3& scale, Quaternion& rotation, Vector3& translation) { - using namespace DirectX; + using namespace DirectX; - XMVECTOR s, r, t; + XMVECTOR s, r, t; - if ( !XMMatrixDecompose( &s, &r, &t, *this ) ) - return false; + if (!XMMatrixDecompose(&s, &r, &t, *this)) + return false; - XMStoreFloat3( &scale, s ); - XMStoreFloat4( &rotation, r ); - XMStoreFloat3( &translation, t ); + XMStoreFloat3(&scale, s); + XMStoreFloat4(&rotation, r); + XMStoreFloat3(&translation, t); - return true; + return true; } inline Matrix Matrix::Transpose() const { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( this ); - Matrix R; - XMStoreFloat4x4( &R, XMMatrixTranspose( M ) ); - return R; + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(this); + Matrix R; + XMStoreFloat4x4(&R, XMMatrixTranspose(M)); + return R; } -inline void Matrix::Transpose( Matrix& result ) const +inline void Matrix::Transpose(Matrix& result) const { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( this ); - XMStoreFloat4x4( &result, XMMatrixTranspose( M ) ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(this); + XMStoreFloat4x4(&result, XMMatrixTranspose(M)); } inline Matrix Matrix::Invert() const { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( this ); - Matrix R; - XMVECTOR det; - XMStoreFloat4x4( &R, XMMatrixInverse( &det, M ) ); - return R; + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(this); + Matrix R; + XMVECTOR det; + XMStoreFloat4x4(&R, XMMatrixInverse(&det, M)); + return R; } -inline void Matrix::Invert( Matrix& result ) const +inline void Matrix::Invert(Matrix& result) const { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( this ); - XMVECTOR det; - XMStoreFloat4x4( &result, XMMatrixInverse( &det, M ) ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(this); + XMVECTOR det; + XMStoreFloat4x4(&result, XMMatrixInverse(&det, M)); } inline float Matrix::Determinant() const { - using namespace DirectX; - XMMATRIX M = XMLoadFloat4x4( this ); - return XMVectorGetX( XMMatrixDeterminant( M ) ); + using namespace DirectX; + XMMATRIX M = XMLoadFloat4x4(this); + return XMVectorGetX(XMMatrixDeterminant(M)); } //------------------------------------------------------------------------------ @@ -2207,372 +2271,381 @@ inline float Matrix::Determinant() const //------------------------------------------------------------------------------ _Use_decl_annotations_ -inline Matrix Matrix::CreateBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, const Vector3* cameraForward ) + +inline Matrix Matrix::CreateBillboard(const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, + const Vector3* cameraForward) { - using namespace DirectX; - XMVECTOR O = XMLoadFloat3( &object ); - XMVECTOR C = XMLoadFloat3( &cameraPosition ); - XMVECTOR Z = XMVectorSubtract( O, C ); + using namespace DirectX; + XMVECTOR O = XMLoadFloat3(&object); + XMVECTOR C = XMLoadFloat3(&cameraPosition); + XMVECTOR Z = XMVectorSubtract(O, C); - XMVECTOR N = XMVector3LengthSq( Z ); - if ( XMVector3Less( N, g_XMEpsilon ) ) - { - if ( cameraForward ) - { - XMVECTOR F = XMLoadFloat3( cameraForward ); - Z = XMVectorNegate( F ); - } - else - Z = g_XMNegIdentityR2; - } - else - { - Z = XMVector3Normalize( Z ); - } + XMVECTOR N = XMVector3LengthSq(Z); + if (XMVector3Less(N, g_XMEpsilon)) + { + if (cameraForward) + { + XMVECTOR F = XMLoadFloat3(cameraForward); + Z = XMVectorNegate(F); + } + else + Z = g_XMNegIdentityR2; + } + else + { + Z = XMVector3Normalize(Z); + } - XMVECTOR up = XMLoadFloat3( &cameraUp ); - XMVECTOR X = XMVector3Cross( up, Z ); - X = XMVector3Normalize( X ); + XMVECTOR up = XMLoadFloat3(&cameraUp); + XMVECTOR X = XMVector3Cross(up, Z); + X = XMVector3Normalize(X); - XMVECTOR Y = XMVector3Cross( Z, X ); + XMVECTOR Y = XMVector3Cross(Z, X); - XMMATRIX M; - M.r[0] = X; - M.r[1] = Y; - M.r[2] = Z; - M.r[3] = XMVectorSetW( O, 1.f ); + XMMATRIX M; + M.r[0] = X; + M.r[1] = Y; + M.r[2] = Z; + M.r[3] = XMVectorSetW(O, 1.f); - Matrix R; - XMStoreFloat4x4( &R, M ); - return R; + Matrix R; + XMStoreFloat4x4(&R, M); + return R; } _Use_decl_annotations_ -inline Matrix Matrix::CreateConstrainedBillboard( const Vector3& object, const Vector3& cameraPosition, const Vector3& rotateAxis, - const Vector3* cameraForward, const Vector3* objectForward ) + +inline Matrix Matrix::CreateConstrainedBillboard(const Vector3& object, const Vector3& cameraPosition, + const Vector3& rotateAxis, + const Vector3* cameraForward, const Vector3* objectForward) { - using namespace DirectX; + using namespace DirectX; - static const XMVECTORF32 s_minAngle = { 0.99825467075f, 0.99825467075f, 0.99825467075f, 0.99825467075f }; // 1.0 - XMConvertToRadians( 0.1f ); + static const XMVECTORF32 s_minAngle = {0.99825467075f, 0.99825467075f, 0.99825467075f, 0.99825467075f}; + // 1.0 - XMConvertToRadians( 0.1f ); - XMVECTOR O = XMLoadFloat3( &object ); - XMVECTOR C = XMLoadFloat3( &cameraPosition ); - XMVECTOR faceDir = XMVectorSubtract( O, C ); + XMVECTOR O = XMLoadFloat3(&object); + XMVECTOR C = XMLoadFloat3(&cameraPosition); + XMVECTOR faceDir = XMVectorSubtract(O, C); - XMVECTOR N = XMVector3LengthSq( faceDir ); - if (XMVector3Less(N, g_XMEpsilon)) - { - if (cameraForward) - { - XMVECTOR F = XMLoadFloat3( cameraForward ); - faceDir = XMVectorNegate( F ); - } - else - faceDir = g_XMNegIdentityR2; - } - else - { - faceDir = XMVector3Normalize( faceDir ); - } + XMVECTOR N = XMVector3LengthSq(faceDir); + if (XMVector3Less(N, g_XMEpsilon)) + { + if (cameraForward) + { + XMVECTOR F = XMLoadFloat3(cameraForward); + faceDir = XMVectorNegate(F); + } + else + faceDir = g_XMNegIdentityR2; + } + else + { + faceDir = XMVector3Normalize(faceDir); + } - XMVECTOR Y = XMLoadFloat3( &rotateAxis ); - XMVECTOR X, Z; + XMVECTOR Y = XMLoadFloat3(&rotateAxis); + XMVECTOR X, Z; - XMVECTOR dot = XMVectorAbs( XMVector3Dot( Y, faceDir ) ); - if ( XMVector3Greater( dot, s_minAngle ) ) - { - if ( objectForward ) - { - Z = XMLoadFloat3( objectForward ); - dot = XMVectorAbs( XMVector3Dot( Y, Z ) ); - if ( XMVector3Greater( dot, s_minAngle ) ) - { - dot = XMVectorAbs( XMVector3Dot( Y, g_XMNegIdentityR2 ) ); - Z = ( XMVector3Greater( dot, s_minAngle ) ) ? g_XMIdentityR0 : g_XMNegIdentityR2; - } - } - else - { - dot = XMVectorAbs( XMVector3Dot( Y, g_XMNegIdentityR2 ) ); - Z = ( XMVector3Greater( dot, s_minAngle ) ) ? g_XMIdentityR0 : g_XMNegIdentityR2; - } + XMVECTOR dot = XMVectorAbs(XMVector3Dot(Y, faceDir)); + if (XMVector3Greater(dot, s_minAngle)) + { + if (objectForward) + { + Z = XMLoadFloat3(objectForward); + dot = XMVectorAbs(XMVector3Dot(Y, Z)); + if (XMVector3Greater(dot, s_minAngle)) + { + dot = XMVectorAbs(XMVector3Dot(Y, g_XMNegIdentityR2)); + Z = (XMVector3Greater(dot, s_minAngle)) ? g_XMIdentityR0 : g_XMNegIdentityR2; + } + } + else + { + dot = XMVectorAbs(XMVector3Dot(Y, g_XMNegIdentityR2)); + Z = (XMVector3Greater(dot, s_minAngle)) ? g_XMIdentityR0 : g_XMNegIdentityR2; + } - X = XMVector3Cross( Y, Z ); - X = XMVector3Normalize( X ); + X = XMVector3Cross(Y, Z); + X = XMVector3Normalize(X); - Z = XMVector3Cross( X, Y ); - Z = XMVector3Normalize( Z ); - } - else - { - X = XMVector3Cross( Y, faceDir ); - X = XMVector3Normalize( X ); + Z = XMVector3Cross(X, Y); + Z = XMVector3Normalize(Z); + } + else + { + X = XMVector3Cross(Y, faceDir); + X = XMVector3Normalize(X); - Z = XMVector3Cross( X, Y ); - Z = XMVector3Normalize( Z ); - } + Z = XMVector3Cross(X, Y); + Z = XMVector3Normalize(Z); + } - XMMATRIX M; - M.r[0] = X; - M.r[1] = Y; - M.r[2] = Z; - M.r[3] = XMVectorSetW( O, 1.f ); + XMMATRIX M; + M.r[0] = X; + M.r[1] = Y; + M.r[2] = Z; + M.r[3] = XMVectorSetW(O, 1.f); - Matrix R; - XMStoreFloat4x4( &R, M ); - return R; + Matrix R; + XMStoreFloat4x4(&R, M); + return R; } -inline Matrix Matrix::CreateTranslation( const Vector3& position ) +inline Matrix Matrix::CreateTranslation(const Vector3& position) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixTranslation( position.x, position.y, position.z ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixTranslation(position.x, position.y, position.z)); + return R; } -inline Matrix Matrix::CreateTranslation( float x, float y, float z ) +inline Matrix Matrix::CreateTranslation(float x, float y, float z) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixTranslation( x, y, z ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixTranslation(x, y, z)); + return R; } -inline Matrix Matrix::CreateScale( const Vector3& scales ) +inline Matrix Matrix::CreateScale(const Vector3& scales) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixScaling( scales.x, scales.y, scales.z ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixScaling(scales.x, scales.y, scales.z)); + return R; } -inline Matrix Matrix::CreateScale( float xs, float ys, float zs ) +inline Matrix Matrix::CreateScale(float xs, float ys, float zs) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixScaling( xs, ys, zs ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixScaling(xs, ys, zs)); + return R; } -inline Matrix Matrix::CreateScale( float scale ) +inline Matrix Matrix::CreateScale(float scale) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixScaling( scale, scale, scale ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixScaling(scale, scale, scale)); + return R; } -inline Matrix Matrix::CreateRotationX( float radians ) +inline Matrix Matrix::CreateRotationX(float radians) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixRotationX( radians ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixRotationX(radians)); + return R; } -inline Matrix Matrix::CreateRotationY( float radians ) +inline Matrix Matrix::CreateRotationY(float radians) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixRotationY( radians ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixRotationY(radians)); + return R; } -inline Matrix Matrix::CreateRotationZ( float radians ) +inline Matrix Matrix::CreateRotationZ(float radians) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixRotationZ( radians ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixRotationZ(radians)); + return R; } -inline Matrix Matrix::CreateFromAxisAngle( const Vector3& axis, float angle ) +inline Matrix Matrix::CreateFromAxisAngle(const Vector3& axis, float angle) { - using namespace DirectX; - Matrix R; - XMVECTOR a = XMLoadFloat3( &axis ); - XMStoreFloat4x4( &R, XMMatrixRotationAxis( a, angle ) ); - return R; + using namespace DirectX; + Matrix R; + XMVECTOR a = XMLoadFloat3(&axis); + XMStoreFloat4x4(&R, XMMatrixRotationAxis(a, angle)); + return R; } -inline Matrix Matrix::CreatePerspectiveFieldOfView( float fov, float aspectRatio, float nearPlane, float farPlane ) +inline Matrix Matrix::CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane, float farPlane) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixPerspectiveFovRH( fov, aspectRatio, nearPlane, farPlane ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane)); + return R; } -inline Matrix Matrix::CreatePerspective( float width, float height, float nearPlane, float farPlane ) +inline Matrix Matrix::CreatePerspective(float width, float height, float nearPlane, float farPlane) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixPerspectiveRH( width, height, nearPlane, farPlane ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane)); + return R; } -inline Matrix Matrix::CreatePerspectiveOffCenter( float left, float right, float bottom, float top, float nearPlane, float farPlane ) +inline Matrix Matrix::CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlane, + float farPlane) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixPerspectiveOffCenterRH( left, right, bottom, top, nearPlane, farPlane ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixPerspectiveOffCenterRH(left, right, bottom, top, nearPlane, farPlane)); + return R; } -inline Matrix Matrix::CreateOrthographic( float width, float height, float zNearPlane, float zFarPlane ) +inline Matrix Matrix::CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixOrthographicRH( width, height, zNearPlane, zFarPlane ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixOrthographicRH(width, height, zNearPlane, zFarPlane)); + return R; } -inline Matrix Matrix::CreateOrthographicOffCenter( float left, float right, float bottom, float top, float zNearPlane, float zFarPlane ) +inline Matrix Matrix::CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, + float zFarPlane) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixOrthographicOffCenterRH( left, right, bottom, top, zNearPlane, zFarPlane ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixOrthographicOffCenterRH(left, right, bottom, top, zNearPlane, zFarPlane)); + return R; } -inline Matrix Matrix::CreateLookAt( const Vector3& eye, const Vector3& target, const Vector3& up ) +inline Matrix Matrix::CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up) { - using namespace DirectX; - Matrix R; - XMVECTOR eyev = XMLoadFloat3( &eye ); - XMVECTOR targetv = XMLoadFloat3( &target ); - XMVECTOR upv = XMLoadFloat3( &up ); - XMStoreFloat4x4( &R, XMMatrixLookAtRH( eyev, targetv, upv ) ); - return R; + using namespace DirectX; + Matrix R; + XMVECTOR eyev = XMLoadFloat3(&eye); + XMVECTOR targetv = XMLoadFloat3(&target); + XMVECTOR upv = XMLoadFloat3(&up); + XMStoreFloat4x4(&R, XMMatrixLookAtRH(eyev, targetv, upv)); + return R; } -inline Matrix Matrix::CreateWorld( const Vector3& position, const Vector3& forward, const Vector3& up ) +inline Matrix Matrix::CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up) { - using namespace DirectX; - XMVECTOR zaxis = XMVector3Normalize( XMVectorNegate( XMLoadFloat3( &forward ) ) ); - XMVECTOR yaxis = XMLoadFloat3( &up ); - XMVECTOR xaxis = XMVector3Normalize( XMVector3Cross( yaxis, zaxis ) ); - yaxis = XMVector3Cross( zaxis, xaxis ); - - Matrix R; - XMStoreFloat3( reinterpret_cast( &R._11 ), xaxis ); - XMStoreFloat3( reinterpret_cast( &R._21 ), yaxis ); - XMStoreFloat3( reinterpret_cast( &R._31 ), zaxis ); - R._14 = R._24 = R._34 = 0.f; - R._41 = position.x; R._42 = position.y; R._43 = position.z; - R._44 = 1.f; - return R; + using namespace DirectX; + XMVECTOR zaxis = XMVector3Normalize(XMVectorNegate(XMLoadFloat3(&forward))); + XMVECTOR yaxis = XMLoadFloat3(&up); + XMVECTOR xaxis = XMVector3Normalize(XMVector3Cross(yaxis, zaxis)); + yaxis = XMVector3Cross(zaxis, xaxis); + + Matrix R; + XMStoreFloat3(reinterpret_cast(&R._11), xaxis); + XMStoreFloat3(reinterpret_cast(&R._21), yaxis); + XMStoreFloat3(reinterpret_cast(&R._31), zaxis); + R._14 = R._24 = R._34 = 0.f; + R._41 = position.x; + R._42 = position.y; + R._43 = position.z; + R._44 = 1.f; + return R; } -inline Matrix Matrix::CreateFromQuaternion( const Quaternion& rotation ) +inline Matrix Matrix::CreateFromQuaternion(const Quaternion& rotation) { - using namespace DirectX; - Matrix R; - XMVECTOR quatv = XMLoadFloat4( &rotation ); - XMStoreFloat4x4( &R, XMMatrixRotationQuaternion( quatv ) ); - return R; + using namespace DirectX; + Matrix R; + XMVECTOR quatv = XMLoadFloat4(&rotation); + XMStoreFloat4x4(&R, XMMatrixRotationQuaternion(quatv)); + return R; } -inline Matrix Matrix::CreateFromYawPitchRoll( float yaw, float pitch, float roll ) +inline Matrix Matrix::CreateFromYawPitchRoll(float yaw, float pitch, float roll) { - using namespace DirectX; - Matrix R; - XMStoreFloat4x4( &R, XMMatrixRotationRollPitchYaw( pitch, yaw, roll ) ); - return R; + using namespace DirectX; + Matrix R; + XMStoreFloat4x4(&R, XMMatrixRotationRollPitchYaw(pitch, yaw, roll)); + return R; } -inline Matrix Matrix::CreateShadow( const Vector3& lightDir, const Plane& plane ) +inline Matrix Matrix::CreateShadow(const Vector3& lightDir, const Plane& plane) { - using namespace DirectX; - Matrix R; - XMVECTOR light = XMLoadFloat3( &lightDir ); - XMVECTOR planev = XMLoadFloat4( &plane ); - XMStoreFloat4x4( &R, XMMatrixShadow( planev, light ) ); - return R; + using namespace DirectX; + Matrix R; + XMVECTOR light = XMLoadFloat3(&lightDir); + XMVECTOR planev = XMLoadFloat4(&plane); + XMStoreFloat4x4(&R, XMMatrixShadow(planev, light)); + return R; } -inline Matrix Matrix::CreateReflection( const Plane& plane ) +inline Matrix Matrix::CreateReflection(const Plane& plane) { - using namespace DirectX; - Matrix R; - XMVECTOR planev = XMLoadFloat4( &plane ); - XMStoreFloat4x4( &R, XMMatrixReflect( planev ) ); - return R; + using namespace DirectX; + Matrix R; + XMVECTOR planev = XMLoadFloat4(&plane); + XMStoreFloat4x4(&R, XMMatrixReflect(planev)); + return R; } -inline void Matrix::Lerp( const Matrix& M1, const Matrix& M2, float t, Matrix& result ) +inline void Matrix::Lerp(const Matrix& M1, const Matrix& M2, float t, Matrix& result) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M1._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M1._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M1._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M1._41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M1._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M1._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M1._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M1._41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M2._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M2._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M2._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M2._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M2._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M2._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M2._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M2._41)); - x1 = XMVectorLerp( x1, y1, t ); - x2 = XMVectorLerp( x2, y2, t ); - x3 = XMVectorLerp( x3, y3, t ); - x4 = XMVectorLerp( x4, y4, t ); + x1 = XMVectorLerp(x1, y1, t); + x2 = XMVectorLerp(x2, y2, t); + x3 = XMVectorLerp(x3, y3, t); + x4 = XMVectorLerp(x4, y4, t); - XMStoreFloat4( reinterpret_cast(&result._11), x1 ); - XMStoreFloat4( reinterpret_cast(&result._21), x2 ); - XMStoreFloat4( reinterpret_cast(&result._31), x3 ); - XMStoreFloat4( reinterpret_cast(&result._41), x4 ); + XMStoreFloat4(reinterpret_cast(&result._11), x1); + XMStoreFloat4(reinterpret_cast(&result._21), x2); + XMStoreFloat4(reinterpret_cast(&result._31), x3); + XMStoreFloat4(reinterpret_cast(&result._41), x4); } -inline Matrix Matrix::Lerp( const Matrix& M1, const Matrix& M2, float t ) +inline Matrix Matrix::Lerp(const Matrix& M1, const Matrix& M2, float t) { - using namespace DirectX; - XMVECTOR x1 = XMLoadFloat4( reinterpret_cast(&M1._11) ); - XMVECTOR x2 = XMLoadFloat4( reinterpret_cast(&M1._21) ); - XMVECTOR x3 = XMLoadFloat4( reinterpret_cast(&M1._31) ); - XMVECTOR x4 = XMLoadFloat4( reinterpret_cast(&M1._41) ); + using namespace DirectX; + XMVECTOR x1 = XMLoadFloat4(reinterpret_cast(&M1._11)); + XMVECTOR x2 = XMLoadFloat4(reinterpret_cast(&M1._21)); + XMVECTOR x3 = XMLoadFloat4(reinterpret_cast(&M1._31)); + XMVECTOR x4 = XMLoadFloat4(reinterpret_cast(&M1._41)); - XMVECTOR y1 = XMLoadFloat4( reinterpret_cast(&M2._11) ); - XMVECTOR y2 = XMLoadFloat4( reinterpret_cast(&M2._21) ); - XMVECTOR y3 = XMLoadFloat4( reinterpret_cast(&M2._31) ); - XMVECTOR y4 = XMLoadFloat4( reinterpret_cast(&M2._41) ); + XMVECTOR y1 = XMLoadFloat4(reinterpret_cast(&M2._11)); + XMVECTOR y2 = XMLoadFloat4(reinterpret_cast(&M2._21)); + XMVECTOR y3 = XMLoadFloat4(reinterpret_cast(&M2._31)); + XMVECTOR y4 = XMLoadFloat4(reinterpret_cast(&M2._41)); - x1 = XMVectorLerp( x1, y1, t ); - x2 = XMVectorLerp( x2, y2, t ); - x3 = XMVectorLerp( x3, y3, t ); - x4 = XMVectorLerp( x4, y4, t ); + x1 = XMVectorLerp(x1, y1, t); + x2 = XMVectorLerp(x2, y2, t); + x3 = XMVectorLerp(x3, y3, t); + x4 = XMVectorLerp(x4, y4, t); - Matrix result; - XMStoreFloat4( reinterpret_cast(&result._11), x1 ); - XMStoreFloat4( reinterpret_cast(&result._21), x2 ); - XMStoreFloat4( reinterpret_cast(&result._31), x3 ); - XMStoreFloat4( reinterpret_cast(&result._41), x4 ); - return result; + Matrix result; + XMStoreFloat4(reinterpret_cast(&result._11), x1); + XMStoreFloat4(reinterpret_cast(&result._21), x2); + XMStoreFloat4(reinterpret_cast(&result._31), x3); + XMStoreFloat4(reinterpret_cast(&result._41), x4); + return result; } -inline void Matrix::Transform( const Matrix& M, const Quaternion& rotation, Matrix& result ) +inline void Matrix::Transform(const Matrix& M, const Quaternion& rotation, Matrix& result) { - using namespace DirectX; - XMVECTOR quatv = XMLoadFloat4( &rotation ); + using namespace DirectX; + XMVECTOR quatv = XMLoadFloat4(&rotation); - XMMATRIX M0 = XMLoadFloat4x4( &M ); - XMMATRIX M1 = XMMatrixRotationQuaternion( quatv ); + XMMATRIX M0 = XMLoadFloat4x4(&M); + XMMATRIX M1 = XMMatrixRotationQuaternion(quatv); - XMStoreFloat4x4( &result, XMMatrixMultiply( M0, M1 ) ); + XMStoreFloat4x4(&result, XMMatrixMultiply(M0, M1)); } -inline Matrix Matrix::Transform( const Matrix& M, const Quaternion& rotation ) +inline Matrix Matrix::Transform(const Matrix& M, const Quaternion& rotation) { - using namespace DirectX; - XMVECTOR quatv = XMLoadFloat4( &rotation ); + using namespace DirectX; + XMVECTOR quatv = XMLoadFloat4(&rotation); - XMMATRIX M0 = XMLoadFloat4x4( &M ); - XMMATRIX M1 = XMMatrixRotationQuaternion( quatv ); + XMMATRIX M0 = XMLoadFloat4x4(&M); + XMMATRIX M1 = XMMatrixRotationQuaternion(quatv); - Matrix result; - XMStoreFloat4x4( &result, XMMatrixMultiply( M0, M1 ) ); - return result; + Matrix result; + XMStoreFloat4x4(&result, XMMatrixMultiply(M0, M1)); + return result; } @@ -2582,41 +2655,41 @@ inline Matrix Matrix::Transform( const Matrix& M, const Quaternion& rotation ) * ****************************************************************************/ -inline Plane::Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3 ) +inline Plane::Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3) { - using namespace DirectX; - XMVECTOR P0 = XMLoadFloat3( &point1 ); - XMVECTOR P1 = XMLoadFloat3( &point2 ); - XMVECTOR P2 = XMLoadFloat3( &point3 ); - XMStoreFloat4( this, XMPlaneFromPoints( P0, P1, P2 ) ); + using namespace DirectX; + XMVECTOR P0 = XMLoadFloat3(&point1); + XMVECTOR P1 = XMLoadFloat3(&point2); + XMVECTOR P2 = XMLoadFloat3(&point3); + XMStoreFloat4(this, XMPlaneFromPoints(P0, P1, P2)); } inline Plane::Plane(const Vector3& point, const Vector3& normal) { - using namespace DirectX; - XMVECTOR P = XMLoadFloat3( &point ); - XMVECTOR N = XMLoadFloat3( &normal ); - XMStoreFloat4( this, XMPlaneFromPointNormal( P, N ) ); + using namespace DirectX; + XMVECTOR P = XMLoadFloat3(&point); + XMVECTOR N = XMLoadFloat3(&normal); + XMStoreFloat4(this, XMPlaneFromPointNormal(P, N)); } //------------------------------------------------------------------------------ // Comparision operators //------------------------------------------------------------------------------ -inline bool Plane::operator == ( const Plane& p ) const +inline bool Plane::operator ==(const Plane& p) const { - using namespace DirectX; - XMVECTOR p1 = XMLoadFloat4( this ); - XMVECTOR p2 = XMLoadFloat4( &p ); - return XMPlaneEqual( p1, p2 ); + using namespace DirectX; + XMVECTOR p1 = XMLoadFloat4(this); + XMVECTOR p2 = XMLoadFloat4(&p); + return XMPlaneEqual(p1, p2); } -inline bool Plane::operator != ( const Plane& p ) const +inline bool Plane::operator !=(const Plane& p) const { - using namespace DirectX; - XMVECTOR p1 = XMLoadFloat4( this ); - XMVECTOR p2 = XMLoadFloat4( &p ); - return XMPlaneNotEqual( p1, p2 ); + using namespace DirectX; + XMVECTOR p1 = XMLoadFloat4(this); + XMVECTOR p2 = XMLoadFloat4(&p); + return XMPlaneNotEqual(p1, p2); } //------------------------------------------------------------------------------ @@ -2625,86 +2698,86 @@ inline bool Plane::operator != ( const Plane& p ) const inline void Plane::Normalize() { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( this ); - XMStoreFloat4( this, XMPlaneNormalize( p ) ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(this); + XMStoreFloat4(this, XMPlaneNormalize(p)); } -inline void Plane::Normalize( Plane& result ) const +inline void Plane::Normalize(Plane& result) const { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMPlaneNormalize( p ) ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(this); + XMStoreFloat4(&result, XMPlaneNormalize(p)); } -inline float Plane::Dot( const Vector4& v ) const +inline float Plane::Dot(const Vector4& v) const { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( this ); - XMVECTOR v0 = XMLoadFloat4( &v ); - return XMVectorGetX( XMPlaneDot( p, v0 ) ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(this); + XMVECTOR v0 = XMLoadFloat4(&v); + return XMVectorGetX(XMPlaneDot(p, v0)); } -inline float Plane::DotCoordinate( const Vector3& position ) const +inline float Plane::DotCoordinate(const Vector3& position) const { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( this ); - XMVECTOR v0 = XMLoadFloat3( &position ); - return XMVectorGetX( XMPlaneDotCoord( p, v0 ) ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(this); + XMVECTOR v0 = XMLoadFloat3(&position); + return XMVectorGetX(XMPlaneDotCoord(p, v0)); } -inline float Plane::DotNormal( const Vector3& normal ) const +inline float Plane::DotNormal(const Vector3& normal) const { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( this ); - XMVECTOR n0 = XMLoadFloat3( &normal ); - return XMVectorGetX( XMPlaneDotNormal( p, n0 ) ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(this); + XMVECTOR n0 = XMLoadFloat3(&normal); + return XMVectorGetX(XMPlaneDotNormal(p, n0)); } //------------------------------------------------------------------------------ // Static functions //------------------------------------------------------------------------------ -inline void Plane::Transform( const Plane& plane, const Matrix& M, Plane& result ) +inline void Plane::Transform(const Plane& plane, const Matrix& M, Plane& result) { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( &plane ); - XMMATRIX m0 = XMLoadFloat4x4( &M ); - XMStoreFloat4( &result, XMPlaneTransform( p, m0 ) ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(&plane); + XMMATRIX m0 = XMLoadFloat4x4(&M); + XMStoreFloat4(&result, XMPlaneTransform(p, m0)); } -inline Plane Plane::Transform( const Plane& plane, const Matrix& M ) +inline Plane Plane::Transform(const Plane& plane, const Matrix& M) { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( &plane ); - XMMATRIX m0 = XMLoadFloat4x4( &M ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(&plane); + XMMATRIX m0 = XMLoadFloat4x4(&M); - Plane result; - XMStoreFloat4( &result, XMPlaneTransform( p, m0 ) ); - return result; + Plane result; + XMStoreFloat4(&result, XMPlaneTransform(p, m0)); + return result; } -inline void Plane::Transform( const Plane& plane, const Quaternion& rotation, Plane& result ) +inline void Plane::Transform(const Plane& plane, const Quaternion& rotation, Plane& result) { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( &plane ); - XMVECTOR q = XMLoadFloat4( &rotation ); - XMVECTOR X = XMVector3Rotate( p, q ); - X = XMVectorSelect( p, X, g_XMSelect1110 ); // result.d = plane.d - XMStoreFloat4( &result, X ); + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(&plane); + XMVECTOR q = XMLoadFloat4(&rotation); + XMVECTOR X = XMVector3Rotate(p, q); + X = XMVectorSelect(p, X, g_XMSelect1110); // result.d = plane.d + XMStoreFloat4(&result, X); } -inline Plane Plane::Transform( const Plane& plane, const Quaternion& rotation ) +inline Plane Plane::Transform(const Plane& plane, const Quaternion& rotation) { - using namespace DirectX; - XMVECTOR p = XMLoadFloat4( &plane ); - XMVECTOR q = XMLoadFloat4( &rotation ); - XMVECTOR X = XMVector3Rotate( p, q ); - X = XMVectorSelect( p, X, g_XMSelect1110 ); // result.d = plane.d + using namespace DirectX; + XMVECTOR p = XMLoadFloat4(&plane); + XMVECTOR q = XMLoadFloat4(&rotation); + XMVECTOR X = XMVector3Rotate(p, q); + X = XMVectorSelect(p, X, g_XMSelect1110); // result.d = plane.d - Plane result; - XMStoreFloat4( &result, X ); - return result; + Plane result; + XMStoreFloat4(&result, X); + return result; } @@ -2718,152 +2791,152 @@ inline Plane Plane::Transform( const Plane& plane, const Quaternion& rotation ) // Comparision operators //------------------------------------------------------------------------------ -inline bool Quaternion::operator == ( const Quaternion& q ) const +inline bool Quaternion::operator ==(const Quaternion& q) const { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - return XMQuaternionEqual( q1, q2 ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + return XMQuaternionEqual(q1, q2); } -inline bool Quaternion::operator != ( const Quaternion& q ) const +inline bool Quaternion::operator !=(const Quaternion& q) const { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - return XMQuaternionNotEqual( q1, q2 ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + return XMQuaternionNotEqual(q1, q2); } //------------------------------------------------------------------------------ // Assignment operators //------------------------------------------------------------------------------ -inline Quaternion& Quaternion::operator+= (const Quaternion& q) +inline Quaternion& Quaternion::operator+=(const Quaternion& q) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - XMStoreFloat4( this, XMVectorAdd( q1, q2 ) ); - return *this; + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + XMStoreFloat4(this, XMVectorAdd(q1, q2)); + return *this; } -inline Quaternion& Quaternion::operator-= (const Quaternion& q) +inline Quaternion& Quaternion::operator-=(const Quaternion& q) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - XMStoreFloat4( this, XMVectorSubtract( q1, q2 ) ); - return *this; + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + XMStoreFloat4(this, XMVectorSubtract(q1, q2)); + return *this; } -inline Quaternion& Quaternion::operator*= (const Quaternion& q) +inline Quaternion& Quaternion::operator*=(const Quaternion& q) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - XMStoreFloat4( this, XMQuaternionMultiply( q1, q2 ) ); - return *this; + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + XMStoreFloat4(this, XMQuaternionMultiply(q1, q2)); + return *this; } -inline Quaternion& Quaternion::operator*= (float S) +inline Quaternion& Quaternion::operator*=(float S) { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - XMStoreFloat4( this, XMVectorScale( q, S ) ); - return *this; + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + XMStoreFloat4(this, XMVectorScale(q, S)); + return *this; } -inline Quaternion& Quaternion::operator/= (const Quaternion& q) +inline Quaternion& Quaternion::operator/=(const Quaternion& q) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - q2 = XMQuaternionInverse( q2 ); - XMStoreFloat4( this, XMQuaternionMultiply( q1, q2 ) ); - return *this; + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + q2 = XMQuaternionInverse(q2); + XMStoreFloat4(this, XMQuaternionMultiply(q1, q2)); + return *this; } //------------------------------------------------------------------------------ // Urnary operators //------------------------------------------------------------------------------ -inline Quaternion Quaternion::operator- () const +inline Quaternion Quaternion::operator-() const { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); - Quaternion R; - XMStoreFloat4( &R, XMVectorNegate( q ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMVectorNegate(q)); + return R; } //------------------------------------------------------------------------------ // Binary operators //------------------------------------------------------------------------------ -inline Quaternion operator+ (const Quaternion& Q1, const Quaternion& Q2) +inline Quaternion operator+(const Quaternion& Q1, const Quaternion& Q2) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( &Q1 ); - XMVECTOR q2 = XMLoadFloat4( &Q2 ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(&Q1); + XMVECTOR q2 = XMLoadFloat4(&Q2); - Quaternion R; - XMStoreFloat4( &R, XMVectorAdd( q1, q2 ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMVectorAdd(q1, q2)); + return R; } -inline Quaternion operator- (const Quaternion& Q1, const Quaternion& Q2) +inline Quaternion operator-(const Quaternion& Q1, const Quaternion& Q2) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( &Q1 ); - XMVECTOR q2 = XMLoadFloat4( &Q2 ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(&Q1); + XMVECTOR q2 = XMLoadFloat4(&Q2); - Quaternion R; - XMStoreFloat4( &R, XMVectorSubtract( q1, q2 ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMVectorSubtract(q1, q2)); + return R; } -inline Quaternion operator* (const Quaternion& Q1, const Quaternion& Q2) +inline Quaternion operator*(const Quaternion& Q1, const Quaternion& Q2) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( &Q1 ); - XMVECTOR q2 = XMLoadFloat4( &Q2 ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(&Q1); + XMVECTOR q2 = XMLoadFloat4(&Q2); - Quaternion R; - XMStoreFloat4( &R, XMQuaternionMultiply( q1, q2 ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMQuaternionMultiply(q1, q2)); + return R; } -inline Quaternion operator* (const Quaternion& Q, float S) +inline Quaternion operator*(const Quaternion& Q, float S) { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( &Q ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(&Q); - Quaternion R; - XMStoreFloat4( &R, XMVectorScale( q, S ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMVectorScale(q, S)); + return R; } -inline Quaternion operator/ (const Quaternion& Q1, const Quaternion& Q2) +inline Quaternion operator/(const Quaternion& Q1, const Quaternion& Q2) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( &Q1 ); - XMVECTOR q2 = XMLoadFloat4( &Q2 ); - q2 = XMQuaternionInverse( q2 ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(&Q1); + XMVECTOR q2 = XMLoadFloat4(&Q2); + q2 = XMQuaternionInverse(q2); - Quaternion R; - XMStoreFloat4( &R, XMQuaternionMultiply( q1, q2 ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMQuaternionMultiply(q1, q2)); + return R; } -inline Quaternion operator* (float S, const Quaternion& Q) +inline Quaternion operator*(float S, const Quaternion& Q) { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( &Q ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(&Q); - Quaternion R; - XMStoreFloat4( &R, XMVectorScale( q1, S ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMVectorScale(q1, S)); + return R; } //------------------------------------------------------------------------------ @@ -2872,181 +2945,181 @@ inline Quaternion operator* (float S, const Quaternion& Q) inline float Quaternion::Length() const { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - return XMVectorGetX( XMQuaternionLength( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + return XMVectorGetX(XMQuaternionLength(q)); } inline float Quaternion::LengthSquared() const { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - return XMVectorGetX( XMQuaternionLengthSq( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + return XMVectorGetX(XMQuaternionLengthSq(q)); } inline void Quaternion::Normalize() { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - XMStoreFloat4( this, XMQuaternionNormalize( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + XMStoreFloat4(this, XMQuaternionNormalize(q)); } -inline void Quaternion::Normalize( Quaternion& result ) const +inline void Quaternion::Normalize(Quaternion& result) const { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMQuaternionNormalize( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + XMStoreFloat4(&result, XMQuaternionNormalize(q)); } inline void Quaternion::Conjugate() { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - XMStoreFloat4( this, XMQuaternionConjugate( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + XMStoreFloat4(this, XMQuaternionConjugate(q)); } -inline void Quaternion::Conjugate( Quaternion& result ) const +inline void Quaternion::Conjugate(Quaternion& result) const { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMQuaternionConjugate( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + XMStoreFloat4(&result, XMQuaternionConjugate(q)); } -inline void Quaternion::Inverse( Quaternion& result ) const +inline void Quaternion::Inverse(Quaternion& result) const { - using namespace DirectX; - XMVECTOR q = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMQuaternionInverse( q ) ); + using namespace DirectX; + XMVECTOR q = XMLoadFloat4(this); + XMStoreFloat4(&result, XMQuaternionInverse(q)); } -inline float Quaternion::Dot( const Quaternion& q ) const +inline float Quaternion::Dot(const Quaternion& q) const { - using namespace DirectX; - XMVECTOR q1 = XMLoadFloat4( this ); - XMVECTOR q2 = XMLoadFloat4( &q ); - return XMVectorGetX( XMQuaternionDot( q1, q2 ) ); + using namespace DirectX; + XMVECTOR q1 = XMLoadFloat4(this); + XMVECTOR q2 = XMLoadFloat4(&q); + return XMVectorGetX(XMQuaternionDot(q1, q2)); } //------------------------------------------------------------------------------ // Static functions //------------------------------------------------------------------------------ -inline Quaternion Quaternion::CreateFromAxisAngle( const Vector3& axis, float angle ) +inline Quaternion Quaternion::CreateFromAxisAngle(const Vector3& axis, float angle) { - using namespace DirectX; - XMVECTOR a = XMLoadFloat3( &axis ); + using namespace DirectX; + XMVECTOR a = XMLoadFloat3(&axis); - Quaternion R; - XMStoreFloat4( &R, XMQuaternionRotationAxis( a, angle ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMQuaternionRotationAxis(a, angle)); + return R; } -inline Quaternion Quaternion::CreateFromYawPitchRoll( float yaw, float pitch, float roll ) +inline Quaternion Quaternion::CreateFromYawPitchRoll(float yaw, float pitch, float roll) { - using namespace DirectX; - Quaternion R; - XMStoreFloat4( &R, XMQuaternionRotationRollPitchYaw( pitch, yaw, roll ) ); - return R; + using namespace DirectX; + Quaternion R; + XMStoreFloat4(&R, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll)); + return R; } -inline Quaternion Quaternion::CreateFromRotationMatrix( const Matrix& M ) +inline Quaternion Quaternion::CreateFromRotationMatrix(const Matrix& M) { - using namespace DirectX; - XMMATRIX M0 = XMLoadFloat4x4( &M ); + using namespace DirectX; + XMMATRIX M0 = XMLoadFloat4x4(&M); - Quaternion R; - XMStoreFloat4( &R, XMQuaternionRotationMatrix( M0 ) ); - return R; + Quaternion R; + XMStoreFloat4(&R, XMQuaternionRotationMatrix(M0)); + return R; } -inline void Quaternion::Lerp( const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result ) +inline void Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) { - using namespace DirectX; - XMVECTOR Q0 = XMLoadFloat4( &q1 ); - XMVECTOR Q1 = XMLoadFloat4( &q2 ); + using namespace DirectX; + XMVECTOR Q0 = XMLoadFloat4(&q1); + XMVECTOR Q1 = XMLoadFloat4(&q2); - XMVECTOR dot = XMVector4Dot( Q0, Q1 ); + XMVECTOR dot = XMVector4Dot(Q0, Q1); - XMVECTOR R; - if ( XMVector4GreaterOrEqual( dot, XMVectorZero() ) ) - { - R = XMVectorLerp( Q0, Q1, t ); - } - else - { - XMVECTOR tv = XMVectorReplicate( t ); - XMVECTOR t1v = XMVectorReplicate( 1.f - t ); - XMVECTOR X0 = XMVectorMultiply( Q0, t1v ); - XMVECTOR X1 = XMVectorMultiply( Q1, tv ); - R = XMVectorSubtract( X0, X1 ); - } + XMVECTOR R; + if (XMVector4GreaterOrEqual(dot, XMVectorZero())) + { + R = XMVectorLerp(Q0, Q1, t); + } + else + { + XMVECTOR tv = XMVectorReplicate(t); + XMVECTOR t1v = XMVectorReplicate(1.f - t); + XMVECTOR X0 = XMVectorMultiply(Q0, t1v); + XMVECTOR X1 = XMVectorMultiply(Q1, tv); + R = XMVectorSubtract(X0, X1); + } - XMStoreFloat4( &result, XMQuaternionNormalize( R ) ); + XMStoreFloat4(&result, XMQuaternionNormalize(R)); } -inline Quaternion Quaternion::Lerp( const Quaternion& q1, const Quaternion& q2, float t ) +inline Quaternion Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t) { - using namespace DirectX; - XMVECTOR Q0 = XMLoadFloat4( &q1 ); - XMVECTOR Q1 = XMLoadFloat4( &q2 ); + using namespace DirectX; + XMVECTOR Q0 = XMLoadFloat4(&q1); + XMVECTOR Q1 = XMLoadFloat4(&q2); - XMVECTOR dot = XMVector4Dot( Q0, Q1 ); + XMVECTOR dot = XMVector4Dot(Q0, Q1); - XMVECTOR R; - if ( XMVector4GreaterOrEqual( dot, XMVectorZero() ) ) - { - R = XMVectorLerp( Q0, Q1, t ); - } - else - { - XMVECTOR tv = XMVectorReplicate( t ); - XMVECTOR t1v = XMVectorReplicate( 1.f - t ); - XMVECTOR X0 = XMVectorMultiply( Q0, t1v ); - XMVECTOR X1 = XMVectorMultiply( Q1, tv ); - R = XMVectorSubtract( X0, X1 ); - } + XMVECTOR R; + if (XMVector4GreaterOrEqual(dot, XMVectorZero())) + { + R = XMVectorLerp(Q0, Q1, t); + } + else + { + XMVECTOR tv = XMVectorReplicate(t); + XMVECTOR t1v = XMVectorReplicate(1.f - t); + XMVECTOR X0 = XMVectorMultiply(Q0, t1v); + XMVECTOR X1 = XMVectorMultiply(Q1, tv); + R = XMVectorSubtract(X0, X1); + } - Quaternion result; - XMStoreFloat4( &result, XMQuaternionNormalize( R ) ); - return result; + Quaternion result; + XMStoreFloat4(&result, XMQuaternionNormalize(R)); + return result; } -inline void Quaternion::Slerp( const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result ) +inline void Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) { - using namespace DirectX; - XMVECTOR Q0 = XMLoadFloat4( &q1 ); - XMVECTOR Q1 = XMLoadFloat4( &q2 ); - XMStoreFloat4( &result, XMQuaternionSlerp( Q0, Q1, t ) ); + using namespace DirectX; + XMVECTOR Q0 = XMLoadFloat4(&q1); + XMVECTOR Q1 = XMLoadFloat4(&q2); + XMStoreFloat4(&result, XMQuaternionSlerp(Q0, Q1, t)); } -inline Quaternion Quaternion::Slerp( const Quaternion& q1, const Quaternion& q2, float t ) +inline Quaternion Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, float t) { - using namespace DirectX; - XMVECTOR Q0 = XMLoadFloat4( &q1 ); - XMVECTOR Q1 = XMLoadFloat4( &q2 ); + using namespace DirectX; + XMVECTOR Q0 = XMLoadFloat4(&q1); + XMVECTOR Q1 = XMLoadFloat4(&q2); - Quaternion result; - XMStoreFloat4( &result, XMQuaternionSlerp( Q0, Q1, t ) ); - return result; + Quaternion result; + XMStoreFloat4(&result, XMQuaternionSlerp(Q0, Q1, t)); + return result; } -inline void Quaternion::Concatenate( const Quaternion& q1, const Quaternion& q2, Quaternion& result ) +inline void Quaternion::Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result) { - using namespace DirectX; - XMVECTOR Q0 = XMLoadFloat4( &q1 ); - XMVECTOR Q1 = XMLoadFloat4( &q2 ); - XMStoreFloat4( &result, XMQuaternionMultiply( Q1, Q0 ) ); + using namespace DirectX; + XMVECTOR Q0 = XMLoadFloat4(&q1); + XMVECTOR Q1 = XMLoadFloat4(&q2); + XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q0)); } -inline Quaternion Quaternion::Concatenate( const Quaternion& q1, const Quaternion& q2 ) +inline Quaternion Quaternion::Concatenate(const Quaternion& q1, const Quaternion& q2) { - using namespace DirectX; - XMVECTOR Q0 = XMLoadFloat4( &q1 ); - XMVECTOR Q1 = XMLoadFloat4( &q2 ); + using namespace DirectX; + XMVECTOR Q0 = XMLoadFloat4(&q1); + XMVECTOR Q1 = XMLoadFloat4(&q2); - Quaternion result; - XMStoreFloat4( &result, XMQuaternionMultiply( Q1, Q0 ) ); - return result; + Quaternion result; + XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q0)); + return result; } @@ -3056,172 +3129,172 @@ inline Quaternion Quaternion::Concatenate( const Quaternion& q1, const Quaternio * ****************************************************************************/ -inline Color::Color( const DirectX::PackedVector::XMCOLOR& Packed ) +inline Color::Color(const DirectX::PackedVector::XMCOLOR& Packed) { - using namespace DirectX; - XMStoreFloat4( this, PackedVector::XMLoadColor( &Packed ) ); + using namespace DirectX; + XMStoreFloat4(this, PackedVector::XMLoadColor(&Packed)); } -inline Color::Color( const DirectX::PackedVector::XMUBYTEN4& Packed ) +inline Color::Color(const DirectX::PackedVector::XMUBYTEN4& Packed) { - using namespace DirectX; - XMStoreFloat4( this, PackedVector::XMLoadUByteN4( &Packed ) ); + using namespace DirectX; + XMStoreFloat4(this, PackedVector::XMLoadUByteN4(&Packed)); } //------------------------------------------------------------------------------ // Comparision operators //------------------------------------------------------------------------------ -inline bool Color::operator == ( const Color& c ) const +inline bool Color::operator ==(const Color& c) const { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( this ); - XMVECTOR c2 = XMLoadFloat4( &c ); - return XMColorEqual( c1, c2 ); + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(this); + XMVECTOR c2 = XMLoadFloat4(&c); + return XMColorEqual(c1, c2); } -inline bool Color::operator != ( const Color& c ) const +inline bool Color::operator !=(const Color& c) const { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( this ); - XMVECTOR c2 = XMLoadFloat4( &c ); - return XMColorNotEqual( c1, c2 ); + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(this); + XMVECTOR c2 = XMLoadFloat4(&c); + return XMColorNotEqual(c1, c2); } //------------------------------------------------------------------------------ // Assignment operators //------------------------------------------------------------------------------ -inline Color& Color::operator= (const DirectX::PackedVector::XMCOLOR& Packed) +inline Color& Color::operator=(const DirectX::PackedVector::XMCOLOR& Packed) { - using namespace DirectX; - XMStoreFloat4( this, PackedVector::XMLoadColor( &Packed ) ); - return *this; + using namespace DirectX; + XMStoreFloat4(this, PackedVector::XMLoadColor(&Packed)); + return *this; } -inline Color& Color::operator= (const DirectX::PackedVector::XMUBYTEN4& Packed) +inline Color& Color::operator=(const DirectX::PackedVector::XMUBYTEN4& Packed) { - using namespace DirectX; - XMStoreFloat4( this, PackedVector::XMLoadUByteN4( &Packed ) ); - return *this; + using namespace DirectX; + XMStoreFloat4(this, PackedVector::XMLoadUByteN4(&Packed)); + return *this; } -inline Color& Color::operator+= (const Color& c) +inline Color& Color::operator+=(const Color& c) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( this ); - XMVECTOR c2 = XMLoadFloat4( &c ); - XMStoreFloat4( this, XMVectorAdd( c1, c2 ) ); - return *this; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(this); + XMVECTOR c2 = XMLoadFloat4(&c); + XMStoreFloat4(this, XMVectorAdd(c1, c2)); + return *this; } -inline Color& Color::operator-= (const Color& c) +inline Color& Color::operator-=(const Color& c) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( this ); - XMVECTOR c2 = XMLoadFloat4( &c ); - XMStoreFloat4( this, XMVectorSubtract( c1, c2 ) ); - return *this; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(this); + XMVECTOR c2 = XMLoadFloat4(&c); + XMStoreFloat4(this, XMVectorSubtract(c1, c2)); + return *this; } -inline Color& Color::operator*= (const Color& c) +inline Color& Color::operator*=(const Color& c) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( this ); - XMVECTOR c2 = XMLoadFloat4( &c ); - XMStoreFloat4( this, XMVectorMultiply( c1, c2 ) ); - return *this; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(this); + XMVECTOR c2 = XMLoadFloat4(&c); + XMStoreFloat4(this, XMVectorMultiply(c1, c2)); + return *this; } -inline Color& Color::operator*= (float S) +inline Color& Color::operator*=(float S) { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( this, XMVectorScale( c, S ) ); - return *this; + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(this, XMVectorScale(c, S)); + return *this; } -inline Color& Color::operator/= (const Color& c) +inline Color& Color::operator/=(const Color& c) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( this ); - XMVECTOR c2 = XMLoadFloat4( &c ); - XMStoreFloat4( this, XMVectorDivide( c1, c2 ) ); - return *this; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(this); + XMVECTOR c2 = XMLoadFloat4(&c); + XMStoreFloat4(this, XMVectorDivide(c1, c2)); + return *this; } //------------------------------------------------------------------------------ // Urnary operators //------------------------------------------------------------------------------ -inline Color Color::operator- () const +inline Color Color::operator-() const { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - Color R; - XMStoreFloat4( &R, XMVectorNegate( c ) ); - return R; + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + Color R; + XMStoreFloat4(&R, XMVectorNegate(c)); + return R; } //------------------------------------------------------------------------------ // Binary operators //------------------------------------------------------------------------------ -inline Color operator+ (const Color& C1, const Color& C2) +inline Color operator+(const Color& C1, const Color& C2) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( &C1 ); - XMVECTOR c2 = XMLoadFloat4( &C2 ); - Color R; - XMStoreFloat4( &R, XMVectorAdd( c1, c2 ) ); - return R; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(&C1); + XMVECTOR c2 = XMLoadFloat4(&C2); + Color R; + XMStoreFloat4(&R, XMVectorAdd(c1, c2)); + return R; } -inline Color operator- (const Color& C1, const Color& C2) +inline Color operator-(const Color& C1, const Color& C2) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( &C1 ); - XMVECTOR c2 = XMLoadFloat4( &C2 ); - Color R; - XMStoreFloat4( &R, XMVectorSubtract( c1, c2 ) ); - return R; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(&C1); + XMVECTOR c2 = XMLoadFloat4(&C2); + Color R; + XMStoreFloat4(&R, XMVectorSubtract(c1, c2)); + return R; } -inline Color operator* (const Color& C1, const Color& C2) +inline Color operator*(const Color& C1, const Color& C2) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( &C1 ); - XMVECTOR c2 = XMLoadFloat4( &C2 ); - Color R; - XMStoreFloat4( &R, XMVectorMultiply( c1, c2 ) ); - return R; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(&C1); + XMVECTOR c2 = XMLoadFloat4(&C2); + Color R; + XMStoreFloat4(&R, XMVectorMultiply(c1, c2)); + return R; } -inline Color operator* (const Color& C, float S) +inline Color operator*(const Color& C, float S) { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( &C ); - Color R; - XMStoreFloat4( &R, XMVectorScale( c, S ) ); - return R; + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(&C); + Color R; + XMStoreFloat4(&R, XMVectorScale(c, S)); + return R; } -inline Color operator/ (const Color& C1, const Color& C2) +inline Color operator/(const Color& C1, const Color& C2) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( &C1 ); - XMVECTOR c2 = XMLoadFloat4( &C2 ); - Color R; - XMStoreFloat4( &R, XMVectorDivide( c1, c2 ) ); - return R; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(&C1); + XMVECTOR c2 = XMLoadFloat4(&C2); + Color R; + XMStoreFloat4(&R, XMVectorDivide(c1, c2)); + return R; } -inline Color operator* (float S, const Color& C) +inline Color operator*(float S, const Color& C) { - using namespace DirectX; - XMVECTOR c1 = XMLoadFloat4( &C ); - Color R; - XMStoreFloat4( &R, XMVectorScale( c1, S ) ); - return R; + using namespace DirectX; + XMVECTOR c1 = XMLoadFloat4(&C); + Color R; + XMStoreFloat4(&R, XMVectorScale(c1, S)); + return R; } //------------------------------------------------------------------------------ @@ -3230,146 +3303,146 @@ inline Color operator* (float S, const Color& C) inline DirectX::PackedVector::XMCOLOR Color::BGRA() const { - using namespace DirectX; - XMVECTOR clr = XMLoadFloat4( this ); - PackedVector::XMCOLOR Packed; - PackedVector::XMStoreColor( &Packed, clr ); - return Packed; + using namespace DirectX; + XMVECTOR clr = XMLoadFloat4(this); + PackedVector::XMCOLOR Packed; + PackedVector::XMStoreColor(&Packed, clr); + return Packed; } inline DirectX::PackedVector::XMUBYTEN4 Color::RGBA() const { - using namespace DirectX; - XMVECTOR clr = XMLoadFloat4( this ); - PackedVector::XMUBYTEN4 Packed; - PackedVector::XMStoreUByteN4( &Packed, clr ); - return Packed; + using namespace DirectX; + XMVECTOR clr = XMLoadFloat4(this); + PackedVector::XMUBYTEN4 Packed; + PackedVector::XMStoreUByteN4(&Packed, clr); + return Packed; } inline Vector3 Color::ToVector3() const { - return Vector3( x, y, z ); + return Vector3(x, y, z); } inline Vector4 Color::ToVector4() const { - return Vector4( x, y, z, w ); + return Vector4(x, y, z, w); } inline void Color::Negate() { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( this, XMColorNegative( c) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(this, XMColorNegative(c)); } -inline void Color::Negate( Color& result ) const +inline void Color::Negate(Color& result) const { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMColorNegative( c ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(&result, XMColorNegative(c)); } inline void Color::Saturate() { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( this, XMVectorSaturate( c ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(this, XMVectorSaturate(c)); } -inline void Color::Saturate( Color& result ) const +inline void Color::Saturate(Color& result) const { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMVectorSaturate( c ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(&result, XMVectorSaturate(c)); } inline void Color::Premultiply() { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMVECTOR a = XMVectorSplatW( c ); - a = XMVectorSelect( g_XMIdentityR3, a, g_XMSelect1110 ); - XMStoreFloat4( this, XMVectorMultiply( c, a ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMVECTOR a = XMVectorSplatW(c); + a = XMVectorSelect(g_XMIdentityR3, a, g_XMSelect1110); + XMStoreFloat4(this, XMVectorMultiply(c, a)); } -inline void Color::Premultiply( Color& result ) const +inline void Color::Premultiply(Color& result) const { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMVECTOR a = XMVectorSplatW( c ); - a = XMVectorSelect( g_XMIdentityR3, a, g_XMSelect1110 ); - XMStoreFloat4( &result, XMVectorMultiply( c, a ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMVECTOR a = XMVectorSplatW(c); + a = XMVectorSelect(g_XMIdentityR3, a, g_XMSelect1110); + XMStoreFloat4(&result, XMVectorMultiply(c, a)); } -inline void Color::AdjustSaturation( float sat ) +inline void Color::AdjustSaturation(float sat) { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( this, XMColorAdjustSaturation( c, sat ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(this, XMColorAdjustSaturation(c, sat)); } -inline void Color::AdjustSaturation( float sat, Color& result ) const +inline void Color::AdjustSaturation(float sat, Color& result) const { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMColorAdjustSaturation( c, sat ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(&result, XMColorAdjustSaturation(c, sat)); } -inline void Color::AdjustContrast( float contrast ) +inline void Color::AdjustContrast(float contrast) { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( this, XMColorAdjustContrast( c, contrast ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(this, XMColorAdjustContrast(c, contrast)); } -inline void Color::AdjustContrast( float contrast, Color& result ) const +inline void Color::AdjustContrast(float contrast, Color& result) const { - using namespace DirectX; - XMVECTOR c = XMLoadFloat4( this ); - XMStoreFloat4( &result, XMColorAdjustContrast( c, contrast ) ); + using namespace DirectX; + XMVECTOR c = XMLoadFloat4(this); + XMStoreFloat4(&result, XMColorAdjustContrast(c, contrast)); } //------------------------------------------------------------------------------ // Static functions //------------------------------------------------------------------------------ -inline void Color::Modulate( const Color& c1, const Color& c2, Color& result ) +inline void Color::Modulate(const Color& c1, const Color& c2, Color& result) { - using namespace DirectX; - XMVECTOR C0 = XMLoadFloat4( &c1 ); - XMVECTOR C1 = XMLoadFloat4( &c2 ); - XMStoreFloat4( &result, XMColorModulate( C0, C1 ) ); + using namespace DirectX; + XMVECTOR C0 = XMLoadFloat4(&c1); + XMVECTOR C1 = XMLoadFloat4(&c2); + XMStoreFloat4(&result, XMColorModulate(C0, C1)); } -inline Color Color::Modulate( const Color& c1, const Color& c2 ) +inline Color Color::Modulate(const Color& c1, const Color& c2) { - using namespace DirectX; - XMVECTOR C0 = XMLoadFloat4( &c1 ); - XMVECTOR C1 = XMLoadFloat4( &c2 ); + using namespace DirectX; + XMVECTOR C0 = XMLoadFloat4(&c1); + XMVECTOR C1 = XMLoadFloat4(&c2); - Color result; - XMStoreFloat4( &result, XMColorModulate( C0, C1 ) ); - return result; + Color result; + XMStoreFloat4(&result, XMColorModulate(C0, C1)); + return result; } -inline void Color::Lerp( const Color& c1, const Color& c2, float t, Color& result ) +inline void Color::Lerp(const Color& c1, const Color& c2, float t, Color& result) { - using namespace DirectX; - XMVECTOR C0 = XMLoadFloat4( &c1 ); - XMVECTOR C1 = XMLoadFloat4( &c2 ); - XMStoreFloat4( &result, XMVectorLerp( C0, C1, t ) ); + using namespace DirectX; + XMVECTOR C0 = XMLoadFloat4(&c1); + XMVECTOR C1 = XMLoadFloat4(&c2); + XMStoreFloat4(&result, XMVectorLerp(C0, C1, t)); } -inline Color Color::Lerp( const Color& c1, const Color& c2, float t ) +inline Color Color::Lerp(const Color& c1, const Color& c2, float t) { - using namespace DirectX; - XMVECTOR C0 = XMLoadFloat4( &c1 ); - XMVECTOR C1 = XMLoadFloat4( &c2 ); + using namespace DirectX; + XMVECTOR C0 = XMLoadFloat4(&c1); + XMVECTOR C1 = XMLoadFloat4(&c2); - Color result; - XMStoreFloat4( &result, XMVectorLerp( C0, C1, t ) ); - return result; + Color result; + XMStoreFloat4(&result, XMVectorLerp(C0, C1, t)); + return result; } @@ -3382,78 +3455,78 @@ inline Color Color::Lerp( const Color& c1, const Color& c2, float t ) //----------------------------------------------------------------------------- // Comparision operators //------------------------------------------------------------------------------ -inline bool Ray::operator == ( const Ray& r ) const +inline bool Ray::operator ==(const Ray& r) const { - using namespace DirectX; - XMVECTOR r1p = XMLoadFloat3( &position ); - XMVECTOR r2p = XMLoadFloat3( &r.position ); - XMVECTOR r1d = XMLoadFloat3( &direction ); - XMVECTOR r2d = XMLoadFloat3( &r.direction ); - return XMVector3Equal( r1p, r2p ) && XMVector3Equal( r1d, r2d ); + using namespace DirectX; + XMVECTOR r1p = XMLoadFloat3(&position); + XMVECTOR r2p = XMLoadFloat3(&r.position); + XMVECTOR r1d = XMLoadFloat3(&direction); + XMVECTOR r2d = XMLoadFloat3(&r.direction); + return XMVector3Equal(r1p, r2p) && XMVector3Equal(r1d, r2d); } -inline bool Ray::operator != ( const Ray& r ) const +inline bool Ray::operator !=(const Ray& r) const { - using namespace DirectX; - XMVECTOR r1p = XMLoadFloat3( &position ); - XMVECTOR r2p = XMLoadFloat3( &r.position ); - XMVECTOR r1d = XMLoadFloat3( &direction ); - XMVECTOR r2d = XMLoadFloat3( &r.direction ); - return XMVector3NotEqual( r1p, r2p ) && XMVector3NotEqual( r1d, r2d ); + using namespace DirectX; + XMVECTOR r1p = XMLoadFloat3(&position); + XMVECTOR r2p = XMLoadFloat3(&r.position); + XMVECTOR r1d = XMLoadFloat3(&direction); + XMVECTOR r2d = XMLoadFloat3(&r.direction); + return XMVector3NotEqual(r1p, r2p) && XMVector3NotEqual(r1d, r2d); } //----------------------------------------------------------------------------- // Ray operators //------------------------------------------------------------------------------ -inline bool Ray::Intersects( const BoundingSphere& sphere, _Out_ float& Dist ) const +inline bool Ray::Intersects(const BoundingSphere& sphere, _Out_ float& Dist) const { - return sphere.Intersects( position, direction, Dist ); + return sphere.Intersects(position, direction, Dist); } -inline bool Ray::Intersects( const BoundingBox& box, _Out_ float& Dist ) const +inline bool Ray::Intersects(const BoundingBox& box, _Out_ float& Dist) const { - return box.Intersects( position, direction, Dist ); + return box.Intersects(position, direction, Dist); } -inline bool Ray::Intersects( const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist ) const +inline bool Ray::Intersects(const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist) const { - return DirectX::TriangleTests::Intersects( position, direction, tri0, tri1, tri2, Dist ); + return DirectX::TriangleTests::Intersects(position, direction, tri0, tri1, tri2, Dist); } -inline bool Ray::Intersects( const Plane& plane, _Out_ float& Dist ) const +inline bool Ray::Intersects(const Plane& plane, _Out_ float& Dist) const { - using namespace DirectX; + using namespace DirectX; - XMVECTOR p = XMLoadFloat4( &plane ); - XMVECTOR dir = XMLoadFloat3( &direction ); + XMVECTOR p = XMLoadFloat4(&plane); + XMVECTOR dir = XMLoadFloat3(&direction); - XMVECTOR nd = XMPlaneDotNormal( p, dir ); + XMVECTOR nd = XMPlaneDotNormal(p, dir); - if ( XMVector3LessOrEqual( XMVectorAbs( nd ), g_RayEpsilon ) ) - { - Dist = 0.f; - return false; - } - else - { - // t = -(dot(n,origin) + D) / dot(n,dir) - XMVECTOR pos = XMLoadFloat3( &position ); - XMVECTOR v = XMPlaneDotNormal( p, pos ); - v = XMVectorAdd( v, XMVectorSplatW(p) ); - v = XMVectorDivide( v, nd ); - float dist = - XMVectorGetX( v ); - if (dist < 0) - { - Dist = 0.f; - return false; - } - else - { - Dist = dist; - return true; - } - } + if (XMVector3LessOrEqual(XMVectorAbs(nd), g_RayEpsilon)) + { + Dist = 0.f; + return false; + } + else + { + // t = -(dot(n,origin) + D) / dot(n,dir) + XMVECTOR pos = XMLoadFloat3(&position); + XMVECTOR v = XMPlaneDotNormal(p, pos); + v = XMVectorAdd(v, XMVectorSplatW(p)); + v = XMVectorDivide(v, nd); + float dist = - XMVectorGetX(v); + if (dist < 0) + { + Dist = 0.f; + return false; + } + else + { + Dist = dist; + return true; + } + } } @@ -3467,47 +3540,55 @@ inline bool Ray::Intersects( const Plane& plane, _Out_ float& Dist ) const // Comparision operators //------------------------------------------------------------------------------ -inline bool Viewport::operator == ( const Viewport& vp ) const +inline bool Viewport::operator ==(const Viewport& vp) const { - return (x == vp.x && y == vp.y - && width == vp.width && height == vp.height - && minDepth == vp.minDepth && maxDepth == vp.maxDepth); + return (x == vp.x && y == vp.y + && width == vp.width && height == vp.height + && minDepth == vp.minDepth && maxDepth == vp.maxDepth); } -inline bool Viewport::operator != ( const Viewport& vp ) const +inline bool Viewport::operator !=(const Viewport& vp) const { - return (x != vp.x || y != vp.y - || width != vp.width || height != vp.height - || minDepth != vp.minDepth || maxDepth != vp.maxDepth); + return (x != vp.x || y != vp.y + || width != vp.width || height != vp.height + || minDepth != vp.minDepth || maxDepth != vp.maxDepth); } //------------------------------------------------------------------------------ // Assignment operators //------------------------------------------------------------------------------ -inline Viewport& Viewport::operator= (const Viewport& vp) +inline Viewport& Viewport::operator=(const Viewport& vp) { - x = vp.x; y = vp.y; - width = vp.width; height = vp.height; - minDepth = vp.minDepth; maxDepth = vp.maxDepth; - return *this; + x = vp.x; + y = vp.y; + width = vp.width; + height = vp.height; + minDepth = vp.minDepth; + maxDepth = vp.maxDepth; + return *this; } -inline Viewport& Viewport::operator= (const RECT& rct) +inline Viewport& Viewport::operator=(const RECT& rct) { - x = float(rct.left); y = float(rct.top); - width = float(rct.right - rct.left); - height = float(rct.bottom - rct.top); - minDepth = 0.f; maxDepth = 1.f; - return *this; + x = float(rct.left); + y = float(rct.top); + width = float(rct.right - rct.left); + height = float(rct.bottom - rct.top); + minDepth = 0.f; + maxDepth = 1.f; + return *this; } -inline Viewport& Viewport::operator= (const D3D11_VIEWPORT& vp) +inline Viewport& Viewport::operator=(const D3D11_VIEWPORT& vp) { - x = vp.TopLeftX; y = vp.TopLeftY; - width = vp.Width; height = vp.Height; - minDepth = vp.MinDepth; maxDepth = vp.MaxDepth; - return *this; + x = vp.TopLeftX; + y = vp.TopLeftY; + width = vp.Width; + height = vp.Height; + minDepth = vp.MinDepth; + maxDepth = vp.MaxDepth; + return *this; } //------------------------------------------------------------------------------ @@ -3516,48 +3597,50 @@ inline Viewport& Viewport::operator= (const D3D11_VIEWPORT& vp) inline float Viewport::AspectRatio() const { - if (width == 0.f || height == 0.f) - return 0.f; + if (width == 0.f || height == 0.f) + return 0.f; - return (width / height); + return (width / height); } inline Vector3 Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const { - using namespace DirectX; - XMVECTOR v = XMLoadFloat3(&p); - XMMATRIX projection = XMLoadFloat4x4(&proj); - v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world); - Vector3 result; - XMStoreFloat3(&result, v); - return result; + using namespace DirectX; + XMVECTOR v = XMLoadFloat3(&p); + XMMATRIX projection = XMLoadFloat4x4(&proj); + v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world); + Vector3 result; + XMStoreFloat3(&result, v); + return result; } -inline void Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const +inline void Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, + Vector3& result) const { - using namespace DirectX; - XMVECTOR v = XMLoadFloat3(&p); - XMMATRIX projection = XMLoadFloat4x4(&proj); - v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world); - XMStoreFloat3(&result, v); + using namespace DirectX; + XMVECTOR v = XMLoadFloat3(&p); + XMMATRIX projection = XMLoadFloat4x4(&proj); + v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world); + XMStoreFloat3(&result, v); } inline Vector3 Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const { - using namespace DirectX; - XMVECTOR v = XMLoadFloat3(&p); - XMMATRIX projection = XMLoadFloat4x4(&proj); - v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world); - Vector3 result; - XMStoreFloat3(&result, v); - return result; + using namespace DirectX; + XMVECTOR v = XMLoadFloat3(&p); + XMMATRIX projection = XMLoadFloat4x4(&proj); + v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world); + Vector3 result; + XMStoreFloat3(&result, v); + return result; } -inline void Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const +inline void Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, + Vector3& result) const { - using namespace DirectX; - XMVECTOR v = XMLoadFloat3(&p); - XMMATRIX projection = XMLoadFloat4x4(&proj); - v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world); - XMStoreFloat3(&result, v); + using namespace DirectX; + XMVECTOR v = XMLoadFloat3(&p); + XMMATRIX projection = XMLoadFloat4x4(&proj); + v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world); + XMStoreFloat3(&result, v); } diff --git a/Windows/DirectXTK/SpriteBatch.h b/Windows/DirectXTK/SpriteBatch.h index 9c974e1..23c0b85 100644 --- a/Windows/DirectXTK/SpriteBatch.h +++ b/Windows/DirectXTK/SpriteBatch.h @@ -46,76 +46,98 @@ namespace DirectX { - #if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) +#if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) #define XM_CALLCONV __fastcall typedef const XMVECTOR& HXMVECTOR; typedef const XMMATRIX& FXMMATRIX; - #endif +#endif - enum SpriteSortMode - { - SpriteSortMode_Deferred, - SpriteSortMode_Immediate, - SpriteSortMode_Texture, - SpriteSortMode_BackToFront, - SpriteSortMode_FrontToBack, - }; - - - enum SpriteEffects - { - SpriteEffects_None = 0, - SpriteEffects_FlipHorizontally = 1, - SpriteEffects_FlipVertically = 2, - SpriteEffects_FlipBoth = SpriteEffects_FlipHorizontally | SpriteEffects_FlipVertically, - }; + enum SpriteSortMode + { + SpriteSortMode_Deferred, + SpriteSortMode_Immediate, + SpriteSortMode_Texture, + SpriteSortMode_BackToFront, + SpriteSortMode_FrontToBack, + }; - - class SpriteBatch - { - public: - explicit SpriteBatch(_In_ ID3D11DeviceContext* deviceContext); - SpriteBatch(SpriteBatch&& moveFrom); - SpriteBatch& operator= (SpriteBatch&& moveFrom); - virtual ~SpriteBatch(); - // Begin/End a batch of sprite drawing operations. - void XM_CALLCONV Begin(SpriteSortMode sortMode = SpriteSortMode_Deferred, _In_opt_ ID3D11BlendState* blendState = nullptr, _In_opt_ ID3D11SamplerState* samplerState = nullptr, _In_opt_ ID3D11DepthStencilState* depthStencilState = nullptr, _In_opt_ ID3D11RasterizerState* rasterizerState = nullptr, - _In_opt_ std::function setCustomShaders = nullptr, FXMMATRIX transformMatrix = MatrixIdentity); - void __cdecl End(); + enum SpriteEffects + { + SpriteEffects_None = 0, + SpriteEffects_FlipHorizontally = 1, + SpriteEffects_FlipVertically = 2, + SpriteEffects_FlipBoth = SpriteEffects_FlipHorizontally | SpriteEffects_FlipVertically, + }; - // Draw overloads specifying position, origin and scale as XMFLOAT2. - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, XMFLOAT2 const& position, FXMVECTOR color = Colors::White); - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, XMFLOAT2 const& position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, XMFLOAT2 const& position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); - // Draw overloads specifying position, origin and scale via the first two components of an XMVECTOR. - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, FXMVECTOR color = Colors::White); - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, FXMVECTOR origin = g_XMZero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); + class SpriteBatch + { + public: + explicit SpriteBatch(_In_ ID3D11DeviceContext* deviceContext); + SpriteBatch(SpriteBatch&& moveFrom); + SpriteBatch& operator=(SpriteBatch&& moveFrom); + virtual ~SpriteBatch(); - // Draw overloads specifying position as a RECT. - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, RECT const& destinationRectangle, FXMVECTOR color = Colors::White); - void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, RECT const& destinationRectangle, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); + // Begin/End a batch of sprite drawing operations. + void XM_CALLCONV Begin(SpriteSortMode sortMode = SpriteSortMode_Deferred, + _In_opt_ ID3D11BlendState* blendState = nullptr, + _In_opt_ ID3D11SamplerState* samplerState = nullptr, + _In_opt_ ID3D11DepthStencilState* depthStencilState = nullptr, + _In_opt_ ID3D11RasterizerState* rasterizerState = nullptr, + _In_opt_ std::function setCustomShaders = nullptr, + FXMMATRIX transformMatrix = MatrixIdentity); + void __cdecl End(); - // Rotation mode to be applied to the sprite transformation - void __cdecl SetRotation( DXGI_MODE_ROTATION mode ); - DXGI_MODE_ROTATION __cdecl GetRotation() const; + // Draw overloads specifying position, origin and scale as XMFLOAT2. + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, XMFLOAT2 const& position, + FXMVECTOR color = Colors::White); + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, XMFLOAT2 const& position, + _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, + XMFLOAT2 const& origin = Float2Zero, float scale = 1, + SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, XMFLOAT2 const& position, + _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, + XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects = SpriteEffects_None, + float layerDepth = 0); - // Set viewport for sprite transformation - void __cdecl SetViewport( const D3D11_VIEWPORT& viewPort ); + // Draw overloads specifying position, origin and scale via the first two components of an XMVECTOR. + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, + FXMVECTOR color = Colors::White); + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, + _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, + FXMVECTOR origin = g_XMZero, float scale = 1, SpriteEffects effects = SpriteEffects_None, + float layerDepth = 0); + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, + _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, FXMVECTOR origin, + GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0); - private: - // Private implementation. - class Impl; + // Draw overloads specifying position as a RECT. + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, RECT const& destinationRectangle, + FXMVECTOR color = Colors::White); + void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, RECT const& destinationRectangle, + _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, + XMFLOAT2 const& origin = Float2Zero, SpriteEffects effects = SpriteEffects_None, + float layerDepth = 0); - std::unique_ptr pImpl; + // Rotation mode to be applied to the sprite transformation + void __cdecl SetRotation(DXGI_MODE_ROTATION mode); + DXGI_MODE_ROTATION __cdecl GetRotation() const; - static const XMMATRIX MatrixIdentity; - static const XMFLOAT2 Float2Zero; + // Set viewport for sprite transformation + void __cdecl SetViewport(const D3D11_VIEWPORT& viewPort); - // Prevent copying. - SpriteBatch(SpriteBatch const&) DIRECTX_CTOR_DELETE - SpriteBatch& operator= (SpriteBatch const&) DIRECTX_CTOR_DELETE - }; + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + static const XMMATRIX MatrixIdentity; + static const XMFLOAT2 Float2Zero; + + // Prevent copying. + SpriteBatch(SpriteBatch const&) DIRECTX_CTOR_DELETE + SpriteBatch& operator=(SpriteBatch const&) DIRECTX_CTOR_DELETE + }; } diff --git a/Windows/DirectXTK/SpriteFont.h b/Windows/DirectXTK/SpriteFont.h index 47db082..b9b1420 100644 --- a/Windows/DirectXTK/SpriteFont.h +++ b/Windows/DirectXTK/SpriteFont.h @@ -29,61 +29,72 @@ namespace DirectX { - class SpriteFont - { - public: - struct Glyph; + class SpriteFont + { + public: + struct Glyph; - SpriteFont(_In_ ID3D11Device* device, _In_z_ wchar_t const* fileName); - SpriteFont(_In_ ID3D11Device* device, _In_reads_bytes_(dataSize) uint8_t const* dataBlob, _In_ size_t dataSize); - SpriteFont(_In_ ID3D11ShaderResourceView* texture, _In_reads_(glyphCount) Glyph const* glyphs, _In_ size_t glyphCount, _In_ float lineSpacing); + SpriteFont(_In_ ID3D11Device* device, _In_z_ wchar_t const* fileName); + SpriteFont(_In_ ID3D11Device* device, _In_reads_bytes_(dataSize) uint8_t const* dataBlob, _In_ size_t dataSize); + SpriteFont(_In_ ID3D11ShaderResourceView* texture, _In_reads_(glyphCount) Glyph const* glyphs, + _In_ size_t glyphCount, _In_ float lineSpacing); - SpriteFont(SpriteFont&& moveFrom); - SpriteFont& operator= (SpriteFont&& moveFrom); - virtual ~SpriteFont(); + SpriteFont(SpriteFont&& moveFrom); + SpriteFont& operator=(SpriteFont&& moveFrom); + virtual ~SpriteFont(); - void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; - void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; - void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, FXMVECTOR color = Colors::White, float rotation = 0, FXMVECTOR origin = g_XMZero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; - void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; + void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, + FXMVECTOR color = Colors::White, float rotation = 0, + XMFLOAT2 const& origin = Float2Zero, float scale = 1, + SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; + void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, + FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, + SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; + void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, + FXMVECTOR color = Colors::White, float rotation = 0, FXMVECTOR origin = g_XMZero, + float scale = 1, SpriteEffects effects = SpriteEffects_None, + float layerDepth = 0) const; + void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, + FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, + SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const; - XMVECTOR XM_CALLCONV MeasureString(_In_z_ wchar_t const* text) const; + XMVECTOR XM_CALLCONV MeasureString(_In_z_ wchar_t const* text) const; - // Spacing properties - float __cdecl GetLineSpacing() const; - void __cdecl SetLineSpacing(float spacing); + // Spacing properties + float __cdecl GetLineSpacing() const; + void __cdecl SetLineSpacing(float spacing); - // Font properties - wchar_t __cdecl GetDefaultCharacter() const; - void __cdecl SetDefaultCharacter(wchar_t character); + // Font properties + wchar_t __cdecl GetDefaultCharacter() const; + void __cdecl SetDefaultCharacter(wchar_t character); - bool __cdecl ContainsCharacter(wchar_t character) const; + bool __cdecl ContainsCharacter(wchar_t character) const; - // Custom layout/rendering - Glyph const* __cdecl FindGlyph(wchar_t character) const; - void GetSpriteSheet( ID3D11ShaderResourceView** texture ) const; + // Custom layout/rendering + Glyph const* __cdecl FindGlyph(wchar_t character) const; + void GetSpriteSheet(ID3D11ShaderResourceView** texture) const; - // Describes a single character glyph. - struct Glyph - { - uint32_t Character; - RECT Subrect; - float XOffset; - float YOffset; - float XAdvance; - }; + // Describes a single character glyph. + struct Glyph + { + uint32_t Character; + RECT Subrect; + float XOffset; + float YOffset; + float XAdvance; + }; - private: - // Private implementation. - class Impl; + private: + // Private implementation. + class Impl; - std::unique_ptr pImpl; + std::unique_ptr pImpl; - static const XMFLOAT2 Float2Zero; + static const XMFLOAT2 Float2Zero; - // Prevent copying. - SpriteFont(SpriteFont const&) DIRECTX_CTOR_DELETE - SpriteFont& operator= (SpriteFont const&) DIRECTX_CTOR_DELETE - }; + // Prevent copying. + SpriteFont(SpriteFont const&) DIRECTX_CTOR_DELETE + SpriteFont& operator=(SpriteFont const&) DIRECTX_CTOR_DELETE + }; } diff --git a/Windows/DirectXTK/VertexTypes.h b/Windows/DirectXTK/VertexTypes.h index 0ee7629..b999bc1 100644 --- a/Windows/DirectXTK/VertexTypes.h +++ b/Windows/DirectXTK/VertexTypes.h @@ -35,299 +35,318 @@ namespace DirectX { - #if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) +#if (DIRECTX_MATH_VERSION < 305) && !defined(XM_CALLCONV) #define XM_CALLCONV __fastcall typedef const XMVECTOR& HXMVECTOR; typedef const XMMATRIX& FXMMATRIX; - #endif +#endif - // Vertex struct holding position and color information. - struct VertexPositionColor - { - VertexPositionColor() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position and color information. + struct VertexPositionColor + { + VertexPositionColor() DIRECTX_CTOR_DEFAULT - VertexPositionColor(XMFLOAT3 const& position, XMFLOAT4 const& color) - : position(position), - color(color) - { } + VertexPositionColor(XMFLOAT3 const& position, XMFLOAT4 const& color) + : position(position), + color(color) + { + } - VertexPositionColor(FXMVECTOR position, FXMVECTOR color) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat4(&this->color, color); - } + VertexPositionColor(FXMVECTOR position, FXMVECTOR color) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat4(&this->color, color); + } - XMFLOAT3 position; - XMFLOAT4 color; + XMFLOAT3 position; + XMFLOAT4 color; - static const int InputElementCount = 2; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 2; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct holding position and texture mapping information. - struct VertexPositionTexture - { - VertexPositionTexture() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position and texture mapping information. + struct VertexPositionTexture + { + VertexPositionTexture() DIRECTX_CTOR_DEFAULT - VertexPositionTexture(XMFLOAT3 const& position, XMFLOAT2 const& textureCoordinate) - : position(position), - textureCoordinate(textureCoordinate) - { } + VertexPositionTexture(XMFLOAT3 const& position, XMFLOAT2 const& textureCoordinate) + : position(position), + textureCoordinate(textureCoordinate) + { + } - VertexPositionTexture(FXMVECTOR position, FXMVECTOR textureCoordinate) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat2(&this->textureCoordinate, textureCoordinate); - } + VertexPositionTexture(FXMVECTOR position, FXMVECTOR textureCoordinate) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat2(&this->textureCoordinate, textureCoordinate); + } - XMFLOAT3 position; - XMFLOAT2 textureCoordinate; + XMFLOAT3 position; + XMFLOAT2 textureCoordinate; - static const int InputElementCount = 2; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 2; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct holding position and normal vector. - struct VertexPositionNormal - { - VertexPositionNormal() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position and normal vector. + struct VertexPositionNormal + { + VertexPositionNormal() DIRECTX_CTOR_DEFAULT - VertexPositionNormal(XMFLOAT3 const& position, XMFLOAT3 const& normal) - : position(position), - normal(normal) - { } + VertexPositionNormal(XMFLOAT3 const& position, XMFLOAT3 const& normal) + : position(position), + normal(normal) + { + } - VertexPositionNormal(FXMVECTOR position, FXMVECTOR normal) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat3(&this->normal, normal); - } + VertexPositionNormal(FXMVECTOR position, FXMVECTOR normal) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat3(&this->normal, normal); + } - XMFLOAT3 position; - XMFLOAT3 normal; + XMFLOAT3 position; + XMFLOAT3 normal; - static const int InputElementCount = 2; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 2; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct holding position, color, and texture mapping information. - struct VertexPositionColorTexture - { - VertexPositionColorTexture() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position, color, and texture mapping information. + struct VertexPositionColorTexture + { + VertexPositionColorTexture() DIRECTX_CTOR_DEFAULT - VertexPositionColorTexture(XMFLOAT3 const& position, XMFLOAT4 const& color, XMFLOAT2 const& textureCoordinate) - : position(position), - color(color), - textureCoordinate(textureCoordinate) - { } + VertexPositionColorTexture(XMFLOAT3 const& position, XMFLOAT4 const& color, XMFLOAT2 const& textureCoordinate) + : position(position), + color(color), + textureCoordinate(textureCoordinate) + { + } - VertexPositionColorTexture(FXMVECTOR position, FXMVECTOR color, FXMVECTOR textureCoordinate) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat4(&this->color, color); - XMStoreFloat2(&this->textureCoordinate, textureCoordinate); - } + VertexPositionColorTexture(FXMVECTOR position, FXMVECTOR color, FXMVECTOR textureCoordinate) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat4(&this->color, color); + XMStoreFloat2(&this->textureCoordinate, textureCoordinate); + } - XMFLOAT3 position; - XMFLOAT4 color; - XMFLOAT2 textureCoordinate; + XMFLOAT3 position; + XMFLOAT4 color; + XMFLOAT2 textureCoordinate; - static const int InputElementCount = 3; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 3; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct holding position, normal vector, and color information. - struct VertexPositionNormalColor - { - VertexPositionNormalColor() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position, normal vector, and color information. + struct VertexPositionNormalColor + { + VertexPositionNormalColor() DIRECTX_CTOR_DEFAULT - VertexPositionNormalColor(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& color) - : position(position), - normal(normal), - color(color) - { } + VertexPositionNormalColor(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& color) + : position(position), + normal(normal), + color(color) + { + } - VertexPositionNormalColor(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR color) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat3(&this->normal, normal); - XMStoreFloat4(&this->color, color); - } + VertexPositionNormalColor(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR color) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat3(&this->normal, normal); + XMStoreFloat4(&this->color, color); + } - XMFLOAT3 position; - XMFLOAT3 normal; - XMFLOAT4 color; + XMFLOAT3 position; + XMFLOAT3 normal; + XMFLOAT4 color; - static const int InputElementCount = 3; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 3; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct holding position, normal vector, and texture mapping information. - struct VertexPositionNormalTexture - { - VertexPositionNormalTexture() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position, normal vector, and texture mapping information. + struct VertexPositionNormalTexture + { + VertexPositionNormalTexture() DIRECTX_CTOR_DEFAULT - VertexPositionNormalTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT2 const& textureCoordinate) - : position(position), - normal(normal), - textureCoordinate(textureCoordinate) - { } + VertexPositionNormalTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT2 const& textureCoordinate) + : position(position), + normal(normal), + textureCoordinate(textureCoordinate) + { + } - VertexPositionNormalTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR textureCoordinate) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat3(&this->normal, normal); - XMStoreFloat2(&this->textureCoordinate, textureCoordinate); - } + VertexPositionNormalTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR textureCoordinate) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat3(&this->normal, normal); + XMStoreFloat2(&this->textureCoordinate, textureCoordinate); + } - XMFLOAT3 position; - XMFLOAT3 normal; - XMFLOAT2 textureCoordinate; + XMFLOAT3 position; + XMFLOAT3 normal; + XMFLOAT2 textureCoordinate; - static const int InputElementCount = 3; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 3; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct holding position, normal vector, color, and texture mapping information. - struct VertexPositionNormalColorTexture - { - VertexPositionNormalColorTexture() DIRECTX_CTOR_DEFAULT + // Vertex struct holding position, normal vector, color, and texture mapping information. + struct VertexPositionNormalColorTexture + { + VertexPositionNormalColorTexture() DIRECTX_CTOR_DEFAULT - VertexPositionNormalColorTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& color, XMFLOAT2 const& textureCoordinate) - : position(position), - normal(normal), - color(color), - textureCoordinate(textureCoordinate) - { } + VertexPositionNormalColorTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& color, + XMFLOAT2 const& textureCoordinate) + : position(position), + normal(normal), + color(color), + textureCoordinate(textureCoordinate) + { + } - VertexPositionNormalColorTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR color, CXMVECTOR textureCoordinate) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat3(&this->normal, normal); - XMStoreFloat4(&this->color, color); - XMStoreFloat2(&this->textureCoordinate, textureCoordinate); - } + VertexPositionNormalColorTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR color, + CXMVECTOR textureCoordinate) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat3(&this->normal, normal); + XMStoreFloat4(&this->color, color); + XMStoreFloat2(&this->textureCoordinate, textureCoordinate); + } - XMFLOAT3 position; - XMFLOAT3 normal; - XMFLOAT4 color; - XMFLOAT2 textureCoordinate; + XMFLOAT3 position; + XMFLOAT3 normal; + XMFLOAT4 color; + XMFLOAT2 textureCoordinate; - static const int InputElementCount = 4; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 4; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct for Visual Studio Shader Designer (DGSL) holding position, normal, - // tangent, color (RGBA), and texture mapping information - struct VertexPositionNormalTangentColorTexture - { - VertexPositionNormalTangentColorTexture() DIRECTX_CTOR_DEFAULT + // Vertex struct for Visual Studio Shader Designer (DGSL) holding position, normal, + // tangent, color (RGBA), and texture mapping information + struct VertexPositionNormalTangentColorTexture + { + VertexPositionNormalTangentColorTexture() DIRECTX_CTOR_DEFAULT - XMFLOAT3 position; - XMFLOAT3 normal; - XMFLOAT4 tangent; - uint32_t color; - XMFLOAT2 textureCoordinate; + XMFLOAT3 position; + XMFLOAT3 normal; + XMFLOAT4 tangent; + uint32_t color; + XMFLOAT2 textureCoordinate; - VertexPositionNormalTangentColorTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& tangent, uint32_t rgba, XMFLOAT2 const& textureCoordinate) - : position(position), - normal(normal), - tangent(tangent), - color(rgba), - textureCoordinate(textureCoordinate) - { - } + VertexPositionNormalTangentColorTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& tangent, + uint32_t rgba, XMFLOAT2 const& textureCoordinate) + : position(position), + normal(normal), + tangent(tangent), + color(rgba), + textureCoordinate(textureCoordinate) + { + } - VertexPositionNormalTangentColorTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, uint32_t rgba, CXMVECTOR textureCoordinate) - : color(rgba) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat3(&this->normal, normal); - XMStoreFloat4(&this->tangent, tangent); - XMStoreFloat2(&this->textureCoordinate, textureCoordinate); - } + VertexPositionNormalTangentColorTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, uint32_t rgba, + CXMVECTOR textureCoordinate) + : color(rgba) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat3(&this->normal, normal); + XMStoreFloat4(&this->tangent, tangent); + XMStoreFloat2(&this->textureCoordinate, textureCoordinate); + } - VertexPositionNormalTangentColorTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& tangent, XMFLOAT4 const& color, XMFLOAT2 const& textureCoordinate) - : position(position), - normal(normal), - tangent(tangent), - textureCoordinate(textureCoordinate) - { - SetColor( color ); - } + VertexPositionNormalTangentColorTexture(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& tangent, + XMFLOAT4 const& color, XMFLOAT2 const& textureCoordinate) + : position(position), + normal(normal), + tangent(tangent), + textureCoordinate(textureCoordinate) + { + SetColor(color); + } - VertexPositionNormalTangentColorTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, CXMVECTOR color, CXMVECTOR textureCoordinate) - { - XMStoreFloat3(&this->position, position); - XMStoreFloat3(&this->normal, normal); - XMStoreFloat4(&this->tangent, tangent); - XMStoreFloat2(&this->textureCoordinate, textureCoordinate); + VertexPositionNormalTangentColorTexture(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, CXMVECTOR color, + CXMVECTOR textureCoordinate) + { + XMStoreFloat3(&this->position, position); + XMStoreFloat3(&this->normal, normal); + XMStoreFloat4(&this->tangent, tangent); + XMStoreFloat2(&this->textureCoordinate, textureCoordinate); - SetColor( color ); - } + SetColor(color); + } - void __cdecl SetColor( XMFLOAT4 const& icolor ) { SetColor( XMLoadFloat4( &icolor ) ); } - void XM_CALLCONV SetColor( FXMVECTOR icolor ); + void __cdecl SetColor(XMFLOAT4 const& icolor) { SetColor(XMLoadFloat4(&icolor)); } + void XM_CALLCONV SetColor(FXMVECTOR icolor); - static const int InputElementCount = 5; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 5; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; - // Vertex struct for Visual Studio Shader Designer (DGSL) holding position, normal, - // tangent, color (RGBA), texture mapping information, and skinning weights - struct VertexPositionNormalTangentColorTextureSkinning : public VertexPositionNormalTangentColorTexture - { - VertexPositionNormalTangentColorTextureSkinning() DIRECTX_CTOR_DEFAULT + // Vertex struct for Visual Studio Shader Designer (DGSL) holding position, normal, + // tangent, color (RGBA), texture mapping information, and skinning weights + struct VertexPositionNormalTangentColorTextureSkinning : public VertexPositionNormalTangentColorTexture + { + VertexPositionNormalTangentColorTextureSkinning() DIRECTX_CTOR_DEFAULT - uint32_t indices; - uint32_t weights; + uint32_t indices; + uint32_t weights; - VertexPositionNormalTangentColorTextureSkinning(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& tangent, uint32_t rgba, - XMFLOAT2 const& textureCoordinate, XMUINT4 const& indices, XMFLOAT4 const& weights) - : VertexPositionNormalTangentColorTexture(position,normal,tangent,rgba,textureCoordinate) - { - SetBlendIndices( indices ); - SetBlendWeights( weights ); - } + VertexPositionNormalTangentColorTextureSkinning(XMFLOAT3 const& position, XMFLOAT3 const& normal, + XMFLOAT4 const& tangent, uint32_t rgba, + XMFLOAT2 const& textureCoordinate, XMUINT4 const& indices, + XMFLOAT4 const& weights) + : VertexPositionNormalTangentColorTexture(position, normal, tangent, rgba, textureCoordinate) + { + SetBlendIndices(indices); + SetBlendWeights(weights); + } - VertexPositionNormalTangentColorTextureSkinning(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, uint32_t rgba, CXMVECTOR textureCoordinate, - XMUINT4 const& indices, CXMVECTOR weights) - : VertexPositionNormalTangentColorTexture(position,normal,tangent,rgba,textureCoordinate) - { - SetBlendIndices( indices ); - SetBlendWeights( weights ); - } + VertexPositionNormalTangentColorTextureSkinning(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, + uint32_t rgba, CXMVECTOR textureCoordinate, + XMUINT4 const& indices, CXMVECTOR weights) + : VertexPositionNormalTangentColorTexture(position, normal, tangent, rgba, textureCoordinate) + { + SetBlendIndices(indices); + SetBlendWeights(weights); + } - VertexPositionNormalTangentColorTextureSkinning(XMFLOAT3 const& position, XMFLOAT3 const& normal, XMFLOAT4 const& tangent, XMFLOAT4 const& color, - XMFLOAT2 const& textureCoordinate, XMUINT4 const& indices, XMFLOAT4 const& weights) - : VertexPositionNormalTangentColorTexture(position,normal,tangent,color,textureCoordinate) - { - SetBlendIndices( indices ); - SetBlendWeights( weights ); - } + VertexPositionNormalTangentColorTextureSkinning(XMFLOAT3 const& position, XMFLOAT3 const& normal, + XMFLOAT4 const& tangent, XMFLOAT4 const& color, + XMFLOAT2 const& textureCoordinate, XMUINT4 const& indices, + XMFLOAT4 const& weights) + : VertexPositionNormalTangentColorTexture(position, normal, tangent, color, textureCoordinate) + { + SetBlendIndices(indices); + SetBlendWeights(weights); + } - VertexPositionNormalTangentColorTextureSkinning(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, CXMVECTOR color, CXMVECTOR textureCoordinate, - XMUINT4 const& indices, CXMVECTOR weights) - : VertexPositionNormalTangentColorTexture(position,normal,tangent,color,textureCoordinate) - { - SetBlendIndices( indices ); - SetBlendWeights( weights ); - } + VertexPositionNormalTangentColorTextureSkinning(FXMVECTOR position, FXMVECTOR normal, FXMVECTOR tangent, + CXMVECTOR color, CXMVECTOR textureCoordinate, + XMUINT4 const& indices, CXMVECTOR weights) + : VertexPositionNormalTangentColorTexture(position, normal, tangent, color, textureCoordinate) + { + SetBlendIndices(indices); + SetBlendWeights(weights); + } - void __cdecl SetBlendIndices( XMUINT4 const& iindices ); + void __cdecl SetBlendIndices(XMUINT4 const& iindices); - void __cdecl SetBlendWeights( XMFLOAT4 const& iweights ) { SetBlendWeights( XMLoadFloat4( &iweights ) ); } - void XM_CALLCONV SetBlendWeights( FXMVECTOR iweights ); + void __cdecl SetBlendWeights(XMFLOAT4 const& iweights) { SetBlendWeights(XMLoadFloat4(&iweights)); } + void XM_CALLCONV SetBlendWeights(FXMVECTOR iweights); - static const int InputElementCount = 7; - static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; - }; + static const int InputElementCount = 7; + static const D3D11_INPUT_ELEMENT_DESC InputElements[InputElementCount]; + }; } diff --git a/Windows/DirectXTK/WICTextureLoader.h b/Windows/DirectXTK/WICTextureLoader.h index ae8b705..e19f869 100644 --- a/Windows/DirectXTK/WICTextureLoader.h +++ b/Windows/DirectXTK/WICTextureLoader.h @@ -44,111 +44,111 @@ namespace DirectX { - // Standard version - HRESULT __cdecl CreateWICTextureFromMemory( _In_ ID3D11Device* d3dDevice, - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); + // Standard version + HRESULT __cdecl CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); - HRESULT __cdecl CreateWICTextureFromFile( _In_ ID3D11Device* d3dDevice, - _In_z_ const wchar_t* szFileName, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); + HRESULT __cdecl CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); - // Standard version with optional auto-gen mipmap support - #if defined(_XBOX_ONE) && defined(_TITLE) + // Standard version with optional auto-gen mipmap support +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateWICTextureFromMemory( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateWICTextureFromMemory( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); +#else + HRESULT __cdecl CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); - #if defined(_XBOX_ONE) && defined(_TITLE) +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateWICTextureFromFile( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateWICTextureFromFile( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_z_ const wchar_t* szFileName, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView, - _In_ size_t maxsize = 0 - ); +#else + HRESULT __cdecl CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_z_ const wchar_t* szFileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 + ); - // Extended version - HRESULT __cdecl CreateWICTextureFromMemoryEx( _In_ ID3D11Device* d3dDevice, - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); + // Extended version + HRESULT __cdecl CreateWICTextureFromMemoryEx(_In_ ID3D11Device* d3dDevice, + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); - HRESULT __cdecl CreateWICTextureFromFileEx( _In_ ID3D11Device* d3dDevice, - _In_z_ const wchar_t* szFileName, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); + HRESULT __cdecl CreateWICTextureFromFileEx(_In_ ID3D11Device* d3dDevice, + _In_z_ const wchar_t* szFileName, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); - // Extended version with optional auto-gen mipmap support - #if defined(_XBOX_ONE) && defined(_TITLE) + // Extended version with optional auto-gen mipmap support +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateWICTextureFromMemoryEx( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateWICTextureFromMemoryEx( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_reads_bytes_(wicDataSize) const uint8_t* wicData, - _In_ size_t wicDataSize, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); +#else + HRESULT __cdecl CreateWICTextureFromMemoryEx(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_reads_bytes_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); - #if defined(_XBOX_ONE) && defined(_TITLE) +#if defined(_XBOX_ONE) && defined(_TITLE) HRESULT __cdecl CreateWICTextureFromFileEx( _In_ ID3D11DeviceX* d3dDevice, _In_opt_ ID3D11DeviceContextX* d3dContext, - #else - HRESULT __cdecl CreateWICTextureFromFileEx( _In_ ID3D11Device* d3dDevice, - _In_opt_ ID3D11DeviceContext* d3dContext, - #endif - _In_z_ const wchar_t* szFileName, - _In_ size_t maxsize, - _In_ D3D11_USAGE usage, - _In_ unsigned int bindFlags, - _In_ unsigned int cpuAccessFlags, - _In_ unsigned int miscFlags, - _In_ bool forceSRGB, - _Out_opt_ ID3D11Resource** texture, - _Out_opt_ ID3D11ShaderResourceView** textureView - ); -} \ No newline at end of file +#else + HRESULT __cdecl CreateWICTextureFromFileEx(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, +#endif + _In_z_ const wchar_t* szFileName, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView + ); +} diff --git a/Windows/DirectXTK/XboxDDSTextureLoader.h b/Windows/DirectXTK/XboxDDSTextureLoader.h index f303b67..aa3efef 100644 --- a/Windows/DirectXTK/XboxDDSTextureLoader.h +++ b/Windows/DirectXTK/XboxDDSTextureLoader.h @@ -31,31 +31,31 @@ namespace Xbox { - enum DDS_ALPHA_MODE - { - DDS_ALPHA_MODE_UNKNOWN = 0, - DDS_ALPHA_MODE_STRAIGHT = 1, - DDS_ALPHA_MODE_PREMULTIPLIED = 2, - DDS_ALPHA_MODE_OPAQUE = 3, - DDS_ALPHA_MODE_CUSTOM = 4, - }; + enum DDS_ALPHA_MODE + { + DDS_ALPHA_MODE_UNKNOWN = 0, + DDS_ALPHA_MODE_STRAIGHT = 1, + DDS_ALPHA_MODE_PREMULTIPLIED = 2, + DDS_ALPHA_MODE_OPAQUE = 3, + DDS_ALPHA_MODE_CUSTOM = 4, + }; - HRESULT __cdecl CreateDDSTextureFromMemory( _In_ ID3D11DeviceX* d3dDevice, - _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, - _In_ size_t ddsDataSize, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _Outptr_ void** grfxMemory, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr, - _In_ bool forceSRGB = false - ); + HRESULT __cdecl CreateDDSTextureFromMemory(_In_ ID3D11DeviceX* d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _Outptr_ void** grfxMemory, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr, + _In_ bool forceSRGB = false + ); - HRESULT __cdecl CreateDDSTextureFromFile( _In_ ID3D11DeviceX* d3dDevice, - _In_z_ const wchar_t* szFileName, - _Outptr_opt_ ID3D11Resource** texture, - _Outptr_opt_ ID3D11ShaderResourceView** textureView, - _Outptr_ void** grfxMemory, - _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr, - _In_ bool forceSRGB = false - ); -} \ No newline at end of file + HRESULT __cdecl CreateDDSTextureFromFile(_In_ ID3D11DeviceX* d3dDevice, + _In_z_ const wchar_t* szFileName, + _Outptr_opt_ ID3D11Resource** texture, + _Outptr_opt_ ID3D11ShaderResourceView** textureView, + _Outptr_ void** grfxMemory, + _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr, + _In_ bool forceSRGB = false + ); +} diff --git a/Windows/Renderer.cpp b/Windows/Renderer.cpp index 65273ff..34bd6de 100644 --- a/Windows/Renderer.cpp +++ b/Windows/Renderer.cpp @@ -13,7 +13,8 @@ using namespace DirectX; -Renderer::Renderer(shared_ptr console, HWND hWnd, bool registerAsMessageManager) : BaseRenderer(console, registerAsMessageManager) +Renderer::Renderer(shared_ptr console, HWND hWnd, bool registerAsMessageManager) : BaseRenderer( + console, registerAsMessageManager) { _hWnd = hWnd; @@ -23,7 +24,8 @@ Renderer::Renderer(shared_ptr console, HWND hWnd, bool registerAsMessag Renderer::~Renderer() { shared_ptr videoRenderer = _console->GetVideoRenderer(); - if(videoRenderer) { + if (videoRenderer) + { videoRenderer->UnregisterRenderingDevice(this); } CleanupDevice(); @@ -31,7 +33,8 @@ Renderer::~Renderer() void Renderer::SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) { - if(fullscreen != _fullscreen || _hWnd != (HWND)windowHandle) { + if (fullscreen != _fullscreen || _hWnd != (HWND)windowHandle) + { _hWnd = (HWND)windowHandle; _monitorWidth = monitorWidth; _monitorHeight = monitorHeight; @@ -43,21 +46,29 @@ void Renderer::SetScreenSize(uint32_t width, uint32_t height) { ScreenSize screenSize = _console->GetVideoDecoder()->GetScreenSize(false); VideoConfig cfg = _console->GetSettings()->GetVideoConfig(); - if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen || _useBilinearInterpolation != cfg.UseBilinearInterpolation) { + if (_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || + _nesFrameWidth != width || _newFullscreen != _fullscreen || _useBilinearInterpolation != cfg. + UseBilinearInterpolation) + { auto frameLock = _frameLock.AcquireSafe(); auto textureLock = _textureLock.AcquireSafe(); screenSize = _console->GetVideoDecoder()->GetScreenSize(false); - if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen || _useBilinearInterpolation != cfg.UseBilinearInterpolation) { + if (_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || + _nesFrameWidth != width || _newFullscreen != _fullscreen || _useBilinearInterpolation != cfg. + UseBilinearInterpolation) + { _nesFrameHeight = height; _nesFrameWidth = width; - _newFrameBufferSize = width*height; + _newFrameBufferSize = width * height; bool needReset = _fullscreen != _newFullscreen || _useBilinearInterpolation != cfg.UseBilinearInterpolation; bool fullscreenResizeMode = _fullscreen && _newFullscreen; - if(_pSwapChain && _fullscreen && !_newFullscreen) { + if (_pSwapChain && _fullscreen && !_newFullscreen) + { HRESULT hr = _pSwapChain->SetFullscreenState(FALSE, NULL); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("SetFullscreenState(FALSE) failed - Error:" + std::to_string(hr)); } } @@ -67,21 +78,26 @@ void Renderer::SetScreenSize(uint32_t width, uint32_t height) _screenHeight = screenSize.Height; _screenWidth = screenSize.Width; - if(_fullscreen) { + if (_fullscreen) + { _realScreenHeight = _monitorHeight; _realScreenWidth = _monitorWidth; //Ensure the screen width/height is smaller or equal to the fullscreen resolution, no matter the requested scale - if(_monitorHeight < _screenHeight || _monitorWidth < _screenWidth) { + if (_monitorHeight < _screenHeight || _monitorWidth < _screenWidth) + { double scale = (double)screenSize.Width / (double)screenSize.Height; _screenHeight = _monitorHeight; _screenWidth = (uint32_t)(scale * _screenHeight); - if(_monitorWidth < _screenWidth) { + if (_monitorWidth < _screenWidth) + { _screenWidth = _monitorWidth; _screenHeight = (uint32_t)(_screenWidth / scale); } } - } else { + } + else + { _realScreenHeight = screenSize.Height; _realScreenWidth = screenSize.Width; } @@ -89,15 +105,21 @@ void Renderer::SetScreenSize(uint32_t width, uint32_t height) _leftMargin = (_realScreenWidth - _screenWidth) / 2; _topMargin = (_realScreenHeight - _screenHeight) / 2; - _screenBufferSize = _realScreenHeight*_realScreenWidth; + _screenBufferSize = _realScreenHeight * _realScreenWidth; - if(!_pSwapChain || needReset) { + if (!_pSwapChain || needReset) + { Reset(); - } else { - if(fullscreenResizeMode) { + } + else + { + if (fullscreenResizeMode) + { ResetNesBuffers(); CreateNesBuffers(); - } else { + } + else + { ResetNesBuffers(); ReleaseRenderTargetView(); _pSwapChain->ResizeBuffers(1, _realScreenWidth, _realScreenHeight, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, 0); @@ -113,9 +135,12 @@ void Renderer::Reset() { auto lock = _frameLock.AcquireSafe(); CleanupDevice(); - if(FAILED(InitDevice())) { + if (FAILED(InitDevice())) + { CleanupDevice(); - } else { + } + else + { _console->GetVideoRenderer()->RegisterRenderingDevice(this); } } @@ -124,28 +149,34 @@ void Renderer::CleanupDevice() { ResetNesBuffers(); ReleaseRenderTargetView(); - if(_pAlphaEnableBlendingState) { + if (_pAlphaEnableBlendingState) + { _pAlphaEnableBlendingState->Release(); _pAlphaEnableBlendingState = nullptr; } - if(_pDepthDisabledStencilState) { + if (_pDepthDisabledStencilState) + { _pDepthDisabledStencilState->Release(); _pDepthDisabledStencilState = nullptr; } - if(_samplerState) { + if (_samplerState) + { _samplerState->Release(); _samplerState = nullptr; } - if(_pSwapChain) { + if (_pSwapChain) + { _pSwapChain->SetFullscreenState(false, nullptr); _pSwapChain->Release(); _pSwapChain = nullptr; } - if(_pDeviceContext) { + if (_pDeviceContext) + { _pDeviceContext->Release(); _pDeviceContext = nullptr; } - if(_pd3dDevice) { + if (_pd3dDevice) + { _pd3dDevice->Release(); _pd3dDevice = nullptr; } @@ -153,19 +184,23 @@ void Renderer::CleanupDevice() void Renderer::ResetNesBuffers() { - if(_pTexture) { + if (_pTexture) + { _pTexture->Release(); _pTexture = nullptr; } - if(_overlayTexture) { + if (_overlayTexture) + { _overlayTexture->Release(); _overlayTexture = nullptr; } - if(_pTextureSrv) { + if (_pTextureSrv) + { _pTextureSrv->Release(); _pTextureSrv = nullptr; } - if(_pOverlaySrv) { + if (_pOverlaySrv) + { _pOverlaySrv->Release(); _pOverlaySrv = nullptr; } @@ -178,7 +213,8 @@ void Renderer::ResetNesBuffers() void Renderer::ReleaseRenderTargetView() { - if(_pRenderTargetView) { + if (_pRenderTargetView) + { _pRenderTargetView->Release(); _pRenderTargetView = nullptr; } @@ -189,14 +225,16 @@ HRESULT Renderer::CreateRenderTargetView() // Create a render target view ID3D11Texture2D* pBackBuffer = nullptr; HRESULT hr = _pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("SwapChain::GetBuffer() failed - Error:" + std::to_string(hr)); return hr; } hr = _pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &_pRenderTargetView); pBackBuffer->Release(); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("D3DDevice::CreateRenderTargetView() failed - Error:" + std::to_string(hr)); return hr; } @@ -218,25 +256,29 @@ HRESULT Renderer::CreateNesBuffers() vp.TopLeftY = 0; _pDeviceContext->RSSetViewports(1, &vp); - _textureBuffer[0] = new uint8_t[_nesFrameWidth*_nesFrameHeight * 4]; - _textureBuffer[1] = new uint8_t[_nesFrameWidth*_nesFrameHeight * 4]; - memset(_textureBuffer[0], 0, _nesFrameWidth*_nesFrameHeight * 4); - memset(_textureBuffer[1], 0, _nesFrameWidth*_nesFrameHeight * 4); + _textureBuffer[0] = new uint8_t[_nesFrameWidth * _nesFrameHeight * 4]; + _textureBuffer[1] = new uint8_t[_nesFrameWidth * _nesFrameHeight * 4]; + memset(_textureBuffer[0], 0, _nesFrameWidth * _nesFrameHeight * 4); + memset(_textureBuffer[1], 0, _nesFrameWidth * _nesFrameHeight * 4); _pTexture = CreateTexture(_nesFrameWidth, _nesFrameHeight); - if(!_pTexture) { + if (!_pTexture) + { return S_FALSE; } _overlayTexture = CreateTexture(8, 8); - if(!_overlayTexture) { + if (!_overlayTexture) + { return S_FALSE; } _pTextureSrv = GetShaderResourceView(_pTexture); - if(!_pTextureSrv) { + if (!_pTextureSrv) + { return S_FALSE; } _pOverlaySrv = GetShaderResourceView(_overlayTexture); - if(!_pOverlaySrv) { + if (!_pOverlaySrv) + { return S_FALSE; } @@ -296,38 +338,49 @@ HRESULT Renderer::InitDevice() D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_NULL; D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_1; - for(UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) { + for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) + { driverType = driverTypes[driverTypeIndex]; featureLevel = D3D_FEATURE_LEVEL_11_1; - hr = D3D11CreateDeviceAndSwapChain(nullptr, driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &featureLevel, &_pDeviceContext); + hr = D3D11CreateDeviceAndSwapChain(nullptr, driverType, nullptr, createDeviceFlags, featureLevels, + numFeatureLevels, D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, + &featureLevel, &_pDeviceContext); /*if(FAILED(hr)) { MessageManager::Log("D3D11CreateDeviceAndSwapChain() failed - Error:" + std::to_string(hr)); }*/ - if(hr == E_INVALIDARG) { + if (hr == E_INVALIDARG) + { // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it featureLevel = D3D_FEATURE_LEVEL_11_0; - hr = D3D11CreateDeviceAndSwapChain(nullptr, driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &featureLevel, &_pDeviceContext); + hr = D3D11CreateDeviceAndSwapChain(nullptr, driverType, nullptr, createDeviceFlags, &featureLevels[1], + numFeatureLevels - 1, D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, + &featureLevel, &_pDeviceContext); } - if(SUCCEEDED(hr)) { + if (SUCCEEDED(hr)) + { break; } } - - if(FAILED(hr)) { + + if (FAILED(hr)) + { MessageManager::Log("D3D11CreateDeviceAndSwapChain() failed - Error:" + std::to_string(hr)); return hr; } - if(_fullscreen) { + if (_fullscreen) + { hr = _pSwapChain->SetFullscreenState(TRUE, NULL); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("SetFullscreenState(true) failed - Error:" + std::to_string(hr)); MessageManager::Log("Switching back to windowed mode"); hr = _pSwapChain->SetFullscreenState(FALSE, NULL); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("SetFullscreenState(false) failed - Error:" + std::to_string(hr)); return hr; } @@ -335,7 +388,8 @@ HRESULT Renderer::InitDevice() } hr = CreateRenderTargetView(); - if(FAILED(hr)) { + if (FAILED(hr)) + { return hr; } @@ -358,7 +412,8 @@ HRESULT Renderer::InitDevice() // Create the state using the device. hr = _pd3dDevice->CreateDepthStencilState(&depthDisabledStencilDesc, &_pDepthDisabledStencilState); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("D3DDevice::CreateDepthStencilState() failed - Error:" + std::to_string(hr)); return hr; } @@ -379,7 +434,8 @@ HRESULT Renderer::InitDevice() // Create the blend state using the description. hr = _pd3dDevice->CreateBlendState(&blendStateDescription, &_pAlphaEnableBlendingState); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("D3DDevice::CreateBlendState() failed - Error:" + std::to_string(hr)); return hr; } @@ -389,17 +445,19 @@ HRESULT Renderer::InitDevice() blendFactor[1] = 0.0f; blendFactor[2] = 0.0f; blendFactor[3] = 0.0f; - + _pDeviceContext->OMSetBlendState(_pAlphaEnableBlendingState, blendFactor, 0xffffffff); _pDeviceContext->OMSetDepthStencilState(_pDepthDisabledStencilState, 1); hr = CreateNesBuffers(); - if(FAILED(hr)) { + if (FAILED(hr)) + { return hr; } hr = CreateSamplerState(); - if(FAILED(hr)) { + if (FAILED(hr)) + { return hr; } @@ -425,7 +483,8 @@ HRESULT Renderer::CreateSamplerState() samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; HRESULT hr = _pd3dDevice->CreateSamplerState(&samplerDesc, &_samplerState); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("D3DDevice::CreateSamplerState() failed - Error:" + std::to_string(hr)); } @@ -452,7 +511,8 @@ ID3D11Texture2D* Renderer::CreateTexture(uint32_t width, uint32_t height) desc.MiscFlags = 0; HRESULT hr = _pd3dDevice->CreateTexture2D(&desc, nullptr, &texture); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("D3DDevice::CreateTexture() failed - Error:" + std::to_string(hr)); return nullptr; } @@ -461,9 +521,10 @@ ID3D11Texture2D* Renderer::CreateTexture(uint32_t width, uint32_t height) ID3D11ShaderResourceView* Renderer::GetShaderResourceView(ID3D11Texture2D* texture) { - ID3D11ShaderResourceView *shaderResourceView = nullptr; + ID3D11ShaderResourceView* shaderResourceView = nullptr; HRESULT hr = _pd3dDevice->CreateShaderResourceView(texture, nullptr, &shaderResourceView); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("D3DDevice::CreateShaderResourceView() failed - Error:" + std::to_string(hr)); return nullptr; } @@ -477,25 +538,29 @@ void Renderer::DrawString(string message, float x, float y, DirectX::FXMVECTOR c DrawString(textStr, x, y, color, scale, font); } -void Renderer::DrawString(std::wstring message, float x, float y, DirectX::FXMVECTOR color, float scale, SpriteFont* font) +void Renderer::DrawString(std::wstring message, float x, float y, DirectX::FXMVECTOR color, float scale, + SpriteFont* font) { - const wchar_t *text = message.c_str(); - if(font == nullptr) { + const wchar_t* text = message.c_str(); + if (font == nullptr) + { font = _font.get(); } - font->DrawString(_spriteBatch.get(), text, XMFLOAT2(x+_leftMargin, y+_topMargin), color, 0.0f, XMFLOAT2(0, 0), scale); + font->DrawString(_spriteBatch.get(), text, XMFLOAT2(x + _leftMargin, y + _topMargin), color, 0.0f, XMFLOAT2(0, 0), + scale); } -void Renderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) +void Renderer::UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height) { SetScreenSize(width, height); uint32_t bpp = 4; auto lock = _textureLock.AcquireSafe(); - if(_textureBuffer[0]) { + if (_textureBuffer[0]) + { //_textureBuffer[0] may be null if directx failed to initialize properly - memcpy(_textureBuffer[0], frameBuffer, width*height*bpp); + memcpy(_textureBuffer[0], frameBuffer, width * height * bpp); _needFlip = true; _frameChanged = true; } @@ -504,14 +569,16 @@ void Renderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) void Renderer::DrawScreen() { //Swap buffers - emulator always writes to _textureBuffer[0], screen always draws _textureBuffer[1] - if(_needFlip) { + if (_needFlip) + { auto lock = _textureLock.AcquireSafe(); uint8_t* textureBuffer = _textureBuffer[0]; _textureBuffer[0] = _textureBuffer[1]; _textureBuffer[1] = textureBuffer; _needFlip = false; - if(_frameChanged) { + if (_frameChanged) + { _frameChanged = false; _renderedFrameCount++; } @@ -522,13 +589,15 @@ void Renderer::DrawScreen() uint32_t rowPitch = _nesFrameWidth * bpp; D3D11_MAPPED_SUBRESOURCE dd; HRESULT hr = _pDeviceContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("DeviceContext::Map() failed - Error:" + std::to_string(hr)); return; } uint8_t* surfacePointer = (uint8_t*)dd.pData; uint8_t* videoBuffer = _textureBuffer[1]; - for(uint32_t i = 0, iMax = _nesFrameHeight; i < iMax; i++) { + for (uint32_t i = 0, iMax = _nesFrameHeight; i < iMax; i++) + { memcpy(surfacePointer, videoBuffer, rowPitch); videoBuffer += rowPitch; surfacePointer += dd.RowPitch; @@ -538,15 +607,15 @@ void Renderer::DrawScreen() RECT destRect; destRect.left = _leftMargin; destRect.top = _topMargin; - destRect.right = _screenWidth+_leftMargin; - destRect.bottom = _screenHeight+_topMargin; + destRect.right = _screenWidth + _leftMargin; + destRect.bottom = _screenHeight + _topMargin; _spriteBatch->Draw(_pTextureSrv, destRect); } void Renderer::DrawPauseScreen() { - const static XMVECTORF32 transparentBlue = { { { 1.0f, 0.6f, 0.0f, 0.66f } } }; + const static XMVECTORF32 transparentBlue = {{{1.0f, 0.6f, 0.0f, 0.66f}}}; DrawString("I", 15, 15, transparentBlue, 2.0f, _font.get()); DrawString("I", 32, 15, transparentBlue, 2.0f, _font.get()); } @@ -555,18 +624,22 @@ void Renderer::Render() { bool paused = _console->IsPaused(); - if(_noUpdateCount > 10 || _frameChanged || paused || IsMessageShown()) { + if (_noUpdateCount > 10 || _frameChanged || paused || IsMessageShown()) + { _noUpdateCount = 0; - + auto lock = _frameLock.AcquireSafe(); - if(_newFullscreen != _fullscreen) { + if (_newFullscreen != _fullscreen) + { SetScreenSize(_nesFrameWidth, _nesFrameHeight); } - if(_pDeviceContext == nullptr) { + if (_pDeviceContext == nullptr) + { //DirectX failed to initialize, try to init Reset(); - if(_pDeviceContext == nullptr) { + if (_pDeviceContext == nullptr) + { //Can't init, prevent crash return; } @@ -580,8 +653,10 @@ void Renderer::Render() //Draw screen DrawScreen(); - if(_console->IsRunning()) { - if(paused) { + if (_console->IsRunning()) + { + if (paused) + { DrawPauseScreen(); } DrawCounters(); @@ -595,23 +670,29 @@ void Renderer::Render() bool waitVSync = _console->GetSettings()->GetVideoConfig().VerticalSync; HRESULT hr = _pSwapChain->Present(waitVSync ? 1 : 0, 0); - if(FAILED(hr)) { + if (FAILED(hr)) + { MessageManager::Log("SwapChain::Present() failed - Error:" + std::to_string(hr)); - if(hr == DXGI_ERROR_DEVICE_REMOVED) { - MessageManager::Log("D3DDevice: GetDeviceRemovedReason: " + std::to_string(_pd3dDevice->GetDeviceRemovedReason())); + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + MessageManager::Log( + "D3DDevice: GetDeviceRemovedReason: " + std::to_string(_pd3dDevice->GetDeviceRemovedReason())); } MessageManager::Log("Trying to reset DX..."); Reset(); } - } else { + } + else + { _noUpdateCount++; } } void Renderer::DrawString(std::wstring message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity) { - XMVECTORF32 color = { (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)opacity / 255.0f }; - _font->DrawString(_spriteBatch.get(), message.c_str(), XMFLOAT2((float)x+_leftMargin, (float)y+_topMargin), color); + XMVECTORF32 color = {(float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)opacity / 255.0f}; + _font->DrawString(_spriteBatch.get(), message.c_str(), XMFLOAT2((float)x + _leftMargin, (float)y + _topMargin), + color); } float Renderer::MeasureString(std::wstring text) @@ -624,4 +705,4 @@ float Renderer::MeasureString(std::wstring text) bool Renderer::ContainsCharacter(wchar_t character) { return _font->ContainsCharacter(character); -} \ No newline at end of file +} diff --git a/Windows/Renderer.h b/Windows/Renderer.h index 0d6e2bb..0959344 100644 --- a/Windows/Renderer.h +++ b/Windows/Renderer.h @@ -12,7 +12,8 @@ using namespace DirectX; class Console; -namespace DirectX { +namespace DirectX +{ class SpriteBatch; class SpriteFont; } @@ -20,33 +21,33 @@ namespace DirectX { class Renderer : public BaseRenderer, public IRenderingDevice { private: - HWND _hWnd = nullptr; + HWND _hWnd = nullptr; - ID3D11Device* _pd3dDevice = nullptr; - ID3D11DeviceContext* _pDeviceContext = nullptr; - IDXGISwapChain* _pSwapChain = nullptr; + ID3D11Device* _pd3dDevice = nullptr; + ID3D11DeviceContext* _pDeviceContext = nullptr; + IDXGISwapChain* _pSwapChain = nullptr; ID3D11RenderTargetView* _pRenderTargetView = nullptr; ID3D11DepthStencilState* _pDepthDisabledStencilState = nullptr; - ID3D11BlendState* _pAlphaEnableBlendingState = nullptr; + ID3D11BlendState* _pAlphaEnableBlendingState = nullptr; - ID3D11SamplerState* _samplerState = nullptr; - - atomic _needFlip = false; - uint8_t* _textureBuffer[2] = { nullptr, nullptr }; - ID3D11Texture2D* _pTexture = nullptr; - ID3D11ShaderResourceView* _pTextureSrv = nullptr; - ID3D11Texture2D* _overlayTexture = nullptr; - ID3D11ShaderResourceView* _pOverlaySrv = nullptr; + ID3D11SamplerState* _samplerState = nullptr; - bool _frameChanged = true; - SimpleLock _frameLock; - SimpleLock _textureLock; + atomic _needFlip = false; + uint8_t* _textureBuffer[2] = {nullptr, nullptr}; + ID3D11Texture2D* _pTexture = nullptr; + ID3D11ShaderResourceView* _pTextureSrv = nullptr; + ID3D11Texture2D* _overlayTexture = nullptr; + ID3D11ShaderResourceView* _pOverlaySrv = nullptr; + + bool _frameChanged = true; + SimpleLock _frameLock; + SimpleLock _textureLock; bool _useBilinearInterpolation = false; - unique_ptr _font; - unique_ptr _largeFont; - + unique_ptr _font; + unique_ptr _largeFont; + unique_ptr _spriteBatch; const uint32_t _bytesPerPixel = 4; @@ -77,9 +78,10 @@ private: ID3D11ShaderResourceView* GetShaderResourceView(ID3D11Texture2D* texture); void DrawScreen(); void DrawPauseScreen(); - + void DrawString(string message, float x, float y, DirectX::FXMVECTOR color, float scale, SpriteFont* font = nullptr); - void DrawString(std::wstring message, float x, float y, DirectX::FXMVECTOR color, float scale, SpriteFont* font = nullptr); + void DrawString(std::wstring message, float x, float y, DirectX::FXMVECTOR color, float scale, + SpriteFont* font = nullptr); void DrawString(std::wstring message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity); float MeasureString(std::wstring text); @@ -100,5 +102,5 @@ public: void Reset(); void Render(); - void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height); -}; \ No newline at end of file + void UpdateFrame(void* frameBuffer, uint32_t width, uint32_t height); +}; diff --git a/Windows/SoundManager.cpp b/Windows/SoundManager.cpp index 53528a1..1d064c1 100644 --- a/Windows/SoundManager.cpp +++ b/Windows/SoundManager.cpp @@ -15,16 +15,20 @@ SoundManager::SoundManager(shared_ptr console, HWND hwnd) memset(&_audioDeviceID, 0, sizeof(_audioDeviceID)); - if(InitializeDirectSound(44100, true)) { + if (InitializeDirectSound(44100, true)) + { _console->GetSoundMixer()->RegisterAudioDevice(this); - } else { + } + else + { MessageManager::DisplayMessage("Error", "CouldNotInitializeAudioSystem"); } } SoundManager::~SoundManager() { - if(_console && _console->GetSoundMixer()) { + if (_console && _console->GetSoundMixer()) + { _console->GetSoundMixer()->RegisterAudioDevice(nullptr); } Release(); @@ -32,13 +36,16 @@ SoundManager::~SoundManager() bool CALLBACK SoundManager::DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext) { - vector *devices = (vector*)lpContext; + vector* devices = (vector*)lpContext; SoundDeviceInfo deviceInfo; deviceInfo.description = utf8::utf8::encode(lpszDesc); - if(lpGUID != nullptr) { + if (lpGUID != nullptr) + { memcpy((void*)&deviceInfo.guid, lpGUID, 16); - } else { + } + else + { memset((void*)&deviceInfo.guid, 0, 16); } devices->push_back(deviceInfo); @@ -56,7 +63,8 @@ vector SoundManager::GetAvailableDeviceInfo() string SoundManager::GetAvailableDevices() { string deviceString; - for(SoundDeviceInfo device : GetAvailableDeviceInfo()) { + for (SoundDeviceInfo device : GetAvailableDeviceInfo()) + { deviceString += device.description + "||"s; } return deviceString; @@ -64,11 +72,15 @@ string SoundManager::GetAvailableDevices() void SoundManager::SetAudioDevice(string deviceName) { - if(_audioDeviceName != deviceName) { - for(SoundDeviceInfo device : GetAvailableDeviceInfo()) { - if(device.description.compare(deviceName) == 0) { + if (_audioDeviceName != deviceName) + { + for (SoundDeviceInfo device : GetAvailableDeviceInfo()) + { + if (device.description.compare(deviceName) == 0) + { _audioDeviceName = deviceName; - if(memcmp(&_audioDeviceID, &device.guid, 16) != 0) { + if (memcmp(&_audioDeviceID, &device.guid, 16) != 0) + { memcpy(&_audioDeviceID, &device.guid, 16); _needReset = true; } @@ -83,17 +95,19 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo) HRESULT result; DSBUFFERDESC bufferDesc; WAVEFORMATEX waveFormat; - + // Initialize the direct sound interface pointer for the default sound device. result = DirectSoundCreate8(&_audioDeviceID, &_directSound, NULL); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to create direct sound device."); return false; } // Set the cooperative level to priority so the format of the primary sound buffer can be modified. result = _directSound->SetCooperativeLevel(_hWnd, DSSCL_PRIORITY); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to set cooperative level."); return false; } @@ -108,7 +122,8 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo) // Get control of the primary sound buffer on the default sound device. result = _directSound->CreateSoundBuffer(&bufferDesc, &_primaryBuffer, NULL); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to create primary sound buffer."); return false; } @@ -127,7 +142,8 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo) // Set the primary buffer to be the wave format specified. result = _primaryBuffer->SetFormat(&waveFormat); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to set the sound format."); return false; } @@ -138,7 +154,8 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo) // Set the buffer description of the secondary sound buffer that the wave file will be loaded onto. bufferDesc.dwSize = sizeof(DSBUFFERDESC); - bufferDesc.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + bufferDesc.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | + DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; bufferDesc.dwBufferBytes = _bufferSize; bufferDesc.dwReserved = 0; bufferDesc.lpwfxFormat = &waveFormat; @@ -147,21 +164,24 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo) // Create a temporary sound buffer with the specific buffer settings. IDirectSoundBuffer* tempBuffer; result = _directSound->CreateSoundBuffer(&bufferDesc, &tempBuffer, NULL); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to create temporary sound buffer."); return false; } // Test the buffer format against the direct sound 8 interface and create the secondary buffer. result = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)&_secondaryBuffer); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to obtain secondary sound buffer."); return false; } // Set volume of the buffer to 100%. result = _secondaryBuffer->SetVolume(DSBVOLUME_MAX); - if(FAILED(result)) { + if (FAILED(result)) + { MessageManager::Log("[Audio] Failed to set volume of the secondary sound buffer."); return false; } @@ -180,17 +200,20 @@ void SoundManager::Release() _needReset = false; _lastWriteOffset = 0; - if(_secondaryBuffer) { + if (_secondaryBuffer) + { _secondaryBuffer->Release(); _secondaryBuffer = nullptr; } - if(_primaryBuffer) { + if (_primaryBuffer) + { _primaryBuffer->Release(); _primaryBuffer = nullptr; } - - if(_directSound) { + + if (_directSound) + { _directSound->Release(); _directSound = nullptr; } @@ -208,18 +231,20 @@ void SoundManager::ClearSecondaryBuffer() _lastWriteOffset = 0; } -void SoundManager::CopyToSecondaryBuffer(uint8_t *data, uint32_t size) +void SoundManager::CopyToSecondaryBuffer(uint8_t* data, uint32_t size) { uint8_t* bufferPtrA; uint8_t* bufferPtrB; DWORD bufferASize; DWORD bufferBSize; - _secondaryBuffer->Lock(_lastWriteOffset, size, (void**)&bufferPtrA, (DWORD*)&bufferASize, (void**)&bufferPtrB, (DWORD*)&bufferBSize, 0); + _secondaryBuffer->Lock(_lastWriteOffset, size, (void**)&bufferPtrA, (DWORD*)&bufferASize, (void**)&bufferPtrB, + (DWORD*)&bufferBSize, 0); _lastWriteOffset = (_lastWriteOffset + size) % _bufferSize; memcpy(bufferPtrA, data, bufferASize); - if(bufferPtrB && bufferBSize > 0) { + if (bufferPtrB && bufferBSize > 0) + { memcpy(bufferPtrB, data + bufferASize, bufferBSize); } @@ -228,7 +253,8 @@ void SoundManager::CopyToSecondaryBuffer(uint8_t *data, uint32_t size) void SoundManager::Pause() { - if(_secondaryBuffer) { + if (_secondaryBuffer) + { _secondaryBuffer->Stop(); } _playing = false; @@ -236,7 +262,8 @@ void SoundManager::Pause() void SoundManager::Stop() { - if(_secondaryBuffer) { + if (_secondaryBuffer) + { _secondaryBuffer->Stop(); ClearSecondaryBuffer(); } @@ -247,7 +274,8 @@ void SoundManager::Stop() void SoundManager::Play() { - if(_secondaryBuffer) { + if (_secondaryBuffer) + { _secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING); _playing = true; } @@ -256,9 +284,12 @@ void SoundManager::Play() void SoundManager::ValidateWriteCursor(DWORD safeWriteCursor) { int32_t writeGap = _lastWriteOffset - safeWriteCursor; - if(writeGap < -10000) { + if (writeGap < -10000) + { writeGap += _bufferSize; - } else if(writeGap < 0) { + } + else if (writeGap < 0) + { _bufferUnderrunEventCount++; _lastWriteOffset = safeWriteCursor; } @@ -273,7 +304,8 @@ void SoundManager::ProcessEndOfFrame() uint32_t emulationSpeed = _console->GetSettings()->GetEmulationSpeed(); uint32_t targetRate = _sampleRate; - if(emulationSpeed > 0 && emulationSpeed < 100) { + if (emulationSpeed > 0 && emulationSpeed < 100) + { //Slow down playback when playing at less than 100% targetRate = (uint32_t)(targetRate * ((double)emulationSpeed / 100.0)); } @@ -284,17 +316,20 @@ void SoundManager::ProcessEndOfFrame() AudioConfig cfg = _console->GetSettings()->GetAudioConfig(); SetAudioDevice(cfg.AudioDevice); - if(_averageLatency > 0 && emulationSpeed <= 100 && emulationSpeed > 0 && std::abs(_averageLatency - cfg.AudioLatency) > 50) { + if (_averageLatency > 0 && emulationSpeed <= 100 && emulationSpeed > 0 && std::abs( + _averageLatency - cfg.AudioLatency) > 50) + { //Latency is way off (over 50ms gap), stop audio & start again Stop(); } } -void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) +void SoundManager::PlayBuffer(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) { uint32_t bytesPerSample = 2 * (isStereo ? 2 : 1); uint32_t latency = _console->GetSettings()->GetAudioConfig().AudioLatency; - if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset || latency != _previousLatency) { + if (_sampleRate != sampleRate || _isStereo != isStereo || _needReset || latency != _previousLatency) + { _previousLatency = latency; Release(); InitializeDirectSound(sampleRate, isStereo); @@ -307,11 +342,13 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32 uint32_t soundBufferSize = sampleCount * bytesPerSample; CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize); - - if(!_playing) { + + if (!_playing) + { DWORD byteLatency = (int32_t)((float)(sampleRate * latency) / 1000.0f * bytesPerSample); - if(_lastWriteOffset >= byteLatency / 2) { + if (_lastWriteOffset >= byteLatency / 2) + { Play(); } } -} \ No newline at end of file +} diff --git a/Windows/SoundManager.h b/Windows/SoundManager.h index 3888b1a..c695ab1 100644 --- a/Windows/SoundManager.h +++ b/Windows/SoundManager.h @@ -19,8 +19,8 @@ public: void Release(); void ProcessEndOfFrame(); - void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); - void Play(); + void PlayBuffer(int16_t* soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); + void Play(); void Pause(); void Stop(); @@ -32,7 +32,7 @@ private: static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext); bool InitializeDirectSound(uint32_t sampleRate, bool isStereo); void ClearSecondaryBuffer(); - void CopyToSecondaryBuffer(uint8_t *data, uint32_t size); + void CopyToSecondaryBuffer(uint8_t* data, uint32_t size); void ValidateWriteCursor(DWORD safeWriteCursor); private: diff --git a/Windows/WindowsKeyManager.cpp b/Windows/WindowsKeyManager.cpp index 2abd719..f25417f 100644 --- a/Windows/WindowsKeyManager.cpp +++ b/Windows/WindowsKeyManager.cpp @@ -4,199 +4,207 @@ static vector _keyDefinitions = { //{ "VK_LBUTTON", 0x01, "Left mouse button", "" }, //{ "VK_RBUTTON", 0x02, "Right mouse button", "" }, - { "VK_CANCEL", 0x03, "Control-break processing", "" }, + {"VK_CANCEL", 0x03, "Control-break processing", ""}, //{ "VK_MBUTTON", 0x04, "Middle mouse button (three-button mouse)", "" }, //{ "VK_XBUTTON1", 0x05, "X1 mouse button", "" }, //{ "VK_XBUTTON2", 0x06, "X2 mouse button", "" }, - { "-", 0x07, "Undefined", "" }, - { "VK_BACK", 0x08, "Backspace", "" }, - { "VK_TAB", 0x09, "Tab", "" }, + {"-", 0x07, "Undefined", ""}, + {"VK_BACK", 0x08, "Backspace", ""}, + {"VK_TAB", 0x09, "Tab", ""}, //{ "-", 0x0A - 0B, "Reserved", "" }, - { "VK_CLEAR", 0x0C, "Numpad 5", "" }, - { "VK_RETURN", 0x0D, "Enter", "Numpad Enter" }, + {"VK_CLEAR", 0x0C, "Numpad 5", ""}, + {"VK_RETURN", 0x0D, "Enter", "Numpad Enter"}, //{ "-", 0x0E - 0F, "Undefined", "" }, - { "VK_SHIFT", 0x10, "Shift", "" }, - { "VK_CONTROL", 0x11, "Ctrl", "" }, - { "VK_MENU", 0x12, "Alt", "" }, - { "VK_PAUSE", 0x13, "Pause", "" }, - { "VK_CAPITAL", 0x14, "Caps Lock", "" }, - { "VK_KANA", 0x15, "IME Kana mode", "" }, - { "VK_HANGUEL", 0x15, "IME Hanguel mode", "" }, - { "VK_HANGUL", 0x15, "IME Hangul mode", "" }, + {"VK_SHIFT", 0x10, "Shift", ""}, + {"VK_CONTROL", 0x11, "Ctrl", ""}, + {"VK_MENU", 0x12, "Alt", ""}, + {"VK_PAUSE", 0x13, "Pause", ""}, + {"VK_CAPITAL", 0x14, "Caps Lock", ""}, + {"VK_KANA", 0x15, "IME Kana mode", ""}, + {"VK_HANGUEL", 0x15, "IME Hanguel mode", ""}, + {"VK_HANGUL", 0x15, "IME Hangul mode", ""}, //{ "-", 0x16, "Undefined", "" }, - { "VK_JUNJA", 0x17, "IME Junja mode", "" }, - { "VK_FINAL", 0x18, "IME final mode", "" }, - { "VK_HANJA", 0x19, "IME Hanja mode", "" }, - { "VK_KANJI", 0x19, "IME Kanji mode", "" }, + {"VK_JUNJA", 0x17, "IME Junja mode", ""}, + {"VK_FINAL", 0x18, "IME final mode", ""}, + {"VK_HANJA", 0x19, "IME Hanja mode", ""}, + {"VK_KANJI", 0x19, "IME Kanji mode", ""}, //{ "-", 0x1A, "Undefined", "" }, - { "VK_ESCAPE", 0x1B, "Esc", "" }, - { "VK_CONVERT", 0x1C, "IME convert", "" }, - { "VK_NONCONVERT", 0x1D, "IME nonconvert", "" }, - { "VK_ACCEPT", 0x1E, "IME accept", "" }, - { "VK_MODECHANGE", 0x1F, "IME mode change request", "" }, - { "VK_SPACE", 0x20, "Spacebar", "" }, - { "VK_PRIOR", 0x21, "Numpad 9", "Page Up" }, - { "VK_NEXT", 0x22, "Numpad 3", "Page Down" }, - { "VK_END", 0x23, "Numpad 1", "End" }, - { "VK_HOME", 0x24, "Numpad 7", "Home" }, - { "VK_LEFT", 0x25, "Numpad 4", "Left Arrow" }, - { "VK_UP", 0x26, "Numpad 8", "Up Arrow" }, - { "VK_RIGHT", 0x27, "Numpad 6", "Right Arrow" }, - { "VK_DOWN", 0x28, "Numpad 2", "Down Arrow" }, - { "VK_SELECT", 0x29, "Select", "" }, - { "VK_PRINT", 0x2A, "Print", "" }, - { "VK_EXECUTE", 0x2B, "Execute", "" }, - { "VK_SNAPSHOT", 0x2C, "Print Screen", "" }, - { "VK_INSERT", 0x2D, "Numpad 0", "Insert" }, - { "VK_DELETE", 0x2E, "Numpad .", "Delete" }, - { "VK_HELP", 0x2F, "Help", "" }, - { "0", 0x30, "0", "" }, - { "1", 0x31, "1", "" }, - { "2", 0x32, "2", "" }, - { "3", 0x33, "3", "" }, - { "4", 0x34, "4", "" }, - { "5", 0x35, "5", "" }, - { "6", 0x36, "6", "" }, - { "7", 0x37, "7", "" }, - { "8", 0x38, "8", "" }, - { "9", 0x39, "9", "" }, + {"VK_ESCAPE", 0x1B, "Esc", ""}, + {"VK_CONVERT", 0x1C, "IME convert", ""}, + {"VK_NONCONVERT", 0x1D, "IME nonconvert", ""}, + {"VK_ACCEPT", 0x1E, "IME accept", ""}, + {"VK_MODECHANGE", 0x1F, "IME mode change request", ""}, + {"VK_SPACE", 0x20, "Spacebar", ""}, + {"VK_PRIOR", 0x21, "Numpad 9", "Page Up"}, + {"VK_NEXT", 0x22, "Numpad 3", "Page Down"}, + {"VK_END", 0x23, "Numpad 1", "End"}, + {"VK_HOME", 0x24, "Numpad 7", "Home"}, + {"VK_LEFT", 0x25, "Numpad 4", "Left Arrow"}, + {"VK_UP", 0x26, "Numpad 8", "Up Arrow"}, + {"VK_RIGHT", 0x27, "Numpad 6", "Right Arrow"}, + {"VK_DOWN", 0x28, "Numpad 2", "Down Arrow"}, + {"VK_SELECT", 0x29, "Select", ""}, + {"VK_PRINT", 0x2A, "Print", ""}, + {"VK_EXECUTE", 0x2B, "Execute", ""}, + {"VK_SNAPSHOT", 0x2C, "Print Screen", ""}, + {"VK_INSERT", 0x2D, "Numpad 0", "Insert"}, + {"VK_DELETE", 0x2E, "Numpad .", "Delete"}, + {"VK_HELP", 0x2F, "Help", ""}, + {"0", 0x30, "0", ""}, + {"1", 0x31, "1", ""}, + {"2", 0x32, "2", ""}, + {"3", 0x33, "3", ""}, + {"4", 0x34, "4", ""}, + {"5", 0x35, "5", ""}, + {"6", 0x36, "6", ""}, + {"7", 0x37, "7", ""}, + {"8", 0x38, "8", ""}, + {"9", 0x39, "9", ""}, //{ "undefined", 0x3A - 40, "undefined", "" }, - { "A", 0x41, "A", "" }, - { "B", 0x42, "B", "" }, - { "C", 0x43, "C", "" }, - { "D", 0x44, "D", "" }, - { "E", 0x45, "E", "" }, - { "F", 0x46, "F", "" }, - { "G", 0x47, "G", "" }, - { "H", 0x48, "H", "" }, - { "I", 0x49, "I", "" }, - { "J", 0x4A, "J", "" }, - { "K", 0x4B, "K", "" }, - { "L", 0x4C, "L", "" }, - { "M", 0x4D, "M", "" }, - { "N", 0x4E, "N", "" }, - { "O", 0x4F, "O", "" }, - { "P", 0x50, "P", "" }, - { "Q", 0x51, "Q", "" }, - { "R", 0x52, "R", "" }, - { "S", 0x53, "S", "" }, - { "T", 0x54, "T", "" }, - { "U", 0x55, "U", "" }, - { "V", 0x56, "V", "" }, - { "W", 0x57, "W", "" }, - { "X", 0x58, "X", "" }, - { "Y", 0x59, "Y", "" }, - { "Z", 0x5A, "Z", "" }, - { "VK_LWIN", 0x5B, "Left Windows", "" }, - { "VK_RWIN", 0x5C, "Right Windows", "" }, - { "VK_APPS", 0x5D, "Applications Key", "" }, + {"A", 0x41, "A", ""}, + {"B", 0x42, "B", ""}, + {"C", 0x43, "C", ""}, + {"D", 0x44, "D", ""}, + {"E", 0x45, "E", ""}, + {"F", 0x46, "F", ""}, + {"G", 0x47, "G", ""}, + {"H", 0x48, "H", ""}, + {"I", 0x49, "I", ""}, + {"J", 0x4A, "J", ""}, + {"K", 0x4B, "K", ""}, + {"L", 0x4C, "L", ""}, + {"M", 0x4D, "M", ""}, + {"N", 0x4E, "N", ""}, + {"O", 0x4F, "O", ""}, + {"P", 0x50, "P", ""}, + {"Q", 0x51, "Q", ""}, + {"R", 0x52, "R", ""}, + {"S", 0x53, "S", ""}, + {"T", 0x54, "T", ""}, + {"U", 0x55, "U", ""}, + {"V", 0x56, "V", ""}, + {"W", 0x57, "W", ""}, + {"X", 0x58, "X", ""}, + {"Y", 0x59, "Y", ""}, + {"Z", 0x5A, "Z", ""}, + {"VK_LWIN", 0x5B, "Left Windows", ""}, + {"VK_RWIN", 0x5C, "Right Windows", ""}, + {"VK_APPS", 0x5D, "Applications Key", ""}, //{ "-", 0x5E, "Reserved", "" }, - { "VK_SLEEP", 0x5F, "Computer Sleep", "" }, - { "VK_NUMPAD0", 0x60, "Keypad 0", "" }, - { "VK_NUMPAD1", 0x61, "Keypad 1", "" }, - { "VK_NUMPAD2", 0x62, "Keypad 2", "" }, - { "VK_NUMPAD3", 0x63, "Keypad 3", "" }, - { "VK_NUMPAD4", 0x64, "Keypad 4", "" }, - { "VK_NUMPAD5", 0x65, "Keypad 5", "" }, - { "VK_NUMPAD6", 0x66, "Keypad 6", "" }, - { "VK_NUMPAD7", 0x67, "Keypad 7", "" }, - { "VK_NUMPAD8", 0x68, "Keypad 8", "" }, - { "VK_NUMPAD9", 0x69, "Keypad 9", "" }, - { "VK_MULTIPLY", 0x6A, "Numpad *", "" }, - { "VK_ADD", 0x6B, "Numpad +", "" }, - { "VK_SEPARATOR", 0x6C, "Separator", "" }, - { "VK_SUBTRACT", 0x6D, "Numpad -", "" }, - { "VK_DECIMAL", 0x6E, "Decimal", "" }, - { "VK_DIVIDE", 0x6F, "Numpad /", "" }, - { "VK_F1", 0x70, "F1", "" }, - { "VK_F2", 0x71, "F2", "" }, - { "VK_F3", 0x72, "F3", "" }, - { "VK_F4", 0x73, "F4", "" }, - { "VK_F5", 0x74, "F5", "" }, - { "VK_F6", 0x75, "F6", "" }, - { "VK_F7", 0x76, "F7", "" }, - { "VK_F8", 0x77, "F8", "" }, - { "VK_F9", 0x78, "F9", "" }, - { "VK_F10", 0x79, "F10", "" }, - { "VK_F11", 0x7A, "F11", "" }, - { "VK_F12", 0x7B, "F12", "" }, - { "VK_F13", 0x7C, "F13", "" }, - { "VK_F14", 0x7D, "F14", "" }, - { "VK_F15", 0x7E, "F15", "" }, - { "VK_F16", 0x7F, "F16", "" }, - { "VK_F17", 0x80, "F17", "" }, - { "VK_F18", 0x81, "F18", "" }, - { "VK_F19", 0x82, "F19", "" }, - { "VK_F20", 0x83, "F20", "" }, - { "VK_F21", 0x84, "F21", "" }, - { "VK_F22", 0x85, "F22", "" }, - { "VK_F23", 0x86, "F23", "" }, - { "VK_F24", 0x87, "F24", "" }, + {"VK_SLEEP", 0x5F, "Computer Sleep", ""}, + {"VK_NUMPAD0", 0x60, "Keypad 0", ""}, + {"VK_NUMPAD1", 0x61, "Keypad 1", ""}, + {"VK_NUMPAD2", 0x62, "Keypad 2", ""}, + {"VK_NUMPAD3", 0x63, "Keypad 3", ""}, + {"VK_NUMPAD4", 0x64, "Keypad 4", ""}, + {"VK_NUMPAD5", 0x65, "Keypad 5", ""}, + {"VK_NUMPAD6", 0x66, "Keypad 6", ""}, + {"VK_NUMPAD7", 0x67, "Keypad 7", ""}, + {"VK_NUMPAD8", 0x68, "Keypad 8", ""}, + {"VK_NUMPAD9", 0x69, "Keypad 9", ""}, + {"VK_MULTIPLY", 0x6A, "Numpad *", ""}, + {"VK_ADD", 0x6B, "Numpad +", ""}, + {"VK_SEPARATOR", 0x6C, "Separator", ""}, + {"VK_SUBTRACT", 0x6D, "Numpad -", ""}, + {"VK_DECIMAL", 0x6E, "Decimal", ""}, + {"VK_DIVIDE", 0x6F, "Numpad /", ""}, + {"VK_F1", 0x70, "F1", ""}, + {"VK_F2", 0x71, "F2", ""}, + {"VK_F3", 0x72, "F3", ""}, + {"VK_F4", 0x73, "F4", ""}, + {"VK_F5", 0x74, "F5", ""}, + {"VK_F6", 0x75, "F6", ""}, + {"VK_F7", 0x76, "F7", ""}, + {"VK_F8", 0x77, "F8", ""}, + {"VK_F9", 0x78, "F9", ""}, + {"VK_F10", 0x79, "F10", ""}, + {"VK_F11", 0x7A, "F11", ""}, + {"VK_F12", 0x7B, "F12", ""}, + {"VK_F13", 0x7C, "F13", ""}, + {"VK_F14", 0x7D, "F14", ""}, + {"VK_F15", 0x7E, "F15", ""}, + {"VK_F16", 0x7F, "F16", ""}, + {"VK_F17", 0x80, "F17", ""}, + {"VK_F18", 0x81, "F18", ""}, + {"VK_F19", 0x82, "F19", ""}, + {"VK_F20", 0x83, "F20", ""}, + {"VK_F21", 0x84, "F21", ""}, + {"VK_F22", 0x85, "F22", ""}, + {"VK_F23", 0x86, "F23", ""}, + {"VK_F24", 0x87, "F24", ""}, //{ "-", 0x88 - 8F, "Unassigned", "" }, - { "VK_NUMLOCK", 0x90, "Pause", "Num Lock" }, - { "VK_SCROLL", 0x91, "Scroll Lock", "" }, + {"VK_NUMLOCK", 0x90, "Pause", "Num Lock"}, + {"VK_SCROLL", 0x91, "Scroll Lock", ""}, //{"-", 0x92-96,"OEM specific"}, //{ "-", 0x97 - 9F, "Unassigned", "" }, - { "VK_LSHIFT", 0xA0, "Left Shift", "" }, - { "VK_RSHIFT", 0xA1, "Right Shift", "" }, - { "VK_LCONTROL", 0xA2, "Left Control", "" }, - { "VK_RCONTROL", 0xA3, "Right Control", "" }, - { "VK_LMENU", 0xA4, "Left Menu", "" }, - { "VK_RMENU", 0xA5, "Right Menu", "" }, - { "VK_BROWSER_BACK", 0xA6, "Browser Back", "" }, - { "VK_BROWSER_FORWARD", 0xA7, "Browser Forward", "" }, - { "VK_BROWSER_REFRESH", 0xA8, "Browser Refresh", "" }, - { "VK_BROWSER_STOP", 0xA9, "Browser Stop", "" }, - { "VK_BROWSER_SEARCH", 0xAA, "Browser Search", "" }, - { "VK_BROWSER_FAVORITES", 0xAB, "Browser Favorites", "" }, - { "VK_BROWSER_HOME", 0xAC, "Browser Start and Home", "" }, - { "VK_VOLUME_MUTE", 0xAD, "Volume Mute", "" }, - { "VK_VOLUME_DOWN", 0xAE, "Volume Down", "" }, - { "VK_VOLUME_UP", 0xAF, "Volume Up", "" }, - { "VK_MEDIA_NEXT_TRACK", 0xB0, "Next Track", "" }, - { "VK_MEDIA_PREV_TRACK", 0xB1, "Previous Track", "" }, - { "VK_MEDIA_STOP", 0xB2, "Stop Media", "" }, - { "VK_MEDIA_PLAY_PAUSE", 0xB3, "Play/Pause Media", "" }, - { "VK_LAUNCH_MAIL", 0xB4, "Start Mail", "" }, - { "VK_LAUNCH_MEDIA_SELECT", 0xB5, "Select Media", "" }, - { "VK_LAUNCH_APP1", 0xB6, "Start Application 1", "" }, - { "VK_LAUNCH_APP2", 0xB7, "Start Application 2", "" }, + {"VK_LSHIFT", 0xA0, "Left Shift", ""}, + {"VK_RSHIFT", 0xA1, "Right Shift", ""}, + {"VK_LCONTROL", 0xA2, "Left Control", ""}, + {"VK_RCONTROL", 0xA3, "Right Control", ""}, + {"VK_LMENU", 0xA4, "Left Menu", ""}, + {"VK_RMENU", 0xA5, "Right Menu", ""}, + {"VK_BROWSER_BACK", 0xA6, "Browser Back", ""}, + {"VK_BROWSER_FORWARD", 0xA7, "Browser Forward", ""}, + {"VK_BROWSER_REFRESH", 0xA8, "Browser Refresh", ""}, + {"VK_BROWSER_STOP", 0xA9, "Browser Stop", ""}, + {"VK_BROWSER_SEARCH", 0xAA, "Browser Search", ""}, + {"VK_BROWSER_FAVORITES", 0xAB, "Browser Favorites", ""}, + {"VK_BROWSER_HOME", 0xAC, "Browser Start and Home", ""}, + {"VK_VOLUME_MUTE", 0xAD, "Volume Mute", ""}, + {"VK_VOLUME_DOWN", 0xAE, "Volume Down", ""}, + {"VK_VOLUME_UP", 0xAF, "Volume Up", ""}, + {"VK_MEDIA_NEXT_TRACK", 0xB0, "Next Track", ""}, + {"VK_MEDIA_PREV_TRACK", 0xB1, "Previous Track", ""}, + {"VK_MEDIA_STOP", 0xB2, "Stop Media", ""}, + {"VK_MEDIA_PLAY_PAUSE", 0xB3, "Play/Pause Media", ""}, + {"VK_LAUNCH_MAIL", 0xB4, "Start Mail", ""}, + {"VK_LAUNCH_MEDIA_SELECT", 0xB5, "Select Media", ""}, + {"VK_LAUNCH_APP1", 0xB6, "Start Application 1", ""}, + {"VK_LAUNCH_APP2", 0xB7, "Start Application 2", ""}, //{ "-", 0xB8 - B9, "Reserved", "" }, - { "VK_OEM_1", 0xBA, ";", "" }, - { "VK_OEM_PLUS", 0xBB, "=", "" }, - { "VK_OEM_COMMA", 0xBC, ",", "" }, - { "VK_OEM_MINUS", 0xBD, "-", "" }, - { "VK_OEM_PERIOD", 0xBE, ".", "" }, - { "VK_OEM_2", 0xBF, "/", "Numpad /" }, - { "VK_OEM_3", 0xC0, "`", "" }, + {"VK_OEM_1", 0xBA, ";", ""}, + {"VK_OEM_PLUS", 0xBB, "=", ""}, + {"VK_OEM_COMMA", 0xBC, ",", ""}, + {"VK_OEM_MINUS", 0xBD, "-", ""}, + {"VK_OEM_PERIOD", 0xBE, ".", ""}, + {"VK_OEM_2", 0xBF, "/", "Numpad /"}, + {"VK_OEM_3", 0xC0, "`", ""}, //{ "-", 0xC1 - D7, "Reserved", "" }, //{ "-", 0xD8 - DA, "Unassigned", "" }, - { "VK_OEM_4", 0xDB, "[", "" }, - { "VK_OEM_5", 0xDC, "\\", "" }, - { "VK_OEM_6", 0xDD, "]", "" }, - { "VK_OEM_7", 0xDE, "'", "" }, - { "VK_OEM_8", 0xDF, "Used for miscellaneous characters; it can vary by keyboard.", "" }, + {"VK_OEM_4", 0xDB, "[", ""}, + {"VK_OEM_5", 0xDC, "\\", ""}, + {"VK_OEM_6", 0xDD, "]", ""}, + {"VK_OEM_7", 0xDE, "'", ""}, + {"VK_OEM_8", 0xDF, "Used for miscellaneous characters; it can vary by keyboard.", ""}, //{ "-", 0xE0, "Reserved", "" }, //{ "-", 0xE1, "OEM specific", "" }, - { "VK_OEM_102", 0xE2, "Pipe", "" }, + {"VK_OEM_102", 0xE2, "Pipe", ""}, //{ "-", 0xE3 - E4, "OEM specific", "" }, - { "VK_PROCESSKEY", 0xE5, "IME PROCESS", "" }, + {"VK_PROCESSKEY", 0xE5, "IME PROCESS", ""}, //{ "-", 0xE6, "OEM specific", "" }, - { "VK_PACKET", 0xE7, "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP", "" }, + { + "VK_PACKET", 0xE7, + "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP", + "" + }, //{ "-", 0xE8, "Unassigned", "" }, // {"-",0xE6,"OEM specific"}, - { "VK_PACKET", 0xE7, "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP", "" }, + { + "VK_PACKET", 0xE7, + "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP", + "" + }, // {"-",0xE8,"Unassigned"}, //{ "-", 0xE9 - F5, "OEM specific", "" }, - { "VK_ATTN", 0xF6, "Attn", "" }, - { "VK_CRSEL", 0xF7, "CrSel", "" }, - { "VK_EXSEL", 0xF8, "ExSel", "" }, - { "VK_EREOF", 0xF9, "Erase EOF", "Menu" }, - { "VK_PLAY", 0xFA, "Play", "" }, - { "VK_ZOOM", 0xFB, "Zoom", "" }, - { "VK_NONAME", 0xFC, "Reserved", "" }, - { "VK_PA1", 0xFD, "PA1", "" }, - { "VK_OEM_CLEAR", 0xFE, "Clear", "" } + {"VK_ATTN", 0xF6, "Attn", ""}, + {"VK_CRSEL", 0xF7, "CrSel", ""}, + {"VK_EXSEL", 0xF8, "ExSel", ""}, + {"VK_EREOF", 0xF9, "Erase EOF", "Menu"}, + {"VK_PLAY", 0xFA, "Play", ""}, + {"VK_ZOOM", 0xFB, "Zoom", ""}, + {"VK_NONAME", 0xFC, "Reserved", ""}, + {"VK_PA1", 0xFD, "PA1", ""}, + {"VK_OEM_CLEAR", 0xFE, "Clear", ""} }; WindowsKeyManager::WindowsKeyManager(shared_ptr console, HWND hWnd) @@ -207,35 +215,57 @@ WindowsKeyManager::WindowsKeyManager(shared_ptr console, HWND hWnd) ResetKeyState(); //Init XInput buttons - vector buttonNames = { "Up", "Down", "Left", "Right", "Start", "Back", "L3", "R3", "L1", "R1", "?", "?", "A", "B", "X", "Y", "L2", "R2", "RT Up", "RT Down", "RT Left", "RT Right", "LT Up", "LT Down", "LT Left", "LT Right" }; - for(int i = 0; i < 4; i++) { - for(int j = 0; j < (int)buttonNames.size(); j++) { - _keyDefinitions.push_back({ "", (uint32_t)(0xFFFF + i * 0x100 + j + 1), "Pad" + std::to_string(i + 1) + " " + buttonNames[j] }); + vector buttonNames = { + "Up", "Down", "Left", "Right", "Start", "Back", "L3", "R3", "L1", "R1", "?", "?", "A", "B", "X", "Y", "L2", "R2", + "RT Up", "RT Down", "RT Left", "RT Right", "LT Up", "LT Down", "LT Left", "LT Right" + }; + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < (int)buttonNames.size(); j++) + { + _keyDefinitions.push_back({ + "", (uint32_t)(0xFFFF + i * 0x100 + j + 1), "Pad" + std::to_string(i + 1) + " " + buttonNames[j] + }); } } //Init DirectInput buttons - vector diButtonNames = { "Y+", "Y-", "X-", "X+", "Y2+", "Y2-", "X2-", "X2+", "Z+", "Z-", "Z2+", "Z2-", "DPad Up", "DPad Down", "DPad Right", "DPad Left" }; - for(int i = 0; i < 16; i++) { - for(int j = 0; j < (int)diButtonNames.size(); j++) { - _keyDefinitions.push_back({ "", (uint32_t)(0x11000 + i * 0x100 + j), "Joy" + std::to_string(i + 1) + " " + diButtonNames[j] }); + vector diButtonNames = { + "Y+", "Y-", "X-", "X+", "Y2+", "Y2-", "X2-", "X2+", "Z+", "Z-", "Z2+", "Z2-", "DPad Up", "DPad Down", + "DPad Right", "DPad Left" + }; + for (int i = 0; i < 16; i++) + { + for (int j = 0; j < (int)diButtonNames.size(); j++) + { + _keyDefinitions.push_back({ + "", (uint32_t)(0x11000 + i * 0x100 + j), "Joy" + std::to_string(i + 1) + " " + diButtonNames[j] + }); } - for(int j = 0; j < 128; j++) { - _keyDefinitions.push_back({ "", (uint32_t)(0x11000 + i * 0x100 + j + 0x10), "Joy" + std::to_string(i + 1) + " But" + std::to_string(j+1)}); + for (int j = 0; j < 128; j++) + { + _keyDefinitions.push_back({ + "", (uint32_t)(0x11000 + i * 0x100 + j + 0x10), + "Joy" + std::to_string(i + 1) + " But" + std::to_string(j + 1) + }); } } - for(KeyDefinition& keyDef : _keyDefinitions) { + for (KeyDefinition& keyDef : _keyDefinitions) + { _keyNames[keyDef.keyCode] = keyDef.description; - _keyExtendedNames[keyDef.keyCode | 0x100] = keyDef.extDescription.empty() ? "Ext " + keyDef.description : keyDef.extDescription; + _keyExtendedNames[keyDef.keyCode | 0x100] = keyDef.extDescription.empty() + ? "Ext " + keyDef.description + : keyDef.extDescription; _keyCodes[keyDef.description] = keyDef.keyCode; - if(!keyDef.extDescription.empty()) { + if (!keyDef.extDescription.empty()) + { _keyCodes[keyDef.extDescription] = 0x100 | (keyDef.keyCode); } } - + StartUpdateDeviceThread(); } @@ -248,14 +278,17 @@ WindowsKeyManager::~WindowsKeyManager() void WindowsKeyManager::StartUpdateDeviceThread() { - _updateDeviceThread = std::thread([=]() { + _updateDeviceThread = std::thread([=]() + { _xInput.reset(new XInputManager(_console)); _directInput.reset(new DirectInputManager(_console, _hWnd)); - while(!_stopUpdateDeviceThread) { + while (!_stopUpdateDeviceThread) + { //Check for newly plugged in XInput controllers every 5 secs //Do not check for DirectInput controllers because this takes more time and sometimes causes issues/freezes - if(_xInput->NeedToUpdate()) { + if (_xInput->NeedToUpdate()) + { _xInput->UpdateDeviceList(); } _stopSignal.Wait(5000); @@ -265,7 +298,8 @@ void WindowsKeyManager::StartUpdateDeviceThread() void WindowsKeyManager::RefreshState() { - if(!_xInput || !_directInput) { + if (!_xInput || !_directInput) + { return; } @@ -275,27 +309,35 @@ void WindowsKeyManager::RefreshState() bool WindowsKeyManager::IsKeyPressed(uint32_t key) { - if(_disableAllKeys) { + if (_disableAllKeys) + { return false; } - if(key >= 0x10000) { - if(!_xInput || !_directInput) { + if (key >= 0x10000) + { + if (!_xInput || !_directInput) + { return false; } - if(key >= 0x11000) { + if (key >= 0x11000) + { //Directinput key uint8_t gamepadPort = (key - 0x11000) / 0x100; uint8_t gamepadButton = (key - 0x11000) % 0x100; return _directInput->IsPressed(gamepadPort, gamepadButton); - } else { + } + else + { //XInput key uint8_t gamepadPort = (key - 0xFFFF) / 0x100; uint8_t gamepadButton = (key - 0xFFFF) % 0x100; return _xInput->IsPressed(gamepadPort, gamepadButton); } - } else if(key < 0x200) { + } + else if (key < 0x200) + { return _keyState[key] != 0; } return false; @@ -303,10 +345,11 @@ bool WindowsKeyManager::IsKeyPressed(uint32_t key) bool WindowsKeyManager::IsMouseButtonPressed(MouseButton button) { - switch(button) { - case MouseButton::LeftButton: return _mouseState[0]; - case MouseButton::RightButton: return _mouseState[1]; - case MouseButton::MiddleButton: return _mouseState[2]; + switch (button) + { + case MouseButton::LeftButton: return _mouseState[0]; + case MouseButton::RightButton: return _mouseState[1]; + case MouseButton::MiddleButton: return _mouseState[2]; } return false; @@ -315,30 +358,39 @@ bool WindowsKeyManager::IsMouseButtonPressed(MouseButton button) vector WindowsKeyManager::GetPressedKeys() { vector result; - if(!_xInput || !_directInput) { + if (!_xInput || !_directInput) + { return result; } _xInput->RefreshState(); - for(int i = 0; i < XUSER_MAX_COUNT; i++) { - for(int j = 1; j <= 26; j++) { - if(_xInput->IsPressed(i, j)) { + for (int i = 0; i < XUSER_MAX_COUNT; i++) + { + for (int j = 1; j <= 26; j++) + { + if (_xInput->IsPressed(i, j)) + { result.push_back(0xFFFF + i * 0x100 + j); } } } _directInput->RefreshState(); - for(int i = _directInput->GetJoystickCount() - 1; i >= 0; i--) { - for(int j = 0; j < 16+128; j++) { - if(_directInput->IsPressed(i, j)) { + for (int i = _directInput->GetJoystickCount() - 1; i >= 0; i--) + { + for (int j = 0; j < 16 + 128; j++) + { + if (_directInput->IsPressed(i, j)) + { result.push_back(0x11000 + i * 0x100 + j); } } } - for(int i = 0; i < 0x200; i++) { - if(_keyState[i]) { + for (int i = 0; i < 0x200; i++) + { + if (_keyState[i]) + { result.push_back(i); } } @@ -349,7 +401,8 @@ string WindowsKeyManager::GetKeyName(uint32_t keyCode) { bool extendedKey = (keyCode <= 0xFFFF && (keyCode & 0x100)); auto keyDef = (extendedKey ? _keyExtendedNames : _keyNames).find(keyCode); - if(keyDef != (extendedKey ? _keyExtendedNames : _keyNames).end()) { + if (keyDef != (extendedKey ? _keyExtendedNames : _keyNames).end()) + { return keyDef->second; } return ""; @@ -358,7 +411,8 @@ string WindowsKeyManager::GetKeyName(uint32_t keyCode) uint32_t WindowsKeyManager::GetKeyCode(string keyName) { auto keyDef = _keyCodes.find(keyName); - if(keyDef != _keyCodes.end()) { + if (keyDef != _keyCodes.end()) + { return keyDef->second; } return 0; @@ -366,7 +420,8 @@ uint32_t WindowsKeyManager::GetKeyCode(string keyName) void WindowsKeyManager::UpdateDevices() { - if(!_xInput || !_directInput) { + if (!_xInput || !_directInput) + { return; } @@ -376,11 +431,15 @@ void WindowsKeyManager::UpdateDevices() void WindowsKeyManager::SetKeyState(uint16_t scanCode, bool state) { - if(scanCode > 0x1FF) { + if (scanCode > 0x1FF) + { _mouseState[scanCode & 0x03] = state; - } else { + } + else + { uint32_t keyCode = MapVirtualKeyEx(scanCode & 0xFF, MAPVK_VSC_TO_VK, GetKeyboardLayout(0)); - if(keyCode >= 0x10 && keyCode <= 0x12) { + if (keyCode >= 0x10 && keyCode <= 0x12) + { //Ignore "ext" flag for alt, ctrl & shift scanCode = MapVirtualKeyEx(keyCode, MAPVK_VK_TO_VSC, GetKeyboardLayout(0)); } @@ -397,4 +456,4 @@ void WindowsKeyManager::ResetKeyState() { memset(_mouseState, 0, sizeof(_mouseState)); memset(_keyState, 0, sizeof(_keyState)); -} \ No newline at end of file +} diff --git a/Windows/WindowsKeyManager.h b/Windows/WindowsKeyManager.h index 01594f3..4f4a327 100644 --- a/Windows/WindowsKeyManager.h +++ b/Windows/WindowsKeyManager.h @@ -8,7 +8,8 @@ #include "XInputManager.h" #include "DirectInputManager.h" -struct KeyDefinition { +struct KeyDefinition +{ string name; uint32_t keyCode; string description; @@ -19,40 +20,40 @@ class Console; class WindowsKeyManager : public IKeyManager { - private: - HWND _hWnd; - shared_ptr _console; +private: + HWND _hWnd; + shared_ptr _console; - bool _keyState[0x200]; - bool _mouseState[0x03]; - unique_ptr _directInput; - unique_ptr _xInput; - std::unordered_map _keyNames; - std::unordered_map _keyExtendedNames; - std::unordered_map _keyCodes; + bool _keyState[0x200]; + bool _mouseState[0x03]; + unique_ptr _directInput; + unique_ptr _xInput; + std::unordered_map _keyNames; + std::unordered_map _keyExtendedNames; + std::unordered_map _keyCodes; - AutoResetEvent _stopSignal; - - std::thread _updateDeviceThread; - atomic _stopUpdateDeviceThread = false; - bool _disableAllKeys = false; + AutoResetEvent _stopSignal; - void StartUpdateDeviceThread(); + std::thread _updateDeviceThread; + atomic _stopUpdateDeviceThread = false; + bool _disableAllKeys = false; - public: - WindowsKeyManager(shared_ptr console, HWND hWnd); - ~WindowsKeyManager(); + void StartUpdateDeviceThread(); - void RefreshState(); - bool IsKeyPressed(uint32_t key); - bool IsMouseButtonPressed(MouseButton button); - vector GetPressedKeys(); - string GetKeyName(uint32_t key); - uint32_t GetKeyCode(string keyName); +public: + WindowsKeyManager(shared_ptr console, HWND hWnd); + ~WindowsKeyManager(); - void SetKeyState(uint16_t scanCode, bool state); - void ResetKeyState(); - void SetDisabled(bool disabled); + void RefreshState(); + bool IsKeyPressed(uint32_t key); + bool IsMouseButtonPressed(MouseButton button); + vector GetPressedKeys(); + string GetKeyName(uint32_t key); + uint32_t GetKeyCode(string keyName); - void UpdateDevices(); + void SetKeyState(uint16_t scanCode, bool state); + void ResetKeyState(); + void SetDisabled(bool disabled); + + void UpdateDevices(); }; diff --git a/Windows/XInputManager.cpp b/Windows/XInputManager.cpp index c90053d..4a0ab5f 100644 --- a/Windows/XInputManager.cpp +++ b/Windows/XInputManager.cpp @@ -6,7 +6,8 @@ XInputManager::XInputManager(shared_ptr console) { _console = console; - for(int i = 0; i < XUSER_MAX_COUNT; i++) { + for (int i = 0; i < XUSER_MAX_COUNT; i++) + { _gamePadStates.push_back(shared_ptr(new XINPUT_STATE())); _gamePadConnected.push_back(true); } @@ -15,13 +16,18 @@ XInputManager::XInputManager(shared_ptr console) void XInputManager::RefreshState() { XINPUT_STATE state; - for(DWORD i = 0; i < XUSER_MAX_COUNT; i++) { - if(_gamePadConnected[i]) { - if(XInputGetState(i, &state) != ERROR_SUCCESS) { + for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) + { + if (_gamePadConnected[i]) + { + if (XInputGetState(i, &state) != ERROR_SUCCESS) + { //XInputGetState is incredibly slow when no controller is plugged in ZeroMemory(_gamePadStates[i].get(), sizeof(XINPUT_STATE)); _gamePadConnected[i] = false; - } else { + } + else + { *_gamePadStates[i] = state; } } @@ -30,10 +36,13 @@ void XInputManager::RefreshState() bool XInputManager::NeedToUpdate() { - for(int i = 0; i < XUSER_MAX_COUNT; i++) { - if(!_gamePadConnected[i]) { + for (int i = 0; i < XUSER_MAX_COUNT; i++) + { + if (!_gamePadConnected[i]) + { XINPUT_STATE state; - if(XInputGetState(i, &state) == ERROR_SUCCESS) { + if (XInputGetState(i, &state) == ERROR_SUCCESS) + { return true; } } @@ -44,32 +53,38 @@ bool XInputManager::NeedToUpdate() void XInputManager::UpdateDeviceList() { //Periodically detect if a controller has been plugged in to allow controllers to be plugged in after the emu is started - for(int i = 0; i < XUSER_MAX_COUNT; i++) { + for (int i = 0; i < XUSER_MAX_COUNT; i++) + { _gamePadConnected[i] = true; } } bool XInputManager::IsPressed(uint8_t gamepadPort, uint8_t button) { - if(_gamePadConnected[gamepadPort]) { - XINPUT_GAMEPAD &gamepad = _gamePadStates[gamepadPort]->Gamepad; - if(button <= 16) { + if (_gamePadConnected[gamepadPort]) + { + XINPUT_GAMEPAD& gamepad = _gamePadStates[gamepadPort]->Gamepad; + if (button <= 16) + { WORD xinputButton = 1 << (button - 1); return (_gamePadStates[gamepadPort]->Gamepad.wButtons & xinputButton) != 0; - } else { + } + else + { double ratio = _console->GetSettings()->GetControllerDeadzoneRatio() * 2; - switch(button) { - case 17: return gamepad.bLeftTrigger > (XINPUT_GAMEPAD_TRIGGER_THRESHOLD * ratio); - case 18: return gamepad.bRightTrigger > (XINPUT_GAMEPAD_TRIGGER_THRESHOLD * ratio); - case 19: return gamepad.sThumbRY > (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); - case 20: return gamepad.sThumbRY < -(XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); - case 21: return gamepad.sThumbRX < -(XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); - case 22: return gamepad.sThumbRX > (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); - case 23: return gamepad.sThumbLY > (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); - case 24: return gamepad.sThumbLY < -(XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); - case 25: return gamepad.sThumbLX < -(XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); - case 26: return gamepad.sThumbLX > (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); + switch (button) + { + case 17: return gamepad.bLeftTrigger > (XINPUT_GAMEPAD_TRIGGER_THRESHOLD * ratio); + case 18: return gamepad.bRightTrigger > (XINPUT_GAMEPAD_TRIGGER_THRESHOLD * ratio); + case 19: return gamepad.sThumbRY > (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); + case 20: return gamepad.sThumbRY < -(XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); + case 21: return gamepad.sThumbRX < -(XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); + case 22: return gamepad.sThumbRX > (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * ratio); + case 23: return gamepad.sThumbLY > (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); + case 24: return gamepad.sThumbLY < -(XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); + case 25: return gamepad.sThumbLX < -(XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); + case 26: return gamepad.sThumbLX > (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * ratio); } } } diff --git a/Windows/XInputManager.h b/Windows/XInputManager.h index 019d343..93d990d 100644 --- a/Windows/XInputManager.h +++ b/Windows/XInputManager.h @@ -7,16 +7,16 @@ class Console; class XInputManager { - private: - shared_ptr _console; - vector> _gamePadStates; - vector _gamePadConnected; +private: + shared_ptr _console; + vector> _gamePadStates; + vector _gamePadConnected; - public: - XInputManager(shared_ptr console); +public: + XInputManager(shared_ptr console); - bool NeedToUpdate(); - void UpdateDeviceList(); - void RefreshState(); - bool IsPressed(uint8_t gamepadPort, uint8_t button); + bool NeedToUpdate(); + void UpdateDeviceList(); + void RefreshState(); + bool IsPressed(uint8_t gamepadPort, uint8_t button); }; diff --git a/Windows/stdafx.h b/Windows/stdafx.h index 4db3bd9..1fe9af6 100644 --- a/Windows/stdafx.h +++ b/Windows/stdafx.h @@ -44,4 +44,4 @@ using std::list; using std::vector; using std::shared_ptr; using std::string; -using namespace std::literals::string_literals; \ No newline at end of file +using namespace std::literals::string_literals;