1 | #include "format.h" |
---|
2 | #include <QDebug> |
---|
3 | |
---|
4 | using namespace QPunchCard; |
---|
5 | |
---|
6 | QList<QString> FileFormatFactory::availableFormats() { |
---|
7 | QList<QString> ret; |
---|
8 | ret << "Jones Emulated Card Deck File" << "Punch Card Markup Language File"; |
---|
9 | return ret; |
---|
10 | } |
---|
11 | |
---|
12 | const FileFormat* FileFormatFactory::createFormat(const QString& name) { |
---|
13 | if(name == "Jones Emulated Card Deck File") |
---|
14 | return new JonesFileFormat; |
---|
15 | if(name == "Punch Card Markup Language File") |
---|
16 | return new PunchCardMarkupLanguageFormat; |
---|
17 | else { |
---|
18 | qDebug() << "FileFormatFactory: Invalid createFormat name: " << name; |
---|
19 | return 0; |
---|
20 | } |
---|
21 | } |
---|
22 | |
---|
23 | QString FileFormatFactory::autoDetectFormat(const QFile&) { |
---|
24 | // spaeter per magic bytes-Erkennung machen |
---|
25 | return QString("Jones Emulated Card Deck File"); |
---|
26 | } |
---|
27 | |
---|
28 | bool JonesFileFormat::read(QFile& file, Deck& deck) const { |
---|
29 | qDebug() << "Jones reading"; |
---|
30 | |
---|
31 | if(!file.isOpen()) { |
---|
32 | // oeffne Datei |
---|
33 | if(! file.open(QIODevice::ReadOnly)) |
---|
34 | return false; |
---|
35 | } |
---|
36 | |
---|
37 | // Now we have an open file at `file`. Use |
---|
38 | // QIODevice methods: |
---|
39 | |
---|
40 | // At first, check the file prefix (magic bytes) |
---|
41 | char char1, char2, char3; |
---|
42 | file.getChar(&char1); |
---|
43 | file.getChar(&char2); |
---|
44 | file.getChar(&char3); |
---|
45 | if( (char1 == 'H') && (char2 == '8') && (char3 == '0') ) { |
---|
46 | //this.default_col_length = 80; // hum... nice |
---|
47 | } else if ((char1 == 'H') && (char2 == '8') && (char3 == '2')) { |
---|
48 | //this.default_col_length = 82; |
---|
49 | return false; // hum... bad |
---|
50 | } else { |
---|
51 | // Fehler spezifizieren...: |
---|
52 | // Input file not a card file |
---|
53 | return false; |
---|
54 | } |
---|
55 | |
---|
56 | // Process card deck |
---|
57 | while( file.bytesAvailable() > 0 ) { |
---|
58 | //Card* cur_card = new Card(); |
---|
59 | Card cur_card; |
---|
60 | // try to read in 120 (body) + 3 (header) bytes |
---|
61 | QByteArray data = file.read(123); |
---|
62 | |
---|
63 | if( ((data[0] & 0x08) == 0) |
---|
64 | || ((data[1] & 0x08) == 0) |
---|
65 | || ((data[2] & 0x08) == 0)) { |
---|
66 | // This card was corrupt or there were no more data. |
---|
67 | // Break it. Don't save the current card any more. |
---|
68 | break; |
---|
69 | } |
---|
70 | |
---|
71 | /* This algorithm is based on the C algorithm |
---|
72 | of Jones */ |
---|
73 | int x = 3; |
---|
74 | for(int cur_col = 0; cur_col < 80; ) { |
---|
75 | /* read in 3 bytes */ |
---|
76 | int first = data[x++]; |
---|
77 | int second = data[x++]; |
---|
78 | int third = data[x++]; |
---|
79 | |
---|
80 | /* convert to 2 columns */ |
---|
81 | int even_col = (first << 4) | (second >> 4); |
---|
82 | int odd_col = ((second & 0017) << 8) | third; |
---|
83 | |
---|
84 | /* save the columns in the card */ |
---|
85 | // This is integer => Column conversion with |
---|
86 | // implicit knowledge that this followes the |
---|
87 | // Jones file format |
---|
88 | cur_card.column[cur_col++] = jones_integer_to_column(even_col); |
---|
89 | cur_card.column[cur_col++] = jones_integer_to_column(odd_col); |
---|
90 | } |
---|
91 | |
---|
92 | /* push card on the card deck*/ |
---|
93 | // TODO: Das muss irgendwie ggf. in das UNDO-System eingebaut |
---|
94 | // werden (hier falsche Stelle -- in Deck-Class muss das eingebaut |
---|
95 | // werden |
---|
96 | deck.push_back(cur_card); |
---|
97 | } // while ! eof |
---|
98 | |
---|
99 | file.close(); |
---|
100 | return true; |
---|
101 | } // jones reader |
---|
102 | |
---|
103 | // jones writer |
---|
104 | bool JonesFileFormat::write(QFile& file, const Deck& deck) const { |
---|
105 | qDebug() << "Jones writing"; |
---|
106 | |
---|
107 | if(!file.isOpen()) { |
---|
108 | // oeffne Datei |
---|
109 | if(! file.open(QIODevice::WriteOnly)) { |
---|
110 | qDebug() << "Failed to open file: " << file.errorString(); |
---|
111 | return false; |
---|
112 | } |
---|
113 | } |
---|
114 | |
---|
115 | int col_length = 80; |
---|
116 | |
---|
117 | // Write out file prefix |
---|
118 | qDebug() << "Beginning Jones writing"; |
---|
119 | file.putChar('H'); |
---|
120 | file.putChar('8'); |
---|
121 | file.putChar(col_length==80 ? '0' : '2'); |
---|
122 | |
---|
123 | //QVector::iterator i; |
---|
124 | |
---|
125 | //for(i = begin(); i != end(); i++ ) { |
---|
126 | for(int i=0; i < deck.count(); i++) { |
---|
127 | // iterate throught the Cards |
---|
128 | // erhmm... write a header... |
---|
129 | file.putChar(0x80); |
---|
130 | file.putChar(0x80); |
---|
131 | file.putChar(0x80); |
---|
132 | |
---|
133 | //int cur_col = 0; |
---|
134 | //int max_col = i->col_length; |
---|
135 | |
---|
136 | //while(cur_col < max_col) { |
---|
137 | for(int cur_col = 0; cur_col < 80; ) { |
---|
138 | char first, second, third; |
---|
139 | |
---|
140 | int even = jones_column_to_integer( deck.at(i).get(cur_col++) ); |
---|
141 | int odd = jones_column_to_integer( deck.at(i).get(cur_col++) ); |
---|
142 | |
---|
143 | first = even >> 4; |
---|
144 | second = ((even & 017) << 4) | (odd >> 8); |
---|
145 | third = odd & 00377; |
---|
146 | |
---|
147 | file.putChar(first); |
---|
148 | file.putChar(second); |
---|
149 | file.putChar(third); |
---|
150 | } // while columns |
---|
151 | } // for cards |
---|
152 | |
---|
153 | file.close(); |
---|
154 | qDebug() << "Jones File written."; |
---|
155 | return true; // done. |
---|
156 | } // jones writer |
---|
157 | |
---|
158 | /** |
---|
159 | * Like Douglas Jones says in his punchcard proposal: |
---|
160 | * |
---|
161 | * Top Bottom |
---|
162 | * _ _ _ _ _ _ _ _ _ _ _ _ |
---|
163 | * |_|_|_|_|_|_|_|_|_|_|_|_| |
---|
164 | * 12 11 0 1 2 3 4 5 6 7 8 9 |
---|
165 | * | | | |
---|
166 | * |Zone | Numeric | |
---|
167 | * |
---|
168 | **/ |
---|
169 | int JonesFileFormat::jones_column_to_integer(const Column& col) { |
---|
170 | static const int Mapping[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 14, 10, 11 }; |
---|
171 | // where 14 is a dummy position outside the range since column[10] is also |
---|
172 | // a dummy position ;-) |
---|
173 | |
---|
174 | int r; |
---|
175 | // das hier sollte im Idealfall gleich sein ;-) |
---|
176 | for(int i = 0; i < col.size() && i < (int)sizeof(Mapping); i++) |
---|
177 | r |= (col[i] << Mapping[i]); |
---|
178 | return r; |
---|
179 | } |
---|
180 | |
---|
181 | Column JonesFileFormat::jones_integer_to_column(int data) { |
---|
182 | static const int Mapping[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 14, 10, 11 }; |
---|
183 | // where 14 is a dummy position outside the range since column[10] is also |
---|
184 | // a dummy position ;-) |
---|
185 | |
---|
186 | // this is just the inverse... |
---|
187 | Column r; |
---|
188 | for(int i = 0; i < (int)sizeof(Mapping); i++) { |
---|
189 | r[i] = ( (1 << Mapping[i]) & data != 0 ); |
---|
190 | } |
---|
191 | return r; |
---|
192 | } |
---|