1 /*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
2  *
3  *  Use of this source code is governed by a BSD-style license that can
4  *  be found in the License.html file in the root of the source tree.
5  */
6 
7 // RegressionTest.cpp : Defines the entry point for the console application.
8 //
9 
10 #include <iostream>
11 #include <stdio.h>
12 #include <map>
13 #include "tchar.h"
14 #include "MediaInfoDLL/MediaInfoDLL.h"
15 #include "MediaInfo/MediaInfo_Events.h"
16 #include "ZenLib/ZtringListListF.h"
17 #include "ZenLib/Dir.h"
18 #include "ZenLib/File.h"
19 #include "ZenLib/FileName.h"
20 #include "RegressionTest/RegressionTest.h"
21 using namespace MediaInfoDLL;
22 using namespace ZenLib;
23 using namespace std;
24 
25 const char* F_FileName;
26 #define echoF(_format) Events_UserHandle_struct::perevent &PerEvent=UserHandle->PerEvent[Event->EventCode]; if (!PerEvent.F_MoreThanOnce) {fprintf(PerEvent.F, _format); PerEvent.F_MoreThanOnce=true; } fprintf(PerEvent.F, "\n");
27 #define echo0(_format) fprintf(PerEvent.F, _format)
28 #define echo1(_format, Arg1) fprintf(PerEvent.F, _format, Arg1)
29 #define echo2(_format, Arg1, Arg2) fprintf(PerEvent.F, _format, Arg1, Arg2)
30 #define echo4(_format, Arg1, Arg2, Arg3, Arg4) fprintf(PerEvent.F, _format, Arg1, Arg2, Arg3, Arg4)
31 
32 struct Events_UserHandle_struct
33 {
34     FileName Name;
35     Ztring Files;
36     Ztring DataBaseDirectory;
37     struct perevent
38     {
39         FILE* F;
40         bool  F_MoreThanOnce;
41     };
42     map<int32u, perevent> PerEvent;
43     int32u Scenario;
44     bool Custom;
45     bool ParseSpeed;
46     bool NextPacket;
47     bool DemuxContainerOnly;
48     bool Seek;
49 
Events_UserHandle_structEvents_UserHandle_struct50     Events_UserHandle_struct()
51     {
52         Custom=false;
53         ParseSpeed=false;
54         NextPacket=false;
55         DemuxContainerOnly=false;
56         Seek=false;
57     }
58 
ClearEvents_UserHandle_struct59     void Clear()
60     {
61         for (map<int32u, perevent>::iterator Item=PerEvent.begin(); Item!=PerEvent.end(); ++Item)
62             fclose (Item->second.F);
63         PerEvent.clear();
64     }
65 
66 };
67 
General_Start_0(struct MediaInfo_Event_General_Start_0 * Event,struct Events_UserHandle_struct * UserHandle)68 void General_Start_0 (struct MediaInfo_Event_General_Start_0* Event, struct Events_UserHandle_struct* UserHandle)
69 {
70     echoF("MediaInfo starts\n");
71 
72     echo1("Stream_Size=%i\n", Event->Stream_Size);
73 }
74 
General_End_0(struct MediaInfo_Event_General_End_0 * Event,struct Events_UserHandle_struct * UserHandle)75 void General_End_0 (struct MediaInfo_Event_General_End_0* Event, struct Events_UserHandle_struct* UserHandle)
76 {
77     echoF("MediaInfo ends\n");
78 
79     echo1("Stream_Bytes_Analyzed=%i\n", Event->Stream_Bytes_Analyzed);
80 }
81 
General_Parser_Selected_0(struct MediaInfo_Event_General_Parser_Selected_0 * Event,struct Events_UserHandle_struct * UserHandle)82 void General_Parser_Selected_0 (struct MediaInfo_Event_General_Parser_Selected_0* Event, struct Events_UserHandle_struct* UserHandle)
83 {
84     echoF("MediaInfo has selected the parser\n");
85 
86     echo1("Name=%s\n", Event->Name);
87 }
88 
General_Move_Request_0(struct MediaInfo_Event_General_Move_Request_0 * Event,struct Events_UserHandle_struct * UserHandle)89 void General_Move_Request_0 (struct MediaInfo_Event_General_Move_Request_0* Event, struct Events_UserHandle_struct* UserHandle)
90 {
91     echoF("MediaInfo has requested to seek\n");
92 
93     echo1("StreamOffset=%08x\n", Event->StreamOffset);
94 }
95 
General_Move_Done_0(struct MediaInfo_Event_General_Move_Done_0 * Event,struct Events_UserHandle_struct * UserHandle)96 void General_Move_Done_0 (struct MediaInfo_Event_General_Move_Done_0* Event, struct Events_UserHandle_struct* UserHandle)
97 {
98     echoF("MediaInfo has seek\n");
99 
100     echo1("StreamOffset=%08x\n", Event->StreamOffset);
101 }
102 
General_SubFile_Start_0(struct MediaInfo_Event_General_SubFile_Start_0 * Event,struct Events_UserHandle_struct * UserHandle)103 void General_SubFile_Start_0 (struct MediaInfo_Event_General_SubFile_Start_0* Event, struct Events_UserHandle_struct* UserHandle)
104 {
105     echoF("MediaInfo is parsing a new file from the source file\n");
106 
107     echo1("FileName_Relative=%s\n", Event->FileName_Relative);
108     echo1("FileName_Absolute=%s\n", Event->FileName_Absolute);
109 }
110 
General_SubFile_End_0(struct MediaInfo_Event_General_SubFile_End_0 * Event,struct Events_UserHandle_struct * UserHandle)111 void General_SubFile_End_0 (struct MediaInfo_Event_General_SubFile_End_0* Event, struct Events_UserHandle_struct* UserHandle)
112 {
113     echoF("MediaInfo has finished the parsing a new file from the source file\n");
114 }
115 
Global_Demux_4(struct MediaInfo_Event_Global_Demux_4 * Event,struct Events_UserHandle_struct * UserHandle)116 void Global_Demux_4(struct MediaInfo_Event_Global_Demux_4 *Event, struct Events_UserHandle_struct* UserHandle)
117 {
118     if (!UserHandle->DemuxContainerOnly)
119         return;
120 
121     echoF("MediaInfo Demux\n");
122 
123     echo1("StreamOffset=%08x,", Event->StreamOffset);
124     echo1(" Frame_Number=%u\n", Event->FrameNumber);
125     echo0("IDs=");
126     for (size_t Pos=0; Pos<Event->StreamIDs_Size; Pos++)
127         switch (Event->StreamIDs_Width[Pos])
128         {
129             case 2: echo1("%02x, ", Event->StreamIDs[Pos]); break;
130             case 4: echo1("%04x, ", Event->StreamIDs[Pos]); break;
131             case 8: echo1("%08x, ", Event->StreamIDs[Pos]); break;
132             default: echo1("%08x, ", Event->StreamIDs[Pos]); break;
133         }
134     echo0("\n");
135     if (Event->PCR!=(int64u)-1)
136         echo1("PCR=%s, ", Ztring().Duration_From_Milliseconds(Event->PCR/1000000).To_Local().c_str());
137     if (Event->PTS!=(int64u)-1)
138         echo1("PTS=%s, ", Ztring().Duration_From_Milliseconds(Event->PTS/1000000).To_Local().c_str());
139     if (Event->DTS!=(int64u)-1)
140         echo1("DTS=%s, ", Ztring().Duration_From_Milliseconds(Event->DTS/1000000).To_Local().c_str());
141     if (Event->DUR!=(int64u)-1)
142         echo1("DUR=%s, ", Ztring().Duration_From_Milliseconds(Event->DUR/1000000).To_Local().c_str());
143     if (Event->PCR!=(int64u)-1 || Event->PTS!=(int64u)-1 || Event->DTS!=(int64u)-1 || Event->DUR!=(int64u)-1)
144         echo0("\n");
145     echo1("Content_Type=%i,", Event->Content_Type);
146     echo1(" Content_Size=%i,", Event->Content_Size);
147     echo1(" Flags=%08x\n", Event->Flags);
148 }
149 
Video_SliceInfo_0(struct MediaInfo_Event_Video_SliceInfo_0 * Event,struct Events_UserHandle_struct * UserHandle)150 void Video_SliceInfo_0(struct MediaInfo_Event_Video_SliceInfo_0 *Event, struct Events_UserHandle_struct* UserHandle)
151 {
152     if (!UserHandle->DemuxContainerOnly)
153         return;
154 
155     echoF("MediaInfo Demux\n");
156 
157     echo1("StreamOffset=%08x,", Event->StreamOffset);
158     echo1(" FramePosition=%u,", Event->FrameNumber);
159     echo1(" FieldPosition=%u,", Event->FieldPosition);
160     echo1(" SlicePosition=%u,", Event->SlicePosition);
161     echo0("IDs=");
162     for (size_t Pos=0; Pos<Event->StreamIDs_Size; Pos++)
163         switch (Event->StreamIDs_Width[Pos])
164         {
165             case 2: echo1("%02x, ", Event->StreamIDs[Pos]); break;
166             case 4: echo1("%04x, ", Event->StreamIDs[Pos]); break;
167             case 8: echo1("%08x, ", Event->StreamIDs[Pos]); break;
168             default: echo1("%08x, ", Event->StreamIDs[Pos]); break;
169         }
170     echo0("\n");
171     if (Event->PCR!=(int64u)-1)
172         echo1("PCR=%s, ", Ztring().Duration_From_Milliseconds(Event->PCR/1000000).To_Local().c_str());
173     if (Event->PTS!=(int64u)-1)
174         echo1("PTS=%s, ", Ztring().Duration_From_Milliseconds(Event->PTS/1000000).To_Local().c_str());
175     if (Event->DTS!=(int64u)-1)
176         echo1("DTS=%s, ", Ztring().Duration_From_Milliseconds(Event->DTS/1000000).To_Local().c_str());
177     if (Event->DUR!=(int64u)-1)
178         echo1("DUR=%s, ", Ztring().Duration_From_Milliseconds(Event->DUR/1000000).To_Local().c_str());
179     if (Event->PCR!=(int64u)-1 || Event->PTS!=(int64u)-1 || Event->DTS!=(int64u)-1 || Event->DUR!=(int64u)-1)
180         echo0("\n");
181     echo1("SliceType=%i,", Event->SliceType);
182     echo1(" Flags=%08x\n", Event->Flags);
183 }
184 
185 /***************************************************************************/
186 /* The callback function                                                   */
187 /***************************************************************************/
188 
189 #define CASE(_PARSER,_EVENT,_VERSION) \
190     case MediaInfo_Event_##_PARSER##_##_EVENT : if (EventVersion==_VERSION && Data_Size>=sizeof(struct MediaInfo_Event_##_PARSER##_##_EVENT##_##_VERSION)) _PARSER##_##_EVENT##_##_VERSION((struct MediaInfo_Event_##_PARSER##_##_EVENT##_##_VERSION*)Data_Content, UserHandle); break;
191 
Event_CallBackFunction(unsigned char * Data_Content,size_t Data_Size,void * UserHandle_Void)192 void __stdcall Event_CallBackFunction(unsigned char* Data_Content, size_t Data_Size, void* UserHandle_Void)
193 {
194     /*Retrieving UserHandle*/
195     struct Events_UserHandle_struct*           UserHandle=(struct Events_UserHandle_struct*)UserHandle_Void;
196     struct MediaInfo_Event_Generic*     Event_Generic=(struct MediaInfo_Event_Generic*) Data_Content;
197     unsigned char                       ParserID;
198     unsigned short                      EventID;
199     unsigned char                       EventVersion;
200 
201     /*integrity tests*/
202     if (Data_Size<4)
203         return; //There is a problem
204 
205     if (UserHandle->PerEvent[Event_Generic->EventCode].F==NULL)
206     {
207         Ztring Number; Number.From_Number(Event_Generic->EventCode, 16);
208         while (Number.size()<8)
209             Number.insert(0, 1, __T('0'));
210         Ztring Name=Ztring(UserHandle->DataBaseDirectory+__T("\\Events\\New\\")+Ztring::ToZtring(UserHandle->Scenario)+__T("\\")+Number+__T("\\")+UserHandle->Name.Name_Get()+__T(".txt"));
211         if (!Dir::Exists(UserHandle->DataBaseDirectory+__T("\\Events\\New")))
212             Dir::Create(UserHandle->DataBaseDirectory+__T("\\Events\\New"));
213        if (!Dir::Exists(UserHandle->DataBaseDirectory+__T("\\Events\\New\\")+Ztring::ToZtring(UserHandle->Scenario)))
214             Dir::Create(UserHandle->DataBaseDirectory+__T("\\Events\\New\\")+Ztring::ToZtring(UserHandle->Scenario));
215        if (!Dir::Exists(UserHandle->DataBaseDirectory+__T("\\Events\\New\\")+Ztring::ToZtring(UserHandle->Scenario)+__T("\\")+Number))
216             Dir::Create(UserHandle->DataBaseDirectory+__T("\\Events\\New\\")+Ztring::ToZtring(UserHandle->Scenario)+__T("\\")+Number);
217         if (!Dir::Exists(FileName(Name).Path_Get()))
218             Dir::Create(FileName(Name).Path_Get());
219         UserHandle->PerEvent[Event_Generic->EventCode].F=fopen(Name.To_Local().c_str(), "w");
220     }
221 
222     /*Retrieving EventID*/
223     ParserID    =(unsigned char) ((Event_Generic->EventCode&0xFF000000)>>24);
224     EventID     =(unsigned short)((Event_Generic->EventCode&0x00FFFF00)>>8 );
225     EventVersion=(unsigned char) ( Event_Generic->EventCode&0x000000FF     );
226 
227 
228     //*Global to all parsers
229     switch (EventID)
230     {
231                     CASE (Global, Demux, 4)
232                     CASE (Video, SliceInfo, 0)
233                     default                                                                     : ;
234     }
235 
236     switch (ParserID)
237     {
238         case MediaInfo_Parser_None :
239                 switch (EventID)
240                 {
241                     case MediaInfo_Event_General_Start                                          : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_Start_0)) General_Start_0((struct MediaInfo_Event_General_Start_0*)Data_Content, UserHandle); break;
242                     case MediaInfo_Event_General_End                                            : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_End_0)) General_End_0((struct MediaInfo_Event_General_End_0*)Data_Content, UserHandle); break;
243                     case MediaInfo_Event_General_Parser_Selected                                : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_Parser_Selected_0)) General_Parser_Selected_0((struct MediaInfo_Event_General_Parser_Selected_0*)Data_Content, UserHandle); break;
244                     case MediaInfo_Event_General_Move_Request                                   : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_Move_Request_0)) General_Move_Request_0((struct MediaInfo_Event_General_Move_Request_0*)Data_Content, UserHandle); break;
245                     case MediaInfo_Event_General_Move_Done                                      : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_Move_Done_0)) General_Move_Done_0((struct MediaInfo_Event_General_Move_Done_0*)Data_Content, UserHandle); break;
246                     case MediaInfo_Event_General_SubFile_Start                                  : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_SubFile_Start_0)) General_SubFile_Start_0((struct MediaInfo_Event_General_SubFile_Start_0*)Data_Content, UserHandle); break;
247                     case MediaInfo_Event_General_SubFile_End                                    : if (EventVersion==0 && Data_Size==sizeof(struct MediaInfo_Event_General_SubFile_End_0)) General_SubFile_End_0((struct MediaInfo_Event_General_SubFile_End_0*)Data_Content, UserHandle); break;
248                     default                                                                     : ;
249                 }
250                 break;
251         default : ; //ParserID is unknown
252     }
253 }
254 
RegressionTest_Events(Ztring Files,Ztring DataBaseDirectory,int32u Scenario)255 void RegressionTest_Events(Ztring Files, Ztring DataBaseDirectory, int32u Scenario)
256 {
257     // Scenarios:
258     // bit  0 : quick parsing / full parsing
259     // bit  1 : next packet interface
260     // bit  2 : demux (by container only)
261     // bit  3 : do some seeks
262 
263 
264     cout<<" Analyzing"<<endl;
265     ZtringListListF FilesList_Source;
266     if (FileName(Files).Extension_Get()==__T("csv"))
267         FilesList_Source.Load(DataBaseDirectory+__T("\\Events\\FilesList.csv"));
268     else
269     {
270         if (File::Exists(Files))
271             FilesList_Source.push_back(Files);
272         else
273             FilesList_Source.push_back(Files+__T("\\*.*"));
274     }
275     vector<Events_UserHandle_struct> FilesList;
276     for (size_t FilesList_Source_Pos=0; FilesList_Source_Pos<FilesList_Source.size(); FilesList_Source_Pos++)
277     {
278         ZtringList Temp=Dir::GetAllFileNames(FilesList_Source[FilesList_Source_Pos](0));
279         for (size_t Temp_Pos=0; Temp_Pos<Temp.size(); Temp_Pos++)
280         {
281             struct Events_UserHandle_struct ToAdd;
282             ToAdd.Name=Temp[Temp_Pos];
283             ToAdd.DataBaseDirectory=DataBaseDirectory;
284             ToAdd.Files=Files;
285             ToAdd.Scenario=Scenario;
286             if (Scenario&(1<<0))
287                 ToAdd.ParseSpeed=true;
288             if (Scenario&(1<<1))
289                 ToAdd.NextPacket=true;
290             if (Scenario&(1<<2))
291                 ToAdd.DemuxContainerOnly=true;
292             if (Scenario&(1<<3))
293                 ToAdd.Seek=true;
294 
295             FilesList.push_back(ToAdd);
296         }
297     }
298 
299 
300     for (size_t FilesList_Pos=0; FilesList_Pos<FilesList.size(); FilesList_Pos++)
301     {
302         cout<<" "<<FilesList_Pos+1<<"/"<<FilesList.size()<<" "<<FilesList[FilesList_Pos].Name.To_Local()<<endl;
303 
304         MediaInfo MI;
305         Ztring MI_Result;
306 
307         //**********************************************************************
308         // Configuring
309         //**********************************************************************
310 
311         // CallBack configuration
312         // MediaInfo need pointer as text (for compatibility with older version) + 64-bit OS handling
313         // form is "CallBack=memory://handlerInDecimal;UserHandler=memory://handlerInDecimal"
314         // UserHandler is a unique value wich will be provided to the callback function, in order to know which MediaInfo instance send the event
315         wostringstream Event_CallBackFunction_Text;
316         Event_CallBackFunction_Text<<__T("CallBack=memory://")<<(MediaInfo_int64u)Event_CallBackFunction<<__T(";UserHandler=memory://")<<(MediaInfo_int64u)&FilesList[FilesList_Pos];
317         MI_Result=MI.Option(__T("File_Event_CallBackFunction"), Event_CallBackFunction_Text.str());
318         if (!MI_Result.empty())
319         {
320             wcout<<__T("MediaInfo error: ")<<MI_Result<<endl;
321             return;
322         }
323 
324         //Retrieiving basic data
325         MI.Open(FilesList[FilesList_Pos].Name);
326         Ztring Delay_10s=Ztring().Duration_From_Milliseconds(Ztring(MI.Get(Stream_Video, 0, __T("Delay"))).To_int64u()+10000);
327 
328         if (FilesList[FilesList_Pos].ParseSpeed)
329         {
330             MI_Result=MI.Option(__T("ParseSpeed"), __T("1.0"));
331             if (!MI_Result.empty())
332             {
333                 wcout<<__T("MediaInfo error: ")<<MI_Result<<endl;
334                 return;
335             }
336         }
337 
338         if (FilesList[FilesList_Pos].DemuxContainerOnly)
339         {
340             MI_Result=MI.Option(__T("Demux"), __T("container"));
341             if (!MI_Result.empty())
342             {
343                 wcout<<__T("MediaInfo error: ")<<MI_Result<<endl;
344                 return;
345             }
346 
347             MI_Result=MI.Option(__T("File_Demux_Unpacketize"), __T("1"));
348             if (!MI_Result.empty())
349             {
350                 wcout<<__T("MediaInfo error: ")<<MI_Result<<endl;
351                 return;
352             }
353 
354             MI_Result=MI.Option(__T("File_Demux_PCM_20bitTo16bit"), __T("1"));
355             if (!MI_Result.empty())
356             {
357                 wcout<<__T("MediaInfo error: ")<<MI_Result<<endl;
358                 return;
359             }
360         }
361 
362         if (FilesList[FilesList_Pos].NextPacket)
363         {
364             MI_Result=MI.Option(__T("File_NextPacket"), __T("1"));
365             if (!MI_Result.empty())
366             {
367                 wcout<<__T("MediaInfo error: ")<<MI_Result<<endl;
368                 return;
369             }
370         }
371 
372         MI.Open(FilesList[FilesList_Pos].Name);
373 
374         if (FilesList[FilesList_Pos].NextPacket)
375         {
376             int Counter=0;
377             while (MI.Open_NextPacket()&0x100)
378             {
379                 if (FilesList[FilesList_Pos].Seek)
380                 {
381                     Counter++;
382                     if (Counter==0)
383                         MI.Option(__T("File_Seek"), __T("0"));
384                     if (Counter==100)
385                         MI.Option(__T("File_Seek"), Delay_10s);
386                     if (Counter==200)
387                         MI.Option(__T("File_Seek"), __T("Frame=100"));
388                     if (Counter==300)
389                         MI.Option(__T("File_Seek"), __T("95%"));
390                 }
391             }
392         }
393 
394         FilesList[FilesList_Pos].Clear();
395     }
396 
397     cout<<" Diff"<<endl;
398     ZtringList Ref=Dir::GetAllFileNames(DataBaseDirectory+__T("\\Events\\Ref\\")+FileName(Files).Name_Get()+__T("\\")+Ztring::ToZtring(Scenario)+__T("*.*"));
399     ZtringList New=Dir::GetAllFileNames(DataBaseDirectory+__T("\\Events\\New\\")+FileName(Files).Name_Get()+__T("\\")+Ztring::ToZtring(Scenario)+__T("*.*"));
400     for (size_t Ref_Pos=0; Ref_Pos<Ref.size(); Ref_Pos++)
401     {
402         Ztring Ref_ToFind=Ref[Ref_Pos];
403         Ref_ToFind.FindAndReplace(__T("\\Events\\Ref\\"), __T("\\Events\\New\\"));
404         size_t New_RefPos=New.Find(Ref_ToFind);
405         bool IsDiff=false;
406         if (New_RefPos!=(size_t)-1)
407         {
408             File F_Ref; F_Ref.Open(Ref[Ref_Pos]);
409             File F_New; F_New.Open(New[New_RefPos]);
410             if (F_Ref.Size_Get()==F_New.Size_Get())
411             {
412                 int64u Size=F_Ref.Size_Get();
413                 if (Size>100000000)
414                     Size=100000000;
415                 int8u* F_Ref_Buffer=new int8u[(size_t)Size];
416                 F_Ref.Read(F_Ref_Buffer, (size_t)Size);
417                 int8u* F_New_Buffer=new int8u[(size_t)Size];
418                 F_New.Read(F_New_Buffer, (size_t)Size);
419 
420                 if (memcmp(F_Ref_Buffer, F_New_Buffer, (size_t)Size))
421                     IsDiff=true;
422 
423                 delete[] F_Ref_Buffer;
424                 delete[] F_New_Buffer;
425             }
426             else
427                 IsDiff=true;
428         }
429         if (New_RefPos==(size_t)-1 || IsDiff)
430         {
431             //Not in new or is different
432             Ztring Diff_Name=Ref[Ref_Pos];
433             Diff_Name.FindAndReplace(__T("\\Events\\Ref\\"), __T("\\Events\\Diff\\"));
434             if (!Dir::Exists(DataBaseDirectory+__T("\\Events\\Diff")))
435                 Dir::Create(DataBaseDirectory+__T("\\Events\\Diff"));
436             if (!Dir::Exists(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get()))
437                 Dir::Create(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get());
438             if (!Dir::Exists(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get()+__T("\\")+Ztring::ToZtring(Scenario)))
439                 Dir::Create(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get()+__T("\\")+Ztring::ToZtring(Scenario));
440             if (!Dir::Exists(FileName(Diff_Name).Path_Get()))
441                 Dir::Create(FileName(Diff_Name).Path_Get());
442             if (!IsDiff)
443                 File::Copy(Ref[Ref_Pos], Diff_Name+__T(".RefAlone.txt")); //Not in new
444             else
445             {
446                 File::Copy(Ref[Ref_Pos], Diff_Name+__T(".Ref.txt")); //Diff
447                 File::Copy(New[New_RefPos], Diff_Name+__T(".New.txt"));
448             }
449         }
450         if (New_RefPos!=(size_t)-1)
451             New.erase(New.begin()+New_RefPos);
452     }
453     for (size_t New_Pos=0; New_Pos<New.size(); New_Pos++)
454     {
455         //Not in ref
456         Ztring Diff_Name=New[New_Pos];
457         Diff_Name.FindAndReplace(__T("\\Events\\New\\"), __T("\\Events\\Diff\\"));
458         if (!Dir::Exists(DataBaseDirectory+__T("\\Events\\Diff")))
459             Dir::Create(DataBaseDirectory+__T("\\Events\\Diff"));
460         if (!Dir::Exists(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get()))
461             Dir::Create(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get());
462         if (!Dir::Exists(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get()+__T("\\")+Ztring::ToZtring(Scenario)))
463             Dir::Create(DataBaseDirectory+__T("\\Events\\Diff\\")+FileName(Files).Name_Get()+__T("\\")+Ztring::ToZtring(Scenario));
464         if (!Dir::Exists(FileName(Diff_Name).Path_Get()))
465             Dir::Create(FileName(Diff_Name).Path_Get());
466          File::Copy(New[New_Pos], Diff_Name+__T(".NewAlone.txt")); //Not in new
467     }
468 }
469