1 // ==========================================================================
2 //                 SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2018, Knut Reinert, FU Berlin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 //       notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above copyright
13 //       notice, this list of conditions and the following disclaimer in the
14 //       documentation and/or other materials provided with the distribution.
15 //     * Neither the name of Knut Reinert or the FU Berlin nor the names of
16 //       its contributors may be used to endorse or promote products derived
17 //       from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 // DAMAGE.
30 //
31 // ==========================================================================
32 // Author: David Weese <david.weese@fu-berlin.de>
33 // ==========================================================================
34 // Defines basic file access functions.
35 // ==========================================================================
36 
37 #ifndef SEQAN_INCLUDE_SEQAN_FILE_BASE_H_
38 #define SEQAN_INCLUDE_SEQAN_FILE_BASE_H_
39 
40 /* IOREV
41  * _doc_
42  *
43  * base class with SPecs and Tags
44  * also contains standard calls for IO as wrappers around members
45  * in system/file_sync.h and system/file_ssync.h
46  * (these files are built around c++ fstream IO)
47  * well documented (in comparison to other files)
48  *
49  * SEQAN_DIRECTIO Macro mentioned here but not documented or tested
50  */
51 
52 namespace seqan {
53 
54 // Manual Forward.
55 template < typename TSpec, typename TPos >
56 inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs, int origin);
57 template < typename TSpec, typename TPos >
58 inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs);
59 
60     //////////////////////////////////////////////////////////////////////////////
61     // generic open/close interface
62 
63 /*!
64  * @fn File#open
65  * @brief Opens a file, stream, or persistent string.
66  *
67  * @signature bool open(file, fileName, openMode);
68  *
69  * @param[in,out] file     The File to open.
70  * @param[in]     fileName A <tt>char const *</tt> string containing the file name.
71  * @param[in]     openMode Combination of flags defining how the file should be opened.  See @link FileOpenMode
72  *                         @endlink for more details.  Type: <tt>int</tt>.  If you omit the <tt>OPEN_APPEND</tt> flag in
73  *                         write mode, the file will be cleared when opened.  Default: <tt>OPEN_RDWR | OPEN_CREATE |
74  *                         OPEN_APPEND</tt>.
75  *
76  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
77  */
78 
79     template < typename TSpec >
open(File<TSpec> & me,const char * fileName,int openMode)80     inline bool open(File<TSpec> &me, const char *fileName, int openMode)
81     {
82 //IOREV resolves to member in file_(a)sync.h which resolves to fstream
83         return me.open(fileName, openMode);
84     }
85 
86     template < typename TSpec >
open(File<TSpec> & me,const char * fileName)87     inline bool open(File<TSpec> &me, const char *fileName)
88     {
89 //IOREV
90         return open(me, fileName, DefaultOpenMode<File<TSpec> >::VALUE);
91     }
92 
93 /*!
94  * @fn File#openTemp
95  * @brief Opens a temporary file.
96  *
97  * @signature bool openTemp(file);
98  *
99  * @param[in,out] file The File object to open the temporary file.
100  *
101  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
102  *
103  * @section Remarks
104  *
105  * After closing this file will be deleted automatically.  The openmode (see @link File#open @endlink) is <tt>OPEN_RDWR
106  * | OPEN_CREATE</tt>.
107  *
108  * @return bool <tt>true</tt> on success <tt>false</tt> on failure.
109  */
110 
111     template < typename TSpec >
openTemp(File<TSpec> & me)112     inline bool openTemp(File<TSpec> &me)
113     {
114 //IOREV
115         return me.openTemp();
116     }
117 
118     template < typename TSpec >
openTemp(File<TSpec> & me,int openMode)119     inline bool openTemp(File<TSpec> &me, int openMode)
120     {
121 //IOREV
122         return me.openTemp(openMode);
123     }
124 
125     template < typename File >
reopen(File &,int)126     inline void reopen(File &, int)
127     {
128 //IOREV _stub_ _nodoc_ This is currently a no-op. Is that intended?
129     }
130 
131 /*!
132  * @fn File#close
133  * @brief Close a file.
134  *
135  * @signature bool close(file);
136  *
137  * @param[in,out] file The File object to close.
138  *
139  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
140  */
141 
142     template < typename TSpec >
close(File<TSpec> & me)143     inline bool close(File<TSpec> & me)
144     {
145 //IOREV
146         return me.close();
147     }
148 
149     template < typename TSpec >
sectorSize(File<TSpec> const &)150     inline unsigned sectorSize(File<TSpec> const & /*me*/)
151     {
152 //IOREV _duplicate_ _nodoc_ duplicate or identical spec. in file_cstyle.h should'nt this be variable
153         return 4096;
154     }
155 
156 
157     //////////////////////////////////////////////////////////////////////////////
158     // generic read(At)/write(At) interface
159 
160 /*!
161  * @fn File#read
162  * @brief Loads record from a file.
163  *
164  * @signature bool read(file, memPtr, count);
165  *
166  * @param[in,out] file   The File object.
167  * @param[out]    memPtr A pointer to the first destination record in memory.
168  * @param[in]     count  The amount of records to be read.
169  *
170  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
171  *
172  * @section Remarks
173  *
174  * The records are read from the position pointed to by the current file pointer (see @link File#seek @endlink).
175  */
176 
177     template < typename TSpec, typename TValue, typename TSize >
read(File<TSpec> & me,TValue * memPtr,TSize const count)178     inline bool read(File<TSpec> & me, TValue *memPtr, TSize const count)
179     {
180 //IOREV
181         typedef typename Size<File<TSpec> >::Type TFileSize;
182         TFileSize nbytes = (TFileSize)count * (TFileSize)sizeof(TValue);
183         return me.read(memPtr, nbytes) == nbytes;
184     }
185 
186 /*!
187  * @fn File#write
188  * @brief Saves records to a file.
189  *
190  * @signature bool write(file, memPtr, count);
191  *
192  * @param[in,out] file   The File object.
193  * @param[in]     memPtr Pointer to the source for the data to write.
194  * @param[in]     count  The number of records to write.
195  *
196  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
197  *
198  * @section Remarks
199  *
200  * The records are written at the position pointed to by the current file pointer (see @link File#seek @endlink).
201  */
202 
203     template < typename TSpec, typename TValue, typename TSize >
write(File<TSpec> & me,TValue const * memPtr,TSize const count)204     inline bool write(File<TSpec> & me, TValue const *memPtr, TSize const count)
205     {
206 //IOREV
207         typedef typename Size<File<TSpec> >::Type TFileSize;
208         TFileSize nbytes = (TFileSize)count * (TFileSize)sizeof(TValue);
209         return me.write(memPtr, nbytes) == nbytes;
210     }
211 
212 /*!
213  * @fn File#readAt
214  * @brief Loads records from a specific position in a file.
215  *
216  * @signature bool readAt(file, memPtr, count, fileOfs);
217  *
218  * @param[in,out] file    The File object to read from.
219  * @param[out]    memPtr  A pointer to the first destination record in memory.
220  * @param[in]     count   The amount of records to be read.
221  * @param[in]     fileOfs The absolute file position in bytes measured from the beginning.
222  *
223  * @return bool <tt>true</tt> on success and <tt>false</tt> on failure.
224  */
225 
226     template < typename TFile, typename TValue, typename TSize, typename TPos >
readAt(TFile & me,TValue * memPtr,TSize const count,TPos const fileOfs)227     inline bool readAt(TFile & me, TValue *memPtr, TSize const count, TPos const fileOfs)
228     {
229 //IOREV
230         typedef typename Position<TFile>::Type pos_t;
231         seek(me, (pos_t)fileOfs * (pos_t)sizeof(TValue));
232         return read(me, memPtr, count);
233     }
234 
235 /*!
236  * @fn File#writeAt
237  * @brief Saves records to a specific position in a file.
238  *
239  * @signature bool writeAt(file, memPtr, count, fileOfs);
240  *
241  * @param[in,out] file    The File object to write to.
242  * @param[in]     memPtr  Pointer to the memory to write.
243  * @param[in]     count   The amount of records to be written.
244  * @param[in]     fileOfs The absolute file position in bytes measured from the beginning.
245  *
246  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
247  */
248 
249     template < typename TFile, typename TValue, typename TSize, typename TPos >
writeAt(TFile & me,TValue const * memPtr,TSize const count,TPos const fileOfs)250     inline bool writeAt(TFile & me, TValue const *memPtr, TSize const count, TPos const fileOfs)
251     {
252 //IOREV
253         typedef typename Position<TFile>::Type pos_t;
254         seek(me, (pos_t)fileOfs * (pos_t)sizeof(TValue));
255         return write(me, memPtr, count);
256     }
257 
258 
259 
260     //////////////////////////////////////////////////////////////////////////////
261     // generic seek/tell/size/resize interface
262 
263 /*!
264  * @fn File#seek
265  * @brief Changes the current file pointer.
266  *
267  * @signature TPosition seek(file, fileOfs[, origin]);
268  *
269  * @param[in,out] file    The File object to seek in.
270  * @param[in]     fileOfs A file offset measured in bytes relative to <tt>origin</tt>.
271  * @param[in]     origin  Selects the origin from where to calculate the new position.  One of <tt>SEEK_BEGIN</tt>,
272  *                        <tt>SEEK_CURRENT</tt>, and <tt>SEEK_END<tt> (origin is beginning, current pointer, end of
273  *                        the file).  Default: <tt>SEEK_BEGIN</tt>.
274  *
275  * @return TPosition The new file position measured in bytes from the beginning.
276  */
277 
278     template < typename TSpec, typename TPos >
seek(File<TSpec> & me,TPos const fileOfs,int origin)279     inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs, int origin)
280     {
281 //IOREV
282         typedef typename Position< File<TSpec> >::Type TFilePos;
283         TFilePos newOfs = me.seek(fileOfs, origin);
284         #if SEQAN_ENABLE_DEBUG || SEQAN_ENABLE_TESTING
285             if (origin == SEEK_BEGIN && newOfs != (TFilePos)fileOfs) {
286                 std::cerr << "seek returned " << std::hex << newOfs << " instead of " << fileOfs << std::dec << std::endl;
287             }
288         #endif
289         return newOfs;
290     }
291 
292     template < typename TSpec, typename TPos >
seek(File<TSpec> & me,TPos const fileOfs)293     inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs)
294     {
295 //IOREV
296         return seek(me, fileOfs, SEEK_BEGIN);
297     }
298 
299 /*!
300  * @fn File#tell
301  * @brief Gets the current file pointer.
302  *
303  * @signature TPosition tell(file);
304  *
305  * @param[in] file The File object to query for the current position.
306  *
307  * @return TPosition The current position in the file.
308  */
309 
310     template < typename TSpec >
tell(File<TSpec> & me)311     inline typename Position< File<TSpec> >::Type tell(File<TSpec> &me)
312     {
313 //IOREV
314         return me.tell();
315     }
316 
317 /*!
318  * @fn File#rewind
319  * @brief Sets the current file pointer to the beginning of a file.
320  *
321  * @signature void rewind(file);
322  *
323  * @param[in,out] file The file to reset the file pointer of.
324  */
325 
326     template < typename File >
rewind(File & me)327     inline void rewind(File &me)
328     {
329 //IOREV
330         seek(me, 0);
331     }
332 
333 /*!
334  * @fn File#length
335  * @brief Return the file size.
336  *
337  * @signature TSize length(file);
338  *
339  * @param[in] file The File object to query for its size.
340  *
341  * @return TSize The file size measured in bytes.
342  */
343 
344     template < typename TSpec >
length(File<TSpec> & me)345     inline typename Size<File<TSpec> >::Type length(File<TSpec> &me)
346     {
347 //IOREV
348         typename Size<File<TSpec> >::Type old_pos = tell(me);
349         typename Size<File<TSpec> >::Type result = seek(me, 0, SEEK_END);
350         seek(me, old_pos, SEEK_BEGIN);
351         return result;
352     }
353 
354 /*!
355  * @fn File#resize
356  * @brief A file object.
357  *
358  * @signature void resize(file, newLength);
359  *
360  * @param[in,out] file      The File object to resize.
361  * @param[in]     newLength The file size in bytes to resize to in bytes.
362  */
363 
364     template < typename TSpec, typename TSize >
resize(File<TSpec> & me,TSize new_length)365     inline void resize(File<TSpec> &me, TSize new_length)
366     {
367 //IOREV possibly not standard-conformant, see resize() in file_cstyle.h
368         typename Size<File<TSpec> >::Type old_pos = tell(me);
369         seek(me, new_length, SEEK_BEGIN);
370         setEof(me);
371         seek(me, old_pos, SEEK_BEGIN);
372     }
373 
374 /*!
375  * @fn File#setEof
376  * @brief Sets the file end to the current pointer.
377  *
378  * @signature bool setEof(file);
379  *
380  * @param[in,out] file The File object to set the end of.
381  *
382  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
383  */
384 
385     template < typename TSpec >
setEof(File<TSpec> &)386     inline bool setEof(File<TSpec> &/*me*/)
387     {
388 //IOREV _noop_ specialized for async file access but not for sync
389         return true;
390     }
391 
392 
393     //////////////////////////////////////////////////////////////////////
394     // Pseudo asynchronous Methods
395     //////////////////////////////////////////////////////////////////////
396 
397     //////////////////////////////////////////////////////////////////////
398     // callback based read/write
399 /*
400     template < typename File, typename TValue, typename TSize,
401                typename aCallback, typename aHint >
402     inline typename AsyncRequest<File>::Type
403     asyncRead(File & me, TValue *memPtr, TSize const count,
404         aCallback* cb, aHint* hint)
405     {
406         result = read(me, memPtr, count);
407         cb(hint);
408         return NULL;
409     }
410 
411     template < typename File, typename TValue, typename TSize,
412                typename aCallback, typename aHint >
413     inline typename AsyncRequest<File>::Type
414     asyncWrite(File & me, TValue const *memPtr, TSize const count,
415         aCallback* cb, aHint* hint)
416     {
417         write(me, memPtr, count);
418         cb(hint);
419         return NULL;
420     }
421 
422     template < typename File, typename TValue, typename TSize, typename TPos,
423                typename aCallback, typename aHint >
424     inline typename AsyncRequest<File>::Type
425     asyncReadAt(File & me, TValue *memPtr, TSize const count, TPos const fileOfs,
426         aCallback* cb, aHint* hint)
427     {
428         readAt(me, memPtr, count, fileOfs);
429         cb(hint);
430         return NULL;
431     }
432 
433     template < typename File, typename TValue, typename TSize, typename TPos,
434                typename aCallback, typename aHint >
435     inline typename AsyncRequest<File>::Type
436     asyncWriteAt(File & me, TValue const *memPtr, TSize const count, TPos const fileOfs,
437         aCallback* cb, aHint* hint)
438     {
439         result = writeAt(me, memPtr, count, fileOfs);
440         cb(hint);
441         return NULL;
442     }
443 
444 
445     //////////////////////////////////////////////////////////////////////
446     // event based read/write
447 
448     template < typename File, typename TValue, typename TSize,
449                typename aEvent >
450     inline typename AsyncRequest<File>::Type
451     asyncRead(File & me, TValue *memPtr, TSize const count,
452         aEvent &event)
453     {
454         read(me, memPtr, count);
455         event.signal();
456         return NULL;
457     }
458 
459     template < typename File, typename TValue, typename TSize,
460                typename aEvent >
461     inline typename AsyncRequest<File>::Type
462     asyncWrite(File & me, TValue const *memPtr, TSize const count,
463         aEvent &event)
464     {
465         write(me, memPtr, count);
466         event.signal();
467         return NULL;
468     }
469 
470     template < typename File, typename TValue, typename TSize, typename TPos,
471                typename aEvent >
472     inline typename AsyncRequest<File>::Type
473     asyncReadAt(File & me, TValue *memPtr, TSize const count, TPos const fileOfs,
474         aEvent &event)
475     {
476         readAt(me, memPtr, count, fileOfs);
477         event.signal();
478         return NULL;
479     }
480 
481     template < typename File, typename TValue, typename TSize, typename TPos,
482                typename aEvent >
483     inline typename AsyncRequest<File>::Type
484     asyncWriteAt(File & me, TValue const *memPtr, TSize const count, TPos const fileOfs,
485         aEvent &event)
486     {
487         writeAt(me, memPtr, count, fileOfs);
488         event.signal();
489         return NULL;
490     }
491 */
492 
493     //////////////////////////////////////////////////////////////////////
494     // queue-less request based pseudo asynchronous read/write
495 
496 /*!
497  * @fn File#asyncReadAt
498  * @brief Asynchronously loads records from a specific position in a file.
499  *
500  * @signature bool asyncReadAt(file, memPtr, count, fileOfs, request);
501  *
502  * @param[in,out] file    The File object to read from.
503  * @param[out]    memPtr  A pointer to the first destination record in memory.
504  * @param[in]     count   The amount of records to be read.
505  * @param[in]     fileOfs The absolute file position in bytes measured from the beginning.
506  * @param[in]     request Reference to a structure that will be associated with this asynchronous request.  Type:
507  *                        @link AsyncRequest @endlink.
508  *
509  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
510  */
511 
512     template < typename File, typename TValue, typename TSize, typename TPos,
513                typename AsyncRequest >
514     inline bool
asyncReadAt(File & me,TValue * memPtr,TSize const count,TPos const fileOfs,AsyncRequest &)515     asyncReadAt(File & me, TValue *memPtr, TSize const count, TPos const fileOfs,
516         AsyncRequest &)
517     {
518 //IOREV _stub_ see general discussion about AsynRequest
519         return readAt(me, memPtr, count, fileOfs);
520     }
521 
522 /*!
523  * @fn File#asyncWriteAt
524  * @brief Asynchronously writes records to a specific position in a file.
525  *
526  * @signature bool asyncWriteAt(file, memPtr, count, fileOfs, request);
527  *
528  * @param[in,out] file    The File object.
529  * @param[in]     memPtr  A pointer to the first source record in memory.
530  * @param[in]     count   The amount of records to be written.
531  * @param[in]     fileOfs The absolute file position in bytes measured form the beginning.
532  * @param[in]     request Reference to a structure that will be associated with this asynchronous request.
533  *
534  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
535  */
536 
537     template < typename File, typename TValue, typename TSize, typename TPos,
538                typename TAsyncRequest >
539     inline bool
asyncWriteAt(File & me,TValue const * memPtr,TSize const count,TPos const fileOfs,TAsyncRequest &)540     asyncWriteAt(File & me, TValue const *memPtr, TSize const count, TPos const fileOfs,
541         TAsyncRequest &)
542     {
543 //IOREV _stub_ see general discussion about AsynRequest
544         return writeAt(me, memPtr, count, fileOfs);
545     }
546 
547 
548     //////////////////////////////////////////////////////////////////////
549     // pseudo queue specific functions
550 
551 /*!
552  * @fn File#flush
553  * @brief Waits for all open requests to complete.
554  *
555  * @signature void flush(file);
556  *
557  * @param[in,out] file The File object to flush.
558  */
559 
560     template < typename TSpec >
flush(File<TSpec> &)561     inline void flush(File<TSpec> &)
562     {
563 //IOREV _noop_ specialized for async file access but not for sync
564     }
565 
566 /*!
567  * @fn File#waitFor
568  * @brief Waits for an asynchronous request to complete.
569  *
570  * @signature bool waitFor(request[, timeout]);
571  *
572  * @param[in,out] request Reference to an AsyncRequest.
573  * @param[in]     timeout A timeout value in milliseconds.  A value of 0 can be used to test for completion without
574  *                        waiting.  Default: 0.
575  *
576  * @return bool <tt>true</tt> on completion, <tt>false</tt> on timeout.
577  *
578  * @section Remarks
579  *
580  * <tt>waitfor</tt> block sand suspends the calling thread process until <tt>request</tt> is completed or after
581  * <tt>timeout</tt> milliseconds.
582  */
583 
waitFor(AsyncDummyRequest &)584     inline bool waitFor(AsyncDummyRequest &)
585     {
586 //IOREV _noop_ see general discussion about AsynRequest
587         return true;
588     }
589 
590     template < typename TTime >
waitFor(AsyncDummyRequest &,TTime,bool & inProgress)591     inline bool waitFor(AsyncDummyRequest &, TTime, bool &inProgress)
592     {
593 //IOREV _noop_ see general discussion about AsynRequest
594         inProgress = false;
595         return true;
596     }
597 
598     // deprecated
599     template < typename TSpec, typename AsyncRequest >
600     [[deprecated]]
release(File<TSpec> &,AsyncRequest &)601     inline void release(File<TSpec> &, AsyncRequest &)
602     {
603 //IOREV _noop_ see general discussion about AsynRequest
604     }
605 
606 /*!
607  * @fn File#cancel
608  * @brief Cancels an asynchronous request.
609  *
610  * @signature bool cancel(file, request);
611  *
612  * @param[in,out] file    The File to cancel the request for.
613  * @param[in]     request Reference to an AsyncRequest object.  Type: @link AsyncRequest @endlink.
614  *
615  * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
616  */
617 
618     template < typename TSpec, typename AsyncRequest >
cancel(File<TSpec> &,AsyncRequest &)619     inline bool cancel(File<TSpec> &, AsyncRequest &)
620     {
621 //IOREV _noop_ see general discussion about AsynRequest
622         return true;
623     }
624 
625 
626     // little helpers
627 
628     template <typename T1, typename T2> inline
enclosingBlocks(T1 _size,T2 _blockSize)629     T1 enclosingBlocks(T1 _size, T2 _blockSize)
630     {
631 //IOREV not sure what this does, but is used in several places
632         return (_size + (T1)_blockSize - (T1)1) / (T1)_blockSize;
633     }
634 
635     template <typename T1, typename T2> inline
alignSize(T1 _size,T2 _aligning)636     T1 alignSize(T1 _size, T2 _aligning)
637     {
638 //IOREV not sure what this does, but is used in several places
639         if (_size < (T1)_aligning)
640             return _aligning;
641         else
642             return (_size / (T1)_aligning) * (T1)_aligning;
643     }
644 }  // namespace seqan
645 
646 #endif  // #ifndef SEQAN_INCLUDE_SEQAN_FILE_BASE_H_
647