<commit_before>/***************************************************************************
                          mapihd.cpp  -  description
                             -------------------
    begin                : Tue Jul 25 2000
    copyright            : (C) 2000 by Hans Dijkema
    email                : kmailcvt@hum.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "pab_pablib.h"

bool operator < (mapitag_t & a,mapitag_t & b)  { return a._order<b._order; }
bool operator > (mapitag_t & a,mapitag_t & b)  { return a._order>b._order; }
bool operator == (mapitag_t & a,mapitag_t & b) { return a._order==b._order; }

word_t
map_givenname[]=
   { pr_givenname,
          SET_MS_GIVEN_NAME,
          0
   },
map_email[]=
   { pr_email,
          SET_MS_EMAIL,
          0
   },
map_firstname[]=
   { pr_firstname,
	  SET_MS_FIRSTNAME,
          0
   },
map_lastname[]=
   { pr_lastname,
          SET_MS_LASTNAME,
          0
   },
map_additionalname[]=
   { pr_additionalname,
          SET_MS_MIDDLENAME,
          0
   },
map_title[]=
   { pr_title,
          SET_MS_TITLE,
          0
   },
map_address[]=
   { pr_address,
          SET_MS_ADDRESS,
          0
   },
map_zip[]=
   { pr_zip,
          SET_MS_ZIP,
          0
   },
map_state[]=
   { pr_state,
          SET_MS_STATE,
          0
   },
map_town[]=
   { pr_town,
          SET_MS_TOWN,
          0
   },
map_country[]=
   { pr_country,
          SET_MS_COUNTRY,
          0
   },
map_tel[]=
   { pr_tel,
          SET_MS_TEL,
          0
   },
map_mobile[]=
   { pr_mobile,
          SET_MS_MOBILE,
          0
   },
map_fax[]=
   { pr_fax,
          SET_MS_FAX,
          0
   },
map_job[]=
   { pr_job,
          HP_OPENMAIL_JOB,
          0
   },
map_organization[]=
   { pr_organization,
          SET_MS_ORGANIZATION,
          HP_OPENMAIL_ORGANIZATION,
          0
   },
map_department[]=
   { pr_department,
          SET_MS_DEPARTMENT,
          HP_OPENMAIL_DEPARTMENT,
          0
   },
map_subdep[]=
   { pr_subdep,
          HP_OPENMAIL_SUBDEP,
          0
   },
map_notes[]=
   { pr_notes,
          SET_MS_COMMENT,
          0
   },
map_notused[]=
   { pr_notused,
          HP_OPENMAIL_LOCATION_OF_WORK,           // location of work
	  SET_NOT_USED,
          0
   };

word_t *mapi_map[]={ map_givenname, map_email,
                     map_firstname, map_lastname, map_additionalname,map_title,
                     map_address,   map_town, map_zip, map_state, map_country,
                     map_tel, map_mobile, map_fax,
                     map_organization, map_department, map_subdep, map_job,
                     map_notes,
                     map_notused,
                     NULL
                   };

pabrec_entry mapitag_t::matchTag(void)
{
int          i,j;
pabrec_entry e=pr_unknown;

  for(i=0;mapi_map[i]!=NULL && e==pr_unknown;i++) {
    for(j=1;mapi_map[i][j]!=0 && _tag!=mapi_map[i][j];j++);
    if (mapi_map[i][j]!=0) {
      e=(pabrec_entry) mapi_map[i][0];
    }
  }
return e;
}

pabfields_t::pabfields_t(pabrec & R, QWidget * /*parent*/)
{
  // Skip the first two words, because they're always the
  // same 000c 0014 ==> 0014 gives us the types, so we
  // parse from 0014 till the next offset and order the tags.

  int         mb,me;
  uint        i,k;
  content_t   _tag,_order;

  mb=R[1];
  me=R[2];

  while (mb<me) {
    _tag=R.read(mb);mb+=sizeof(_tag);
    _order=R.read(mb);mb+=sizeof(_order);

    {mapitag_t mt(_tag,_order);
     tags[tags.size()]=mt;
     context_tags[context_tags.size()]=mt;
    }
  }
  tags.sort();

  // get the right entries now

  for(i=2,k=0;i<R.N() && k<tags.size();i++,k++) {
    if (!isUsed(k)) { i-=1; }
    else {pabrec_entry e;
          QString      E;

       e=isWhat(k);
       E=R.getEntry(i);
       { QString s=E;
           s=s.stripWhiteSpace();
           E=s;
       }

       /*
       {  char m[1024];
          snprintf(m, sizeof(m), "%d %d %04x %08lx %d %s %d %d",i,k,literal(k),order(k),e,E.latin1(),E[0].latin1(),E.length());
          info->addLog(m);
       }
       */

       if (!E.isEmpty()) {

         switch (e) {
           case pr_givenname: givenName=E;
           break;
           case pr_email:     email=E;
           break;
           case pr_firstname: firstName=E;
           break;
           case pr_additionalname: additionalName=E;
           break;
           case pr_lastname:  lastName=E;
           break;
           case pr_title:     title=E;
           break;
           case pr_address:   address=E;
           break;
           case pr_town:      town=E;
           break;
           case pr_state:     state=E;
           break;
           case pr_zip:       zip=E;
           break;
           case pr_country:  country=E;
           break;
           case pr_organization: organization=E;
           break;
           case pr_department: department=E;
           break;
           case pr_subdep:     subDep=E;
           break;
           case pr_job:        job=E;
           break;
           case pr_tel:        tel=E;
           break;
           case pr_fax:        fax=E;
           break;
           case pr_modem:      modem=E;
           break;
           case pr_mobile:     mobile=E;
           break;
           case pr_url:        homepage=E;
           break;
           case pr_talk:       talk=E;
           break;
           case pr_notes:      comment=E;
           break;
           case pr_birthday:   birthday=E;
           break;
           case pr_notused:
           break;
           default:            {/*char m[250];
                                  snprintf(m,sizeof(m),"unknown tag '%x'",literal(k));
                                  info->log(m);*/
                               }
           break;
         }
      }
    }
  }

  if (!firstName.isEmpty() && !lastName.isEmpty()) {
    givenName=lastName+", "+firstName;
  }

  // Determine if the record is ok.

  OK=true;
}

bool pabfields_t::isUsed(int k)
{
return tags[k].isUsed();
}

pabrec_entry pabfields_t::isWhat(int k)
{
return tags[k].matchTag();
}

word_t pabfields_t::literal(int k)
{
return tags[k].literal();
}

content_t pabfields_t::order(int k)
{
return tags[k].order();
}

KABC::Addressee pabfields_t::get() {
  KABC::Addressee a;
  if (!givenName.isEmpty()) a.setFormattedName(givenName);
  if (!email.isEmpty()) a.insertEmail(email);
  if (!title.isEmpty()) a.setTitle(title);
  if (!firstName.isEmpty()) a.setName(firstName);
  if (!additionalName.isEmpty()) a.setAdditionalName(additionalName);
  if (!lastName.isEmpty()) a.setFamilyName(lastName);

  KABC::Address addr;
  if (!address.isEmpty()) addr.setStreet(address);
  if (!town.isEmpty()) addr.setLocality(town);
  if (!zip.isEmpty()) addr.setPostalCode(zip);
  if (!state.isEmpty()) addr.setRegion(state);
  if (!country.isEmpty()) addr.setCountry(country);
  a.insertAddress(addr);

  if (!organization.isEmpty()) a.setOrganization(organization);
  if (!department.isEmpty()) a.setRole(department);
  // Miss out department, subDep, job
  if (!tel.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( tel, KABC::PhoneNumber::Voice ) );
  if (!fax.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( fax, KABC::PhoneNumber::Fax ) );
  if (!mobile.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( mobile, KABC::PhoneNumber::Cell ) );
  if (!modem.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( modem, KABC::PhoneNumber::Modem ) );
  if (!homepage.isEmpty()) a.setUrl(homepage);
  // Miss out talk
  if (!comment.isEmpty()) a.setNote(comment);
  // Miss out birthday
  return a;
}

/* class pabrec {
   private:
     char   entry[1024];
     byte   *_mem;
     word_t *_N;
     word_t *_w;
   public:
     pabrec(pab *);       // expects record the begin at reading point (ftell).
    ~pabrec();
   public:
     word_t N(void)           { return _N[0]; }
     word_t operator[](int i) { return _w[i]; }
     const char *getEntry(int i);
   public:
     content_t read(word_t offset);
 };
*/

pabrec::pabrec(pab & P)
{
adr_t     A=P.tell();
content_t hdr;
word_t    offset,size,dummy;
int       i;

  hdr=P.go(A);
  offset=P.lower(hdr);

  size=offset;
  _mem=new byte[size];
  P.read(_mem,size);

  P.go(A+offset);
  P.read(m_N);
  m_W=new word_t[m_N+1];

  P.read(dummy);
  for(i=0;i<=m_N;i++) {
    P.read(m_W[i]);
  }
}

pabrec::~pabrec()
{
  delete _mem;
  delete m_W;
}

content_t pabrec::read(word_t offset)
{
content_t R;
  R=_mem[offset+3];
  R<<=8;R+=_mem[offset+2];
  R<<=8;R+=_mem[offset+1];
  R<<=8;R+=_mem[offset];
return R;
}

