Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /branches/mty-makai/key.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 252 - (hide annotations) (download) (as text)
Mon Dec 27 03:23:48 2010 UTC (13 years, 3 months ago) by notanpe
File MIME type: text/x-csrc
File size: 15586 byte(s)
本家 R245 をベースに全てやりなおし。
1 notanpe 252 /***********************************************************************
2     *
3     * file: key.c
4     *
5     * $Id: key.c 241 2010-03-15 14:28:18Z chapuni $
6     *
7     */
8    
9     #include <assert.h>
10     #include <stdlib.h>
11    
12     #include "cp932.h"
13     #include "desconst.h"
14     #include "key.h"
15     #include "translate.h"
16    
17     #if USE_DT
18     #include "dt4.h"
19     #endif
20    
21     /* 拡張鍵クラス */
22     #define KCLS_DT0 64
23     #define KCLS_DT1 128
24     #define KCLS_K2 256
25    
26     #if USE_DT
27     /* 鍵キメ用辞書インデクス */
28     struct DT *kd[8 + 8];
29    
30     /* 辞書インデクス */
31     struct DT *dtidx[0x100 + 1];
32     #endif
33    
34     /* 指定されたクラスと入っているキーから、classify を行う */
35     void
36     key_make_map(struct KS_KEY *key, int n)
37     {
38     int i, j;
39     unsigned c = key->map[n][key->key[n]];
40    
41     #if USE_DT
42     if (3 <= n && n < 7 && kd[n - 3])
43     {
44     /* 辞書のケツの文字。後ろにナニヤラキャラクタが来る */
45     c = kd[n - 3]->c[0];
46     if ((0x81 <= c && c <= 0x9F)
47     || (0xE0 <= c && c <= 0xFC))
48     c = KCLS_K2;
49     else
50     c = (cp932[256 * key->key[n]]
51     | cp932[256 * (key->key[n] ^ 0x80)]);
52     #if DEBUG>=1
53     printf("*n=%d, key=%02X, cls=%04X\n",
54     n,
55     key[n],
56     c);
57     #endif
58     }
59     else if (2 <= n && n < 6 && kd[n - 2])
60     {
61     return;
62     }
63     else if (1 <= n && n < 5 && kd[n - 1])
64     {
65     return;
66     }
67     #if USE_DT
68     else if (1 <= n && n < 5 && !kd[n - 1]
69     //&& (c & KCLS_K2)
70     && (c & KCLS_DT1))
71     {
72     /* 漢字2文字を拾っていきまつ */
73     #if DEBUG>=1
74     printf("(%d)%02X %02X(%02X:%02X:%02X:%02X)\n",
75     n, key->key[n - 1], key->key[n],
76     cp932[(256 * key->key[n - 1] + key->key[n])],
77     cp932[(256 * key->key[n - 1] + key->key[n]) ^ 0x0080],
78     cp932[(256 * key->key[n - 1] + key->key[n]) ^ 0x8000],
79     cp932[(256 * key->key[n - 1] + key->key[n]) ^ 0x8080]);
80     #endif
81     if (n != 1 && n != 2
82     && (cp932[(256 * key->key[n - 1] + key->key[n]) ^ 0x0080] & KCLS_DT1))
83     key->key[n] ^= 0x80;
84     else if (n != 2 && n != 3
85     && (cp932[(256 * key->key[n - 1] + key->key[n]) ^ 0x8000] & KCLS_DT1))
86     key->key[n - 1] ^= 0x80;
87     else if (n > 3 && (cp932[(256 * key->key[n - 1] + key->key[n]) ^ 0x8080] & KCLS_DT1))
88     key->key[n - 1] ^= 0x80, key->key[n] ^= 0x80;
89     if (cp932[256 * key->key[n - 1] + key->key[n]] & KCLS_DT1)
90     {
91     for (kd[n - 1] = dtidx[key->key[n - 1]];
92     kd[n - 1]->c[1] != key->key[n];
93     kd[n - 1]++)
94     assert(kd[n - 1]->c[0] == key->key[n - 1]);
95     #if DEBUG>=1
96     printf("(%02X%02X:%02X%02X)%c%c%c%c\n",
97     kd[n - 1]->c[0],
98     kd[n - 1]->c[1],
99     kd[n - 1]->c[2],
100     kd[n - 1]->c[3],
101     kd[n - 1]->c[0],
102     kd[n - 1]->c[1],
103     kd[n - 1]->c[2],
104     kd[n - 1]->c[3]);
105     #endif
106     return;
107     }
108     }
109     else if (n < 4 && (c & KCLS_DT0) && kd[n] == NULL)
110     {
111     /* カタカナ埋め込みいきます */
112     assert(kd[n] == NULL);
113     #if DEBUG>=1
114     printf("n=%d, key=%02X\n", n, key->key[n]);
115     #endif
116     kd[n] = dtidx[key->key[n]];
117     if (!kd[n]
118     && !(n == 1 || n == 2)
119     && dtidx[key->key[n] ^ 0x80])
120     {
121     key->key[n] ^= 0x80;
122     kd[n] = dtidx[key->key[n]];
123     }
124     if (kd[n])
125     return;
126     }
127     #endif
128     else
129     {
130     kd[n] = NULL;
131     }
132     #endif
133    
134     /* 最後の部分は class map を生成する必要ナシ */
135     if (n >= 6)
136     return;
137    
138     for (i = 0; i < 256; i++)
139     {
140     unsigned bm = 0;
141     #if 1
142     if (c & KCLS_K1)
143     {
144     if (cp932[256 * key->key[n] + i] & KCLS_K1)
145     bm |= KCLS_K2 | (cp932[256 * key->key[n] + i] & KCLS_DT1);
146     if (cp932[256 * (key->key[n] ^ 0x80) + i] & KCLS_K1)
147     bm |= KCLS_K2 | (cp932[256 * (key->key[n] ^ 0x80) + i] & KCLS_DT1);
148     #if 0
149     bm |= ((cp932[256 * key->key[n] + i] & KCLS_K1)
150     || (cp932[256 * (key->key[n] ^ 0x80) + i] & KCLS_K1)
151     ? KCLS_K2 : 0);
152     #endif
153     }
154     if (c & (KCLS_AN | KCLS_KA | KCLS_K2))
155     for (j = 0; j < 256; j++)
156     {
157     bm |= cp932[256 * i + j] & (KCLS_AN | KCLS_KA | KCLS_K1
158     | KCLS_DT0);
159     #if 0
160     if (j >= 127 && !(n == 0 || n == 1))
161     break;
162     #endif
163     }
164     key->map[n + 1][i] = bm;
165     #endif
166     if (i >= 128 && !(n == 0 || n == 1))
167     key->map[n + 1][i - 128] |= key->map[n + 1][i];
168     }
169    
170     if (n < 6)
171     key->map[n + 1][0x00] = key->map[n + 1][0x80] = 0;
172     if (n == 6)
173     key->map[7][0x00] |= KCLS_AN;
174     }
175    
176     #if USE_DT
177     unsigned
178     dt_get(int kdn,
179     int xn,
180     int n,
181     int ch)
182     {
183     int i;
184     #if DEBUG>=1
185     printf("*dt_get(%d)%c%c%c%c(%02X%02X:%02X%02X)->ch=%d",
186     n,
187     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
188     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
189     ch);
190     #endif
191     /* まずは数える */
192     for (i = 0;
193     kd[kdn][i].c[xn] == kd[kdn]->c[xn];
194     i++)
195     ;
196     assert(i > 0);
197     kd[kdn] += ch % i;
198     #if DEBUG>=1
199     printf("/%d\n dt_get: %c%c%c%c(%02X%02X:%02X%02X)->ch=%d\n",
200     i,
201     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
202     kd[kdn]->c[0], kd[kdn]->c[1], kd[kdn]->c[2], kd[kdn]->c[3],
203     ch);
204     #endif
205     return kd[kdn]->c[n];
206     }
207     #endif
208    
209     /* マップから文字を拾ってセット */
210     unsigned
211     key_set(struct KS_KEY *key, int n, unsigned ch)
212     {
213     int cnt = 0, i;
214    
215     #if USE_DT
216     if (3 <= n && n < 7 && kd[n - 3])
217     {
218     return dt_get(n - 3, 2, 3, ch);
219     return kd[n - 3]->c[3];
220     }
221     else if (2 <= n && n < 6 && kd[n - 2])
222     {
223     return dt_get(n - 2, 1, 2, ch);
224     return kd[n - 2]->c[2];
225     }
226     else if (1 <= n && n < 5 && kd[n - 1])
227     {
228     return dt_get(n - 1, 0, 1, ch);
229     return kd[n - 1]->c[1];
230     }
231     #endif
232    
233     #if DEBUG>=3
234     if (cnt == 0)
235     {
236     printf("n=%d, ch=%d, (n-1)=%02X\n", n, ch, key[n - 1]);
237     int j;
238     for (i = 0; i < 16; i++)
239     {
240     printf("map[0x%02X] =", 16 * i);
241     for (j = 0; j < 16; j++)
242     printf(" %03X", kcls[n].map[16 * i + j]);
243     printf("\n");
244     }
245     }
246     #endif
247     for (i = 0; i < 256; i++)
248     {
249     #if 1
250     /* 鳥屋っぽーい */
251     if (1 <= n && n <= 2 && '.' < i && i <= 'z')
252     continue;
253     #endif
254     if (key->map[n][i])
255     {
256     if (ch-- == 0)
257     return i;
258     cnt++;
259     }
260     if (n != 1 && n != 2 && i >= 127)
261     break;
262     }
263     /* 見つからなかったのでもいっぺん */
264     assert(cnt > 0);
265     ch %= cnt;
266     for (i = 0; i < 256; i++)
267     if (key->map[n][i])
268     {
269     #if 1
270     /* 鳥屋っぽーい */
271     if (1 <= n && n <= 2 && '.' < i && i <= 'z')
272     continue;
273     #endif
274     if (ch-- == 0)
275     return i;
276     }
277     assert(!"not matched");
278     return 0;
279     }
280    
281     /* bitwise key をセット */
282     void
283     key_set64(struct KEY *key64,
284     int n,
285     unsigned k,
286     unsigned vk,
287     unsigned sk)
288     {
289     int i, j;
290     if (!((vk | sk) & 0x7F))
291     return;
292    
293     for (i = 0; i < 7; i++)
294     {
295     if (n == 7 && i < N_STRIDE) continue;
296     if (sk & (1 << i))
297     {
298     /* セット */
299     int o = tr_pc1[n][6 - i] - 1;
300     if (o < 28)
301     {
302     assert(o >= 0);
303     for (j = 0; j < N_ALU; j++)
304     key64->k[0][0][o].a[j]
305     = key64->k[0][1][o].a[j]
306     = -!!(k & (1 << i));
307     }
308     else
309     {
310     assert(o >= 28);
311     assert(o < 56);
312     for (j = 0; j < N_ALU; j++)
313     key64->k[1][0][o - 28].a[j]
314     = key64->k[1][1][o - 28].a[j]
315     = -!!(k & (1 << i));
316     }
317     }
318     else if (vk & (1 << i))
319     {
320     /* 反転 */
321     int o = tr_pc1[n][6 - i] - 1;
322     if (o < 28)
323     {
324     assert(o >= 0);
325     for (j = 0; j < N_ALU; j++)
326     key64->k[0][0][o].a[j]
327     = key64->k[0][1][o].a[j]
328     = ~key64->k[0][0][o].a[j];
329     }
330     else
331     {
332     assert(o >= 28);
333     assert(o < 56);
334     for (j = 0; j < N_ALU; j++)
335     key64->k[1][0][o - 28].a[j]
336     = key64->k[1][1][o - 28].a[j]
337     = ~key64->k[1][0][o - 28].a[j];
338     }
339     }
340     }
341     }
342    
343     /* 指定されたクラスの開始値にリセット
344     直前の文字のクラスに縛られる */
345     int
346     key_reset(struct KS_KEY *key, int n)
347     {
348     if (n >= 8)
349     return 1;
350     if (n == 7)
351     {
352     key->key[7] = 0;
353     return 1;
354     }
355    
356     /* 0-2 文字目はランダムに決める
357     3 文字目以降は初期値に */
358     if (n >= KEY_SHUFFLE_POS)
359     key->key[n] = key_set(key, n, 0);
360     else
361     key->key[n] = key_set(key, n, rand());
362    
363     #if DEBUG>=3
364     printf("key[%d]=%02X ncls=%04X\n", n, key[n], kcls[n].map[key[n]]);
365     #endif
366    
367     /* セットされた文字を元に、次キャラの文字クラスを決める */
368     key_make_map(key, n);
369    
370     return key_reset(key, n + 1);
371     }
372    
373     /* 指定された鍵空間の中で、キーをひとつ進める
374     安全にインクリメントできた場合 true を返す */
375     int
376     key_inc(struct KS_KEY *key, int n, int e)
377     {
378     if (n >= 8)
379     return 0;
380     else if (n == 7)
381     {
382     /* 最後のバイト */
383     uint8_t o_k = (key->key[7] + (1 << N_STRIDE)) & 0x7F;
384     if (!o_k)
385     return 0; /* インクリメントできなかったときは次へ進めず待つ */
386    
387     /* 進める */
388     key->key[7] = o_k;
389     return 1;
390     }
391     else if (n >= e - 1)
392     {
393     /* do nothing */
394     }
395     else if (key_inc(key, n + 1, e)
396     /*
397     && key_inc(n + 1)
398     && key_inc(n + 1)
399     && key_inc(n + 1)*/
400     )
401     return 1;
402    
403     /* Salt はインクリメントしない約束にする */
404     if (n == 1 || n == 2)
405     return 1;
406    
407     #if DEBUG>=3
408     printf("key_inc(n=%d,ck=%02X)\n", n, key->key[n]);
409     #endif
410    
411     #if USE_DT
412     /* 辞書語はインクリメントしていい約束にする */
413     if (3 <= n && n < 7 && kd[n - 3])
414     {
415     if ((key->key[n - 3] & 0x7F) == ((kd[n - 3] + 1)->c[0] & 0x7F)
416     && (key->key[n - 2] & 0x7F) == ((kd[n - 3] + 1)->c[1] & 0x7F)
417     && (key->key[n - 1] & 0x7F) == ((kd[n - 3] + 1)->c[2] & 0x7F))
418     {
419     memcpy(&key->key[n - 3], &(++kd[n - 3])->c[0], 4);
420     #if DEBUG>=2
421     printf(">dt_get:%c%c%c%c(%02X%02X:%02X%02X)\n",
422     kd[n - 3]->c[0], kd[n - 3]->c[1], kd[n - 3]->c[2], kd[n - 3]->c[3],
423     kd[n - 3]->c[0], kd[n - 3]->c[1], kd[n - 3]->c[2], kd[n - 3]->c[3]);
424     #endif
425     return 1;
426     }
427     else
428     {
429     return 0;
430     }
431     }
432     else if (2 <= n && n < 6 && kd[n - 2])
433     {
434     if ((key->key[n - 2] & 0x7F) == ((kd[n - 2] + 1)->c[0] & 0x7F)
435     && (key->key[n - 1] & 0x7F) == ((kd[n - 2] + 1)->c[1] & 0x7F))
436     {
437     memcpy(&key->key[n - 2], &(++kd[n - 2])->c[0], 4);
438     #if DEBUG>=2
439     printf(">dt_get:%c%c%c%c(%02X%02X:%02X%02X)\n",
440     kd[n - 2]->c[0], kd[n - 2]->c[1], kd[n - 2]->c[2], kd[n - 2]->c[3],
441     kd[n - 2]->c[0], kd[n - 2]->c[1], kd[n - 2]->c[2], kd[n - 2]->c[3]);
442     #endif
443     return 1;
444     }
445     else
446     {
447     return 0;
448     }
449     if (kd[n - 2]->c[0] == key->key[n - 2])
450     return 1;
451     else
452     return 0;
453     }
454     else if (1 <= n && n < 5 && kd[n - 1])
455     {
456     unsigned c2 = kd[n - 1]->c[0];
457     if ((0x81 <= c2 && c2 <= 0x9F)
458     || (0xE0 <= c2 && c2 <= 0xFC))
459     {
460     kd[n - 1] = NULL;
461     #if 0
462     if (!(n == 1 && n == 2))
463     key->key[n] &= 0x7F;
464     if (!(n == 2 && n == 3))
465     key->key[n - 1] &= 0x7F;
466     #endif
467     key_make_map(n - 1);
468     }
469     else if ((key->key[n - 1] & 0x7F) == ((kd[n - 1] + 1)->c[0] & 0x7F))
470     {
471     memcpy(&key->key[n - 1], &(++kd[n - 1])->c[0], 4);
472     #if DEBUG>=2
473     printf(">dt_get:%c%c%c%c(%02X%02X:%02X%02X)\n",
474     kd[n - 1]->c[0], kd[n - 1]->c[1], kd[n - 1]->c[2], kd[n - 1]->c[3],
475     kd[n - 1]->c[0], kd[n - 1]->c[1], kd[n - 1]->c[2], kd[n - 1]->c[3]);
476     #endif
477     return 1;
478     }
479     else
480     {
481     return 0;
482     }
483     #if 0
484     if (kd[n - 1]->c[0] == key->key[n - 1])
485     return 1;
486     else
487     return 0;
488     #endif
489     }
490     else if (n < 4 && kd[n])
491     {
492     if (0 && kd[n]->c[0] == key->key[n])
493     return 1;
494     kd[n] = NULL;
495     #if 0
496     if (!(n == 1 || n == 2))
497     key->key[n] &= 0x7F;
498     #endif
499     }
500     #endif
501    
502     /* 実際に増やしてみる */
503     assert(n >= 3);
504     for (;;)
505     {
506     #if USE_DT
507     if (n <= 3
508     && !(key->key[n] & 0x80)
509     && kcls[n].map[key->key[n] ^ 0x80] & (KCLS_DT0))
510     {
511     /* 半角カタカナの1バイト目 */
512     key->key[n] ^= 0x80;
513     }
514     else
515     #endif
516     {
517     key->key[n] = (key->key[n] & 0x7F) + 1;
518     if (key->key[n] >= 0x80)
519     {
520     key->key[n] = 0xFF; /* 次に突入させないため */
521     return 0;
522     }
523     }
524    
525     if (key->map[n][key->key[n]])
526     {
527     key_make_map(key, n);
528     key_reset(key, n + 1);
529     return 1;
530     }
531     }
532     }
533    
534     /* 鍵を完全にリセットする
535     Saltもセットし直す */
536     void
537     key_init(struct KS_KEY *key)
538     {
539     int i, j;
540    
541     #if USE_DT
542     /* 辞書を、インデクスを作りながらマップにはめこんで逝く
543     辞書はコード順昇順に並んでるものとする */
544     for (i = 0; i < dtcnt; i++)
545     {
546     unsigned c = dt[i].c[0];
547    
548     assert(dt[i].c[0]
549     && dt[i].c[1]
550     && dt[i].c[2]
551     && dt[i].c[3]);
552    
553     /* BSD 鯖でしにそうな文字は残念ながら除外 */
554     assert((dt[i].c[0] & 0x7F)
555     && (dt[i].c[1] & 0x7F)
556     && (dt[i].c[2] & 0x7F)
557     && (dt[i].c[3] & 0x7F));
558    
559     /* インデクス */
560     if (!dtidx[c])
561     dtidx[c] = &dt[i];
562    
563     if ((0x81 <= c && c <= 0x9F)
564     || (0xE0 <= c && c <= 0xFC))
565     {
566     /* 全角なので、2バイトきまった時点で立てる */
567     cp932[256 * c + dt[i].c[1]] |= KCLS_DT1;
568     }
569     else if (0xA1 <= c && c <= 0xDF)
570     {
571     /* 半角カナ */
572     for (j = 0; j < 256; j++)
573     cp932[256 * c + j] |= KCLS_DT0;
574     }
575     }
576     /* ケツ、ちうか番人 */
577     dtidx[0x100] = &dt[i];
578     #endif
579    
580     key->key[8] = 0;
581    
582     /* 初期マップを組む */
583     for (i = 0; i < 256; i++)
584     {
585     unsigned bm = 0;
586     key->map[0][i] = 0;
587     for (j = 0; j < 256; j++)
588     bm |= cp932[256 * i + j];
589     key->map[0][i] = bm & (KCLS_AN | KCLS_KA | KCLS_K1
590     | KCLS_DT0
591     );
592     if (i >= 128)
593     key->map[0][i - 128] |= key->map[0][i];
594     }
595    
596     key_reset(key, 0);
597     }
598    
599     /***************************************************************
600     *
601     * 固定キーの生成
602     *
603     * 一見 Big Endian に非対応のように見えるだろうが
604     * 随所でに散らばっている kludge により
605     * ALU_T が 64 ビットである限り、これで問題なく動く。
606     *
607     */
608    
609     void
610     key_init_sk(struct KEY *key)
611     {
612     int i, j;
613     int o;
614     uint64_t m;
615    
616     for (i = 5, m = 0xFFFFFFFF00000000ULL;
617     i >= 0;
618     m ^= (m >> (1 << --i)))
619     {
620     o = tr_pc1[7][6 - i] - 1;
621     #if DEBUG>=2
622     printf("%d:%d->%2d: %08X%08X\n",
623     N_Q, i, o,
624     (unsigned)(m >> 32),
625     (unsigned)m);
626     #endif
627     for (j = 0; j < N_Q; j++)
628     if (o < 28)
629     key->k[0][0][o ].q[j] = key->k[0][1][o ].q[j] = m;
630     else
631     key->k[1][0][o - 28].q[j] = key->k[1][1][o - 28].q[j] = m;
632     }
633     #if N_STRIDE==7
634     /* bit 6 は Little Endian として扱う */
635     o = 0;
636     assert(tr_pc1[7][0] - 1 == o);
637     assert(N_Q == 2);
638     key->k[0][0][o].q[0] = key->k[0][1][o].q[0] = 0x0000000000000000ULL;
639     key->k[0][0][o].q[1] = key->k[0][1][o].q[1] = 0xFFFFFFFFFFFFFFFFULL;
640     #endif
641     }
642    
643     /***************************************************************
644     *
645     * Salt のセット
646     * オペランドのオフセットを書き換えて回ってるので注意
647     *
648     */
649    
650     void
651     set_salt(CODE_T *code,
652     struct CRYPT64_DESC const *desc,
653     uint8_t const *k)
654     {
655     int i, j;
656    
657     for (i = 0; i < 2; i++)
658     {
659     unsigned s = k[1 + i] & 255;
660     if (s > 'z')
661     s = 0;
662     else if (s >= 'a')
663     s = s - 'a' + 2 + 10 + 26;
664     else if (s >= 'A')
665     s = s - 'A' + 2 + 10;
666     else if (s >= '.')
667     s = s - '.';
668     else
669     s = 0;
670    
671     #if DEBUG>=1
672     printf("Salt %d:%3o\n", i, s & 63);
673     #endif
674     for (j = 0; j < 6; j++)
675     {
676     #if DEBUG>=2
677     //printf("Salt %d:%d %+3d:%+3d",
678     printf("Salt %d:%d %08lX:%08lX",
679     i, j,
680     LSALT(desc, code, 0, i, j, 0),
681     LSALT(desc, code, 0, i, j, 24));
682     #endif
683     if (s & (1 << j))
684     {
685     LSALT(desc, code, 0, i, j, 0) = sizeof(WS_T) * (((4 * i + j + 15) & 31) - 16);
686     LSALT(desc, code, 0, i, j, 24) = sizeof(WS_T) * (((4 * i + j - 1) & 31) - 16);
687     }
688     else
689     {
690     LSALT(desc, code, 0, i, j, 0) = sizeof(WS_T) * (((4 * i + j - 1) & 31) - 16);
691     LSALT(desc, code, 0, i, j, 24) = sizeof(WS_T) * (((4 * i + j + 15) & 31) - 16);
692     }
693     LSALT(desc, code, 0, i, j, 12) = sizeof(WS_T) * (((4 * i + j + 7) & 31) - 16);
694     LSALT(desc, code, 0, i, j, 36) = sizeof(WS_T) * (((4 * i + j + 23) & 31) - 16);
695     #if DEBUG>=2
696     //printf(" => %+3d:%+3d\n",
697     printf(" => %08lX:%08lX\n",
698     LSALT(desc, code, 0, i, j, 0),
699     LSALT(desc, code, 0, i, j, 24));
700     #endif
701     }
702     }
703     }
704    
705     /*
706     * Local Variables:
707     * tab-width: 4
708     * End:
709     *
710     * EOF */

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26