-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathDocCore.cpp
2063 lines (1618 loc) · 53.7 KB
/
DocCore.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*! @file
@brief ドキュメントの内容の管理をします
このファイルは DocCore.cpp です。
@author SikigamiHNQ
@date 2011/04/30
*/
/*
Orinrin Editor : AsciiArt Story Editor for Japanese Only
Copyright (C) 2011 - 2013 Orinrin/SikigamiHNQ
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 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program.
If not, see <http://www.gnu.org/licenses/>.
*/
//-------------------------------------------------------------------------------------------------
#include "stdafx.h"
#include "OrinrinEditor.h"
//-------------------------------------------------------------------------------------------------
/*
文字数は、キャレットの左側の文字数で数える。キャレットが左端なら0文字目
*/
//-------------------------------------------------------------------------------------------------
// 構造体宣言はコモンへ移動
//-------------------------------------------------------------------------------------------------
#define PAGE_LINE_MAX 80
#define LINE_MOZI_MAX 255
//-------------------------------------------------------------------------------------------------
/*
(*pstTexts).acSjis 構造体ポインタはこれでもおk
ポインタ確保はこうやる
vector<int>::iterator it = vec.begin(); // vec は vector<int>型の変数
it++;
int* p = &*it; // 内部要素のアドレスを取得しようとしている。OK
gstFileを、マクロでイテレータポインタに仕立て上げる
フォーカスしてるファイルは常に一つなので、ポインタの中身を変えるか、
もしくはマクロでイテレータ自体にしてしまえばいいか
(*ltrItr).cchMozi; これでおkっぽい
*/
//#define FILE_PRELOAD // 先に頁のvectorを確保してみる・リストで要らない・文字用にいるか?
EXTERNED list<ONEFILE> gltMultiFiles; //!< 複数ファイル保持
//イテレータのtypedefはヘッダへ
static LPARAM gdNextNumber; //!< 開いたファイルの通し番号・常にインクリ
EXTERNED FILES_ITR gitFileIt; //!< 今見てるファイルの本体
EXTERNED INT gixFocusPage; //!< 注目中のページ・とりあえず0・0インデックス
EXTERNED INT gixDropPage; //!< 投下ホット番号
extern UINT gbUniRadixHex; // ユニコード数値参照が16進数であるか
extern UINT gbCrLfCode; // 改行コード:0したらば・非0YY
//-------------------------------------------------------------------------------------------------
UINT CALLBACK DocPageLoad( LPTSTR, LPCTSTR, INT );
//-------------------------------------------------------------------------------------------------
/*!
なんか初期化
*/
HRESULT DocInitialise( UINT dMode )
{
FILES_ITR itFile;
PAGE_ITR itPage;
if( dMode ) // 作成時
{
gdNextNumber = 1;
}
else
{
for( itFile = gltMultiFiles.begin( ); itFile != gltMultiFiles.end(); itFile++ )
{
for( itPage = itFile->vcCont.begin( ); itPage != itFile->vcCont.end(); itPage++ )
{
FREE( itPage->ptRawData );
}
}
}
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
変更したか
@param[in] dMode 非0変更した 0保存したから変更はなかったことに
@return HRESULT 終了状態コード
*/
HRESULT DocModifyContent( UINT dMode )
{
if( dMode )
{
if( (*gitFileIt).dModify ) return S_FALSE;
// 変更のとき、已に変更の処理してたら何もしなくて良い
MainStatusBarSetText( SB_MODIFY, MODIFY_MSG );
}
else
{
MainStatusBarSetText( SB_MODIFY, TEXT("") );
}
DocMultiFileModify( dMode );
(*gitFileIt).dModify = dMode; // ここで記録しておく
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
新しいファイル置き場を作ってフォーカスする・ファイルコア函数
@param[in] ptDmyName ダミー名を返す。NULL可。MAX_PATHであること
@return LPARAM 対応するユニーク番号
*/
LPARAM DocMultiFileCreate( LPTSTR ptDmyName )
{
ONEFILE stFile;
FILES_ITR itNew;
#ifdef DO_TRY_CATCH
try{
#endif
ZeroMemory( stFile.atFileName, sizeof(stFile.atFileName) );
stFile.dModify = FALSE;
stFile.dNowPage = 0;
stFile.dUnique = gdNextNumber++;
stFile.stCaret.x = 0;
stFile.stCaret.y = 0;
ZeroMemory( stFile.atDummyName, sizeof(stFile.atDummyName) );
StringCchPrintf( stFile.atDummyName, MAX_PATH, TEXT("%s%d.%s"), NAME_DUMMY_NAME, stFile.dUnique, NAME_DUMMY_EXT );
if( ptDmyName ){ StringCchCopy( ptDmyName, MAX_PATH, stFile.atDummyName ); }
stFile.vcCont.clear( );
gltMultiFiles.push_back( stFile );
// 新規作成の準備
gixFocusPage = -1;
PageListClear( ); // ページリストビューも破棄
itNew = gltMultiFiles.end( );
itNew--; // 末端に追加したからこれでおk
gitFileIt = itNew; // ファイルなう
#ifdef DO_TRY_CATCH
}
catch( exception &err ){ return ETC_MSG( err.what(), 0 ); }
catch( ... ){ return ETC_MSG( ("etc error"), 0 ); }
#endif
return stFile.dUnique;
}
//-------------------------------------------------------------------------------------------------
/*!
起動時の完全新規作成・開くファイルが全く無い場合の処理
@param[in] ptFile 開いたファイルのDummy名を返す・MAX_PATHであること
@return HRESULT 終了状態コード
*/
HRESULT DocActivateEmptyCreate( LPTSTR ptFile )
{
INT iNewPage;
DocMultiFileCreate( ptFile ); // 新しいファイル置き場の準備・ここで返り血は要らない
iNewPage = DocPageCreate( -1 ); // ページ作っておく
PageListInsert( iNewPage ); // ページリストビューに追加
DocPageChange( iNewPage ); // その頁にフォーカスを合わせる
MultiFileTabFirst( ptFile ); // 完全新規作成
AppTitleChange( ptFile );
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
内容を変更したらタブのファイル名に[変更]つける
@param[in] dMode 非0変更した 0変更はなかったことに
@return HRESULT 終了状態コード
*/
HRESULT DocMultiFileModify( UINT dMode )
{
TCHAR atFile[MAX_PATH]; //!< ファイル名
StringCchCopy( atFile, MAX_PATH, (*gitFileIt).atFileName );
if( 0 == atFile[0] ){ StringCchCopy( atFile, MAX_PATH , (*gitFileIt).atDummyName ); }
PathStripPath( atFile );
if( dMode ){ StringCchCat( atFile, MAX_PATH, MODIFY_MSG ); }
MultiFileTabRename( (*gitFileIt).dUnique, atFile );
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
ファイルタブを選択した・ファイルコア函数
@param[in] uqNumber 選択されたファイルのUNIQUE番号
@return HRESULT 終了状態コード
*/
HRESULT DocMultiFileSelect( LPARAM uqNumber )
{
FILES_ITR itNow;
POINT stCaret;
for( itNow = gltMultiFiles.begin(); itNow != gltMultiFiles.end(); itNow++ )
{
if( uqNumber == itNow->dUnique ) break;
}
if( itNow == gltMultiFiles.end() ) return E_OUTOFMEMORY;
ViewSelPageAll( -1 ); // 今開いてる頁の範囲選択を破棄
PageListClear( ); // ページリストビューも破棄
gitFileIt = itNow; // ファイルなう
// TODO: 初回読み込み時のバイト数計算間違えてるようだ・なおった?
PageListBuild( NULL ); // ページリスト作り直し
AppTitleChange( itNow->atFileName ); // キャプションの内容も変更
gixFocusPage = itNow->dNowPage;
DocModifyContent( itNow->dModify ); // 変更したかどうか
DocCaretPosMemory( INIT_LOAD, &stCaret ); // 先に読み出さないと次でクルヤーされる
PageListViewChange( gixFocusPage, -1 ); // 全部読み込んだのでラストページを表示する
ViewPosResetCaret( stCaret.x, stCaret.y ); // Caret位置再設定
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
全内容を破棄・ファイルコア函数
@return HRESULT 終了状態コード
*/
HRESULT DocMultiFileCloseAll( VOID )
{
UINT_PTR i, iPage, iLine;
FILES_ITR itNow;
LINE_ITR itLine;
for( itNow = gltMultiFiles.begin( ); itNow != gltMultiFiles.end(); itNow++ )
{
iPage = itNow->vcCont.size( );
for( i = 0; iPage > i; i++ )
{
iLine = itNow->vcCont.at( i ).ltPage.size( );
itLine = itNow->vcCont.at( i ).ltPage.begin();
for( itLine = itNow->vcCont.at( i ).ltPage.begin(); itLine != itNow->vcCont.at( i ).ltPage.end(); itLine++ )
{
itLine->vcLine.clear( ); // 各行の中身全消し
}
itNow->vcCont.at( i ).ltPage.clear( ); // 行を全消し
SqnFreeAll( &(itNow->vcCont.at( i ).stUndoLog) );
}
itNow->vcCont.clear( ); // ページを全消し
}
gltMultiFiles.clear( );
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
ファイルタブを閉じるとき・最後の一つは閉じれないようにするか・ファイルコア函数
@param[in] hWnd ウインドウハンドル
@param[in] uqNumber 閉じたいタブの通し番号
@return LPARAM 開き直したタブの通し番号・失敗したら0
*/
LPARAM DocMultiFileClose( HWND hWnd, LPARAM uqNumber )
{
INT iRslt;
UINT_PTR i, iPage, iLine;
UINT_PTR iCount;
LPARAM dNowNum, dPrevi;
FILES_ITR itNow;
LINE_ITR itLine;
TCHAR atBuffer[MAX_PATH];
// 一つしか開いてないなら閉じない
iCount = gltMultiFiles.size();
if( 1 >= iCount ) return 0;
// 対象は今のファイル以外かもしれない。そういうときはそのファイルに移動して処理する。
// 閉じたら、元ファイルにフォーカスする。開いているファイルを閉じたら、隣のファイルにフォーカスする
dNowNum = gitFileIt->dUnique; // 今開いてるヤツの番号
itNow = gltMultiFiles.begin( );
itNow++; // 次のやつの通し番号を確保しておく。
dPrevi = itNow->dUnique;
// 閉じたいファイルイテレータを探す
for( itNow = gltMultiFiles.begin( ); itNow != gltMultiFiles.end(); itNow++ )
{
if( uqNumber == itNow->dUnique ) break;
dPrevi = itNow->dUnique;
}
if( itNow == gltMultiFiles.end() ) return 0;
// もし削除対象が先頭なら、dPreviは次のやつのまま、次以降なら、直前のが入ってるはず
// この時点で、itNow は削除するファイルである
if( dNowNum != uqNumber ) // 開いてるファイルと閉じたいファイルが異なるなら
{
gixFocusPage = -1;
DocMultiFileSelect( uqNumber ); // 閉じる予定ファイルを開く
dPrevi = dNowNum; // 元に戻さにゃ
}
// もし変更が残ってるなら注意を促す
if( gitFileIt->dModify )
{
StringCchPrintf( atBuffer, MAX_PATH, TEXT("ちょっとまって!\r\n[%s] は変更したままだよ。\r\nここで保存して閉じるかい?"), PathFindFileName( gitFileIt->atFileName ) );
iRslt = MessageBox( hWnd, atBuffer, TEXT("お燐からの確認"), MB_YESNOCANCEL | MB_ICONQUESTION );
if( IDCANCEL == iRslt ){ return 0; }
if( IDYES == iRslt ){ DocFileSave( hWnd, D_SJIS ); }
}
// DocContentsObliterate内のやつ
iPage = itNow->vcCont.size( );
for( i = 0; iPage > i; i++ )
{
iLine = itNow->vcCont.at( i ).ltPage.size( );
for( itLine = itNow->vcCont.at( i ).ltPage.begin(); itLine != itNow->vcCont.at( i ).ltPage.end(); itLine++ )
{
itLine->vcLine.clear( ); // 各行の中身全消し
}
itNow->vcCont.at( i ).ltPage.clear( ); // 行を全消し
FREE( itNow->vcCont.at( i ).ptRawData );
SqnFreeAll( &(itNow->vcCont.at( i ).stUndoLog) );
}
itNow->vcCont.clear( ); // ページを全消し
gltMultiFiles.erase( itNow ); // 本体を消し
gixFocusPage = -1;
DocMultiFileSelect( dPrevi ); // 元ファイルもしくは隣ファイルを開き直す
return dPrevi;
}
//-------------------------------------------------------------------------------------------------
/*!
開いてるタブをもってくる
@param[in] iTgt 読み込みたい番号・負数ならファイル数のみ確保
@param[in] ptFile ファイルパスいれる・MAX_PATHであること
@param[in] ptIniPath INIファイルのパス
@return HRESULT 終了状態コード
*/
INT DocMultiFileFetch( INT iTgt, LPTSTR ptFile, LPTSTR ptIniPath )
{
TCHAR atKeyName[MIN_STRING];
INT iCount;
assert( ptIniPath );
iCount = GetPrivateProfileInt( TEXT("MultiOpen"), TEXT("Count"), 0, ptIniPath );
if( 0 > iTgt ) return iCount;
assert( ptFile );
if( iCount <= iTgt ){ ptFile[0] = NULL; return iCount; }
// オーバーしてたら無効にして終了
StringCchPrintf( atKeyName, MIN_STRING, TEXT("Item%u"), iTgt );
GetPrivateProfileString( TEXT("MultiOpen"), atKeyName, TEXT(""), ptFile, MAX_PATH, ptIniPath );
return iCount;
}
//-------------------------------------------------------------------------------------------------
/*!
開いてるタブを記録する・ファイルコア函数
@param[in] ptIniPath INIファイルのパス
@return HRESULT 終了状態コード
*/
HRESULT DocMultiFileStore( LPTSTR ptIniPath )
{
TCHAR atKeyName[MIN_STRING], atBuff[MIN_STRING];
UINT i;
FILES_ITR itNow;
assert( ptIniPath );
// 一旦セクションを空にする
ZeroMemory( atBuff, sizeof(atBuff) );
WritePrivateProfileSection( TEXT("MultiOpen"), atBuff, ptIniPath );
// ファイルを順次記録
i = 0;
for( itNow = gltMultiFiles.begin( ); itNow != gltMultiFiles.end(); itNow++ )
{
if( NULL != itNow->atFileName[0] )
{
StringCchPrintf( atKeyName, MIN_STRING, TEXT("Item%u"), i );
WritePrivateProfileString( TEXT("MultiOpen"), atKeyName, itNow->atFileName, ptIniPath );
i++;
}
}
// 個数を記録
StringCchPrintf( atBuff, MIN_STRING, TEXT("%u"), i );
WritePrivateProfileString( TEXT("MultiOpen"), TEXT("Count"), atBuff, ptIniPath );
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
対象ファイルの名前をゲッツ!する
@param[in] tabNum 名前を知りたいヤツのタブ番号
@return LPTSTR 名前バッファのポインター・無効ならNULLを返す
*/
LPTSTR DocMultiFileNameGet( INT tabNum )
{
INT i;
FILES_ITR itNow;
// ヒットするまでサーチ
for( i = 0, itNow = gltMultiFiles.begin(); itNow != gltMultiFiles.end(); i++, itNow++ )
{
if( tabNum == i ) break;
}
if( itNow == gltMultiFiles.end() ) return NULL; // ヒット無し・アリエナーイ
// 名無しならダミー名
if( NULL == itNow->atFileName[ 0] ){ return itNow->atDummyName; }
return itNow->atFileName; // ファイル名戻す
}
//-------------------------------------------------------------------------------------------------
/*!
Caret位置を常時記録・ファイル切り替えたときに意味がある
@param[in] dMode 非0ロード 0セーブ
@param[in,out] pstPos Caret位置、ドット、行数
*/
VOID DocCaretPosMemory( UINT dMode, LPPOINT pstPos )
{
if( dMode ) // ロード
{
pstPos->x = gitFileIt->stCaret.x;
pstPos->y = gitFileIt->stCaret.y;
}
else // セーブ
{
gitFileIt->stCaret.x = pstPos->x;
gitFileIt->stCaret.y = pstPos->y;
}
return;
}
//-------------------------------------------------------------------------------------------------
/*!
新しいファイルを開く
@param[in] hWnd 親にするウインドウハンドル
@return HRESULT 終了状態コード
*/
HRESULT DocOpenFromNull( HWND hWnd )
{
LPARAM dNumber;
TCHAR atDummyName[MAX_PATH];
// 複数ファイル扱うなら、破棄は不要、新しいファイルインスタンス作って対応
// 新しいファイル置き場の準備
dNumber = DocMultiFileCreate( atDummyName ); // ファイルを新規作成するとき
MultiFileTabAppend( dNumber, (*gitFileIt).atDummyName ); // ファイルの新規作成した
AppTitleChange( atDummyName );
gixFocusPage = DocPageCreate( -1 );
PageListInsert( gixFocusPage ); // ページリストビューに追加
DocPageChange( 0 );
ViewRedrawSetLine( -1 );
return S_OK;
}
//-------------------------------------------------------------------------------------------------
/*!
ファイル閉じる前に変更を確認
@param[in] hWnd 親にするウインドウハンドル
@param[in] dMode 非0閉じるメッセージあり 0変更無かったら素通り
@return 1閉じておk 0ダメ
*/
INT DocFileCloseCheck( HWND hWnd, UINT dMode )
{
INT rslt, ret;
TCHAR atMessage[BIG_STRING];
BOOLEAN bMod = FALSE;
FILES_ITR itFiles;
// 未保存のファイルをチェキ
for( itFiles = gltMultiFiles.begin(); itFiles != gltMultiFiles.end(); itFiles++ )
{
if( itFiles->dModify )
{
StringCchPrintf( atMessage, BIG_STRING, TEXT("ちょっとまった!\r\n%s は保存してないよ。ここで保存するかい?"), itFiles->atFileName[0] ? PathFindFileName( itFiles->atFileName ) : itFiles->atDummyName );
rslt = MessageBox( hWnd, atMessage, TEXT("お燐からの確認"), MB_YESNOCANCEL | MB_ICONQUESTION );
if( IDCANCEL == rslt ){ return 0; } // キャンセルなら終わること自体とりやめ
if( IDYES == rslt ){ DocFileSave( hWnd, D_SJIS ); } // 保存するならセーブを呼ぶ
// NOなら何もせず次を確認
bMod = TRUE; // 未保存があった
}
}
if( !(bMod) ) // 未保存がなかったなら確認メッセージ
{
rslt = MessageBox( hWnd, TEXT("もう終わるかい?"), TEXT("お燐からの確認"), MB_YESNO | MB_ICONQUESTION );
if( IDYES == rslt ){ ret = 1; }
else{ ret = 0; }
}
return ret;
}
//-------------------------------------------------------------------------------------------------
#ifdef BIG_TEXT_SEPARATE
// 2014/05/28
/*!
ファイル内容を確認して、分割が必要かどうか確認する
@param[in] ptStr 対象文字列へのポインター
@param[in] cchSize その文字列の文字数
@return 0なにもしない 1分割モード 2読込中止
*/
UINT DocFileHugeCheck( LPTSTR ptStr, UINT_PTR cchSize )
{
LPTSTR ptBuff;
// UINT_PTR d;
UINT_PTR dCount;
UINT dRslt;
// ASTなら何もする必要は無い
if( 0 == StrCmpN( AST_SEPARATERW , ptStr, 4 ) ){ return 0; }
ptBuff = StrStr( ptStr, MLT_SEPARATERW ); // セパレータを探す
if( ptBuff ){ return 0; } // 有るなら問題無い
// 行数を確認・100行以上あるなら分割が必要とみなす
dCount = 0;
do{
ptBuff = StrStr( ptStr , TEXT("\r\n") ); // 改行を探す
if( ptBuff ){ dCount++; }else{ break; }
ptStr = ptBuff+2; // 改行分進んだ位置が必要
}while( ptBuff );
// 改行がなく1000文字以上もある場合はエラーとする
if( 0 == dCount && 1000 <= cchSize )
{
DocHugeFileTreatment( 2 );
return 2;
}
if( 100 >= dCount ){ return 0; } // 100行以下なら問題無い
// ここで、大型ファイルなのでどうするかの確認・そのまま/分割/やめる
dRslt = DocHugeFileTreatment( 1 );
return dRslt;
}
//-------------------------------------------------------------------------------------------------
/*!
ファイル内容を分割する
@param[in] ptSource 対象文字列へのポインター・終端NULLが2つ以上確保されていること
@param[in] cchSource その文字列の文字数
@return 分割結果の入ったポインター・開放は呼んだ方でやる・NULLなら失敗
*/
LPTSTR DocFileHugeSeparate( LPTSTR ptSource, UINT_PTR cchSource )
{
LPTSTR ptDest, ptBuff;
UINT_PTR dd, ds, dLineCnt, dEmptyCnt, cchDest;
cchDest = cchSource; // とりあえず現状で確保・足りなくなったらreallocするか
ptDest = (LPTSTR)malloc( sizeof(TCHAR) * cchDest );
if( !(ptDest) ){ return NULL; } // なんかエラー・普通は無い
ZeroMemory( ptDest, sizeof(TCHAR) * cchDest );
dd = 0;
dLineCnt = 0; // この行数は、頁更新があったらリセットする
dEmptyCnt = 0;
for( ds = 0; cchSource > ds; ds++ )
{
if( NULL == ptSource[ds] ) break;
ptDest[dd] = ptSource[ds]; // とりあえず文字を写していく
dd++; // こっちは進めておk
ptDest[dd] = NULL; // ターミネート
if( 0xD == ptSource[ds] && 0xA == ptSource[ds+1] ) // 改行があった場合
{
ds++; // その改行をうつす
ptDest[dd] = ptSource[ds];
dd++; // こっちは進めておk
ptDest[dd] = NULL; // ターミネート
if( cchDest <= (dd+12) ) // 残り少なくなってきたら
{
ptBuff = (LPTSTR)realloc( ptDest, sizeof(TCHAR) * (cchDest + 0x800) ); // 適当に拡張
if( !(ptBuff) ) // もしエラーになったら
{
free( ptDest ); // 使用領域は開放する
return NULL; // エラー戻り
}
ptDest = ptBuff; // 付け替える
cchDest += 0x800; // サイズ拡張
}//ここには要らないかも
dLineCnt++; // 行数増える
if( 40 <= dLineCnt ){ dEmptyCnt++; } // 規定行数超えたら空行カウント開始
// 40行以降で4行以上の空きがあるか、100行以降で1行以上の空きがあるか、256行以上続いている
if( (5 <= dEmptyCnt) || (100 <= dLineCnt && 2 <= dEmptyCnt) || (256 <= dLineCnt) )
{
StringCchCat( ptDest, cchDest, MLT_SEPARATERW );
StringCchCat( ptDest, cchDest, TEXT("\r\n") );
StringCchLength( ptDest, cchDest, &dd ); // 位置合わせ
dLineCnt = 0;
dEmptyCnt = 0;
}
}
else
{
dEmptyCnt = 0; // 改行以外ならリセット・50行超えてても、通常の文字列が続くなら空カウントは進まない
}
if( cchDest <= (dd+12) ) // 残り少なくなってきたら
{
ptBuff = (LPTSTR)realloc( ptDest, sizeof(TCHAR) * (cchDest + 0x800) ); // 適当に拡張
if( !(ptBuff) ) // もしエラーになったら
{
free( ptDest ); // 使用領域は開放する
return NULL; // エラー戻り
}
ptDest = ptBuff; // 付け替える
cchDest += 0x800; // サイズ拡張
}
}
return ptDest;
}
//-------------------------------------------------------------------------------------------------
#endif
/*!
ファイルを確保
@param[in] ptFileName 指定されたファイル名で開く
@return LPARAM 0失敗 1~成功
*/
LPARAM DocFileInflate( LPTSTR ptFileName )
{
CONST WCHAR rtHead = 0xFEFF; // ユニコードテキストヘッダ
WCHAR rtUniBuf;
HANDLE hFile;
DWORD readed;
LPVOID pBuffer; // 文字列バッファ用ポインター
INT iByteSize;
LPTSTR ptString;
LPSTR pcText;
UINT_PTR cchSize;
LPARAM dNumber;
#ifdef BIG_TEXT_SEPARATE // 頁区切りのないTXTかどうかを確認する
UINT dSepRslt;
LPTSTR ptSepBuff;
#endif
#ifdef _DEBUG
DWORD dTcStart, dTcEnd;
#endif
//TCHAR atBuff[10];
//ZeroMemory( atBuff, sizeof(atBuff) );
#ifdef _DEBUG
dTcStart = GetTickCount( );
#endif
assert( ptFileName ); // ファイル開けないのはバグ
// ファイル名が空っぽだったら自動的にアウツ!
if( NULL == ptFileName[0] ){ return 0; }
// レッツオーポン
hFile = CreateFile( ptFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( INVALID_HANDLE_VALUE == hFile ){ return 0; }
//InitLastOpen( INIT_SAVE, ptFileName ); // 複数ファイルでは意味が無い
// 処理順番入替
iByteSize = GetFileSize( hFile, NULL );
pBuffer = malloc( iByteSize + 4 ); // バッファは少し大きめに取る
ZeroMemory( pBuffer, iByteSize + 4 );
SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
ReadFile( hFile, pBuffer, iByteSize, &readed, NULL );
CloseHandle( hFile ); // 内容全部取り込んだから開放
// ユニコードチェック
CopyMemory( &rtUniBuf, pBuffer, 2 );
if( rtHead == rtUniBuf ) // ユニコードヘッダがあれば
{
ptString = (LPTSTR)pBuffer;
ptString++; // ユニコードヘッダ分進めておく
}
else
{
pcText = (LPSTR)pBuffer;
// シフトJISを開く場合、�の部分をどうにかせんといかん
ptString = SjisDecodeAlloc( pcText ); // ファイルを開くとき
FREE( pBuffer ); // こっちで開放
pBuffer = ptString; // ポイントするところを変更
}
StringCchLength( ptString, STRSAFE_MAX_CCH, &cchSize );
#ifdef BIG_TEXT_SEPARATE // 頁区切りのないTXTかどうかを確認する
dSepRslt = DocFileHugeCheck( ptString, cchSize );
if( 1 == dSepRslt ) // 分割処理する
{
ptSepBuff = DocFileHugeSeparate( ptString, cchSize );
if( !(ptSepBuff) ){ return 0; } // なんかミスってるなら中止
FREE( pBuffer ); // 大本を一旦開放
pBuffer = ptSepBuff; // 最後に開放する領域としてポイントするところを変更
ptString = ptSepBuff; // 読込処理を続ける位置としてセット
StringCchLength( ptString, STRSAFE_MAX_CCH , &cchSize ); // サイズ読込直し
}
else if( 2 == dSepRslt ) // 読込中止
{
FREE( pBuffer ); // 大本を開放
return 0;
}
// 0なら何もしない
#endif
// 新しいファイル置き場の準備 2014/05/28↑にあったのを移動した
dNumber = DocMultiFileCreate( NULL ); // 実際のファイルを開くとき
if( 0 >= dNumber ) return 0;
StringCchCopy( (*gitFileIt).atFileName, MAX_PATH, ptFileName );
// もしASTなら、先頭は[AA]になってるはず・分割は中でやる
if( StrCmpN( AST_SEPARATERW, ptString, 4 ) )
{
DocStringSplitMLT( ptString , cchSize, DocPageLoad );
}
else
{
DocStringSplitAST( ptString , cchSize, DocPageLoad );
}
// ファイル開いたらキャレットとかスクロールをリセットする
ViewEditReset( );
FREE( pBuffer ); // =ptString
DocPageChange( 0 ); // 全部読み込んだので最初のページを表示する
PageListViewChange( -1, -1 ); // 直前頁リセット
AppTitleChange( ptFileName );
#ifdef _DEBUG
dTcEnd = GetTickCount( );
TRACE( TEXT("LOAD START[%u] END[%u] ELAPSE[%u]"), dTcStart, dTcEnd, (dTcEnd - dTcStart) );
#endif
return dNumber;
}
//-------------------------------------------------------------------------------------------------
/*!
頁を作って内容をぶち込む
@param[in] ptName 項目の名前・無い時はNULL
@param[in] ptCont 項目の内容
@param[in] cchSize 内容の文字数
@return UINT 特に意味なし
*/
UINT CALLBACK DocPageLoad( LPTSTR ptName, LPCTSTR ptCont, INT cchSize )
{
gixFocusPage = DocPageCreate( -1 ); // 頁を作成
PageListInsert( gixFocusPage ); // ページリストビューに追加
// 新しく作ったページにうつる
if( ptName ){ DocPageNameSet( ptName ); } // 名前をセットしておく
(*gitFileIt).vcCont.at( gixFocusPage ).ptRawData = (LPTSTR)malloc( (cchSize+2) * sizeof(TCHAR) );
ZeroMemory( (*gitFileIt).vcCont.at( gixFocusPage ).ptRawData, (cchSize+2) * sizeof(TCHAR) );
//HRESULT hRslt =
StringCchCopy( (*gitFileIt).vcCont.at( gixFocusPage ).ptRawData, (cchSize+2), ptCont );
// バッファに文字列を保存だけしておく
DocPageParamGet( NULL, NULL ); // 再計算しちゃう・遅延読込ヒット
return 1;
}
//-------------------------------------------------------------------------------------------------
#ifdef FILE_PRELOAD
/*!
MLTもしくはTXTの頁数を調べる
@param[in] ptStr 分解対象文字列へのポインター
@param[in] cchSize その文字列の文字数
@return UINT 頁数
*/
UINT DocPreloadMLT( LPTSTR ptString, INT cchSize )
{
LPTSTR ptCaret; // 読込開始・現在位置
LPTSTR ptEnd; // ページの末端位置・セパレータの直前
INT iLines, iDots, iMozis;
UINT dPage;
UINT_PTR cchItem;
BOOLEAN bLast = FALSE;
ptCaret = ptString; // まずは最初から
dPage = 0;
// 始点にはセパレータ無いものとみなす。連続するセパレータは、空白内容として扱う
do
{
ptEnd = StrStr( ptCaret, MLT_SEPARATERW ); // セパレータを探す
if( !ptEnd ) // 見つからなかったら=これが最後なら=NULL
{
ptEnd = ptString + cchSize;
bLast = TRUE;
}
cchItem = ptEnd - ptCaret; // WCHAR単位なので計算結果は文字数のようだ
// 最終頁でない場合は末端の改行分引く
if( !(bLast) && 0 < cchItem ){ cchItem -= CH_CRLF_CCH; }
dPage++;
// 頁の情報を確保
iLines = DocStringInfoCount( ptCaret, cchItem, &iDots, &iMozis );
ptCaret = NextLineW( ptEnd ); // セパレータの次の行からが本体
}while( *ptCaret ); // データ有る限りループで探す
return dPage;
}
//-------------------------------------------------------------------------------------------------
#endif
/*!
MLTもしくはTXTなユニコード文字列を受け取って分解しつつページに入れる
@param[in] ptStr 分解対象文字列へのポインター
@param[in] cchSize その文字列の文字数
@param[in] pfPageLoad 内容を入れるコールバック函数のアレ
@return UINT 作成した頁数
*/
UINT DocStringSplitMLT( LPTSTR ptStr, INT cchSize, PAGELOAD pfPageLoad )
{
LPTSTR ptCaret; // 読込開始・現在位置
LPTSTR ptEnd; // ページの末端位置・セパレータの直前
UINT iNumber; // 通し番号カウント
#ifdef FILE_PRELOAD
UINT dPage;
#endif
UINT cchItem;
// INT dmyX = 0, dmyY = 0;
BOOLEAN bLast = FALSE;
ptCaret = ptStr; // まずは最初から
iNumber = 0; // 通し番号0インデックス
// 始点にはセパレータ無いものとみなす。連続するセパレータは、空白内容として扱う
#ifdef FILE_PRELOAD
dPage = DocPreloadMLT( ptStr, cchSize );
#endif
do
{
ptEnd = StrStr( ptCaret, MLT_SEPARATERW ); // セパレータを探す
if( !ptEnd ) // 見つからなかったら=これが最後なら=NULL
{
ptEnd = ptStr + cchSize; // WCHARサイズで計算おk?
bLast = TRUE;
}
cchItem = ptEnd - ptCaret; // WCHAR単位なので計算結果は文字数のようだ
// 最終頁でない場合は末端の改行分引く
if( !(bLast) && 0 < cchItem )
{
cchItem -= CH_CRLF_CCH;
ptCaret[cchItem] = 0;
}
pfPageLoad( NULL, ptCaret, cchItem );
iNumber++;
ptCaret = NextLineW( ptEnd ); // セパレータの次の行からが本体
}while( *ptCaret ); // データ有る限りループで探す
return iNumber;
}
//-------------------------------------------------------------------------------------------------
/*!
ASTなユニコード文字列を受け取って分解しつつページに入れる
@param[in] ptStr 分解対象文字列へのポインター
@param[in] cchSize その文字列の文字数
@param[in] pfPageLoad 内容を入れるコールバック函数のアレ
@return UINT 作成した頁数
*/
UINT DocStringSplitAST( LPTSTR ptStr, INT cchSize, PAGELOAD pfPageLoad )
{
LPTSTR ptCaret; // 読込開始・現在位置
LPTSTR ptStart; // セパレータの直前
LPTSTR ptEnd;
UINT iNumber; // 通し番号カウント
UINT cchItem;
BOOLEAN bLast;
TCHAR atName[MAX_PATH];
ptCaret = ptStr; // まずは最初から
iNumber = 0; // 通し番号0インデックス
bLast = FALSE;
do // とりあえず一番最初はptCaretは[AA]になってる
{
ptStart = NextLineW( ptCaret ); // 次の行からが本番
ptCaret += 5; // [AA][
cchItem = ptStart - ptCaret; // 名前部分の文字数
cchItem -= 3; // ]rn
ZeroMemory( atName, sizeof(atName) ); // 名前確保
if( 0 < cchItem ) StringCchCopyN( atName, MAX_PATH, ptCaret, cchItem );