const char *pabrec::getEntry(int i)
{
int mb,me;
int k;
  mb=m_W[i];me=m_W[i+1];
  for(k=0;mb!=me;mb++) {
    if (_mem[mb]>=' ' || _mem[mb]=='\n' || _mem[mb]==13 || _mem[mb]=='\t') {
      if (_mem[mb]==13) { entry[k]='\n'; }
      else { entry[k]=_mem[mb]; }
      k+=1;
    }
  }
  entry[k]='\0';
return (const char *) entry;
}
<commit_msg>+static<commit_after>/***************************************************************************
                          mapihd.cpp  -  description
                             -------------------
    begin                : Tue Jul 25 2000
    copyright            : (C) 2000 by Hans Dijkema
    email                : kmailcvt@hum.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "pab_pablib.h"

bool operator < (mapitag_t & a,mapitag_t & b)  { return a._order<b._order; }
bool operator > (mapitag_t & a,mapitag_t & b)  { return a._order>b._order; }
bool operator == (mapitag_t & a,mapitag_t & b) { return a._order==b._order; }

static word_t
map_givenname[]=
   { pr_givenname,
          SET_MS_GIVEN_NAME,
          0
   },
map_email[]=
   { pr_email,
          SET_MS_EMAIL,
          0
   },
map_firstname[]=
   { pr_firstname,
	  SET_MS_FIRSTNAME,
          0
   },
map_lastname[]=
   { pr_lastname,
          SET_MS_LASTNAME,
          0
   },
map_additionalname[]=
   { pr_additionalname,
          SET_MS_MIDDLENAME,
          0
   },
map_title[]=
   { pr_title,
          SET_MS_TITLE,
          0
   },
map_address[]=
   { pr_address,
          SET_MS_ADDRESS,
          0
   },
map_zip[]=
   { pr_zip,
          SET_MS_ZIP,
          0
   },
map_state[]=
   { pr_state,
          SET_MS_STATE,
          0
   },
map_town[]=
   { pr_town,
          SET_MS_TOWN,
          0
   },
map_country[]=
   { pr_country,
          SET_MS_COUNTRY,
          0
   },
map_tel[]=
   { pr_tel,
          SET_MS_TEL,
          0
   },
map_mobile[]=
   { pr_mobile,
          SET_MS_MOBILE,
          0
   },
map_fax[]=
   { pr_fax,
          SET_MS_FAX,
          0
   },
map_job[]=
   { pr_job,
          HP_OPENMAIL_JOB,
          0
   },
map_organization[]=
   { pr_organization,
          SET_MS_ORGANIZATION,
          HP_OPENMAIL_ORGANIZATION,
          0
   },
map_department[]=
   { pr_department,
          SET_MS_DEPARTMENT,
          HP_OPENMAIL_DEPARTMENT,
          0
   },
map_subdep[]=
   { pr_subdep,
          HP_OPENMAIL_SUBDEP,
          0
   },
map_notes[]=
   { pr_notes,
          SET_MS_COMMENT,
          0
   },
map_notused[]=
   { pr_notused,
          HP_OPENMAIL_LOCATION_OF_WORK,           // location of work
	  SET_NOT_USED,
          0
   };

static word_t *mapi_map[]={ map_givenname, map_email,
                     map_firstname, map_lastname, map_additionalname,map_title,
                     map_address,   map_town, map_zip, map_state, map_country,
                     map_tel, map_mobile, map_fax,
                     map_organization, map_department, map_subdep, map_job,
                     map_notes,
                     map_notused,
                     NULL
                   };

pabrec_entry mapitag_t::matchTag(void)
{
int          i,j;
pabrec_entry e=pr_unknown;

  for(i=0;mapi_map[i]!=NULL && e==pr_unknown;i++) {
    for(j=1;mapi_map[i][j]!=0 && _tag!=mapi_map[i][j];j++);
    if (mapi_map[i][j]!=0) {
      e=(pabrec_entry) mapi_map[i][0];
    }
  }
return e;
}

pabfields_t::pabfields_t(pabrec & R, QWidget * /*parent*/)
{
  // Skip the first two words, because they're always the
  // same 000c 0014 ==> 0014 gives us the types, so we
  // parse from 0014 till the next offset and order the tags.

  int         mb,me;
  uint        i,k;
  content_t   _tag,_order;

  mb=R[1];
  me=R[2];

  while (mb<me) {
    _tag=R.read(mb);mb+=sizeof(_tag);
    _order=R.read(mb);mb+=sizeof(_order);

    {mapitag_t mt(_tag,_order);
     tags[tags.size()]=mt;
     context_tags[context_tags.size()]=mt;
    }
  }
  tags.sort();

  // get the right entries now

  for(i=2,k=0;i<R.N() && k<tags.size();i++,k++) {
    if (!isUsed(k)) { i-=1; }
    else {pabrec_entry e;
          QString      E;

       e=isWhat(k);
       E=R.getEntry(i);
       { QString s=E;
           s=s.stripWhiteSpace();
           E=s;
       }

       /*
       {  char m[1024];
          snprintf(m, sizeof(m), "%d %d %04x %08lx %d %s %d %d",i,k,literal(k),order(k),e,E.latin1(),E[0].latin1(),E.length());
          info->addLog(m);
       }
       */

       if (!E.isEmpty()) {

         switch (e) {
           case pr_givenname: givenName=E;
           break;
           case pr_email:     email=E;
           break;
           case pr_firstname: firstName=E;
           break;
           case pr_additionalname: additionalName=E;
           break;
           case pr_lastname:  lastName=E;
           break;
           case pr_title:     title=E;
           break;
           case pr_address:   address=E;
           break;
           case pr_town:      town=E;
           break;
           case pr_state:     state=E;
           break;
           case pr_zip:       zip=E;
           break;
           case pr_country:  country=E;
           break;
           case pr_organization: organization=E;
           break;
           case pr_department: department=E;
           break;
           case pr_subdep:     subDep=E;
           break;
           case pr_job:        job=E;
           break;
           case pr_tel:        tel=E;
           break;
           case pr_fax:        fax=E;
           break;
           case pr_modem:      modem=E;
           break;
           case pr_mobile:     mobile=E;
           break;
           case pr_url:        homepage=E;
           break;
           case pr_talk:       talk=E;
           break;
           case pr_notes:      comment=E;
           break;
           case pr_birthday:   birthday=E;
           break;
           case pr_notused:
           break;
           default:            {/*char m[250];
                                  snprintf(m,sizeof(m),"unknown tag '%x'",literal(k));
                                  info->log(m);*/
                               }
           break;
         }
      }
    }
  }

  if (!firstName.isEmpty() && !lastName.isEmpty()) {
    givenName=lastName+", "+firstName;
  }

  // Determine if the record is ok.

  OK=true;
}

bool pabfields_t::isUsed(int k)
{
return tags[k].isUsed();
}

pabrec_entry pabfields_t::isWhat(int k)
{
return tags[k].matchTag();
}

word_t pabfields_t::literal(int k)
{
return tags[k].literal();
}

content_t pabfields_t::order(int k)
{
return tags[k].order();
}

KABC::Addressee pabfields_t::get() {
  KABC::Addressee a;
  if (!givenName.isEmpty()) a.setFormattedName(givenName);
  if (!email.isEmpty()) a.insertEmail(email);
  if (!title.isEmpty()) a.setTitle(title);
  if (!firstName.isEmpty()) a.setName(firstName);
  if (!additionalName.isEmpty()) a.setAdditionalName(additionalName);
  if (!lastName.isEmpty()) a.setFamilyName(lastName);

  KABC::Address addr;
  if (!address.isEmpty()) addr.setStreet(address);
  if (!town.isEmpty()) addr.setLocality(town);
  if (!zip.isEmpty()) addr.setPostalCode(zip);
  if (!state.isEmpty()) addr.setRegion(state);
  if (!country.isEmpty()) addr.setCountry(country);
  a.insertAddress(addr);

  if (!organization.isEmpty()) a.setOrganization(organization);
  if (!department.isEmpty()) a.setRole(department);
  // Miss out department, subDep, job
  if (!tel.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( tel, KABC::PhoneNumber::Voice ) );
  if (!fax.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( fax, KABC::PhoneNumber::Fax ) );
  if (!mobile.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( mobile, KABC::PhoneNumber::Cell ) );
  if (!modem.isEmpty()) a.insertPhoneNumber( KABC::PhoneNumber( modem, KABC::PhoneNumber::Modem ) );
  if (!homepage.isEmpty()) a.setUrl(homepage);
  // Miss out talk
  if (!comment.isEmpty()) a.setNote(comment);
  // Miss out birthday
  return a;
}

/* class pabrec {
   private:
     char   entry[1024];
     byte   *_mem;
     word_t *_N;
     word_t *_w;
   public:
     pabrec(pab *);       // expects record the begin at reading point (ftell).
    ~pabrec();
   public:
     word_t N(void)           { return _N[0]; }
     word_t operator[](int i) { return _w[i]; }
     const char *getEntry(int i);
   public:
     content_t read(word_t offset);
 };
*/

pabrec::pabrec(pab & P)
{
adr_t     A=P.tell();
content_t hdr;
word_t    offset,size,dummy;
int       i;

  hdr=P.go(A);
  offset=P.lower(hdr);

  size=offset;
  _mem=new byte[size];
  P.read(_mem,size);

  P.go(A+offset);
  P.read(m_N);
  m_W=new word_t[m_N+1];

  P.read(dummy);
  for(i=0;i<=m_N;i++) {
    P.read(m_W[i]);
  }
}

pabrec::~pabrec()
{
  delete _mem;
  delete m_W;
}

content_t pabrec::read(word_t offset)
{
content_t R;
  R=_mem[offset+3];
  R<<=8;R+=_mem[offset+2];
  R<<=8;R+=_mem[offset+1];
  R<<=8;R+=_mem[offset];
return R;
}

const char *pabrec::getEntry(int i)
{
int mb,me;
int k;
  mb=m_W[i];me=m_W[i+1];
  for(k=0;mb!=me;mb++) {
    if (_mem[mb]>=' ' || _mem[mb]=='\n' || _mem[mb]==13 || _mem[mb]=='\t') {
      if (_mem[mb]==13) { entry[k]='\n'; }
      else { entry[k]=_mem[mb]; }
      k+=1;
    }
  }
  entry[k]='\0';
return (const char *) entry;
}
<|endoftext|>


