• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegames API Reference
  • KDE Home
  • Contact Us
 

kgoldrunner

  • sources
  • kde-4.14
  • kdegames
  • kgoldrunner
  • src
kgrgameio.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  * Copyright 2006 Ian Wadham <iandw.au@gmail.com> *
3  * Copyright 2009 Ian Wadham <iandw.au@gmail.com> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17  ****************************************************************************/
18 
19 #include "kgrgameio.h"
20 
21 #include <QWidget>
22 #include <QDir>
23 
24 #include <KLocale>
25 #include <KDebug>
26 
27 KGrGameIO::KGrGameIO (QWidget * pView)
28  :
29  view (pView)
30 {
31 }
32 
33 IOStatus KGrGameIO::fetchGameListData
34  (const Owner o, const QString & dir, QList<KGrGameData *> & gameList,
35  QString & filePath)
36 {
37  QDir directory (dir);
38  QStringList pattern;
39  pattern << "game_*";
40  QStringList files = directory.entryList (pattern, QDir::Files, QDir::Name);
41 
42  // KGr 3 has a game's data and all its levels in one file.
43  // KGr 2 has all game-data in "games.dat" and each level in a separate file.
44  bool kgr3Format = (files.count() > 0);
45  if (! kgr3Format) {
46  files << "games.dat";
47  }
48 
49  // Loop to read each file containing game-data.
50  foreach (const QString &filename, files) {
51  if (filename == "game_ende.txt") {
52  continue; // Skip the "ENDE" file.
53  }
54 
55  filePath = dir + filename;
56  KGrGameData * g = initGameData (o);
57  gameList.append (g);
58  // kDebug()<< "GAME PATH:" << filePath;
59 
60  openFile.setFileName (filePath);
61 
62  // Check that the game-file exists.
63  if (! openFile.exists()) {
64  return (NotFound);
65  }
66 
67  // Open the file for read-only.
68  if (! openFile.open (QIODevice::ReadOnly)) {
69  return (NoRead);
70  }
71 
72  char c;
73  QByteArray textLine;
74  QByteArray gameName;
75 
76  // Find the first line of game-data.
77  c = getALine (kgr3Format, textLine);
78  if (kgr3Format) {
79  while ((c != 'G') && (c != '\0')) {
80  c = getALine (kgr3Format, textLine);
81  }
82  }
83  if (c == '\0') {
84  openFile.close();
85  return (UnexpectedEOF); // We reached end-of-file unexpectedly.
86  }
87 
88  // Loop to extract the game-data for each game on the file.
89  while (c != '\0') {
90  if (kgr3Format && (c == 'L')) {
91  break; // End of KGr 3 game-file header.
92  }
93  // Decode line 1 of the game-data.
94  QList<QByteArray> fields = textLine.split (' ');
95  g->nLevels = fields.at (0).toInt();
96  g->rules = fields.at (1).at (0);
97  g->prefix = fields.at (2);
98  // kDebug() << "Levels:" << g->nLevels << "Rules:" << g->rules <<
99  // "Prefix:" << g->prefix;
100 
101  if (kgr3Format) {
102  // KGr 3 Format: get skill, get game-name from next line.
103  g->skill = fields.at (3).at (0);
104  c = getALine (kgr3Format, textLine);
105  if (c == ' ') {
106  gameName = removeNewline (textLine);
107  g->name = i18n (gameName.constData());
108  }
109  }
110  else {
111  // KGr 2 Format: get game-name from end of line 1.
112  int n = 0;
113  // Skip the first 3 fields and extract the rest of the line.
114  n = textLine.indexOf (' ', n) + 1;
115  n = textLine.indexOf (' ', n) + 1;
116  n = textLine.indexOf (' ', n) + 1;
117  gameName = removeNewline (textLine.right (textLine.size() - n));
118  g->name = i18n (gameName.constData());
119  }
120  // kDebug() << "Skill:" << g->skill << "Name:" << g->name;
121 
122  // Loop to accumulate lines of about-data. If kgr3Format, exit on
123  // EOF or 'L' line. If not kgr3Format, exit on EOF or numeric line.
124  while (c != '\0') {
125  c = getALine (kgr3Format, textLine);
126  if ((c == '\0') ||
127  (kgr3Format && (c == 'L')) ||
128  ((! kgr3Format) &&
129  (textLine.at (0) >= '0') && (textLine.at (0) <= '9'))) {
130  break;
131  }
132  g->about.append (textLine);
133  }
134  g->about = removeNewline (g->about); // Remove final '\n'.
135  // kDebug() << "Info about: [" + g->about + "]";
136 
137  if ((! kgr3Format) && (c != '\0')) {
138  filePath = dir + filename;
139  g = initGameData (o);
140  gameList.append (g);
141  }
142  } // END: game-data loop
143 
144  openFile.close();
145 
146  } // END: filename loop
147 
148  return (OK);
149 }
150 
151 bool KGrGameIO::readLevelData (const QString & dir,
152  const QString & prefix,
153  const int levelNo, KGrLevelData & d)
154 {
155  kDebug() << "dir" << dir << "Level" << prefix << levelNo;
156  QString filePath;
157  IOStatus stat = fetchLevelData
158  (dir, prefix, levelNo, d, filePath);
159  switch (stat) {
160  case NotFound:
161  KGrMessage::information (view, i18n ("Read Level Data"),
162  i18n ("Cannot find file '%1'.", filePath));
163  break;
164  case NoRead:
165  case NoWrite:
166  KGrMessage::information (view, i18n ("Read Level Data"),
167  i18n ("Cannot open file '%1' for read-only.", filePath));
168  break;
169  case UnexpectedEOF:
170  KGrMessage::information (view, i18n ("Read Level Data"),
171  i18n ("Reached end of file '%1' without finding level data.",
172  filePath));
173  break;
174  case OK:
175  break;
176  }
177 
178  return (stat == OK);
179 }
180 
181 IOStatus KGrGameIO::fetchLevelData
182  (const QString & dir, const QString & prefix,
183  const int level, KGrLevelData & d, QString & filePath)
184 {
185  filePath = getFilePath (dir, prefix, level);
186  d.level = level; // Level number.
187  d.width = FIELDWIDTH; // Default width of layout grid (28 cells).
188  d.height = FIELDHEIGHT; // Default height of layout grid (20 cells).
189  d.layout = ""; // Codes for the level layout (mandatory).
190  d.name = ""; // Level name (optional).
191  d.hint = ""; // Level hint (optional).
192 
193  // kDebug()<< "LEVEL PATH:" << filePath;
194  openFile.setFileName (filePath);
195 
196  // Check that the level-file exists.
197  if (! openFile.exists()) {
198  return (NotFound);
199  }
200 
201  // Open the file for read-only.
202  if (! openFile.open (QIODevice::ReadOnly)) {
203  return (NoRead);
204  }
205 
206  char c;
207  QByteArray textLine;
208  IOStatus result = UnexpectedEOF;
209 
210  // Determine whether the file is in KGoldrunner v3 or v2 format.
211  bool kgr3Format = (filePath.endsWith (".txt"));
212 
213  if (kgr3Format) {
214  // In KGr 3 format, if a line starts with 'L', check the number.
215  while ((c = getALine (kgr3Format, textLine)) != '\0') {
216  if ((c == 'L') && (textLine.left (3).toInt() == level)) {
217  break; // We have found the required level.
218  }
219  }
220  if (c == '\0') {
221  openFile.close(); // We reached end-of-file.
222  return (UnexpectedEOF);
223  }
224  }
225 
226  // Read in the character-codes for the level layout.
227  if ((c = getALine (kgr3Format, textLine)) == ' ') {
228  result = OK;
229  d.layout = removeNewline (textLine); // Remove '\n'.
230 
231  // Look for a line containing a level name (optional).
232  if ((c = getALine (kgr3Format, textLine)) == ' ') {
233  d.name = removeNewline (textLine); // Remove '\n'.
234 
235  // Look for one or more lines containing a hint (optional).
236  while ((c = getALine (kgr3Format, textLine)) == ' ') {
237  d.hint.append (textLine);
238  }
239  d.hint = removeNewline (d.hint); // Remove final '\n'.
240  }
241  }
242 
243  // kDebug() << "Level:" << level << "Layout length:" << d.layout.size();
244  // kDebug() << "Name:" << "[" + d.name + "]";
245  // kDebug() << "Hint:" << "[" + d.hint + "]";
246 
247  openFile.close();
248  return (result);
249 }
250 
251 QString KGrGameIO::getFilePath
252  (const QString & dir, const QString & prefix, const int level)
253 {
254  QString filePath = ((level == 0) ? "ende" : prefix);
255  filePath = dir + "game_" + filePath + ".txt";
256  QFile test (filePath);
257 
258  // See if there is a game-file or "ENDE" screen in KGoldrunner 3 format.
259  if (test.exists()) {
260  return (filePath);
261  }
262 
263  // If not, we are looking for a file in KGoldrunner 2 format.
264  if (level == 0) {
265  // End of game: show the "ENDE" screen.
266  filePath = dir + "levels/level000.grl";
267  }
268  else {
269  QString num = QString::number (level).rightJustified (3,'0');
270  filePath = dir + "levels/" + prefix + num + ".grl";
271  }
272 
273  return (filePath);
274 }
275 
276 char KGrGameIO::getALine (const bool kgr3, QByteArray & line)
277 {
278  char c;
279  line = "";
280  while (openFile.getChar (&c)) {
281  line = line.append (c);
282  if (c == '\n') {
283  break;
284  }
285  }
286 
287  // kDebug() << "Raw line:" << line;
288  if (line.size() <= 0) {
289  // Return a '\0' byte if end-of-file.
290  return ('\0');
291  }
292  if (kgr3) {
293  // In KGr 3 format, strip off leading and trailing syntax.
294  if (line.startsWith ("// ")) {
295  line = line.right (line.size() - 3);
296  // kDebug() << "Stripped comment is:" << line;
297  }
298  else {
299  if (line.startsWith (" i18n(\"")) {
300  line = ' ' + line.right (line.size() - 7);
301  }
302  else if (line.startsWith (" NOTi18n(\"")) {
303  line = ' ' + line.right (line.size() - 10);
304  }
305  else if (line.startsWith (" \"")) {
306  line = ' ' + line.right (line.size() - 2);
307  }
308  if (line.endsWith ("\");\n")) {
309  line = line.left (line.size() - 4) + '\n';
310  }
311  else if (line.endsWith ("\\n\"\n")) {
312  line = line.left (line.size() - 4) + '\n';
313  }
314  else if (line.endsWith ("\"\n")) {
315  line = line.left (line.size() - 2);
316  }
317  // kDebug() << "Stripped syntax is:" << line;
318  }
319  // In Kgr 3 format, return the first byte if not end-of-file.
320  c = line.at (0);
321  line = line.right (line.size() - 1);
322  return (c);
323  }
324  else {
325  // In KGr 2 format, return a space if not end-of-file.
326  return (' ');
327  }
328 }
329 
330 QByteArray KGrGameIO::removeNewline (const QByteArray & line)
331 {
332  int len = line.size();
333  if ((len > 0) && (line.endsWith ('\n'))) {
334  return (line.left (len -1));
335  }
336  else {
337  return (line);
338  }
339 }
340 
341 KGrGameData * KGrGameIO::initGameData (Owner o)
342 {
343  KGrGameData * g = new KGrGameData;
344  g->owner = o; // Owner of the game: "System" or "User".
345  g->nLevels = 0; // Number of levels in the game.
346  g->rules = 'T'; // Game's rules: KGoldrunner or Traditional.
347  g->prefix = ""; // Game's filename prefix.
348  g->skill = 'N'; // Game's skill: Tutorial, Normal or Champion.
349  g->width = FIELDWIDTH; // Default width of layout grid (28 cells).
350  g->height = FIELDHEIGHT; // Default height of layout grid (20 cells).
351  g->name = ""; // Name of the game (translated, if System game).
352  g->about = ""; // Optional text about the game (untranslated).
353  return (g);
354 }
355 
356 bool KGrGameIO::safeRename (QWidget * theView, const QString & oldName,
357  const QString & newName)
358 {
359  QFile newFile (newName);
360  if (newFile.exists()) {
361  // On some file systems we cannot rename if a file with the new name
362  // already exists. We must delete the existing file, otherwise the
363  // upcoming QFile::rename will fail, according to Qt4 docs. This
364  // seems to be true with reiserfs at least.
365  if (! newFile.remove()) {
366  KGrMessage::information (theView, i18n ("Rename File"),
367  i18n ("Cannot delete previous version of file '%1'.", newName));
368  return false;
369  }
370  }
371  QFile oldFile (oldName);
372  if (! oldFile.rename (newName)) {
373  KGrMessage::information (theView, i18n ("Rename File"),
374  i18n ("Cannot rename file '%1' to '%2'.", oldName, newName));
375  return false;
376  }
377  return true;
378 }
379 
380 #include "kgrgameio.moc"
KGrLevelData::hint
QByteArray hint
Level hint (optional).
Definition: kgrglobals.h:111
QWidget
KGrLevelData::height
int height
Height of grid, in cells.
Definition: kgrglobals.h:108
UnexpectedEOF
Definition: kgrgameio.h:29
KGrGameData::height
int height
Height of grid, in cells.
Definition: kgrglobals.h:97
NotFound
Definition: kgrgameio.h:29
KGrGameData::prefix
QString prefix
Game's filename prefix.
Definition: kgrglobals.h:94
QByteArray::toInt
int toInt(bool *ok, int base) const
QByteArray::split
QList< QByteArray > split(char sep) const
KGrGameIO::KGrGameIO
KGrGameIO(QWidget *pView)
Default constructor.
Definition: kgrgameio.cpp:27
KGrGameData::owner
Owner owner
Owner of the game: "System" or "User".
Definition: kgrglobals.h:91
KGrGameData
KGrGameData structure: contains attributes of a KGoldrunner game.
Definition: kgrglobals.h:88
QByteArray
QByteArray::at
char at(int i) const
QFile::remove
bool remove()
KGrGameIO::fetchGameListData
IOStatus fetchGameListData(const Owner o, const QString &dir, QList< KGrGameData * > &gameList, QString &filePath)
Find and read data for games, into a list of KGrGameData structures.
Definition: kgrgameio.cpp:34
QList::at
const T & at(int i) const
QFile::rename
bool rename(const QString &newName)
KGrGameData::width
int width
Width of grid, in cells.
Definition: kgrglobals.h:96
QByteArray::startsWith
bool startsWith(const QByteArray &ba) const
FIELDHEIGHT
const int FIELDHEIGHT
Definition: kgrglobals.h:49
KGrLevelData::layout
QByteArray layout
Codes for the level layout (mandatory).
Definition: kgrglobals.h:109
QFile::exists
bool exists() const
KGrGameIO::fetchLevelData
IOStatus fetchLevelData(const QString &dir, const QString &prefix, const int level, KGrLevelData &d, QString &filePath)
Find and read data for a level of a game, into a KGrLevelData structure.
Definition: kgrgameio.cpp:182
QFile
NoWrite
Definition: kgrgameio.h:29
KGrGameData::rules
char rules
Game's rules: KGoldrunner or Traditional.
Definition: kgrglobals.h:93
QIODevice::getChar
bool getChar(char *c)
QByteArray::indexOf
int indexOf(char ch, int from) const
KGrGameIO::readLevelData
bool readLevelData(const QString &dir, const QString &prefix, const int levelNo, KGrLevelData &d)
Find and read data for a level of a game.
Definition: kgrgameio.cpp:151
QString::number
QString number(int n, int base)
QList::count
int count(const T &value) const
KGrGameData::about
QByteArray about
Optional info about game (untranslated).
Definition: kgrglobals.h:99
QList::append
void append(const T &value)
QString::rightJustified
QString rightJustified(int width, QChar fill, bool truncate) const
FIELDWIDTH
const int FIELDWIDTH
Definition: kgrglobals.h:48
QByteArray::constData
const char * constData() const
QByteArray::right
QByteArray right(int len) const
KGrMessage::information
static void information(QWidget *parent, const QString &caption, const QString &text, const QString &dontShowAgain=QString())
Definition: kgrdialog.cpp:306
KGrLevelData
KGrLevelData structure: contains attributes of a KGoldrunner level.
Definition: kgrglobals.h:103
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
KGrGameData::nLevels
int nLevels
Number of levels in the game.
Definition: kgrglobals.h:92
QString
QList< KGrGameData * >
QStringList
KGrLevelData::level
int level
Level number.
Definition: kgrglobals.h:106
QByteArray::append
QByteArray & append(char ch)
NoRead
Definition: kgrgameio.h:29
QDir
IOStatus
IOStatus
Return values from I/O operations.
Definition: kgrgameio.h:29
QByteArray::left
QByteArray left(int len) const
QDir::entryList
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
KGrLevelData::width
int width
Width of grid, in cells.
Definition: kgrglobals.h:107
OK
Definition: kgrgameio.h:29
KGrGameData::name
QString name
Name of game (translated, if System game).
Definition: kgrglobals.h:98
QByteArray::size
int size() const
kgrgameio.h
KGrGameData::skill
char skill
Game's skill: Tutorial, Normal or Champion.
Definition: kgrglobals.h:95
KGrGameIO::safeRename
static bool safeRename(QWidget *theView, const QString &oldName, const QString &newName)
Definition: kgrgameio.cpp:356
QByteArray::endsWith
bool endsWith(const QByteArray &ba) const
Owner
Owner
Definition: kgrglobals.h:26
KGrLevelData::name
QByteArray name
Level name (optional).
Definition: kgrglobals.h:110
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:18:24 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kgoldrunner

Skip menu "kgoldrunner"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdegames API Reference

Skip menu "kdegames API Reference"
  • granatier
  • kapman
  • kblackbox
  • kgoldrunner
  • kigo
  • kmahjongg
  • KShisen
  • ksquares
  • libkdegames
  •   highscore
  •   libkdegamesprivate
  •     kgame
  • libkmahjongg
  • palapeli
  •   libpala

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal