void ShipSpinner::Draw() { Graphics::Renderer *r = GetContext()->GetRenderer(); Graphics::Renderer::StateTicket ticket(r); r->SetPerspectiveProjection(45.f, 1.f, 1.f, 10000.f); r->SetTransform(matrix4x4f::Identity()); r->SetDepthTest(true); r->ClearDepthBuffer(); r->SetLights(1, &m_light); Point pos(GetAbsolutePosition() + GetActiveOffset()); Point size(GetActiveArea()); r->SetViewport(pos.x, GetContext()->GetSize().y - pos.y - size.y, size.x, size.y); matrix4x4f rot = matrix4x4f::RotateXMatrix(m_rotX); rot.RotateY(m_rotY); rot[14] = -1.5f * m_model->GetDrawClipRadius(); m_model->Render(r, rot, &m_params); }
void tick(const std::weak_ptr<implementation>& self) { try { produce_timer_.restart(); std::map<int, safe_ptr<basic_frame>> frames; BOOST_FOREACH(auto& layer, layers_) frames[layer.first] = basic_frame::empty(); tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) { auto transform = transforms_[layer.first].fetch_and_tick(1); int hints = frame_producer::NO_HINT; if(format_desc_.field_mode != field_mode::progressive) { hints |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; } if(transform.is_key) hints |= frame_producer::ALPHA_HINT; auto frame = layer.second.receive(hints); auto frame1 = make_safe<core::basic_frame>(frame); frame1->get_frame_transform() = transform; if(format_desc_.field_mode != core::field_mode::progressive) { auto frame2 = make_safe<core::basic_frame>(frame); frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1); frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode); } frames[layer.first] = frame1; }); graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); std::shared_ptr<void> ticket(nullptr, [self](void*) { auto self2 = self.lock(); if(self2) self2->executor_.begin_invoke([=]{tick(self);}); }); target_->send(std::make_pair(frames, ticket)); graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); tick_timer_.restart(); } catch(...) { layers_.clear(); CASPAR_LOG_CURRENT_EXCEPTION(); } }
void ModelSpinner::Draw() { Graphics::Renderer *r = GetContext()->GetRenderer(); Graphics::Renderer::StateTicket ticket(r); const float fov = 45.f; r->SetPerspectiveProjection(fov, 1.f, 1.f, 10000.f); r->SetTransform(matrix4x4f::Identity()); r->SetDepthWrite(true); r->SetDepthTest(true); r->ClearDepthBuffer(); r->SetLights(1, &m_light); Point pos(GetAbsolutePosition() + GetActiveOffset()); Point size(GetActiveArea()); r->SetViewport(pos.x, GetContext()->GetSize().y - pos.y - size.y, size.x, size.y); matrix4x4f rot = matrix4x4f::RotateXMatrix(m_rotX); rot.RotateY(m_rotY); const float dist = m_model->GetDrawClipRadius() / sinf(DEG2RAD(fov*0.5f)); rot[14] = -dist; m_model->Render(rot); }
int main(int argc, char *argv[]) { for (int i=0; i<N; i++) printf("%i\n", ticket() ); return EXIT_SUCCESS; }
void VScrollPortal::Draw() { PROFILE_SCOPED() SetScissor(true); float size[2]; GetSize(size); m_scrollY = vscrollAdjust.GetValue(); float toScroll = m_childSizeY - size[1]; if (toScroll < 0) toScroll = 0; float scale[2]; Screen::GetCoords2Pixels(scale); Graphics::Renderer *r = Gui::Screen::GetRenderer(); Graphics::Renderer::MatrixTicket ticket(r, Graphics::MatrixMode::MODELVIEW); // scroll to whole pixel locations whatever the resolution r->Translate(0, floor((-m_scrollY*toScroll)/scale[1])*scale[1], 0); Container::Draw(); SetScissor(false); }
void Context::Draw() { Graphics::Renderer *r = GetRenderer(); // Ticket for the viewport mostly Graphics::Renderer::StateTicket ticket(r); r->SetViewport(0, 0, m_width, m_height); // reset renderer for each layer for (std::vector<Layer*>::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { r->SetOrthographicProjection(0, m_width, m_height, 0, -1, 1); r->SetTransform(matrix4x4f::Identity()); r->SetClearColor(Color4f::BLACK); DrawWidget(*i); r->SetScissor(false); } if (m_mousePointer && m_mousePointerEnabled) { r->SetOrthographicProjection(0, m_width, m_height, 0, -1, 1); r->SetTransform(matrix4x4f::Identity()); r->SetClearColor(Color4f::BLACK); DrawWidget(m_mousePointer); r->SetScissor(false); } }
const QByteArray Wad::Content( quint16 i ) { if( tmdData.isEmpty() || tikData.isEmpty() ) { Err( "Can't decryte data without a TMD and ticket" ); return QByteArray(); } Ticket ticket( tikData ); Tmd t( tmdData ); if( partsEnc.size() != t.Count() || i >= partsEnc.size() ) { Err( "I dont know whats going on some number is out of range and i dont like it" ); return QByteArray(); } QByteArray encData = partsEnc.at( i ); AesSetKey( ticket.DecryptedKey() ); QByteArray decData = AesDecrypt( t.Index( i ), encData ); decData.resize( t.Size( i ) ); QByteArray realHash = GetSha1( decData ); if( realHash != t.Hash( i ) ) { Err( QString( "hash doesnt match for content %1" ).arg( i ) ); return QByteArray(); } return decData; }
void GameLog::DrawHudMessages(Graphics::Renderer *r) { Graphics::Renderer::StateTicket ticket(r); Graphics::RenderStateDesc rsd; rsd.depthTest = false; rsd.depthWrite = false; Graphics::RenderState *prsd = r->CreateRenderState(rsd); //I'd rather render this as one string, but then we can't //have per-line fade - markup doesn't support alpha r->SetOrthographicProjection(0, m_screenSize.x, m_screenSize.y, 0, -1, 1); r->SetTransform(matrix4x4f::Identity()); r->SetRenderState(prsd); const Color &c = Color::WHITE; float y = 0; for (auto it = m_messages.rbegin(); it != m_messages.rend(); ++it) { float alpha = 1.f; if (it->time > FADE_AFTER) { alpha = 1.0f - (float(it->time - FADE_AFTER) / float(FADE_TIME)); } const Color textColour(c.r, c.g, c.b, Clamp(Uint32(alpha*255), 0U, 255U)); m_font->RenderString(it->msg.c_str(), m_offset.x, m_offset.y + y, textColour); y -= m_lineHeight; } }
void ShipSpinnerWidget::Draw() { float pos[2]; GetAbsolutePosition(pos); m_params.time = Pi::game->GetTime(); float guiscale[2]; Gui::Screen::GetCoords2Pixels(guiscale); static float rot1, rot2; if (Pi::MouseButtonState(SDL_BUTTON_RIGHT)) { int m[2]; Pi::GetMouseMotion(m); rot1 += -0.002*m[1]; rot2 += -0.002*m[0]; } else { rot1 += .5*Pi::GetFrameTime(); rot2 += Pi::GetFrameTime(); } glColor3f(0,0,0); glBegin(GL_QUADS); glVertex2f(0.0f, 0.0f); glVertex2f(0.0f, m_height); glVertex2f(m_width, m_height); glVertex2f(m_width, 0.0f); glEnd(); Graphics::Renderer::StateTicket ticket(Pi::renderer); Pi::renderer->SetPerspectiveProjection(45.f, 1.f, 1.f, 10000.f); Pi::renderer->SetTransform(matrix4x4f::Identity()); Pi::renderer->SetDepthTest(true); Pi::renderer->ClearDepthBuffer(); Pi::renderer->SetLights(1, &m_light); Pi::renderer->SetViewport( int(roundf(pos[0]/guiscale[0])), int(roundf((Gui::Screen::GetHeight() - pos[1] - m_height)/guiscale[1])), int(m_width/guiscale[0]), int(m_height/guiscale[1])); matrix4x4f rot = matrix4x4f::RotateXMatrix(rot1); rot.RotateY(rot2); rot[14] = -1.5f * m_model->GetDrawClipRadius(); m_model->Render(rot, &m_params); }
bool GPlayerAccess::ProcessMessage(GNetMsg & msg,int message) { switch(message) { case IGM_ACCESS: { if(Valid()) { GSocketAccess * sa=static_cast<GSocketAccess*>(socket); GTicketConnectionClient t_connection_client; msg.R(t_connection_client); if (*t_connection_client.access.target_location_ID == 0) { if (t_connection_client.access.target_gamestate_ID > 0) { strcpy(t_connection_client.access.target_location_ID, location_ID_from_gamestate_ID(t_connection_client.access.target_gamestate_ID).c_str()); } } else { t_connection_client.access.target_gamestate_ID = gamestate_ID_from_location_ID(t_connection_client.access.target_location_ID); } sockaddr_in addr; socklen_t len=sizeof(addr); getpeername(socket->GetSocket(),(sockaddr*)&addr,&len); memcpy(&t_connection_client.client_host.addr_detected_by_server,&addr.sin_addr,4); t_connection_client.access.RID=GetRID(); if (Service(ESTClientAccess)->GetOutQueueSize() >= global_serverconfig->net.ticket_queue_busy_limit || Service(ESTClientAccess)->GetWaitQueueSize() >= global_serverconfig->net.ticket_queue_busy_limit) { MsgExt(IGM_CONNECTION_CLOSE).WT("server busy").A(); return true; } GTicketConnectionPtr ticket(new GTicketConnection()); Coerce(*ticket,t_connection_client); TicketInt(ESTClientAccess,IGMITIC_ACCESS,ticket); Coerce(sa->player_info,t_connection_client); sa->group_id = t_connection_client.access.group_ID; } } return true; } return false; };
void GameLog::DrawHudMessages(Graphics::Renderer *r) { Graphics::Renderer::StateTicket ticket(r); Graphics::RenderStateDesc rsd; rsd.depthTest = false; rsd.depthWrite = false; Graphics::RenderState *prsd = r->CreateRenderState(rsd); //I'd rather render this as one string, but then we can't //have per-line fade - markup doesn't support alpha r->SetOrthographicProjection(0, m_screenSize.x, m_screenSize.y, 0, -1, 1); r->SetTransform(matrix4x4f::Identity()); r->SetRenderState(prsd); const Color &c = Color::WHITE; // (re)build buffers const size_t numMessages = m_messages.size(); const bool bRefresh = (numMessages != m_prevMessages); // update message loop float y = 0; for (auto it = m_messages.rbegin(), itEnd = m_messages.rend(); it != itEnd; ++it) { float alpha = 1.f; if (it->time > FADE_AFTER) { alpha = 1.0f - (float(it->time - FADE_AFTER) / float(FADE_TIME)); } Uint32 iAlpha(Clamp(Uint32(alpha*255), 0U, 255U)); const Color textColour(c.r, c.g, c.b, iAlpha); // update only if things have changed or the buffer does not exist if (bRefresh || !it->m_vb.Valid() || iAlpha != it->m_prevAlpha || !it->m_prevoffset.ExactlyEqual(m_offset)) { it->m_prevAlpha = iAlpha; it->m_prevoffset = m_offset; Graphics::VertexArray va(Graphics::ATTRIB_POSITION | Graphics::ATTRIB_DIFFUSE | Graphics::ATTRIB_UV0); m_font->PopulateString(va, it->msg.c_str(), m_offset.x, m_offset.y + y, textColour); it->m_vb.Reset( m_font->CreateVertexBuffer(va) ); } m_font->RenderBuffer( it->m_vb.Get() ); y -= m_lineHeight; } m_prevMessages = numMessages; }
//---------------------------------------------------------------- // InputArea::postponeSingleClickEvent // boost::shared_ptr<CancelableEvent::Ticket> InputArea::postponeSingleClickEvent(PostponeEvent & postponeEvent, int msec, QObject * view, const TVec2D & itemCSysOrigin, const TVec2D & rootCSysPoint) const { boost::shared_ptr<CancelableEvent::Ticket> ticket(new CancelableEvent::Ticket()); ItemPtr itemPtr = self_.lock(); boost::shared_ptr<InputArea> inputAreaPtr = boost::dynamic_pointer_cast<InputArea, Item>(itemPtr); postponeEvent.postpone(msec, view, new SingleClickEvent(ticket, inputAreaPtr, itemCSysOrigin, rootCSysPoint)); return ticket; }
void CMonitorSessionDlg::OnItemOpenViewerDlg(){ POSITION pos=m_list.GetFirstSelectedItemPosition(); int nItem=m_list.GetNextSelectedItem(pos); CString name=m_list.GetItemText(nItem,1); if(pService->GetSockByName(name)->bMonitor==FALSE) return ; CString ticket(pService->GetSockByName(name)->ticket); CViewerDlg dlg; dlg.Create(CViewerDlg::IDD); dlg.SetWindowText(name); dlg.ShowWindow(SW_NORMAL); dlg.Connect((LPTSTR)(LPCTSTR)ticket); dlg.RunModalLoop(); }
Wad::Wad( const QList< QByteArray > &stuff, bool encrypted ) { ok = false; if( stuff.size() < 3 ) { Err( "Cant treate a wad with < 3 items" ); return; } tmdData = stuff.at( 0 ); tikData = stuff.at( 1 ); Ticket ticket( tikData ); Tmd t( tmdData ); quint16 cnt = stuff.size() - 2; if( cnt != t.Count() ) { Err( "The number of items given doesnt match the number in the tmd" ); return; } for( quint16 i = 0; i < cnt; i++ ) { QByteArray encData; if( encrypted ) { encData = stuff.at( i + 2 ); } else { QByteArray decDataPadded = PaddedByteArray( stuff.at( i + 2 ), 0x40 ); //doing this here in case there is some other object that is using the AES that would change the key on us AesSetKey( ticket.DecryptedKey() ); encData = AesEncrypt( t.Index( i ), decDataPadded ); } partsEnc << encData; } ok = true; }
void tick(const std::weak_ptr<implementation>& self) { try { produce_timer_.restart(); std::map<int, safe_ptr<basic_frame>> frames; //fix g++ warning //std::map<int, std::shared_ptr<basic_frame>> frames; for(auto it = layers_.begin(); it != layers_.end(); ++it) frames[it->first] = make_safe<core::basic_frame>(basic_frame::empty()); tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, std::shared_ptr<layer>>::value_type& layer) { auto transform = transforms_[layer.first].fetch_and_tick(1); int hints = frame_producer::NO_HINT; if(format_desc_.field_mode != field_mode::progressive) { hints |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; } if(transform.is_key) hints |= frame_producer::ALPHA_HINT; auto frame = layer.second->receive(hints); auto layer_consumers_it = layer_consumers_.find(layer.first); if (layer_consumers_it != layer_consumers_.end()) { auto consumer_it = (*layer_consumers_it).second | boost::adaptors::map_values; tbb::parallel_for_each(consumer_it.begin(), consumer_it.end(), [&](decltype(*consumer_it.begin()) layer_consumer) { layer_consumer->send(frame); }); } auto frame1 = make_safe<core::basic_frame>(frame); frame1->get_frame_transform() = transform; if(format_desc_.field_mode != core::field_mode::progressive) { auto frame2 = make_safe<core::basic_frame>(frame); frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1); frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode); } frames[layer.first] = std::move(frame1); }); // Tick the transforms that does not have a corresponding layer. BOOST_FOREACH(auto& elem, transforms_) if (layers_.find(elem.first) == layers_.end()) elem.second.fetch_and_tick(format_desc_.field_mode != core::field_mode::progressive ? 2 : 1); graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); std::shared_ptr<void> ticket(nullptr, [=](void*) { auto self2 = self.lock(); if(self2) self2->executor_.begin_invoke([=]{tick(self);}); }); target_->send(std::make_pair(frames, ticket)); //comment out due to g++ warning fix */ graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); tick_timer_.restart(); } catch(...) { layers_.clear(); CASPAR_LOG_CURRENT_EXCEPTION(); } }
Wad::Wad( const QByteArray &stuff ) { ok = false; if( !stuff.size() )//prevent error text when it isnt required return; if( stuff.size() < 0x80 )//less than this and there is definitely nothing there { Err( "Size is < 0x80" ); return; } QByteArray copy = stuff; QBuffer b( © ); b.open( QIODevice::ReadOnly ); quint32 tmp; if(b.read( (char*)&tmp, 4 ) != 4) { b.close(); Err( "Can't read header size" ); return; } if( qFromBigEndian( tmp ) != 0x20 ) { b.close(); hexdump(stuff, 0, 0x10); Err( "Bad header size" ); return; } b.read( (char*)&tmp, 4 ); tmp = qFromBigEndian( tmp ); if( tmp != 0x49730000 && tmp != 0x69620000 && tmp != 0x426b0000 ) { b.close(); hexdump( stuff, 0, 0x40 ); Err( "Bad file magic word" ); return; } quint32 certSize; quint32 tikSize; quint32 tmdSize; quint32 appSize; quint32 footerSize; b.read( (char*)&certSize, 4 ); certSize = qFromBigEndian( certSize ); b.seek( 0x10 ); b.read( (char*)&tikSize, 4 ); tikSize = qFromBigEndian( tikSize ); b.read( (char*)&tmdSize, 4 ); tmdSize = qFromBigEndian( tmdSize ); b.read( (char*)&appSize, 4 ); appSize = qFromBigEndian( appSize ); b.read( (char*)&footerSize, 4 ); footerSize = qFromBigEndian( footerSize ); b.close();//close the buffer, the rest of the data can be checked without it //sanity check this thing quint32 s = stuff.size(); if( s < ( RU( certSize, 0x40 ) + RU( tikSize, 0x40 ) + RU( tmdSize, 0x40 ) + RU( appSize, 0x40 ) + RU( footerSize, 0x40 ) ) ) { Err( "Total size is less than the combined sizes of all the parts that it is supposed to contain" ); return; } quint32 pos = 0x40; certData = stuff.mid( pos, certSize ); pos += RU( certSize, 0x4 ); tikData = stuff.mid( pos, tikSize ); pos += RU( tikSize, 0x40 ); tmdData = stuff.mid( pos, tmdSize ); pos += RU( tmdSize, 0x40 ); Ticket ticket( tikData ); Tmd t( tmdData ); //the constructor for Ticket may have fixed a bad key index. replace the data just incase it did tikData = ticket.Data(); //hexdump( tikData ); //hexdump( tmdData ); if( ticket.Tid() != t.Tid() ) qWarning() << "wad contains 2 different TIDs"; quint32 cnt = t.Count(); //qDebug() << "Wad contains" << hex << cnt << "contents"; //another quick sanity check quint32 totalSize = 0; for( quint32 i = 0; i < cnt; i++ ) totalSize += t.Size( i ); if( totalSize > appSize ) { Err( "Size of all the apps in the tmd is greater than the size in the wad header" ); return; } //read all the contents, check the hash, and remember the data ( still encrypted ) for( quint32 i = 0; i < cnt; i++ ) { quint32 s = RU( t.Size( i ), 0x40 ); //qDebug() << "content" << i << "is at" << hex << pos // << "with size" << s; QByteArray encData = stuff.mid( pos, s ); pos += s; //doing this here in case there is some other object that //is using the AES that would change the key on us AesSetKey( ticket.DecryptedKey() ); QByteArray decData = AesDecrypt( t.Index( i ), encData ); decData.resize( t.Size( i ) ); QByteArray realHash = GetSha1( decData ); if( realHash != t.Hash( i ) ) { Err( QString( "hash doesnt match for content %1" ).arg( i ) ); } partsEnc << encData; } //wtf? some VC titles have a full banner as the footer? maybe somebody's wad packer is busted //QByteArray footer = stuff.mid( pos, stuff.size() - pos ); //qDebug() << "footer"; //hexdump( footer ); ok = true; }
const QByteArray Wad::Data( quint32 magicWord, const QByteArray &footer ) { //qDebug() << "Wad::Data" << hex << magicWord << footer.size(); if( !partsEnc.size() || tmdData.isEmpty() || tikData.isEmpty() || ( certData.isEmpty() && globalCert.isEmpty() ) ) { Err( "Dont have all the parts to make a wad" ); return QByteArray(); } //do some brief checks to make sure that wad is good Ticket ticket( tikData ); Tmd t( tmdData ); if( t.Tid() != ticket.Tid() ) { Err( "Ticket and TMD have different TID" ); return QByteArray(); } if( partsEnc.size() != t.Count() ) { Err( "Dont have enough contents according to the TMD" ); return QByteArray(); } //everything seems in order, try to make the thing QByteArray cert = certData.isEmpty() ? globalCert : certData; quint32 certSize = cert.size(); quint32 tikSize = ticket.SignedSize(); quint32 tmdSize = t.SignedSize(); quint32 appSize = 0; quint32 footerSize = footer.size(); //add all the app sizes together and check that they match the TMD quint16 cnt = t.Count(); for( quint16 i = 0; i < cnt; i++ ) { quint32 s = RU( partsEnc.at( i ).size(), 0x40 ); if( RU( t.Size( i ), 0x40 ) != s ) { Err( QString( "Size of content %1 is bad ( %2, %3, %4 )" ) .arg( i ) .arg( t.Size( i ), 0, 16 ) .arg( RU( t.Size( i ), 0x40 ), 0, 16 ) .arg( s, 0, 16 ) ); return QByteArray(); } appSize += s; } QByteArray header( 0x20, '\0' ); QBuffer buf( &header ); buf.open( QIODevice::WriteOnly ); quint32 tmp = qFromBigEndian( 0x20 );//header size buf.write( (const char*)&tmp, 4 ); tmp = qFromBigEndian( magicWord );//magic word buf.write( (const char*)&tmp, 4 ); tmp = qFromBigEndian( certSize ); buf.write( (const char*)&tmp, 4 ); buf.seek( 0x10 ); tmp = qFromBigEndian( tikSize ); buf.write( (const char*)&tmp, 4 ); tmp = qFromBigEndian( tmdSize ); buf.write( (const char*)&tmp, 4 ); tmp = qFromBigEndian( appSize ); buf.write( (const char*)&tmp, 4 ); tmp = qFromBigEndian( footerSize ); buf.write( (const char*)&tmp, 4 ); buf.close(); //hexdump( header, 0, 0x20 ); QByteArray ret = PaddedByteArray( header, 0x40 ) + PaddedByteArray( cert, 0x40 ); //make sure we dont have the huge ticket and TMD that come when downloading from NUS QByteArray tik = tikData; tik.resize( tikSize ); tik = PaddedByteArray( tik, 0x40 ); QByteArray tm = tmdData; tm.resize( tmdSize ); tm = PaddedByteArray( tm, 0x40 ); //hexdump( tik ); //hexdump( tm ); ret += tik + tm; for( quint16 i = 0; i < cnt; i++ ) { ret += PaddedByteArray( partsEnc.at( i ), 0x40 ); } ret += footer; return ret; }
Wad::Wad( QDir dir ) { ok = false; QFileInfoList tmds = dir.entryInfoList( QStringList() << "*.tmd" << "tmd.*", QDir::Files ); if( tmds.isEmpty() ) { Err( "TMD not found" ); return; } tmdData = ReadFile( tmds.at( 0 ).absoluteFilePath() ); if( tmdData.isEmpty() ) return; QFileInfoList tiks = dir.entryInfoList( QStringList() << "*.tik" << "cetk", QDir::Files ); if( tiks.isEmpty() ) { Err( "Ticket not found" ); return; } tikData = ReadFile( tiks.at( 0 ).absoluteFilePath() ); if( tikData.isEmpty() ) return; Tmd t( tmdData ); Ticket ticket( tikData ); //make sure to only add the tmd & ticket without all the cert mumbo jumbo tmdData = t.Data(); tikData = ticket.Data(); t = Tmd( tmdData ); ticket = Ticket( tikData ); quint16 cnt = t.Count(); bool tmdChanged = false; for( quint16 i = 0; i < cnt; i++ ) { QByteArray appD = ReadFile( dir.absoluteFilePath( t.Cid( i ) + ".app" ) ); if( appD.isEmpty() ) { Err( t.Cid( i ) + ".app not found" ); return; } if( (quint32)appD.size() != t.Size( i ) ) { t.SetSize( i, appD.size() ); tmdChanged = true; } QByteArray realHash = GetSha1( appD ); if( t.Hash( i ) != realHash ) { t.SetHash( i, realHash ); tmdChanged = true; } AesSetKey( ticket.DecryptedKey() ); appD = PaddedByteArray( appD, 0x40 ); QByteArray encData = AesEncrypt( t.Index( i ), appD ); partsEnc << encData; } //if something in the tmd changed, fakesign it if( tmdChanged ) { if( !t.FakeSign() ) { Err( "Error signing the wad" ); return; } else { tmdData = t.Data(); } } QFileInfoList certs = dir.entryInfoList( QStringList() << "*.cert", QDir::Files ); if( !certs.isEmpty() ) { certData = ReadFile( certs.at( 0 ).absoluteFilePath() ); } ok = true; }