<commit_before>/*
    This file is part of KAddressbook.
    Copyright (c) 2000 Hans Dijkema <kmailcvt@hum.org>
    Copyright (c) 2003 Helge Deller <deller@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <QFile>

#include <kdebug.h>
#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <k3process.h>
#include <kstandarddirs.h>
#include <ktemporaryfile.h>
#include <kurl.h>

#include "xxportmanager.h"

#include "pab_xxport.h"

K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_pab_xxport, PABXXPort )

PABXXPort::PABXXPort( KABC::AddressBook *ab, QWidget *parent, const char *name )
  : KAB::XXPort( ab, parent, name )
{
  createImportAction( i18n("Import MS Exchange Personal Address Book (.PAB)") );
}

KABC::Addressee::List PABXXPort::importContacts( const QString& ) const
{
  KABC::Addressee::List addrList;

  QString fileName = KFileDialog::getOpenFileName( QDir::homePath(),
      		"*.[pP][aA][bB]|" + i18n("MS Exchange Personal Address Book Files (*.pab)"), 0 );
  if ( fileName.isEmpty() )
    return addrList;
  if ( !QFile::exists( fileName ) ) {
    KMessageBox::sorry( parentWidget(), i18n( "<qt>Could not find a MS Exchange Personal Address Book %1.</qt>", fileName ) );
    return addrList;
  }

  // pab PAB(QFile::encodeName(file),this,info);
  // info->setFrom(file);
  // PAB.convert();

  return addrList;
}

#include "pab_xxport.moc"

// vim: ts=2 sw=2 et
<commit_msg>unnecessary. kaddressbook: check<commit_after>/*
    This file is part of KAddressbook.
    Copyright (c) 2000 Hans Dijkema <kmailcvt@hum.org>
    Copyright (c) 2003 Helge Deller <deller@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <QFile>

#include <kdebug.h>
#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <ktemporaryfile.h>
#include <kurl.h>

#include "xxportmanager.h"

#include "pab_xxport.h"

K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_pab_xxport, PABXXPort )

PABXXPort::PABXXPort( KABC::AddressBook *ab, QWidget *parent, const char *name )
  : KAB::XXPort( ab, parent, name )
{
  createImportAction( i18n("Import MS Exchange Personal Address Book (.PAB)") );
}

KABC::Addressee::List PABXXPort::importContacts( const QString& ) const
{
  KABC::Addressee::List addrList;

  QString fileName = KFileDialog::getOpenFileName( QDir::homePath(),
      		"*.[pP][aA][bB]|" + i18n("MS Exchange Personal Address Book Files (*.pab)"), 0 );
  if ( fileName.isEmpty() )
    return addrList;
  if ( !QFile::exists( fileName ) ) {
    KMessageBox::sorry( parentWidget(), i18n( "<qt>Could not find a MS Exchange Personal Address Book %1.</qt>", fileName ) );
    return addrList;
  }

  // pab PAB(QFile::encodeName(file),this,info);
  // info->setFrom(file);
  // PAB.convert();

  return addrList;
}

#include "pab_xxport.moc"

// vim: ts=2 sw=2 et
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/html/imports/HTMLImport.h"

#include "core/dom/Document.h"
#include "core/html/imports/HTMLImportStateResolver.h"

namespace WebCore {

HTMLImport* HTMLImport::root()
{
    HTMLImport* i = this;
    while (i->parent())
        i = i->parent();
    return i;
}

bool HTMLImport::precedes(HTMLImport* import)
{
    for (HTMLImport* i = this; i; i = traverseNext(i)) {
        if (i == import)
            return true;
    }

    return false;
}

bool HTMLImport::formsCycle() const
{
    for (const HTMLImport* i = this->parent(); i; i = i->parent()) {
        if (i->document() == this->document())
            return true;
    }

    return false;

}

void HTMLImport::appendImport(HTMLImport* child)
{
    appendChild(child);

    // This prevents HTML parser from going beyond the
    // blockage line before the precise state is computed by recalcState().
    if (child->isSync())
        m_state = HTMLImportState::blockedState();

    stateWillChange();
}

void HTMLImport::stateDidChange()
{
    if (!state().shouldBlockScriptExecution()) {
        if (Document* document = this->document())
            document->didLoadAllImports();
    }
}

void HTMLImport::recalcTreeState(HTMLImport* root)
{
    HashMap<HTMLImport*, HTMLImportState> snapshot;
    Vector<HTMLImport*> updated;

    for (HTMLImport* i = root; i; i = traverseNext(i)) {
        snapshot.add(i, i->state());
        i->m_state = HTMLImportState::invalidState();
    }

    // The post-visit DFS order matters here because
    // HTMLImportStateResolver in recalcState() Depends on
    // |m_state| of its children and precedents of ancestors.
    // Accidental cycle dependency of state computation is prevented
    // by invalidateCachedState() and isStateCacheValid() check.
    for (HTMLImport* i = traverseFirstPostOrder(root); i; i = traverseNextPostOrder(i)) {
        ASSERT(!i->m_state.isValid());
        i->m_state = HTMLImportStateResolver(i).resolve();

        HTMLImportState newState = i->state();
        HTMLImportState oldState = snapshot.get(i);
        // Once the state reaches Ready, it shouldn't go back.
        ASSERT(!oldState.isReady() || oldState <= newState);
        if (newState != oldState)
            updated.append(i);
    }

    for (size_t i = 0; i < updated.size(); ++i)
        updated[i]->stateDidChange();
}

#if !defined(NDEBUG)
void HTMLImport::show()
{
    root()->showTree(this, 0);
}

void HTMLImport::showTree(HTMLImport* highlight, unsigned depth)
{
    for (unsigned i = 0; i < depth*4; ++i)
        fprintf(stderr, " ");

    fprintf(stderr, "%s", this == highlight ? "*" : " ");
    showThis();
    fprintf(stderr, "\n");
    for (HTMLImport* child = firstChild(); child; child = child->next())
        child->showTree(highlight, depth + 1);
}

void HTMLImport::showThis()
{
    fprintf(stderr, "%p state=%d", this, m_state.peekValueForDebug());
}
#endif

} // namespace WebCore
<commit_msg>Oilpan: have HTMLImport::recalcTreeState() use on-heap local variables.<commit_after>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/html/imports/HTMLImport.h"

#include "core/dom/Document.h"
#include "core/html/imports/HTMLImportStateResolver.h"

namespace WebCore {

HTMLImport* HTMLImport::root()
{
    HTMLImport* i = this;
    while (i->parent())
        i = i->parent();
    return i;
}

bool HTMLImport::precedes(HTMLImport* import)
{
    for (HTMLImport* i = this; i; i = traverseNext(i)) {
        if (i == import)
            return true;
    }

    return false;
}

bool HTMLImport::formsCycle() const
{
    for (const HTMLImport* i = this->parent(); i; i = i->parent()) {
        if (i->document() == this->document())
            return true;
    }

    return false;

}

void HTMLImport::appendImport(HTMLImport* child)
{
    appendChild(child);

    // This prevents HTML parser from going beyond the
    // blockage line before the precise state is computed by recalcState().
    if (child->isSync())
        m_state = HTMLImportState::blockedState();

    stateWillChange();
}

void HTMLImport::stateDidChange()
{
    if (!state().shouldBlockScriptExecution()) {
        if (Document* document = this->document())
            document->didLoadAllImports();
    }
}

void HTMLImport::recalcTreeState(HTMLImport* root)
{
    WillBeHeapHashMap<RawPtrWillBeMember<HTMLImport>, HTMLImportState> snapshot;
    WillBeHeapVector<RawPtrWillBeMember<HTMLImport> > updated;

    for (HTMLImport* i = root; i; i = traverseNext(i)) {
        snapshot.add(i, i->state());
        i->m_state = HTMLImportState::invalidState();
    }

    // The post-visit DFS order matters here because
    // HTMLImportStateResolver in recalcState() Depends on
    // |m_state| of its children and precedents of ancestors.
    // Accidental cycle dependency of state computation is prevented
    // by invalidateCachedState() and isStateCacheValid() check.
    for (HTMLImport* i = traverseFirstPostOrder(root); i; i = traverseNextPostOrder(i)) {
        ASSERT(!i->m_state.isValid());
        i->m_state = HTMLImportStateResolver(i).resolve();

        HTMLImportState newState = i->state();
        HTMLImportState oldState = snapshot.get(i);
        // Once the state reaches Ready, it shouldn't go back.
        ASSERT(!oldState.isReady() || oldState <= newState);
        if (newState != oldState)
            updated.append(i);
    }

    for (size_t i = 0; i < updated.size(); ++i)
        updated[i]->stateDidChange();
}

#if !defined(NDEBUG)
void HTMLImport::show()
{
    root()->showTree(this, 0);
}

void HTMLImport::showTree(HTMLImport* highlight, unsigned depth)
{
    for (unsigned i = 0; i < depth*4; ++i)
        fprintf(stderr, " ");

    fprintf(stderr, "%s", this == highlight ? "*" : " ");
    showThis();
    fprintf(stderr, "\n");
    for (HTMLImport* child = firstChild(); child; child = child->next())
        child->showTree(highlight, depth + 1);
}

void HTMLImport::showThis()
{
    fprintf(stderr, "%p state=%d", this, m_state.peekValueForDebug());
}
#endif

} // namespace WebCore
<|endoftext|>


<commit_before>#include "GLPolygonWidget.h"

GLPolygonWidget::GLPolygonWidget(QWidget* parent, GLPolygon* initialPolygon) :
	QGLWidget(parent), polygon(initialPolygon), oldMouseY(0.0f)
{
	setMouseTracking(true);
}

void GLPolygonWidget::setPolygon(GLPolygon* newPolygon)
{
	polygon = newPolygon;
}

void GLPolygonWidget::initializeGL()
{
	glClearColor(0.3, 0.3, 0.3, 0.0);
}

void GLPolygonWidget::resizeGL(int width, int height)
{
	glViewport(0, 0, width, height);
}

void GLPolygonWidget::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT);

	polygon->render();

	glFlush();
}

bool GLPolygonWidget::processMouseEvent(QMouseEvent* event)
{
	bool changeMade = false; // set to true if state of polygon changed

	// Check which mouse buttons are pressed
	if (event->buttons() & Qt::LeftButton) //  if left button pressed
	{
		static const float radius = 0.75;
		float newX = (static_cast<float>(event->x()) / this->width()) - (radius / 2);
		float newY = -(static_cast<float>(event->y()) / this->height()) + (radius / 2);
		polygon->setX(newX);
		polygon->setY(newY);
		changeMade = true;
	}
	if (event->buttons() & Qt::RightButton) // if right button pressed
	{
		float difference = oldMouseY - event->y();
		float newDegrees = polygon->rotationDegrees() + difference;
		polygon->setRotationDegrees(newDegrees);
		changeMade = true;
	}

	// If no mouse button pressed and no change made, just return false
	if (!changeMade) return false;

	// Ensure polygon does not go out of bounds
	if (polygon->x() < -1.0f) polygon->setX(-1.0f);
	else if (polygon->x() > 1.0f) polygon->setX(1.0f);
	if (polygon->y() < -1.0f) polygon->setY(-1.0f);
	else if (polygon->y() > 1.0f) polygon->setY(1.0f);
	if (polygon->rotationDegrees() < 0.0f || polygon->rotationDegrees() > 360.0f)
		polygon->setRotationDegrees(0.0f);

	// Accept event so it's not processed further and redraw widget to reflect changes
	event->accept();
	// Also keep track of the Y value for later use
	oldMouseY = event->y();

	return true; // change made to return true
}

void GLPolygonWidget::mouseMoveEvent(QMouseEvent* event)
{
	if (processMouseEvent(event))
		emit changed();
}

void GLPolygonWidget::mousePressEvent(QMouseEvent* event)
{
	if (processMouseEvent(event))
		emit changed();
}
<commit_msg>Added depth to OpenGL rendering<commit_after>#include "GLPolygonWidget.h"

GLPolygonWidget::GLPolygonWidget(QWidget* parent, GLPolygon* initialPolygon) :
	QGLWidget(parent), polygon(initialPolygon), oldMouseY(0.0f)
{
	setMouseTracking(true);
}

void GLPolygonWidget::setPolygon(GLPolygon* newPolygon)
{
	polygon = newPolygon;
}

void GLPolygonWidget::initializeGL()
{
	glClearColor(0.3, 0.3, 0.3, 0.0);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
}

void GLPolygonWidget::resizeGL(int width, int height)
{
	glViewport(0, 0, width, height);
}

void GLPolygonWidget::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	polygon->render();

	glFlush();
}

bool GLPolygonWidget::processMouseEvent(QMouseEvent* event)
{
	bool changeMade = false; // set to true if state of polygon changed

	// Check which mouse buttons are pressed
	if (event->buttons() & Qt::LeftButton) //  if left button pressed
	{
		static const float radius = 0.75;
		float newX = (static_cast<float>(event->x()) / this->width()) - (radius / 2);
		float newY = -(static_cast<float>(event->y()) / this->height()) + (radius / 2);
		polygon->setX(newX);
		polygon->setY(newY);
		changeMade = true;
	}
	if (event->buttons() & Qt::RightButton) // if right button pressed
	{
		float difference = oldMouseY - event->y();
		float newDegrees = polygon->rotationDegrees() + difference;
		polygon->setRotationDegrees(newDegrees);
		changeMade = true;
	}

	// If no mouse button pressed and no change made, just return false
	if (!changeMade) return false;

	// Ensure polygon does not go out of bounds
	if (polygon->x() < -1.0f) polygon->setX(-1.0f);
	else if (polygon->x() > 1.0f) polygon->setX(1.0f);
	if (polygon->y() < -1.0f) polygon->setY(-1.0f);
	else if (polygon->y() > 1.0f) polygon->setY(1.0f);
	if (polygon->rotationDegrees() < 0.0f || polygon->rotationDegrees() > 360.0f)
		polygon->setRotationDegrees(0.0f);

	// Accept event so it's not processed further and redraw widget to reflect changes
	event->accept();
	// Also keep track of the Y value for later use
	oldMouseY = event->y();

	return true; // change made to return true
}

void GLPolygonWidget::mouseMoveEvent(QMouseEvent* event)
{
	if (processMouseEvent(event))
		emit changed();
}

void GLPolygonWidget::mousePressEvent(QMouseEvent* event)
{
	if (processMouseEvent(event))
		emit changed();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012-2013 BrewPi/Elco Jacobs.
 *
 * This file is part of BrewPi.
 *
 * BrewPi is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BrewPi is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with BrewPi.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Platform.h"
#include "Brewpi.h"
#include "Ticks.h"
#include "Display.h"
#include "TempControl.h"
#include "PiLink.h"
#include "TempSensor.h"
#include "TempSensorMock.h"
#include "TempSensorExternal.h"
#include "ActuatorMocks.h"
#include "Sensor.h"
#include "SettingsManager.h"
#include "UI.h"

#if BREWPI_SIMULATE
	#include "Simulator.h"
#endif

// global class objects static and defined in class cpp and h files

// instantiate and configure the sensors, actuators and controllers we want to use

void setup(void);
void loop (void);

/* Configure the counter and delay timer. The actual type of these will vary depending upon the environment.
 * They are non-virtual to keep code size minimal, so typedefs and preprocessing are used to select the actual compile-time type used. */
