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 //---------------------------------------------------------------------------
8 // For user: you can disable or enable it
9 //#define MEDIAINFO_DEBUG
10 //---------------------------------------------------------------------------
11 
12 //---------------------------------------------------------------------------
13 // Pre-compilation
14 #include "MediaInfo/PreComp.h"
15 #ifdef __BORLANDC__
16     #pragma hdrstop
17 #endif
18 //---------------------------------------------------------------------------
19 
20 //---------------------------------------------------------------------------
21 #include "MediaInfo/Setup.h"
22 //---------------------------------------------------------------------------
23 
24 //---------------------------------------------------------------------------
25 #if defined(MEDIAINFO_FILE_YES)
26 #include "MediaInfo/Reader/Reader_File.h"
27 #include "MediaInfo/File__Analyze.h"
28 #include "ZenLib/FileName.h"
29 #ifdef WINDOWS
30     #undef __TEXT
31     #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L
32         namespace WindowsNamespace
33         {
34     #endif
35     #include "windows.h"
36     #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L
37         }
38         using namespace WindowsNamespace;
39     #endif
40 #endif //WINDOWS
41 using namespace ZenLib;
42 using namespace std;
43 //---------------------------------------------------------------------------
44 // Debug stuff
45 #ifdef MEDIAINFO_DEBUG
46     int64u Reader_File_Offset=0;
47     int64u Reader_File_BytesRead_Total=0;
48     int64u Reader_File_BytesRead=0;
49     int64u Reader_File_Count=1;
50     #include <iostream>
51 #endif // MEDIAINFO_DEBUG
52 //---------------------------------------------------------------------------
53 
54 namespace MediaInfoLib
55 {
56 
57 #if MEDIAINFO_READTHREAD
Entry()58 void Reader_File_Thread::Entry()
59 {
60     ReadSize_Max=Base->Buffer_Max>>3;
61 
62     for (;;)
63     {
64         size_t ToRead;
65         size_t Buffer_ToReadOffset;
66         {
67         CriticalSectionLocker CSL(Base->CS);
68         if (Base->Buffer_Begin==Base->Buffer_Max)
69         {
70             Base->IsLooping=false;
71             Base->Buffer_End=Base->Buffer_End2;
72             Base->Buffer_End2=0;
73             Base->Buffer_Begin=0;
74         }
75 
76         if (Base->IsLooping)
77         {
78             ToRead=Base->Buffer_Begin-Base->Buffer_End2;
79             Buffer_ToReadOffset=Base->Buffer_End2;
80         }
81         else
82         {
83             ToRead=Base->Buffer_Max-Base->Buffer_End;
84             Buffer_ToReadOffset=Base->Buffer_End;
85         }
86         }
87         if (ToRead)
88         {
89             if (ToRead>ReadSize_Max)
90                 ToRead=ReadSize_Max;
91             size_t BytesRead=Base->F.Read(Base->Buffer+Buffer_ToReadOffset, ToRead);
92             if (!BytesRead)
93                 break;
94 
95             {
96             CriticalSectionLocker CSL(Base->CS);
97             if (Base->IsLooping)
98             {
99                 Base->Buffer_End2+=BytesRead;
100             }
101             else
102             {
103                 Base->Buffer_End+=BytesRead;
104                 if (Base->Buffer_End==Base->Buffer_Max)
105                 {
106                     Base->IsLooping=true;
107                 }
108             }
109             }
110             #ifdef WINDOWS
111                 SetEvent(Base->Condition_WaitingForMoreData);
112             #endif //WINDOWS
113         }
114         #ifdef WINDOWS
115             else
116                 WaitForSingleObject(Base->Condition_WaitingForMorePlace, INFINITE);
117         #endif //WINDOWS
118 
119         if (IsTerminating())
120             break;
121         Yield();
122     }
123 
124     #ifdef WINDOWS
125         SetEvent(Base->Condition_WaitingForMoreData); //Sending the last event in case the main threading is waiting for more data
126     #endif //WINDOWS
127 }
128 #endif //MEDIAINFO_READTHREAD
129 
130 const size_t Buffer_NoJump=128*1024;
131 
132 //---------------------------------------------------------------------------
~Reader_File()133 Reader_File::~Reader_File()
134 {
135     #if MEDIAINFO_READTHREAD
136         Destroy_Thread(MI_Internal);
137     #endif //MEDIAINFO_READTHREAD
138 }
139 
140 //---------------------------------------------------------------------------
141 #if MEDIAINFO_READTHREAD
Destroy_Thread(MediaInfo_Internal * MI)142 void Reader_File::Destroy_Thread(MediaInfo_Internal* MI)
143 {
144     if (ThreadInstance)
145     {
146         ThreadInstance->RequestTerminate();
147         SetEvent(Condition_WaitingForMorePlace);
148         while (!ThreadInstance->IsExited())
149             Sleep(0);
150 #ifdef WINDOWS
151         CloseHandle(Condition_WaitingForMorePlace);
152         CloseHandle(Condition_WaitingForMoreData);
153 #endif //WINDOWS
154         delete ThreadInstance; ThreadInstance = NULL;
155 
156         MI->Config.File_Buffer = NULL;
157         MI->Config.File_Buffer_Size = 0;
158         MI->Config.File_Buffer_Size_Max = 0;
159         Buffer_Max = 0;
160         delete[] Buffer; Buffer = NULL;
161         Buffer_Begin = 0;
162         Buffer_End = 0;
163         Buffer_End2 = 0;
164         IsLooping = false;
165     }
166 }
167 #endif //MEDIAINFO_READTHREAD
168 
169 //---------------------------------------------------------------------------
Format_Test(MediaInfo_Internal * MI,String File_Name)170 size_t Reader_File::Format_Test(MediaInfo_Internal* MI, String File_Name)
171 {
172     //std::cout<<Ztring(File_Name).To_Local().c_str()<<std::endl;
173     #if MEDIAINFO_EVENTS
174         {
175             string File_Name_Local=Ztring(File_Name).To_Local();
176             wstring File_Name_Unicode=Ztring(File_Name).To_Unicode();
177             struct MediaInfo_Event_General_Start_0 Event;
178             memset(&Event, 0xFF, sizeof(struct MediaInfo_Event_Generic));
179             Event.EventCode=MediaInfo_EventCode_Create(MediaInfo_Parser_None, MediaInfo_Event_General_Start, 0);
180             Event.EventSize=sizeof(struct MediaInfo_Event_General_Start_0);
181             Event.StreamIDs_Size=0;
182             Event.Stream_Size=File::Size_Get(File_Name);
183             Event.FileName=File_Name_Local.c_str();
184             Event.FileName_Unicode=File_Name_Unicode.c_str();
185             MI->Config.Event_Send(NULL, (const int8u*)&Event, sizeof(MediaInfo_Event_General_Start_0));
186         }
187     #endif //MEDIAINFO_EVENTS
188 
189     //With Parser MultipleParsing
190     /*
191     MI->Open_Buffer_Init((int64u)-1, File_Name);
192     if (Format_Test_PerParser(MI, File_Name))
193          return 1;
194     return 0; //There is a problem
195     */
196 
197     //Get the Extension
198     Ztring Extension=FileName::Extension_Get(File_Name);
199     Extension.MakeLowerCase();
200 
201     //Search the theorical format from extension
202     InfoMap &FormatList=MediaInfoLib::Config.Format_Get();
203     InfoMap::iterator Format=FormatList.end();
204     if (!MI->Config.File_ForceParser_Get().empty())
205         Format=FormatList.find(MI->Config.File_ForceParser_Get());
206     if (Format==FormatList.end())
207     {
208         Format=FormatList.begin();
209         while (Format!=FormatList.end())
210         {
211             ZtringList Extensions;
212             Extensions.Separator_Set(0, __T(" "));
213             Extensions.Write(FormatList.Get(Format->first, InfoFormat_Extensions));
214             if (Extensions.Find(Extension)!=Error)
215                 break;
216             ++Format;
217         }
218     }
219     if (Format!=FormatList.end())
220     {
221         const Ztring &Parser=Format->second(InfoFormat_Parser);
222         if (MI->SelectFromExtension(Parser))
223         {
224             //Test the theorical format
225             if (Format_Test_PerParser(MI, File_Name)>0)
226                  return 1;
227         }
228     }
229 
230     size_t ToReturn=MI->ListFormats(File_Name);
231     return ToReturn;
232 }
233 
234 //---------------------------------------------------------------------------
Format_Test_PerParser(MediaInfo_Internal * MI,const String & File_Name)235 size_t Reader_File::Format_Test_PerParser(MediaInfo_Internal* MI, const String &File_Name)
236 {
237     //Init
238     MI_Internal=MI;
239     #if MEDIAINFO_READTHREAD
240         ThreadInstance=NULL;
241         Buffer_End2=0; //Is also used for counting bytes before activating the thread
242     #endif //MEDIAINFO_READTHREAD
243 
244     //Opening the file
245     F.Open(File_Name);
246     if (!F.Opened_Get())
247         return 0;
248 
249     //Info
250     Status=0;
251     MI->Config.File_Size=F.Size_Get();
252     MI->Config.File_Current_Offset=0;
253     MI->Config.File_Current_Size=MI->Config.File_Size;
254     MI->Config.File_Sizes.clear();
255     MI->Config.File_Sizes.push_back(MI->Config.File_Size);
256     MI->Config.File_Names_Pos=1;
257     if (MI->Config.File_Names.size()>1)
258     {
259         #if MEDIAINFO_ADVANCED
260             if (MI->Config.File_IgnoreSequenceFileSize_Get())
261             {
262                 MI->Config.File_Size=(int64u)-1;
263             }
264             else
265         #endif //MEDIAINFO_ADVANCED
266             {
267                 for (size_t Pos=1; Pos<MI->Config.File_Names.size(); Pos++)
268                 {
269                     int64u Size=File::Size_Get(MI->Config.File_Names[Pos]);
270                     MI->Config.File_Sizes.push_back(Size);
271                     MI->Config.File_Size+=Size;
272                 }
273             }
274     }
275 
276     //Partial file handling
277     Ztring Config_Partial_Begin=MI->Config.File_Partial_Begin_Get();
278     if (!Config_Partial_Begin.empty() && Config_Partial_Begin[0]>=__T('0') && Config_Partial_Begin[0]<=__T('9'))
279     {
280         if (Config_Partial_Begin.find(__T('%'))==Config_Partial_Begin.size()-1)
281             Partial_Begin=float64_int64s(MI->Config.File_Size*Config_Partial_Begin.To_float64()/100);
282         else
283             Partial_Begin=Config_Partial_Begin.To_int64u();
284         if (Partial_Begin)
285             F.GoTo(Partial_Begin);
286     }
287     else
288         Partial_Begin=0;
289     Ztring Config_Partial_End=MI->Config.File_Partial_End_Get();
290     if (!Config_Partial_End.empty() && Config_Partial_End[0]>=__T('0') && Config_Partial_End[0]<=__T('9'))
291     {
292         if (Config_Partial_End.find(__T('%'))==Config_Partial_End.size()-1)
293             Partial_End=float64_int64s(MI->Config.File_Size*Config_Partial_End.To_float64()/100);
294         else
295             Partial_End=Config_Partial_End.To_int64u();
296     }
297     else
298         Partial_End=(int64u)-1;
299     if (Partial_Begin>MI->Config.File_Size)
300         Partial_Begin=0; //Wrong value
301     if (Partial_Begin>Partial_End)
302         Partial_Begin=0; //Wrong value
303     CountOfSeconds=0;
304 
305     //Parser
306     MI->Open_Buffer_Init((Partial_End<=MI->Config.File_Size?Partial_End:MI->Config.File_Size)-Partial_Begin, File_Name);
307 
308     //Buffer
309     MI->Option(__T("File_Buffer_Size_Hint_Pointer"), Ztring::ToZtring((size_t)(&MI->Config.File_Buffer_Size_ToRead)));
310     MI->Config.File_Buffer_Repeat_IsSupported=true;
311 
312     //Test the format with buffer
313     return Format_Test_PerParser_Continue(MI);
314 }
315 
316 //---------------------------------------------------------------------------
Format_Test_PerParser_Continue(MediaInfo_Internal * MI)317 size_t Reader_File::Format_Test_PerParser_Continue (MediaInfo_Internal* MI)
318 {
319     if (MI == NULL)
320         return 0;
321 
322     bool StopAfterFilled=MI->Config.File_StopAfterFilled_Get();
323     bool ShouldContinue=true;
324     if (MI->Info)
325         Status=MI->Info->Status;
326 
327     //Previous data
328     if (MI->Config.File_Buffer_Repeat)
329     {
330         MI->Config.File_Buffer_Repeat=false;
331         #if MEDIAINFO_DEMUX
332             MI->Config.Demux_EventWasSent=false;
333         #endif //MEDIAINFO_DEMUX
334 
335         Status=MI->Open_Buffer_Continue(MI->Config.File_Buffer, MI->Config.File_Buffer_Size);
336 
337         #if MEDIAINFO_READTHREAD
338             if (ThreadInstance && !MI->Config.File_Buffer_Repeat)
339             {
340                 CS.Enter();
341                 Buffer_Begin+=MI->Config.File_Buffer_Size;
342                 #ifdef WINDOWS
343                     if (Buffer_Begin==Buffer_Max)
344                     {
345                         CS.Leave();
346                         SetEvent(Condition_WaitingForMorePlace);
347                     }
348                     else
349                 #endif //WINDOWS
350                         CS.Leave();
351             }
352         #endif //MEDIAINFO_READTHREAD
353 
354         #if MEDIAINFO_DEMUX
355             //Demux
356             if (MI->Config.Demux_EventWasSent)
357                 return 2; //Must return immediately
358         #endif //MEDIAINFO_DEMUX
359 
360         //Threading
361         if (MI->IsTerminating() || MI->Config.RequestTerminate)
362             return 1; //Termination is requested
363 
364         if (Status[File__Analyze::IsFinished] || (StopAfterFilled && Status[File__Analyze::IsFilled]))
365             ShouldContinue=false;
366     }
367 
368     #if MEDIAINFO_DEMUX
369     //PerPacket
370     if (ShouldContinue && MI->Config.Demux_EventWasSent)
371     {
372         MI->Config.Demux_EventWasSent=false;
373 
374         Status=MI->Open_Buffer_Continue(NULL, 0);
375 
376         //Demux
377         if (MI->Config.Demux_EventWasSent)
378             return 2; //Must return immediately
379 
380         //Threading
381         if (MI->IsTerminating() || MI->Config.RequestTerminate)
382             return 1; //Termination is requested
383 
384         if (Status[File__Analyze::IsFinished] || MI->Config.IsFinishing || (StopAfterFilled && Status[File__Analyze::IsFilled]))
385             ShouldContinue=false;
386     }
387     #endif //MEDIAINFO_DEMUX
388 
389     if (ShouldContinue)
390     {
391         //Test the format with buffer
392         while (!(Status[File__Analyze::IsFinished] || (StopAfterFilled && Status[File__Analyze::IsFilled])))
393         {
394             //Seek (if needed)
395             if (MI->Open_Buffer_Continue_GoTo_Get()!=(int64u)-1)
396             {
397                 #ifdef MEDIAINFO_DEBUG
398                     std::cout<<std::hex<<Reader_File_Offset<<" - "<<Reader_File_Offset+Reader_File_BytesRead<<" : "<<std::dec<<Reader_File_BytesRead<<" bytes"<<std::endl;
399                     Reader_File_Offset=MI->Open_Buffer_Continue_GoTo_Get();
400                     Reader_File_BytesRead=0;
401                     Reader_File_Count++;
402                 #endif //MEDIAINFO_DEBUG
403 
404                 #if MEDIAINFO_READTHREAD
405                     Destroy_Thread(MI);
406                     if (Buffer_End2!=(size_t)-1)
407                         Buffer_End2=0;
408                 #endif //MEDIAINFO_READTHREAD
409 
410                 int64u GoTo=Partial_Begin+MI->Open_Buffer_Continue_GoTo_Get();
411                 MI->Config.File_Current_Offset=0;
412                 int64u Buffer_NoJump_Temp=Buffer_NoJump;
413                 if (MI->Config.File_Names.size()>1)
414                 {
415                     size_t Pos;
416                     #if MEDIAINFO_SEEK
417                         if (MI->Config.File_GoTo_IsFrameOffset)
418                         {
419                             Pos=(size_t)MI->Open_Buffer_Continue_GoTo_Get(); //File_GoTo is the frame offset in that case
420                             MI->Info->File_GoTo=(int64u)-1;
421                             MI->Config.File_GoTo_IsFrameOffset=false;
422                             GoTo=0;
423                         }
424                         else
425                     #endif //MEDIAINFO_SEEK
426                     {
427                         for (Pos=0; Pos<MI->Config.File_Names.size(); Pos++)
428                         {
429                             if (Pos==MI->Config.File_Sizes.size())
430                                 MI->Config.File_Sizes.push_back(F.Size_Get());
431                             else if (MI->Config.File_Sizes[Pos]==(int64u)-1)
432                                 MI->Config.File_Sizes[Pos]=F.Size_Get();
433 
434                             if (Pos>=MI->Config.File_Sizes.size() || MI->Config.File_Sizes[Pos]==(int64u)-1)
435                                 break;
436 
437                             if (GoTo<MI->Config.File_Sizes[Pos])
438                                 break;
439 
440                             GoTo-=MI->Config.File_Sizes[Pos];
441                             MI->Config.File_Current_Offset+=MI->Config.File_Sizes[Pos];
442                         }
443                         if (Pos>=MI->Config.File_Sizes.size())
444                             break;
445                     }
446                     if (Pos!=MI->Config.File_Names_Pos-1)
447                     {
448                         F.Close();
449                         F.Open(MI->Config.File_Names[Pos]);
450                         if (Pos>=MI->Config.File_Sizes.size())
451                         {
452                             MI->Config.File_Sizes.resize(Pos, (int64u)-1);
453                             MI->Config.File_Sizes.push_back(F.Size_Get());
454                         }
455                         MI->Config.File_Names_Pos=Pos+1;
456                         MI->Config.File_Current_Size=MI->Config.File_Current_Offset+F.Size_Get();
457                         Buffer_NoJump_Temp=0;
458                     }
459                 }
460 
461                 if (GoTo>=F.Size_Get())
462                     break; //Seek requested, but on a file bigger in theory than what is in the real file, we can't do this
463                 if (!(GoTo>F.Position_Get() && GoTo<F.Position_Get()+Buffer_NoJump_Temp)) //No smal jumps
464                 {
465                      if (!F.GoTo(GoTo))
466                         break; //File is not seekable
467 
468                     MI->Open_Buffer_Init((int64u)-1, MI->Config.File_Current_Offset+F.Position_Get()-Partial_Begin);
469                 }
470             }
471 
472             #if MEDIAINFO_READTHREAD
473                 if (ThreadInstance==NULL && Buffer_End2!=(size_t)-1 && Buffer_End2>=16*1024*1024)
474                 {
475                     if (!MI->Config.File_IsGrowing && MI->Config.File_Names.size()==1)
476                     {
477                         delete[] MI->Config.File_Buffer; MI->Config.File_Buffer=NULL;
478                         MI->Config.File_Buffer_Size_Max=0;
479                         Buffer_Max=MI->Config.File_Buffer_Read_Size_Get();
480                         Buffer=new int8u[Buffer_Max];
481                         Buffer_Begin=0;
482                         Buffer_End=0;
483                         Buffer_End2=0;
484                         IsLooping=false;
485                         #ifdef WINDOWS
486                             Condition_WaitingForMorePlace=CreateEvent(NULL, FALSE, FALSE, NULL);
487                             Condition_WaitingForMoreData=CreateEvent(NULL, FALSE, FALSE, NULL);
488                         #endif //WINDOWS
489                         ThreadInstance=new Reader_File_Thread();
490                         ThreadInstance->Base=this;
491                         ThreadInstance->Run();
492                     }
493                     else
494                         Buffer_End2=(size_t)-1;
495                 }
496             #endif //MEDIAINFO_READTHREAD
497 
498             //Handling of hints
499             if (MI->Config.File_Buffer_Size_ToRead==0)
500                 break; //Problem while config
501             if (
502                 #if MEDIAINFO_READTHREAD
503                     ThreadInstance==NULL &&
504                 #endif //MEDIAINFO_READTHREAD
505                 MI->Config.File_Buffer_Size_ToRead>MI->Config.File_Buffer_Size_Max)
506             {
507                 delete[] MI->Config.File_Buffer;
508                 if (MI->Config.File_Buffer_Size_Max==0)
509                     MI->Config.File_Buffer_Size_Max=1;
510                 while (MI->Config.File_Buffer_Size_ToRead>MI->Config.File_Buffer_Size_Max)
511                     MI->Config.File_Buffer_Size_Max*=2;
512                 if (MI->Config.File_Buffer_Size_Max>=64*1024*1024)
513                 {
514                     MI->Config.File_Buffer_Size_Max=64*1024*1024; //limitation of the buffer in order to avoid to big memory usage
515                     MI->Config.File_Buffer_Size_ToRead=MI->Config.File_Buffer_Size_Max;
516                 }
517                 MI->Config.File_Buffer=new int8u[MI->Config.File_Buffer_Size_Max];
518             }
519 
520             //Testing multiple file per stream
521             if (
522                 #if MEDIAINFO_READTHREAD
523                     ThreadInstance==NULL &&
524                 #endif //MEDIAINFO_READTHREAD
525                 F.Position_Get()>=F.Size_Get())
526             {
527                 #if MEDIAINFO_ADVANCED2
528                 MI->Open_Buffer_SegmentChange();
529                 #endif //MEDIAINFO_ADVANCED2
530                 if (MI->Config.File_Names_Pos && MI->Config.File_Names_Pos<MI->Config.File_Names.size())
531                 {
532                     MI->Config.File_Current_Offset+=MI->Config.File_Names_Pos<=MI->Config.File_Sizes.size()?MI->Config.File_Sizes[MI->Config.File_Names_Pos-1]:F.Size_Get();
533                     F.Close();
534                     #if MEDIAINFO_EVENTS
535                         MI->Config.Event_SubFile_Start(MI->Config.File_Names[MI->Config.File_Names_Pos]);
536                     #endif //MEDIAINFO_EVENTS
537                     F.Open(MI->Config.File_Names[MI->Config.File_Names_Pos]);
538                     while (!F.Opened_Get())
539                     {
540                         #if MEDIAINFO_EVENTS
541                             MI->Config.Event_SubFile_Missing_Absolute(MI->Config.File_Names[MI->Config.File_Names_Pos]);
542                         #endif //MEDIAINFO_EVENTS
543                         if (MI->Config.File_Names_Pos+1<MI->Config.File_Names.size())
544                         {
545                             MI->Config.File_Names_Pos++;
546                             F.Open(MI->Config.File_Names[MI->Config.File_Names_Pos]);
547                         }
548                         else //break the otherwise infinite loop
549                         {
550                             break;
551                         }
552                     }
553                     if (MI->Config.File_Names_Pos>=MI->Config.File_Sizes.size())
554                     {
555                         MI->Config.File_Sizes.resize(MI->Config.File_Names_Pos, 0);
556                         MI->Config.File_Sizes.push_back(F.Size_Get());
557                     }
558                     MI->Config.File_Names_Pos++;
559                     MI->Config.File_Current_Size+=F.Size_Get();
560                 }
561             }
562 
563             #if MEDIAINFO_READTHREAD
564                 if (ThreadInstance)
565                 {
566                     CS.Enter();
567                     #ifdef WINDOWS
568                         if (Buffer_End2+Buffer_End-Buffer_Begin<Buffer_Max/8*7)
569                         {
570                             CS.Leave();
571                             SetEvent(Condition_WaitingForMorePlace);
572                             CS.Enter();
573                         }
574                     #endif //WINDOWS
575 
576                     for (;;)
577                     {
578                         MI->Config.File_Buffer_Size=Buffer_End-Buffer_Begin;
579 
580                         if (MI->Config.File_Buffer_Size)
581                             break;
582 
583                         if (!ThreadInstance->IsExited())
584                         {
585                             CS.Leave();
586                             #ifdef WINDOWS
587                                 WaitForSingleObject(Condition_WaitingForMoreData, INFINITE);
588                             #else //WINDOWS
589                                 Sleep(0);
590                             #endif //WINDOWS
591                             CS.Enter();
592                         }
593                         else
594                         {
595                             if (IsLooping)
596                             {
597                                 IsLooping=false;
598                                 Buffer_End=Buffer_End2;
599                                 Buffer_End2=0;
600                                 Buffer_Begin=0;
601                             }
602 
603                             MI->Config.File_Buffer_Size=Buffer_End-Buffer_Begin;
604                             break;
605                         }
606                     }
607                     MI->Config.File_Buffer=Buffer+Buffer_Begin;
608                     CS.Leave();
609                     if (MI->Config.File_Buffer_Size>MI->Config.File_Buffer_Size_ToRead)
610                         MI->Config.File_Buffer_Size=MI->Config.File_Buffer_Size_ToRead;
611                 }
612                 else
613             #endif //MEDIAINFO_READTHREAD
614             {
615                 size_t SizeToRead=(F.Position_Get()+MI->Config.File_Buffer_Size_ToRead<(Partial_End<=MI->Config.File_Size?Partial_End:MI->Config.File_Size))?MI->Config.File_Buffer_Size_ToRead:((size_t)((Partial_End<=MI->Config.File_Size?Partial_End:MI->Config.File_Size)-F.Position_Get()));
616                 if (MI->Config.File_Buffer_Size_Max>MI->Info->Buffer_Size)
617                 {
618                     size_t SizeToRead_Max=MI->Config.File_Buffer_Size_Max-MI->Info->Buffer_Size;
619                     if (SizeToRead>SizeToRead_Max)
620                         SizeToRead=SizeToRead_Max;
621                 }
622                 MI->Config.File_Buffer_Size=F.Read(MI->Config.File_Buffer, SizeToRead);
623                 #if MEDIAINFO_READTHREAD
624                     if (ThreadInstance==NULL && Buffer_End2!=(size_t)-1)
625                         Buffer_End2+=MI->Config.File_Buffer_Size;
626                 #endif //MEDIAINFO_READTHREAD
627             }
628 
629             /* High CPU usage
630             #if MEDIAINFO_EVENTS
631                 if (MI->Config.File_Buffer_Size)
632                 {
633                     struct MediaInfo_Event_Global_BytesRead_0 Event;
634                     memset(&Event, 0xFF, sizeof(struct MediaInfo_Event_Generic));
635                     Event.EventCode=MediaInfo_EventCode_Create(MediaInfo_Parser_None, MediaInfo_Event_Global_BytesRead, 0);
636                     Event.EventSize=sizeof(struct MediaInfo_Event_Global_BytesRead_0);
637                     Event.StreamIDs_Size=0;
638                     Event.StreamOffset=F.Position_Get()-MI->Config.File_Buffer_Size;
639                     Event.Content_Size=MI->Config.File_Buffer_Size;
640                     Event.Content=MI->Config.File_Buffer;
641                     MI->Config.Event_Send(NULL, (const int8u*)&Event, sizeof(MediaInfo_Event_Global_BytesRead_0));
642                 }
643             #endif //MEDIAINFO_EVENTS
644             */
645 
646             //Testing growing files
647             if (MI->Config.ParseSpeed>=1.0 && !MI->Config.File_IsGrowing && MI->Config.File_Current_Offset+F.Position_Get()>=MI->Config.File_Size)
648             {
649                 if (MI->Config.File_TestContinuousFileNames_Get())
650                 {
651                     //int64u Growing_Temp=MI->Config.File_Names.size();
652                     if (MI->Config.File_Names.size()>=24) // only if already a sequence of files
653                         MI->TestContinuousFileNames();
654                     /* TODO: fix about sequences of files
655                     if (MI->Config.File_Names.size()!=Growing_Temp)
656                         MI->Config.File_IsGrowing=true;
657                     */
658                 }
659                 if (MI->Config.File_Names.size()==1)
660                 {
661                     int64u Growing_Temp=F.Size_Get();
662                     if (MI->Config.File_Size!=Growing_Temp)
663                         MI->Config.File_IsGrowing=true;
664                 }
665             }
666             if (MI->Config.File_IsNotGrowingAnymore)
667             {
668                 MI->Config.File_Current_Size=MI->Config.File_Size=F.Size_Get();
669                 MI->Open_Buffer_Init(MI->Config.File_Size, F.Position_Get()-MI->Config.File_Buffer_Size);
670                 MI->Config.File_IsGrowing=false;
671             }
672             if ((MI->Config.File_IsGrowing                                                                          //Was previously detected as growing
673               || (!MI->Config.File_IsNotGrowingAnymore && MI->Config.File_GrowingFile_Force_Get()))                 //Forced test and container did not indicate it is not growing anymore
674                 #if MEDIAINFO_READTHREAD
675                     && (!ThreadInstance || (!IsLooping && Buffer_Begin+MI->Config.File_Buffer_Size>=Buffer_End))    //File buffer hit the end of buffer
676                 #endif //MEDIAINFO_READTHREAD
677              && F.Opened_Get()                                                                                      //File must be still open
678              && MI->Config.File_Current_Offset+F.Position_Get()>=MI->Config.File_Size                               //File read hit the end of file
679              && MI->Config.File_Names.size()==1) //TODO: fix about sequences of files
680             {
681                 #if MEDIAINFO_EVENTS
682                     {
683                         struct MediaInfo_Event_General_WaitForMoreData_Start_0 Event;
684                         memset(&Event, 0xFF, sizeof(struct MediaInfo_Event_Generic));
685                         Event.EventCode=MediaInfo_EventCode_Create(MediaInfo_Parser_None, MediaInfo_Event_General_WaitForMoreData_Start, 0);
686                         Event.EventSize=sizeof(struct MediaInfo_Event_General_WaitForMoreData_Start_0);
687                         Event.StreamIDs_Size=0;
688                         Event.Duration_Max=(double)MI->Config.File_GrowingFile_Delay_Get();
689                         MI->Config.Event_Send(NULL, (const int8u*)&Event, sizeof(MediaInfo_Event_General_WaitForMoreData_Start_0));
690                     }
691                 #endif //MEDIAINFO_EVENTS
692 
693                 for (; CountOfSeconds<(size_t)MI->Config.File_GrowingFile_Delay_Get(); CountOfSeconds++)
694                 {
695                     int64u LastFile_Size_Old=MI->Config.File_Sizes[MI->Config.File_Sizes.size()-1];
696                     size_t Files_Count_Old=MI->Config.File_Names.size();
697                     //MI->TestContinuousFileNames(); //TODO: fix about sequences of files, "MI->Config.File_Names.size()==1 && " was added "else if (MI->Config.File_TestContinuousFileNames_Get())" commented
698                     int64u LastFile_Size_New=F.Size_Get();
699                     size_t Files_Count_New=MI->Config.File_Names.size();
700                     MI->Open_Buffer_CheckFileModifications();
701 
702                     if (LastFile_Size_New != LastFile_Size_Old || Files_Count_New != Files_Count_Old || MI->Config.File_IsNotGrowingAnymore)
703                     {
704                         #if MEDIAINFO_EVENTS
705                             {
706                                 struct MediaInfo_Event_General_WaitForMoreData_End_0 Event;
707                                 memset(&Event, 0xFF, sizeof(struct MediaInfo_Event_Generic));
708                                 Event.EventCode=MediaInfo_EventCode_Create(MediaInfo_Parser_None, MediaInfo_Event_General_WaitForMoreData_End, 0);
709                                 Event.EventSize=sizeof(struct MediaInfo_Event_General_WaitForMoreData_End_0);
710                                 Event.StreamIDs_Size=0;
711                                 Event.Duration_Max=(double)MI->Config.File_GrowingFile_Delay_Get();
712                                 Event.Duration_Actual=(double)CountOfSeconds;
713                                 Event.Flags=0; //Countinuing
714                                 MI->Config.Event_Send(NULL, (const int8u*)&Event, sizeof(MediaInfo_Event_General_WaitForMoreData_End_0));
715                             }
716                         #endif //MEDIAINFO_EVENTS
717                         CountOfSeconds=0;
718                         MI->Config.File_Current_Size=MI->Config.File_Size=LastFile_Size_New; //TODO: check if it is not doable in Open_Buffer_Init() also when MI->Config.File_Names.size() > 1
719                         if (!MI->Config.File_Sizes.empty())
720                             MI->Config.File_Sizes[MI->Config.File_Sizes.size()-1]=LastFile_Size_New;
721                         if (MI->Config.File_Names.size()==1) //if more than 1 file, file size config is already done in TestContinuousFileNames()
722                             MI->Open_Buffer_Init(MI->Config.File_Size, MI->Config.File_Current_Offset+F.Position_Get()-MI->Config.File_Buffer_Size);
723                         #if MEDIAINFO_READTHREAD
724                             if (ThreadInstance)
725                                 ThreadInstance->RunAgain();
726                         #endif //MEDIAINFO_READTHREAD
727                         break;
728                     }
729 
730                     #ifdef WINDOWS
731                         Sleep(1000);
732                     #endif //WINDOWS
733                 }
734 
735                 if (CountOfSeconds>=(size_t)MI->Config.File_GrowingFile_Delay_Get())
736                 {
737                     #if MEDIAINFO_EVENTS
738                         {
739                             struct MediaInfo_Event_General_WaitForMoreData_End_0 Event;
740                             memset(&Event, 0xFF, sizeof(struct MediaInfo_Event_Generic));
741                             Event.EventCode=MediaInfo_EventCode_Create(MediaInfo_Parser_None, MediaInfo_Event_General_WaitForMoreData_End, 0);
742                             Event.EventSize=sizeof(struct MediaInfo_Event_General_WaitForMoreData_End_0);
743                             Event.StreamIDs_Size=0;
744                             Event.Duration_Max=(double)MI->Config.File_GrowingFile_Delay_Get();
745                             Event.Duration_Actual=(double)CountOfSeconds;
746                             Event.Flags=1; //Giving up
747                             MI->Config.Event_Send(NULL, (const int8u*)&Event, sizeof(MediaInfo_Event_General_WaitForMoreData_End_0));
748                         }
749                     #endif //MEDIAINFO_EVENTS
750 
751                     MI->Config.File_IsGrowing=false;
752                 }
753             }
754 
755             if (!MI->Config.File_Buffer_Size
756              && (MI->Config.File_Current_Offset + F.Position_Get()>=MI->Config.File_Size
757               || (MI->Config.File_Size==(int64u)-1 && MI->Config.File_Names_Pos>=MI->Config.File_Names.size() && F.Position_Get()>=F.Size_Get())))
758                 break; //Finished, and no other data
759 
760             #ifdef MEDIAINFO_DEBUG
761                 Reader_File_BytesRead_Total+=MI->Config.File_Buffer_Size;
762                 Reader_File_BytesRead+=MI->Config.File_Buffer_Size;
763             #endif //MEDIAINFO_DEBUG
764 
765             //Parser
766             Status=MI->Open_Buffer_Continue(MI->Config.File_Buffer, MI->Config.File_Buffer_Size);
767 
768             #if MEDIAINFO_READTHREAD
769                 if (ThreadInstance && !MI->Config.File_Buffer_Repeat)
770                 {
771                     CS.Enter();
772                     Buffer_Begin+=MI->Config.File_Buffer_Size;
773                     #ifdef WINDOWS
774                         if (Buffer_Begin==Buffer_Max)
775                         {
776                             CS.Leave();
777                             SetEvent(Condition_WaitingForMorePlace);
778                         }
779                         else
780                     #endif //WINDOWS
781                            CS.Leave();
782                 }
783             #endif //MEDIAINFO_READTHREAD
784 
785             if (!MI->Config.File_IsGrowing && MI->Config.File_Buffer_Size==0)
786             {
787                 #if MEDIAINFO_EVENTS
788                     MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0xF0F00101, "File read error");
789                 #endif //MEDIAINFO_EVENTS
790                 break;
791             }
792 
793             #if MEDIAINFO_DEMUX
794                 if (MI->Config.Demux_EventWasSent)
795                     return 2; //Must return immediately
796             #endif //MEDIAINFO_DEMUX
797 
798             //Threading
799             if (MI->IsTerminating() || MI->Config.RequestTerminate)
800                 break; //Termination is requested
801         }
802     }
803 
804     //Deleting buffer
805     #if MEDIAINFO_READTHREAD
806         if (ThreadInstance)
807         {
808             Destroy_Thread(MI);
809         }
810         else
811     #endif //MEDIAINFO_READTHREAD
812     {
813         delete[] MI->Config.File_Buffer; MI->Config.File_Buffer=NULL;
814         MI->Config.File_Buffer_Size_Max=0;
815     }
816 
817     #ifdef MEDIAINFO_DEBUG
818         std::cout<<std::hex<<Reader_File_Offset<<" - "<<Reader_File_Offset+Reader_File_BytesRead<<" : "<<std::dec<<Reader_File_BytesRead<<" bytes"<<std::endl;
819         std::cout<<"Total: "<<std::dec<<Reader_File_BytesRead_Total<<" bytes in "<<Reader_File_Count<<" blocks"<<std::endl;
820     #endif //MEDIAINFO_DEBUG
821 
822     if (!MI->Config.File_KeepInfo_Get())
823     {
824         //File
825         F.Close();
826     }
827 
828     //Is this file detected?
829     if (!Status[File__Analyze::IsAccepted])
830         return 0;
831 
832     MI->Open_Buffer_Finalize();
833 
834     #if MEDIAINFO_DEMUX
835         if (MI->Config.Demux_EventWasSent)
836             return 2; //Must return immediately
837     #endif //MEDIAINFO_DEMUX
838 
839     return 1;
840 }
841 
842 //---------------------------------------------------------------------------
843 #if MEDIAINFO_SEEK
Format_Test_PerParser_Seek(MediaInfo_Internal * MI,size_t Method,int64u Value,int64u ID)844 size_t Reader_File::Format_Test_PerParser_Seek (MediaInfo_Internal* MI, size_t Method, int64u Value, int64u ID)
845 {
846     size_t ToReturn=MI->Open_Buffer_Seek(Method, Value, ID);
847 
848     if (ToReturn==0 || ToReturn==1)
849     {
850         //Reset
851         Status=0;
852     }
853 
854     return ToReturn;
855 }
856 #endif //MEDIAINFO_SEEK
857 
858 } //NameSpace
859 
860 #endif //MEDIAINFO_FILE_YES
861