TicksImpl ticks = TicksImpl(TICKS_IMPL_CONFIG);
DelayImpl wait = DelayImpl(DELAY_IMPL_CONFIG);

UI ui;

void setup()
{
    boardInit();
    bool resetEeprom = platform_init();
    eepromManager.init();
    if (resetEeprom) {
        eepromManager.initializeEeprom();
    }
	ui.init();
	piLink.init();
	// flush any waiting input.
    // Linux can put garbage in the serial input buffer during connect
    piLink.flushInput();

    logDebug("started");

    uint32_t start = ticks.millis();
    uint32_t delay = ui.showStartupPage();
    while (ticks.millis()-start <= delay) {
        ui.ticks();
    }

    // initialize OneWire
    if (!primaryOneWireBus.init()) {
        logError(ERROR_ONEWIRE_INIT_FAILED);
    }

#if BREWPI_SIMULATE
	simulator.step();
	// initialize the filters with the assigned initial temp value
	//tempControl.beerSensor->init();
	//tempControl.fridgeSensor->init();
#endif
    settingsManager.loadSettings();

    control.update();

    ui.showControllerPage();

	logDebug("init complete");
}

void brewpiLoop(void)
{
	static unsigned long lastUpdate = -1000; // init at -1000 to update immediately
    ui.ticks();

    if(!ui.inStartup() && (ticks.millis() - lastUpdate >= (1000))) { //update settings every second
		lastUpdate = ticks.millis();
		control.update();
        ui.update();
    }

    control.fastUpdate(); // update actuators as often as possible for PWM

    //listen for incoming serial connections while waiting to update
    piLink.receive();
}

void loop() {
	#if BREWPI_SIMULATE
	simulateLoop();
	#else
	brewpiLoop();
	#endif
}

<commit_msg>show startup screen before serial/wifi init<commit_after>/*
 * Copyright 2012-2013 BrewPi/Elco Jacobs.
 *
 * This file is part of BrewPi.
 *
 * BrewPi is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BrewPi is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with BrewPi.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Platform.h"
#include "Brewpi.h"
#include "Ticks.h"
#include "Display.h"
#include "TempControl.h"
#include "PiLink.h"
#include "TempSensor.h"
#include "TempSensorMock.h"
#include "TempSensorExternal.h"
#include "ActuatorMocks.h"
#include "Sensor.h"
#include "SettingsManager.h"
#include "UI.h"

#if BREWPI_SIMULATE
	#include "Simulator.h"
#endif

// global class objects static and defined in class cpp and h files

// instantiate and configure the sensors, actuators and controllers we want to use

void setup(void);
void loop (void);

/* Configure the counter and delay timer. The actual type of these will vary depending upon the environment.
 * They are non-virtual to keep code size minimal, so typedefs and preprocessing are used to select the actual compile-time type used. */
TicksImpl ticks = TicksImpl(TICKS_IMPL_CONFIG);
DelayImpl wait = DelayImpl(DELAY_IMPL_CONFIG);

UI ui;

void setup()
{
    boardInit();
    bool resetEeprom = platform_init();
    eepromManager.init();
    if (resetEeprom) {
        eepromManager.initializeEeprom();
    }
	ui.init();

    uint32_t start = ticks.millis();
    uint32_t delay = ui.showStartupPage();

    piLink.init();
    // flush any waiting input.
    // Linux can put garbage in the serial input buffer during connect
    piLink.flushInput();

    logDebug("started");

    while (ticks.millis()-start <= delay) {
        ui.ticks();
    }

    // initialize OneWire
    if (!primaryOneWireBus.init()) {
        logError(ERROR_ONEWIRE_INIT_FAILED);
    }

#if BREWPI_SIMULATE
	simulator.step();
	// initialize the filters with the assigned initial temp value
	//tempControl.beerSensor->init();
	//tempControl.fridgeSensor->init();
#endif
    settingsManager.loadSettings();

    control.update();

    ui.showControllerPage();

	logDebug("init complete");
}

void brewpiLoop(void)
{
	static unsigned long lastUpdate = -1000; // init at -1000 to update immediately
    ui.ticks();

    if(!ui.inStartup() && (ticks.millis() - lastUpdate >= (1000))) { //update settings every second
		lastUpdate = ticks.millis();
		control.update();
        ui.update();
    }

    control.fastUpdate(); // update actuators as often as possible for PWM

    //listen for incoming serial connections while waiting to update
    piLink.receive();
}

void loop() {
	#if BREWPI_SIMULATE
	simulateLoop();
	#else
	brewpiLoop();
	#endif
}

<|endoftext|>


<commit_before>#include "Client.h"

/*
Copyright (C) 2016 AGC.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using namespace x801::game;

#include <algorithm>
#include <iostream>
#include <GLFW/glfw3.h>
#include <BitStream.h>
#include <SecureHandshake.h>

void x801::game::Client::initialise() {
  peer = RakNet::RakPeerInterface::GetInstance();
  RakNet::SocketDescriptor clientSocket(0, 0);
  clientSocket.socketFamily = useIPV6 ? AF_INET6 : AF_INET;
  peer->Startup(1, &clientSocket, 1);
  peer->SetOccasionalPing(true);
  RakNet::PublicKey pk;
  pk.publicKeyMode = RakNet::PKM_ACCEPT_ANY_PUBLIC_KEY;
  publicKey = new char[cat::EasyHandshake::PUBLIC_KEY_BYTES];
  pk.remoteServerPublicKey = publicKey;
  auto status = peer->Connect(ipAddress.c_str(), port, nullptr, 0, &pk);
  if (status != RakNet::CONNECTION_ATTEMPT_STARTED) {
    throw "Connection failed...";
  }
  // set packet callbacks
  PacketCallback logoutCallback = {
    [](
      uint8_t packetType,
      uint8_t* body, size_t length,
      RakNet::Packet* p) {
        (void) packetType; (void) body; (void) length; (void) p;
        std::cout << "You have been disconnected.";
      }, -1
  };
  callbacks.insert({ID_CONNECTION_LOST, logoutCallback});
  callbacks.insert({ID_DISCONNECTION_NOTIFICATION, logoutCallback});
  PacketCallback connectCallback = {
    [this](
      uint8_t packetType,
      uint8_t* body, size_t length,
      RakNet::Packet* p) {
        (void) packetType; (void) body; (void) length; (void) p;
        std::cout << "MOTD:\n";
        this->requestMOTD();
      }, -1
  };
  callbacks.insert({ID_CONNECTION_REQUEST_ACCEPTED, connectCallback});
  openWindowConcurrent();
  listen();
}

bool x801::game::Client::handlePacket(
    uint8_t packetType,
    uint8_t* body, size_t length,
    RakNet::Packet* p) {
  (void) body; (void) length; (void) p;
  std::cerr << "It's a packet! ID = " << (int) packetType << "\n";
  switch (packetType) {
  case ID_NO_FREE_INCOMING_CONNECTIONS:
    std::cout << "The server is full.\n";
    return false;
  case ID_CONNECTION_LOST:
  case ID_DISCONNECTION_NOTIFICATION:
    std::cout << "Connection lost.\n";
    return false;
  case ID_CONNECTION_ATTEMPT_FAILED:
    std::cout << "Failed to connect to server.\n";
    return false;
  }
  auto range = callbacks.equal_range(packetType);
  for (auto iterator = range.first; iterator != range.second;) {
    (iterator->second.call)(packetType, body, length, p);
    if (iterator->second.timesLeft != -1) --iterator->second.timesLeft;
    if (iterator->second.timesLeft == 0) iterator = callbacks.erase(iterator);
    else ++iterator;
  }
  return true;
}
bool x801::game::Client::handleLPacket(
    uint16_t lPacketType,
    uint8_t* lbody, size_t llength,
    RakNet::Packet* p) {
  // TODO implement
  (void) lbody; (void) llength; (void) p;
  std::cerr << "It's an lpacket!\n";
  switch (lPacketType) {
    //
  }
  auto range = lCallbacks.equal_range(lPacketType);
  for (auto iterator = range.first; iterator != range.second;) {
    (iterator->second.call)(lPacketType, nullptr, lbody, llength, p);
    if (iterator->second.timesLeft != -1) --iterator->second.timesLeft;
    if (iterator->second.timesLeft == 0) iterator = lCallbacks.erase(iterator);
    else ++iterator;
  }
  return true;
}

void x801::game::Client::listen() {
  bool shouldContinue = true;
  while (shouldContinue) {
    for (
        RakNet::Packet* p = peer->Receive();
        p != nullptr;
        peer->DeallocatePacket(p), p = peer->Receive()) {
      uint8_t packetType = getPacketType(p);
      size_t offset = getPacketOffset(p);
      uint8_t* body = p->data + offset;
      size_t length = p->length - offset;
      if (packetType == PACKET_IM_LOGGED_IN) {
        uint16_t lpacketType = (body[0] << 8) | body[1];
        uint8_t* lbody = body + 2;
        size_t llength = length - 2;
        shouldContinue = handleLPacket(lpacketType, lbody, llength, p);
      } else {
        shouldContinue = handlePacket(packetType, body, length, p);
      }
    }
  }
  if (cw != nullptr) glfwSetWindowShouldClose(cw->underlying(), true);
}

void x801::game::Client::requestMOTD(PacketCallback motdCallback) {
  RakNet::BitStream stream;
  stream.Write(static_cast<uint8_t>(PACKET_MOTD));
  peer->Send(
    &stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0,
    RakNet::UNASSIGNED_RAKNET_GUID, true
  );
  callbacks.insert({PACKET_MOTD, motdCallback});
}

void x801::game::Client::requestMOTD() {
  PacketCallback motdCallback = {
    [this](
      uint8_t packetType,
      uint8_t* body, size_t length,
      RakNet::Packet* p) {
        (void) packetType; (void) p;
        RakNet::BitStream stream(body, length, false);
        const char* s = readStringFromBitstream32(stream);
        std::cout << s << '\n';
        delete[] s;
      }, 1
  };
  requestMOTD(motdCallback);
}

void x801::game::Client::openWindow() {
  cw = new ClientWindow(1024, 768, 0, 0, "Experiment801", 3, 3, false);
  cw->c = this;
  cw->start();
}

void x801::game::Client::openWindowConcurrent() {
  windowThread = std::thread([this]() { this->openWindow(); });
}

x801::game::Client::~Client() {
  done = true;
  RakNet::RakPeerInterface::DestroyInstance(peer);
  delete[] publicKey;
}
<commit_msg>Reorder callback registration and packet sending in requestMOTD<commit_after>#include "Client.h"

/*
Copyright (C) 2016 AGC.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using namespace x801::game;

#include <algorithm>
#include <iostream>
#include <GLFW/glfw3.h>
#include <BitStream.h>
#include <SecureHandshake.h>

void x801::game::Client::initialise() {
  peer = RakNet::RakPeerInterface::GetInstance();
  RakNet::SocketDescriptor clientSocket(0, 0);
  clientSocket.socketFamily = useIPV6 ? AF_INET6 : AF_INET;
  peer->Startup(1, &clientSocket, 1);
  peer->SetOccasionalPing(true);
  RakNet::PublicKey pk;
  pk.publicKeyMode = RakNet::PKM_ACCEPT_ANY_PUBLIC_KEY;
  publicKey = new char[cat::EasyHandshake::PUBLIC_KEY_BYTES];
  pk.remoteServerPublicKey = publicKey;
  auto status = peer->Connect(ipAddress.c_str(), port, nullptr, 0, &pk);
  if (status != RakNet::CONNECTION_ATTEMPT_STARTED) {
    throw "Connection failed...";
  }
  // set packet callbacks
  PacketCallback logoutCallback = {
    [](
      uint8_t packetType,
      uint8_t* body, size_t length,
      RakNet::Packet* p) {
        (void) packetType; (void) body; (void) length; (void) p;
        std::cout << "You have been disconnected.";
      }, -1
  };
  callbacks.insert({ID_CONNECTION_LOST, logoutCallback});
  callbacks.insert({ID_DISCONNECTION_NOTIFICATION, logoutCallback});
  PacketCallback connectCallback = {
    [this](
      uint8_t packetType,
      uint8_t* body, size_t length,
      RakNet::Packet* p) {
        (void) packetType; (void) body; (void) length; (void) p;
        std::cout << "MOTD:\n";
        this->requestMOTD();
      }, -1
  };
  callbacks.insert({ID_CONNECTION_REQUEST_ACCEPTED, connectCallback});
  openWindowConcurrent();
  listen();
}

bool x801::game::Client::handlePacket(
    uint8_t packetType,
    uint8_t* body, size_t length,
    RakNet::Packet* p) {
  (void) body; (void) length; (void) p;
  std::cerr << "It's a packet! ID = " << (int) packetType << "\n";
  switch (packetType) {
  case ID_NO_FREE_INCOMING_CONNECTIONS:
    std::cout << "The server is full.\n";
    return false;
  case ID_CONNECTION_LOST:
  case ID_DISCONNECTION_NOTIFICATION:
    std::cout << "Connection lost.\n";
    return false;
  case ID_CONNECTION_ATTEMPT_FAILED:
    std::cout << "Failed to connect to server.\n";
    return false;
  }
  auto range = callbacks.equal_range(packetType);
  for (auto iterator = range.first; iterator != range.second;) {
    (iterator->second.call)(packetType, body, length, p);
    if (iterator->second.timesLeft != -1) --iterator->second.timesLeft;
    if (iterator->second.timesLeft == 0) iterator = callbacks.erase(iterator);
    else ++iterator;
  }
  return true;
}
bool x801::game::Client::handleLPacket(
    uint16_t lPacketType,
    uint8_t* lbody, size_t llength,
    RakNet::Packet* p) {
  // TODO implement
  (void) lbody; (void) llength; (void) p;
  std::cerr << "It's an lpacket!\n";
  switch (lPacketType) {
    //
  }
  auto range = lCallbacks.equal_range(lPacketType);
  for (auto iterator = range.first; iterator != range.second;) {
    (iterator->second.call)(lPacketType, nullptr, lbody, llength, p);
    if (iterator->second.timesLeft != -1) --iterator->second.timesLeft;
    if (iterator->second.timesLeft == 0) iterator = lCallbacks.erase(iterator);
    else ++iterator;
  }
  return true;
}

void x801::game::Client::listen() {
  bool shouldContinue = true;
  while (shouldContinue) {
    for (
        RakNet::Packet* p = peer->Receive();
        p != nullptr;
        peer->DeallocatePacket(p), p = peer->Receive()) {
      uint8_t packetType = getPacketType(p);
      size_t offset = getPacketOffset(p);
      uint8_t* body = p->data + offset;
      size_t length = p->length - offset;
      if (packetType == PACKET_IM_LOGGED_IN) {
        uint16_t lpacketType = (body[0] << 8) | body[1];
        uint8_t* lbody = body + 2;
        size_t llength = length - 2;
        shouldContinue = handleLPacket(lpacketType, lbody, llength, p);
      } else {
        shouldContinue = handlePacket(packetType, body, length, p);
      }
    }
  }
  if (cw != nullptr) glfwSetWindowShouldClose(cw->underlying(), true);
}

void x801::game::Client::requestMOTD(PacketCallback motdCallback) {
  RakNet::BitStream stream;
  stream.Write(static_cast<uint8_t>(PACKET_MOTD));
  callbacks.insert({PACKET_MOTD, motdCallback});
  peer->Send(
    &stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0,
    RakNet::UNASSIGNED_RAKNET_GUID, true
  );
}

void x801::game::Client::requestMOTD() {
  PacketCallback motdCallback = {
    [this](
      uint8_t packetType,
      uint8_t* body, size_t length,
      RakNet::Packet* p) {
        (void) packetType; (void) p;
        RakNet::BitStream stream(body, length, false);
        const char* s = readStringFromBitstream32(stream);
        std::cout << s << '\n';
        delete[] s;
      }, 1
  };
  requestMOTD(motdCallback);
}

void x801::game::Client::openWindow() {
  cw = new ClientWindow(1024, 768, 0, 0, "Experiment801", 3, 3, false);
  cw->c = this;
  cw->start();
}

void x801::game::Client::openWindowConcurrent() {
  windowThread = std::thread([this]() { this->openWindow(); });
}

x801::game::Client::~Client() {
  done = true;
  RakNet::RakPeerInterface::DestroyInstance(peer);
  delete[] publicKey;
}
<|endoftext|>


<commit_before>#include <Core/Serialization.h>
#include "Mappers.h"

namespace
{
    static const uint32_t ROM_BANK_SIZE = 0x4000;

    static const uint32_t BANK_SIZE_EXTERNAL_RAM = 0x2000;

    static const uint8_t MBC1_RAM_ENABLE_MASK = 0x0f;
    static const uint8_t MBC1_RAM_ENABLE_VALUE = 0x0a;

    static const uint8_t MBC1_ROM_BANK_LOW_MASK = 0x1f;
    static const uint8_t MBC1_ROM_BANK_HIGH_VALID = 0x60;
    static const uint8_t MBC1_ROM_BANK_HIGH_MASK = 0x60;
    static const uint8_t MBC1_ROM_BANK_HIGH_SHIFT = 5;
    static const uint8_t MBC1_ROM_BANK_INVALID_MASK = 0x1f;
    static const uint8_t MBC1_ROM_BANK_INVALID_ADJ = 0x01;

    static const uint8_t MBC1_RAM_BANK_MODE = 0x01;

    static const uint8_t MBC5_RAM_ENABLE_MASK = 0x0f;
    static const uint8_t MBC5_RAM_ENABLE_VALUE = 0x0a;

    static const uint16_t MBC5_ROM_BANK_LOW_MASK = 0x00ff;
    static const uint16_t MBC5_ROM_BANK_HIGH_MASK = 0x0100;
    static const uint16_t MBC5_ROM_BANK_HIGH_SHIFT = 8;

    uint8_t read8null(void* context, int32_t tick, uint32_t addr)
    {
        EMU_INVOKE_ONCE(printf("External RAM read disabled!\n"));
        return 0;
    }

    void write8null(void* context, int32_t tick, uint32_t addr, uint8_t value)
    {
        EMU_INVOKE_ONCE(printf("External RAM write disabled!\n"));
    }
}

namespace gb
{
    MapperBase::MapperBase()
    {
        initialize();
    }

    MapperBase::~MapperBase()
    {
        destroy();
    }

    void MapperBase::initialize()
    {
        mRom = nullptr;
        mMemory = nullptr;
        mEnableExternalRAM = false;
    }

    bool MapperBase::create(const Rom& rom, emu::MemoryBus& memory)
    {
        mRom = &rom;
        mMemory = &memory;

        const auto& desc = rom.getDescription();
        uint8_t* pRAM = nullptr;
        if (desc.hasRam)
        {
            mExternalRAM.resize(desc.ramSize, 0);
            pRAM = mExternalRAM.data();
        }

        const uint8_t* pROM = mRom->getContent().rom;
        for (uint32_t bank = 0, offset = 0; bank < EMU_ARRAY_SIZE(mBankMapROM); ++bank, offset += ROM_BANK_SIZE)
        {
            if (offset >= desc.romSize)
                offset = 0;
            mBankMapROM[bank] = pROM + offset;
        }
        for (uint32_t bank = 0, offset = 0; bank < EMU_ARRAY_SIZE(mBankMapRAM); ++bank, offset += BANK_SIZE_EXTERNAL_RAM)
        {
            if (offset >= desc.ramSize)
                offset = 0;
            mBankMapRAM[bank] = pRAM + offset;
        }

        reset();

        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_READ, 0x0000, 0x3fff, mMemoryROM[0]));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_READ, 0x4000, 0x7fff, mMemoryROM[1]));
        uint16_t size = 0;
        if (!mExternalRAM.empty())
        {
            uint16_t size = static_cast<uint16_t>(mExternalRAM.size());
            if (size > BANK_SIZE_EXTERNAL_RAM)
                size = BANK_SIZE_EXTERNAL_RAM;
            EMU_VERIFY(mMemory->addMemoryRange(0xa000, 0xa000 + size - 1, mMemoryExternalRAM));
        }
        if (size < BANK_SIZE_EXTERNAL_RAM)
        {
            EMU_VERIFY(mMemory->addMemoryRange(0xa000, 0xa000 + BANK_SIZE_EXTERNAL_RAM - size - 1, mMemoryExternalRAMEmpty));
        }
        return true;
    }

    void MapperBase::destroy()
    {
        mExternalRAM.clear();
        initialize();
    }

    void MapperBase::reset()
    {
        mBankROM[0] = 0;
        mBankROM[1] = 1;
        mBankExternalRAM = 0xff;
        mEnableExternalRAM = false;
        updateMemoryMap();
    }

    void MapperBase::enableRam(bool enable)
    {
        mEnableExternalRAM = enable;
    }

    bool MapperBase::updateMemoryMap()
    {
        mMemoryROM[0].setReadMemory(mBankMapROM[mBankROM[0]]);
        mMemoryROM[1].setReadMemory(mBankMapROM[mBankROM[1]]);
        if (!mExternalRAM.empty() && (mEnableExternalRAM || !mRom->getDescription().hasBattery))
        {
            mMemoryExternalRAM.setReadWriteMemory(mBankMapRAM[mBankExternalRAM]);
        }
        else
        {
            mMemoryExternalRAM.read.setReadMethod(&read8null, this);
            mMemoryExternalRAM.write.setWriteMethod(&write8null, this);
        }
        mMemoryExternalRAMEmpty.read.setReadMethod(&read8null, this);
        mMemoryExternalRAMEmpty.write.setWriteMethod(&write8null, this);
        return true;
    }

    void MapperBase::serializeGameData(emu::ISerializer& serializer)
    {
        if (mRom->getDescription().hasBattery)
            serializer.serialize(mExternalRAM);
    }

    void MapperBase::serializeGameState(emu::ISerializer& serializer)
    {
        serializer.serialize(mExternalRAM);
        serializer.serialize(mBankROM, EMU_ARRAY_SIZE(mBankROM));
        serializer.serialize(mBankExternalRAM);
        serializer.serialize(mEnableExternalRAM);
        updateMemoryMap();
    }

    ////////////////////////////////////////////////////////////////////////////

    MapperROM::MapperROM()
    {
    }

    bool MapperROM::create(const Rom& rom, emu::MemoryBus& memory)
    {
        EMU_VERIFY(MapperBase::create(rom, memory));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_WRITE, 0x0000, 0x7fff, mMemoryControlRegs.setWriteMethod(&write8, this)));
        return true;
    }

    void MapperROM::write8(void* context, int32_t tick, uint32_t addr, uint8_t value)
    {
        EMU_NOT_IMPLEMENTED();
    }

    ////////////////////////////////////////////////////////////////////////////

    MapperMBC1::MapperMBC1()
    {
    }

    bool MapperMBC1::create(const Rom& rom, emu::MemoryBus& memory)
    {
        EMU_VERIFY(MapperBase::create(rom, memory));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_WRITE, 0x0000, 0x7fff, mMemoryControlRegs.setWriteMethod(&MapperMBC1::write8, this)));
        return true;
    }

    void MapperMBC1::reset()
    {
        mBankROM = 0;
        mBankRAM = 0;
        mRamBankMode = false;
        MapperBase::reset();
    }

    void MapperMBC1::serializeGameState(emu::ISerializer& serializer)
    {
        serializer.serialize(mBankROM);
        serializer.serialize(mBankRAM);
        serializer.serialize(mRamBankMode);
        MapperBase::serializeGameState(serializer);
    }

    bool MapperMBC1::updateMemoryMap()
    {
        uint8_t validBankROM = mBankROM;
        if ((validBankROM & MBC1_ROM_BANK_INVALID_MASK) == 0)
            validBankROM |= MBC1_ROM_BANK_INVALID_ADJ;
        setRomBank(validBankROM);
        setRamBank(mBankRAM);
        return MapperBase::updateMemoryMap();
    }

    void MapperMBC1::write8(int32_t tick, uint32_t addr, uint8_t value)
    {
        switch (addr >> 13)
        {
        case 0:
        {
            bool enable = (value & MBC1_RAM_ENABLE_MASK) == MBC1_RAM_ENABLE_VALUE;
            enableRam(enable);
            break;
        }
        case 1:
        {
            mBankROM = (mBankROM & ~MBC1_ROM_BANK_LOW_MASK) | (value & MBC1_ROM_BANK_LOW_MASK);
            break;
        }
        case 2:
        {
            value = value & MBC1_ROM_BANK_HIGH_VALID;
            if (mRamBankMode)
            {
                mBankRAM = value;
            }
            else
            {
                mBankROM = (mBankROM & ~MBC1_ROM_BANK_HIGH_MASK) | ((value << MBC1_ROM_BANK_HIGH_SHIFT) & MBC1_ROM_BANK_HIGH_MASK);
            }
            break;
        }
        case 3:
        {
            mRamBankMode = (value & MBC1_RAM_BANK_MODE) != 0;
            break;
        }
        default:
            EMU_ASSERT(false);
        }
        updateMemoryMap();
    }

    ////////////////////////////////////////////////////////////////////////////

    MapperMBC5::MapperMBC5()
    {
    }

    bool MapperMBC5::create(const Rom& rom, emu::MemoryBus& memory)
    {
        EMU_VERIFY(MapperBase::create(rom, memory));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_WRITE, 0x0000, 0x7fff, mMemoryControlRegs.setWriteMethod(&MapperMBC5::write8, this)));
        return true;
    }

    void MapperMBC5::reset()
    {
        mRamBankMode = false;
        MapperBase::reset();
    }

    void MapperMBC5::serializeGameState(emu::ISerializer& serializer)
    {
        serializer.serialize(mRamBankMode);
        MapperBase::serializeGameState(serializer);
    }

    bool MapperMBC5::updateMemoryMap()
    {
        return MapperBase::updateMemoryMap();
    }

    void MapperMBC5::write8(int32_t tick, uint32_t addr, uint8_t value)
    {
        switch (addr >> 12)
        {
        case 0:
        case 1:
        {
            bool enable = (value & MBC5_RAM_ENABLE_MASK) == MBC5_RAM_ENABLE_VALUE;
            enableRam(enable);
            break;
        }
        case 2:
        {
            uint16_t bank = getRomBank();
            bank = (bank & ~MBC5_ROM_BANK_LOW_MASK) | (value & MBC5_ROM_BANK_LOW_MASK);
            setRomBank(bank);
            break;
        }
        case 3:
        {
            uint16_t bank = getRomBank();
            bank = (bank & ~MBC5_ROM_BANK_HIGH_MASK) | ((value << MBC5_ROM_BANK_HIGH_SHIFT) & MBC5_ROM_BANK_HIGH_MASK);
            setRomBank(bank);
            break;
        }
        case 4:
        case 5:
        {
            setRamBank(value);
            break;
        }
        default:
            break;
        }

        updateMemoryMap();
    }

    ////////////////////////////////////////////////////////////////////////////

    IMapper* createMapper(const Rom& rom, emu::MemoryBus& memory)
    {
        const auto& desc = rom.getDescription();

        switch (desc.mapper)
        {
        case Rom::Mapper::ROM:
        {
            auto mapper = new MapperROM();
            if (mapper->create(rom, memory))
                return mapper;
            delete mapper;
            break;
        }

        case Rom::Mapper::MBC1:
        {
            auto mapper = new MapperMBC1();
            if (mapper->create(rom, memory))
                return mapper;
            delete mapper;
            break;
        }

        case Rom::Mapper::MBC5:
        {
            auto mapper = new MapperMBC5();
            if (mapper->create(rom, memory))
                return mapper;
            delete mapper;
            break;
        }

        default:
            EMU_NOT_IMPLEMENTED();
        }
        return nullptr;
    }
}
<commit_msg>Fix a external RAM mapping issues.<commit_after>#include <Core/Serialization.h>
#include "Mappers.h"

namespace
{
    static const uint32_t ROM_BANK_SIZE = 0x4000;

    static const uint32_t BANK_SIZE_EXTERNAL_RAM = 0x2000;

    static const uint8_t MBC1_RAM_ENABLE_MASK = 0x0f;
    static const uint8_t MBC1_RAM_ENABLE_VALUE = 0x0a;

    static const uint8_t MBC1_ROM_BANK_LOW_MASK = 0x1f;
    static const uint8_t MBC1_ROM_BANK_HIGH_VALID = 0x60;
    static const uint8_t MBC1_ROM_BANK_HIGH_MASK = 0x60;
    static const uint8_t MBC1_ROM_BANK_HIGH_SHIFT = 5;
    static const uint8_t MBC1_ROM_BANK_INVALID_MASK = 0x1f;
    static const uint8_t MBC1_ROM_BANK_INVALID_ADJ = 0x01;

    static const uint8_t MBC1_RAM_BANK_MODE = 0x01;

    static const uint8_t MBC5_RAM_ENABLE_MASK = 0x0f;
    static const uint8_t MBC5_RAM_ENABLE_VALUE = 0x0a;

    static const uint16_t MBC5_ROM_BANK_LOW_MASK = 0x00ff;
    static const uint16_t MBC5_ROM_BANK_HIGH_MASK = 0x0100;
    static const uint16_t MBC5_ROM_BANK_HIGH_SHIFT = 8;

    uint8_t read8null(void* context, int32_t tick, uint32_t addr)
    {
        EMU_INVOKE_ONCE(printf("External RAM read disabled!\n"));
        return 0;
    }

    void write8null(void* context, int32_t tick, uint32_t addr, uint8_t value)
    {
        EMU_INVOKE_ONCE(printf("External RAM write disabled!\n"));
    }
}

namespace gb
{
    MapperBase::MapperBase()
    {
        initialize();
    }

    MapperBase::~MapperBase()
    {
        destroy();
    }

    void MapperBase::initialize()
    {
        mRom = nullptr;
        mMemory = nullptr;
        mEnableExternalRAM = false;
    }

    bool MapperBase::create(const Rom& rom, emu::MemoryBus& memory)
    {
        mRom = &rom;
        mMemory = &memory;

        const auto& desc = rom.getDescription();
        uint8_t* pRAM = nullptr;
        if (desc.hasRam)
        {
            mExternalRAM.resize(desc.ramSize, 0);
            pRAM = mExternalRAM.data();
        }

        const uint8_t* pROM = mRom->getContent().rom;
        for (uint32_t bank = 0, offset = 0; bank < EMU_ARRAY_SIZE(mBankMapROM); ++bank, offset += ROM_BANK_SIZE)
        {
            if (offset >= desc.romSize)
                offset = 0;
            mBankMapROM[bank] = pROM + offset;
        }
        for (uint32_t bank = 0, offset = 0; bank < EMU_ARRAY_SIZE(mBankMapRAM); ++bank, offset += BANK_SIZE_EXTERNAL_RAM)
        {
            if (offset >= desc.ramSize)
                offset = 0;
            mBankMapRAM[bank] = pRAM + offset;
        }

        reset();

        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_READ, 0x0000, 0x3fff, mMemoryROM[0]));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_READ, 0x4000, 0x7fff, mMemoryROM[1]));
        uint16_t size = 0;
        if (!mExternalRAM.empty())
        {
            size = static_cast<uint16_t>(mExternalRAM.size());
            if (size > BANK_SIZE_EXTERNAL_RAM)
                size = BANK_SIZE_EXTERNAL_RAM;
            EMU_VERIFY(mMemory->addMemoryRange(0xa000, 0xa000 + size - 1, mMemoryExternalRAM));
        }
        if (size < BANK_SIZE_EXTERNAL_RAM)
        {
            EMU_VERIFY(mMemory->addMemoryRange(0xa000, 0xa000 + BANK_SIZE_EXTERNAL_RAM - size - 1, mMemoryExternalRAMEmpty));
        }
        return true;
    }

    void MapperBase::destroy()
    {
        mExternalRAM.clear();
        initialize();
    }

    void MapperBase::reset()
    {
        mBankROM[0] = 0;
        mBankROM[1] = 1;
        mBankExternalRAM = 0x00;
        mEnableExternalRAM = false;
        updateMemoryMap();
    }

    void MapperBase::enableRam(bool enable)
    {
        mEnableExternalRAM = enable;
    }

    bool MapperBase::updateMemoryMap()
    {
        mMemoryROM[0].setReadMemory(mBankMapROM[mBankROM[0]]);
        mMemoryROM[1].setReadMemory(mBankMapROM[mBankROM[1]]);
        if (!mExternalRAM.empty() && (mEnableExternalRAM || !mRom->getDescription().hasBattery))
        {
            mMemoryExternalRAM.setReadWriteMemory(mBankMapRAM[mBankExternalRAM]);
        }
        else
        {
            mMemoryExternalRAM.read.setReadMethod(&read8null, this);
            mMemoryExternalRAM.write.setWriteMethod(&write8null, this);
        }
        mMemoryExternalRAMEmpty.read.setReadMethod(&read8null, this);
        mMemoryExternalRAMEmpty.write.setWriteMethod(&write8null, this);
        return true;
    }

    void MapperBase::serializeGameData(emu::ISerializer& serializer)
    {
        if (mRom->getDescription().hasBattery)
            serializer.serialize(mExternalRAM);
    }

    void MapperBase::serializeGameState(emu::ISerializer& serializer)
    {
        serializer.serialize(mExternalRAM);
        serializer.serialize(mBankROM, EMU_ARRAY_SIZE(mBankROM));
        serializer.serialize(mBankExternalRAM);
        serializer.serialize(mEnableExternalRAM);
        updateMemoryMap();
    }

    ////////////////////////////////////////////////////////////////////////////

    MapperROM::MapperROM()
    {
    }

    bool MapperROM::create(const Rom& rom, emu::MemoryBus& memory)
    {
        EMU_VERIFY(MapperBase::create(rom, memory));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_WRITE, 0x0000, 0x7fff, mMemoryControlRegs.setWriteMethod(&write8, this)));
        return true;
    }

    void MapperROM::write8(void* context, int32_t tick, uint32_t addr, uint8_t value)
    {
        EMU_NOT_IMPLEMENTED();
    }

    ////////////////////////////////////////////////////////////////////////////

    MapperMBC1::MapperMBC1()
    {
    }

    bool MapperMBC1::create(const Rom& rom, emu::MemoryBus& memory)
    {
        EMU_VERIFY(MapperBase::create(rom, memory));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_WRITE, 0x0000, 0x7fff, mMemoryControlRegs.setWriteMethod(&MapperMBC1::write8, this)));
        return true;
    }

    void MapperMBC1::reset()
    {
        mBankROM = 0;
        mBankRAM = 0;
        mRamBankMode = false;
        MapperBase::reset();
    }

    void MapperMBC1::serializeGameState(emu::ISerializer& serializer)
    {
        serializer.serialize(mBankROM);
        serializer.serialize(mBankRAM);
        serializer.serialize(mRamBankMode);
        MapperBase::serializeGameState(serializer);
    }

    bool MapperMBC1::updateMemoryMap()
    {
        uint8_t validBankROM = mBankROM;
        if ((validBankROM & MBC1_ROM_BANK_INVALID_MASK) == 0)
            validBankROM |= MBC1_ROM_BANK_INVALID_ADJ;
        setRomBank(validBankROM);
        setRamBank(mBankRAM);
        return MapperBase::updateMemoryMap();
    }

    void MapperMBC1::write8(int32_t tick, uint32_t addr, uint8_t value)
    {
        switch (addr >> 13)
        {
        case 0:
        {
            bool enable = (value & MBC1_RAM_ENABLE_MASK) == MBC1_RAM_ENABLE_VALUE;
            enableRam(enable);
            break;
        }
        case 1:
        {
            mBankROM = (mBankROM & ~MBC1_ROM_BANK_LOW_MASK) | (value & MBC1_ROM_BANK_LOW_MASK);
            break;
        }
        case 2:
        {
            value = value & MBC1_ROM_BANK_HIGH_VALID;
            if (mRamBankMode)
            {
                mBankRAM = value;
            }
            else
            {
                mBankROM = (mBankROM & ~MBC1_ROM_BANK_HIGH_MASK) | ((value << MBC1_ROM_BANK_HIGH_SHIFT) & MBC1_ROM_BANK_HIGH_MASK);
            }
            break;
        }
        case 3:
        {
            mRamBankMode = (value & MBC1_RAM_BANK_MODE) != 0;
            break;
        }
        default:
            EMU_ASSERT(false);
        }
        updateMemoryMap();
    }

    ////////////////////////////////////////////////////////////////////////////

    MapperMBC5::MapperMBC5()
    {
    }

    bool MapperMBC5::create(const Rom& rom, emu::MemoryBus& memory)
    {
        EMU_VERIFY(MapperBase::create(rom, memory));
        EMU_VERIFY(mMemory->addMemoryRange(MEMORY_BUS::PAGE_TABLE_WRITE, 0x0000, 0x7fff, mMemoryControlRegs.setWriteMethod(&MapperMBC5::write8, this)));
        return true;
    }

    void MapperMBC5::reset()
    {
        mRamBankMode = false;
        MapperBase::reset();
    }

    void MapperMBC5::serializeGameState(emu::ISerializer& serializer)
    {
        serializer.serialize(mRamBankMode);
        MapperBase::serializeGameState(serializer);
    }

    bool MapperMBC5::updateMemoryMap()
    {
        return MapperBase::updateMemoryMap();
    }

    void MapperMBC5::write8(int32_t tick, uint32_t addr, uint8_t value)
    {
        switch (addr >> 12)
        {
        case 0:
        case 1:
        {
            bool enable = (value & MBC5_RAM_ENABLE_MASK) == MBC5_RAM_ENABLE_VALUE;
            enableRam(enable);
            break;
        }
        case 2:
        {
            uint16_t bank = getRomBank();
            bank = (bank & ~MBC5_ROM_BANK_LOW_MASK) | (value & MBC5_ROM_BANK_LOW_MASK);
            setRomBank(bank);
            break;
        }
        case 3:
        {
            uint16_t bank = getRomBank();
            bank = (bank & ~MBC5_ROM_BANK_HIGH_MASK) | ((value << MBC5_ROM_BANK_HIGH_SHIFT) & MBC5_ROM_BANK_HIGH_MASK);
            setRomBank(bank);
            break;
        }
        case 4:
        case 5:
        {
            setRamBank(value);
            break;
        }
        default:
            break;
        }

        updateMemoryMap();
    }

    ////////////////////////////////////////////////////////////////////////////

    IMapper* createMapper(const Rom& rom, emu::MemoryBus& memory)
    {
        const auto& desc = rom.getDescription();

        switch (desc.mapper)
        {
        case Rom::Mapper::ROM:
        {
            auto mapper = new MapperROM();
            if (mapper->create(rom, memory))
                return mapper;
            delete mapper;
            break;
        }

        case Rom::Mapper::MBC1:
        {
            auto mapper = new MapperMBC1();
            if (mapper->create(rom, memory))
                return mapper;
            delete mapper;
            break;
        }

        case Rom::Mapper::MBC5:
        {
            auto mapper = new MapperMBC5();
            if (mapper->create(rom, memory))
                return mapper;
            delete mapper;
            break;
        }

        default:
            EMU_NOT_IMPLEMENTED();
        }
        return nullptr;
    }
}
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/echocommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "echocommand.h"

#include <gpg-error.h>

#include <QVariant>
#include <QByteArray>
#include <QIODevice>
#include <QList>

#include <boost/bind.hpp>

#include <string>
#include <algorithm>

using namespace Kleo;
using namespace boost;

static const char option_prefix[] = "prefix";

class EchoCommand::Private {
public:
    Private() : operationsInFlight( 0 ), buffer() {}

    int operationsInFlight;
    QByteArray buffer;
};

EchoCommand::EchoCommand()
    : QObject(), AssuanCommandMixin<EchoCommand>(), d( new Private ) {}

EchoCommand::~EchoCommand() {}

int EchoCommand::start( const std::string & line ) {

    if ( bulkInputDevice( "IN" ) && !bulkOutputDevice( "OUT" ) )
        return makeError( GPG_ERR_NOT_SUPPORTED );

    if ( hasOption( option_prefix ) && !option( option_prefix ).toByteArray().isEmpty() )
        return makeError( GPG_ERR_NOT_IMPLEMENTED );

    QList<QByteArray> tokens = QByteArray( line.c_str() ).split( ' ' );
    tokens.erase( std::remove_if( tokens.begin(), tokens.end(),
                                  bind( &QByteArray::isEmpty, _1 ) ),
                  tokens.end() );

    std::string keyword;
    if ( !tokens.empty() && tokens.front() == "--inquire" ) {
        tokens.pop_front();
        if ( tokens.empty() )
            return makeError( GPG_ERR_MISSING_VALUE );
        keyword = tokens.front().constData();
        tokens.pop_front();
    }

    bool optionsExpected = true;
    QByteArray output;
    Q_FOREACH( QByteArray token, tokens ) {
        if ( token == "--" )
            optionsExpected = false;
        else if ( optionsExpected && token.startsWith( "--" ) )
            if ( token == "--inquire" )
                return makeError( GPG_ERR_DUP_VALUE ); // duplicate
            else
                return makeError( GPG_ERR_UNKNOWN_OPTION );
        else
            if ( output.isEmpty() )
                output = token;
            else
                output += ' ' + token;
    }

    // aaand ACTION:

    // 1. echo the command line though the status channel
    if ( const int err = sendStatus( "ECHO", output.constData() ) )
        return err;

    // 2. if --inquire was given, inquire more data from the client:
    if ( !keyword.empty() )
        if ( const int err = inquire( keyword.c_str(), this,
                                      SLOT(slotInquireData(int,QByteArray)) ) )
            return err;
        else
            ++d->operationsInFlight;

    // 3. if INPUT was given, start the data pump for input->output
    if ( QIODevice * const in = bulkInputDevice( "IN" ) ) {
        QIODevice * const out = bulkOutputDevice( "OUT" );

        ++d->operationsInFlight;

        connect( in, SIGNAL(readyRead()), this, SLOT(slotInputReadyRead()) );
        connect( out, SIGNAL(bytesWritten(qint64)), this, SLOT(slotOutputBytesWritten()) );

        if ( in->bytesAvailable() )
            slotInputReadyRead();
    }

    if ( !d->operationsInFlight )
        done();
    return 0;
}

void EchoCommand::canceled() {

}

void EchoCommand::slotInquireData( int rc, const QByteArray & data ) {

    --d->operationsInFlight;

    if ( rc )
        done( rc );

    //else if ( const int err = sendData( data ) )
    else if ( const int err = sendStatus( "ECHOINQ", data ) )
        done( err );

    else if ( !d->operationsInFlight )
        done();

}

void EchoCommand::slotInputReadyRead() {
    QIODevice * const in = bulkInputDevice( "IN" );
    assert( in );

    if ( !in->atEnd() )
        d->buffer += in->readAll();

    slotOutputBytesWritten();
}

void EchoCommand::slotOutputBytesWritten() {
    QIODevice * const out = bulkOutputDevice( "OUT" );
    assert( out );

    if ( d->buffer.isEmpty() ) {
        if ( bulkInputDevice( "IN" )->atEnd() && out->isOpen() ) {
            out->close();
            if ( !--d->operationsInFlight )
                done();
        }
        return;
    }

    if ( out->bytesToWrite() )
        return;

    const qint64 written = out->write( d->buffer );
    if ( written == -1 ) {
        done( makeError( GPG_ERR_EIO ) );
        return;
    }
    d->buffer.remove( 0, written );

}

#include "moc_echocommand.cpp"
<commit_msg>Don't hang when output is a file<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/echocommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "echocommand.h"

#include <gpg-error.h>

#include <QVariant>
#include <QByteArray>
#include <QIODevice>
#include <QList>

#include <boost/bind.hpp>

#include <string>
#include <algorithm>

using namespace Kleo;
using namespace boost;

static const char option_prefix[] = "prefix";

class EchoCommand::Private {
public:
    Private() : operationsInFlight( 0 ), buffer() {}

    int operationsInFlight;
    QByteArray buffer;
};

EchoCommand::EchoCommand()
    : QObject(), AssuanCommandMixin<EchoCommand>(), d( new Private ) {}

EchoCommand::~EchoCommand() {}

int EchoCommand::start( const std::string & line ) {

    if ( bulkInputDevice( "IN" ) && !bulkOutputDevice( "OUT" ) )
        return makeError( GPG_ERR_NOT_SUPPORTED );

    if ( hasOption( option_prefix ) && !option( option_prefix ).toByteArray().isEmpty() )
        return makeError( GPG_ERR_NOT_IMPLEMENTED );

    QList<QByteArray> tokens = QByteArray( line.c_str() ).split( ' ' );
    tokens.erase( std::remove_if( tokens.begin(), tokens.end(),
                                  bind( &QByteArray::isEmpty, _1 ) ),
                  tokens.end() );

    std::string keyword;
    if ( !tokens.empty() && tokens.front() == "--inquire" ) {
        tokens.pop_front();
        if ( tokens.empty() )
            return makeError( GPG_ERR_MISSING_VALUE );
        keyword = tokens.front().constData();
        tokens.pop_front();
    }

    bool optionsExpected = true;
    QByteArray output;
    Q_FOREACH( QByteArray token, tokens ) {
        if ( token == "--" )
            optionsExpected = false;
        else if ( optionsExpected && token.startsWith( "--" ) )
            if ( token == "--inquire" )
                return makeError( GPG_ERR_DUP_VALUE ); // duplicate
            else
                return makeError( GPG_ERR_UNKNOWN_OPTION );
        else
            if ( output.isEmpty() )
                output = token;
            else
                output += ' ' + token;
    }

    // aaand ACTION:

    // 1. echo the command line though the status channel
    if ( const int err = sendStatus( "ECHO", output.constData() ) )
        return err;

    // 2. if --inquire was given, inquire more data from the client:
    if ( !keyword.empty() )
        if ( const int err = inquire( keyword.c_str(), this,
                                      SLOT(slotInquireData(int,QByteArray)) ) )
            return err;
        else
            ++d->operationsInFlight;

    // 3. if INPUT was given, start the data pump for input->output
    if ( QIODevice * const in = bulkInputDevice( "IN" ) ) {
        QIODevice * const out = bulkOutputDevice( "OUT" );

        ++d->operationsInFlight;

        connect( in, SIGNAL(readyRead()), this, SLOT(slotInputReadyRead()) );
        connect( out, SIGNAL(bytesWritten(qint64)), this, SLOT(slotOutputBytesWritten()) );

        if ( in->bytesAvailable() )
            slotInputReadyRead();
    }

    if ( !d->operationsInFlight )
        done();
    return 0;
}

void EchoCommand::canceled() {

}

void EchoCommand::slotInquireData( int rc, const QByteArray & data ) {

    --d->operationsInFlight;

    if ( rc )
        done( rc );

    //else if ( const int err = sendData( data ) )
    else if ( const int err = sendStatus( "ECHOINQ", data ) )
        done( err );

    else if ( !d->operationsInFlight )
        done();

}

void EchoCommand::slotInputReadyRead() {
    QIODevice * const in = bulkInputDevice( "IN" );
    assert( in );

    QByteArray buffer;
    buffer.resize( in->bytesAvailable() );
    const qint64 read = in->read( buffer.data(), buffer.size() );
    if ( read == - 1 ) {
        done( makeError( GPG_ERR_EIO ) );
        return;
    }
    if ( read == 0 || !in->isSequential() && read == in->size() )
        in->close();

    buffer.resize( read );
    d->buffer += buffer;

    slotOutputBytesWritten();
}

void EchoCommand::slotOutputBytesWritten() {
    QIODevice * const out = bulkOutputDevice( "OUT" );
    assert( out );

    if ( !d->buffer.isEmpty() ) {

        if ( out->bytesToWrite() )
            return;

        const qint64 written = out->write( d->buffer );
        if ( written == -1 ) {
            done( makeError( GPG_ERR_EIO ) );
            return;
        }
        d->buffer.remove( 0, written );

    }

    if ( out->isOpen() && d->buffer.isEmpty() && !bulkInputDevice( "IN" )->isOpen() ) {
        out->close();
        if ( !--d->operationsInFlight )
            done();
    }
}

#include "moc_echocommand.cpp"
<|endoftext|>