3 * Copyright (C) 2003 by The Joker / Avalaunch team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "utils/log.h"
28 CD-ROM Mode 1 divides the 2352 byte data area into:
29 -12 bytes of synchronisation
30 -4 bytes of header information
31 -2048 bytes of user information
32 -288 bytes of error correction and detection codes.
34 CD-ROM Mode 2 redefines the use of the 2352 byte data area as follows:
35 -12 bytes of synchronisation
36 -4 bytes of header information
37 -2336 bytes of user data.
40 http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
45 #include "storage/IoSupport.h"
46 #include "utils/CharsetConverter.h"
47 #include "threads/SingleLock.h"
50 #ifndef TARGET_WINDOWS
51 #include "storage/DetectDVDType.h" // for MODE2_DATA_SIZE etc.
53 #include <cdio/bytesex.h>
54 //#define _DEBUG_OUTPUT 1
56 static CCriticalSection m_critSection;
57 class iso9660 m_isoReader;
58 #define BUFFER_SIZE MODE2_DATA_SIZE
66 void cdio_warn(const char* msg, ...) { CLog::Log(LOGWARNING, "%s", msg); }
70 //******************************************************************************************************************
71 const string iso9660::ParseName(struct iso9660_Directory& isodir)
73 string temp_text = (char*)isodir.FileName;
74 temp_text.resize(isodir.Len_Fi);
75 int iPos = isodir.Len_Fi;
77 if (isodir.FileName[iPos] == 0)
82 if (isodir.FileName[iPos] == 'R' && isodir.FileName[iPos + 1] == 'R')
88 if (isodir.FileName[iPos] == 'N' && isodir.FileName[iPos + 1] == 'M')
91 // "N" "M" LEN_NM 1 FLAGS NAMECONTENT
92 // BP1 BP2 BP3 BP4 BP5 BP6-LEN_NM
93 int iNameLen = isodir.FileName[iPos + 2] - 5;
94 temp_text = (char*) & isodir.FileName[iPos + 5];
95 temp_text.resize(iNameLen);
96 iPos += (iNameLen + 5);
98 if ( isascii(isodir.FileName[iPos]) && isascii(isodir.FileName[iPos + 1]))
103 iPos += isodir.FileName[iPos + 2];
106 while (33 + iPos < isodir.ucRecordLength && isodir.FileName[iPos + 2] != 0);
107 // when this isodir.FileName[iPos+2] is equal to 0 it should break out
108 // as it has finished the loop
109 // this is the fix for rockridge support
114 bool iso9660::IsRockRidge(struct iso9660_Directory& isodir)
116 int iPos = isodir.Len_Fi;
118 if (isodir.FileName[iPos] == 0)
123 // found rock ridge in system use field
124 if (isodir.FileName[iPos] == 'R' && isodir.FileName[iPos + 1] == 'R')
130 //******************************************************************************************************************
131 struct iso_dirtree *iso9660::ReadRecursiveDirFromSector( DWORD sector, const char *path )
133 struct iso_dirtree* pDir = NULL;
134 struct iso_dirtree* pFile_Pointer = NULL;
135 char* pCurr_dir_cache = NULL;
136 DWORD iso9660searchpointer;
137 struct iso9660_Directory isodir;
138 struct iso9660_Directory curr_dir;
139 WORD wSectorSize = from_723(m_info.iso.logical_block_size);
142 struct iso_directories *point = m_lastpath;
145 while ( point->next )
147 if (strcmp(path, point->path) == 0) return NULL;
155 strTmp.Format("****************** Adding dir : %s\r", path);
156 OutputDebugString( strTmp.c_str() );
159 pDir = (struct iso_dirtree *)malloc(sizeof(struct iso_dirtree));
162 OutputDebugString("out of memory");
169 pDir->dirpointer = NULL;
170 pFile_Pointer = pDir;
171 m_vecDirsAndFiles.push_back(pDir);
174 ::SetFilePointer( m_info.ISO_HANDLE, wSectorSize * sector, 0, FILE_BEGIN );
175 DWORD lpNumberOfBytesRead = 0;
177 pCurr_dir_cache = (char*)malloc( 16*wSectorSize );
178 if (!pCurr_dir_cache )
180 OutputDebugString("out of memory\n");
184 BOOL bResult = ::ReadFile( m_info.ISO_HANDLE, pCurr_dir_cache, wSectorSize, &lpNumberOfBytesRead, NULL );
185 if (!bResult || lpNumberOfBytesRead != wSectorSize)
187 OutputDebugString("unable to read\n");
191 memcpy( &isodir, pCurr_dir_cache, sizeof(isodir) );
192 memcpy( &curr_dir, pCurr_dir_cache, sizeof(isodir) );
194 DWORD curr_dirSize = from_733(curr_dir.size);
195 if ( curr_dirSize > wSectorSize )
197 free( pCurr_dir_cache );
198 pCurr_dir_cache = (char*)malloc( 16 * from_733(isodir.size) );
199 if (!pCurr_dir_cache )
201 OutputDebugString("out of memory\n");
204 ::SetFilePointer( m_info.ISO_HANDLE, wSectorSize * sector, 0, FILE_BEGIN );
205 bResult = ::ReadFile( m_info.ISO_HANDLE, pCurr_dir_cache , curr_dirSize, &lpNumberOfBytesRead, NULL );
206 if (!bResult || lpNumberOfBytesRead != curr_dirSize)
208 OutputDebugString("unable to read\n");
212 iso9660searchpointer = 0;
216 m_lastpath = m_paths;
219 m_paths = (struct iso_directories *)malloc(sizeof(struct iso_directories));
222 OutputDebugString("out of memory\n");
225 m_paths->path = NULL;
227 m_paths->next = NULL;
228 m_lastpath = m_paths;
232 while ( m_lastpath->next )
233 m_lastpath = m_lastpath->next;
236 m_lastpath->next = ( struct iso_directories *)malloc( sizeof( struct iso_directories ) );
237 if (!m_lastpath->next )
239 OutputDebugString("out of memory\n");
243 m_lastpath = m_lastpath->next;
244 m_lastpath->next = NULL;
245 m_lastpath->dir = pDir;
246 m_lastpath->path = (char *)malloc(strlen(path) + 1);
247 if (!m_lastpath->path )
249 OutputDebugString("out of memory\n");
252 strcpy( m_lastpath->path, path );
256 if ( isodir.ucRecordLength )
257 iso9660searchpointer += isodir.ucRecordLength;
260 iso9660searchpointer = (iso9660searchpointer - (iso9660searchpointer % wSectorSize)) + wSectorSize;
262 if ( curr_dirSize <= iso9660searchpointer )
266 int isize = min(sizeof(isodir), sizeof(m_info.isodir));
267 memcpy( &isodir, pCurr_dir_cache + iso9660searchpointer, isize);
268 if (!isodir.ucRecordLength)
270 if ( !(isodir.byFlags & Flag_NotExist) )
272 if ( (!( isodir.byFlags & Flag_Directory )) && ( isodir.Len_Fi > 1) )
275 bool bContinue = false;
280 isodir.FileName[isodir.Len_Fi] = isodir.FileName[isodir.Len_Fi + 1] = 0; //put terminator by its length
281 temp_text = GetThinText(isodir.FileName, isodir.Len_Fi );
282 // temp_text.resize(isodir.Len_Fi);
285 if (!m_info.joliet && isodir.FileName[0] >= 0x20 )
287 temp_text = ParseName(isodir);
292 int semipos = temp_text.find(";", 0);
294 temp_text.erase(semipos, temp_text.length() - semipos);
297 pFile_Pointer->next = (struct iso_dirtree *)malloc(sizeof(struct iso_dirtree));
298 if (!pFile_Pointer->next)
300 OutputDebugString("out of memory\n");
303 m_vecDirsAndFiles.push_back(pFile_Pointer->next);
304 pFile_Pointer = pFile_Pointer->next;
305 pFile_Pointer->next = 0;
306 pFile_Pointer->dirpointer = NULL;
307 pFile_Pointer->path = (char *)malloc(strlen(path) + 1);
308 if (!pFile_Pointer->path)
310 OutputDebugString("out of memory");
313 strcpy( pFile_Pointer->path, path );
314 pFile_Pointer->name = (char *)malloc( temp_text.length() + 1);
315 if (!pFile_Pointer->name)
317 OutputDebugString("out of memory");
321 strcpy( pFile_Pointer->name , temp_text.c_str());
324 //strTmp.Format("adding sector : %X, File : %s size = %u pos = %x\r",sector,temp_text.c_str(), isodir.dwFileLengthLE, isodir.dwFileLocationLE );
325 //OutputDebugString( strTmp.c_str());
328 pFile_Pointer->Location = from_733(isodir.extent);
329 pFile_Pointer->dirpointer = NULL;
330 pFile_Pointer ->Length = from_733(isodir.size);
332 IsoDateTimeToFileTime(&isodir.DateTime, &pFile_Pointer->filetime);
334 pFile_Pointer->type = 1;
339 iso9660searchpointer = 0;
340 memcpy( &curr_dir, pCurr_dir_cache, sizeof(isodir) );
341 memcpy( &isodir, pCurr_dir_cache, sizeof(isodir) );
344 if ( isodir.ucRecordLength )
345 iso9660searchpointer += isodir.ucRecordLength;
350 iso9660searchpointer = (iso9660searchpointer - (iso9660searchpointer % wSectorSize)) + wSectorSize;
352 if ( from_733(curr_dir.size) <= iso9660searchpointer )
354 free( pCurr_dir_cache );
355 pCurr_dir_cache = NULL;
358 memcpy( &isodir, pCurr_dir_cache + iso9660searchpointer, min(sizeof(isodir), sizeof(m_info.isodir)));
359 if (!isodir.ucRecordLength)
361 if ( !(isodir.byFlags & Flag_NotExist) )
363 if ( (( isodir.byFlags & Flag_Directory )) && ( isodir.Len_Fi > 1) )
366 bool bContinue = false;
370 isodir.FileName[isodir.Len_Fi] = isodir.FileName[isodir.Len_Fi + 1] = 0; //put terminator by its length
371 temp_text = GetThinText(isodir.FileName, isodir.Len_Fi);
372 // temp_text.resize(isodir.Len_Fi);
374 if (!m_info.joliet && isodir.FileName[0] >= 0x20 )
376 temp_text = ParseName(isodir);
382 // int semipos = temp_text.find(";",0); //the directory is not seperate by ";",but by its length
384 // temp_text.erase(semipos,temp_text.length()-semipos);
386 pFile_Pointer->next = (struct iso_dirtree *)malloc(sizeof(struct iso_dirtree));
387 if (!pFile_Pointer->next)
389 OutputDebugString("out of memory");
392 m_vecDirsAndFiles.push_back(pFile_Pointer->next);
393 pFile_Pointer = pFile_Pointer->next;
394 pFile_Pointer->next = 0;
395 pFile_Pointer->dirpointer = NULL;
396 pFile_Pointer->path = (char *)malloc(strlen(path) + 1);
398 if (!pFile_Pointer->path)
400 OutputDebugString("out of memory");
404 strcpy( pFile_Pointer->path, path );
405 pFile_Pointer->name = (char *)malloc( temp_text.length() + 1);
407 if (!pFile_Pointer->name)
409 OutputDebugString("out of memory");
413 strcpy( pFile_Pointer->name , temp_text.c_str());
415 DWORD dwFileLocation = from_733(isodir.extent);
418 strTmp.Format("adding directory sector : %X, File : %s size = %u pos = %x\r", sector, temp_text.c_str(), from_733(isodir.size), dwFileLocation );
419 OutputDebugString( strTmp.c_str());
422 pFile_Pointer->Location = dwFileLocation;
423 pFile_Pointer->dirpointer = NULL;
424 pFile_Pointer->Length = from_733(isodir.size);
426 IsoDateTimeToFileTime(&isodir.DateTime, &pFile_Pointer->filetime);
428 string strPath = path;
429 if ( strlen( path ) > 1 ) strPath += "\\";
430 strPath += temp_text;
432 pFile_Pointer->dirpointer = ReadRecursiveDirFromSector( dwFileLocation, strPath.c_str() );
434 pFile_Pointer->type = 2;
441 //******************************************************************************************************************
444 memset(m_isoFiles, 0, sizeof(m_isoFiles));
447 m_searchpointer = NULL;
453 if (m_hCDROM != NULL)
456 m_hCDROM = CIoSupport::OpenCDROM();
457 CIoSupport::AllocReadBuffer();
461 memset(&m_info, 0, sizeof(m_info));
462 m_info.ISO_HANDLE = m_hCDROM ;
463 m_info.Curr_dir_cache = 0;
464 m_info.Curr_dir = (char*)malloc( 4096 );
465 strcpy( m_info.Curr_dir, "\\" );
467 CSingleLock lock(m_critSection);
469 DWORD lpNumberOfBytesRead = 0;
470 ::SetFilePointer( m_info.ISO_HANDLE, 0x8000, 0, FILE_BEGIN );
472 ::ReadFile( m_info.ISO_HANDLE, &m_info.iso, sizeof(m_info.iso), &lpNumberOfBytesRead, NULL );
474 if (strncmp(m_info.iso.szSignature, "CD001", 5))
476 CIoSupport::CloseCDROM( m_info.ISO_HANDLE);
477 CIoSupport::FreeReadBuffer();
478 m_info.ISO_HANDLE = NULL;
488 m_info.HeaderPos = 0x8000;
489 int current = 0x8000;
491 WORD wSectorSize = from_723(m_info.iso.logical_block_size);
493 // first check if first file in the current VD has a rock-ridge NM. if it has, disable joliet
494 ::SetFilePointer( m_info.ISO_HANDLE, wSectorSize * from_733(((iso9660_Directory*)(&m_info.iso.szRootDir))->extent), 0, FILE_BEGIN );
496 DWORD lpNumberOfBytesRead;
497 char* pCurr_dir_cache = (char*)malloc( 16*wSectorSize );
498 iso9660_Directory isodir;
499 BOOL bResult = ::ReadFile( m_info.ISO_HANDLE, pCurr_dir_cache, wSectorSize, &lpNumberOfBytesRead, NULL );
500 memcpy( &isodir, pCurr_dir_cache, sizeof(isodir));
502 int iso9660searchpointer=0;
503 if ( isodir.ucRecordLength )
504 iso9660searchpointer += isodir.ucRecordLength;
506 iso9660searchpointer = (iso9660searchpointer - (iso9660searchpointer % wSectorSize)) + wSectorSize;
508 memcpy( &isodir, pCurr_dir_cache + iso9660searchpointer,min(sizeof(isodir), sizeof(m_info.isodir)));
509 free(pCurr_dir_cache);
510 if (bResult && lpNumberOfBytesRead == wSectorSize)
511 bResult = IsRockRidge(isodir);
512 while ( m_info.iso.byOne != 255)
514 if ( ( m_info.iso.byZero3[0] == 0x25 ) && ( m_info.iso.byZero3[1] == 0x2f ) && !bResult )
516 switch ( m_info.iso.byZero3[2] )
520 case 0x43 : m_info.HeaderPos = current;
523 // 25 2f 45 or 25 2f 40 or 25 2f 43 = jouliet, and best fitted for reading
526 ::SetFilePointer( m_info.ISO_HANDLE, current, 0, FILE_BEGIN );
527 ::ReadFile( m_info.ISO_HANDLE, &m_info.iso, sizeof(m_info.iso), &lpNumberOfBytesRead, NULL );
529 ::SetFilePointer( m_info.ISO_HANDLE, m_info.HeaderPos, 0, FILE_BEGIN );
530 ::ReadFile( m_info.ISO_HANDLE, &m_info.iso, sizeof(m_info.iso), &lpNumberOfBytesRead, NULL );
531 memcpy( &m_info.isodir, m_info.iso.szRootDir, sizeof(m_info.isodir));
534 memcpy( &m_info.isodir, &m_info.iso.szRootDir, sizeof(m_info.isodir) );
535 ReadRecursiveDirFromSector( from_733(m_info.isodir.extent), "\\" );
538 //******************************************************************************************************************
544 void iso9660::Reset()
548 free(m_info.Curr_dir);
549 m_info.Curr_dir = NULL;
551 if (m_info.Curr_dir_cache)
552 free(m_info.Curr_dir_cache);
553 m_info.Curr_dir_cache = NULL;
557 struct iso_directories* nextpath;
561 nextpath = m_paths->next;
562 if (m_paths->path) free(m_paths->path);
567 for (int i = 0; i < (int)m_vecDirsAndFiles.size(); ++i)
569 struct iso_dirtree* pDir = m_vecDirsAndFiles[i];
570 if (pDir->path) free(pDir->path);
571 if (pDir->name) free(pDir->name);
574 m_vecDirsAndFiles.erase(m_vecDirsAndFiles.begin(), m_vecDirsAndFiles.end());
576 for (intptr_t i = 0; i < MAX_ISO_FILES;++i)
578 FreeFileContext( (HANDLE)i);
583 CIoSupport::CloseCDROM(m_hCDROM);
584 CIoSupport::FreeReadBuffer();
589 //******************************************************************************************************************
590 struct iso_dirtree *iso9660::FindFolder( char *Folder )
594 work = (char *)malloc(from_723(m_info.iso.logical_block_size));
597 struct iso_directories *lastpath = NULL;;
599 if ( strpbrk(Folder, ":") )
600 strcpy(work, strpbrk(Folder, ":") + 1);
602 strcpy(work, Folder);
605 while ( strlen( temp ) > 1 && strpbrk( temp + 1, "\\" ) )
606 temp = strpbrk( temp + 1, "\\" );
608 if ( strlen( work ) > 1 && work[ strlen(work) - 1 ] == '*' )
610 work[ strlen(work) - 1 ] = 0;
612 if ( strlen( work ) > 2 )
613 if ( work[ strlen(work) - 1 ] == '\\' )
614 work[ strlen(work) - 1 ] = 0;
617 lastpath = m_paths->next;
620 if ( !stricmp( lastpath->path, work))
623 return lastpath->dir;
625 lastpath = lastpath->next;
631 //******************************************************************************************************************
632 HANDLE iso9660::FindFirstFile( char *szLocalFolder, WIN32_FIND_DATA *wfdFile )
634 if (m_info.ISO_HANDLE == 0) return (HANDLE)0;
635 memset( wfdFile, 0, sizeof(WIN32_FIND_DATA));
637 m_searchpointer = FindFolder( szLocalFolder );
639 if ( m_searchpointer )
641 m_searchpointer = m_searchpointer->next;
643 if ( m_searchpointer )
645 strcpy(wfdFile->cFileName, m_searchpointer->name );
647 if ( m_searchpointer->type == 2 )
648 wfdFile->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
650 wfdFile->ftLastWriteTime = m_searchpointer->filetime;
651 wfdFile->ftLastAccessTime = m_searchpointer->filetime;
652 wfdFile->ftCreationTime = m_searchpointer->filetime;
654 wfdFile->nFileSizeLow = m_searchpointer->Length;
661 //******************************************************************************************************************
662 int iso9660::FindNextFile( HANDLE szLocalFolder, WIN32_FIND_DATA *wfdFile )
664 memset( wfdFile, 0, sizeof(WIN32_FIND_DATA));
666 if ( m_searchpointer )
667 m_searchpointer = m_searchpointer->next;
669 if ( m_searchpointer )
671 strcpy(wfdFile->cFileName, m_searchpointer->name );
673 if ( m_searchpointer->type == 2 )
674 wfdFile->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
676 wfdFile->ftLastWriteTime = m_searchpointer->filetime;
677 wfdFile->ftLastAccessTime = m_searchpointer->filetime;
678 wfdFile->ftCreationTime = m_searchpointer->filetime;
680 wfdFile->nFileSizeLow = m_searchpointer->Length;
687 //******************************************************************************************************************
688 bool iso9660::FindClose( HANDLE szLocalFolder )
691 if (m_info.Curr_dir_cache) free(m_info.Curr_dir_cache);
692 m_info.Curr_dir_cache = 0;
698 //******************************************************************************************************************
699 string iso9660::GetThinText(BYTE* strTxt, int iLen )
701 // convert from "fat" text (UTF-16BE) to "thin" text (UTF-8)
702 CStdString16 strTxtUnicode((uint16_t*)strTxt, iLen / 2);
703 CStdString utf8String;
705 g_charsetConverter.utf16BEtoUTF8(strTxtUnicode, utf8String);
710 //************************************************************************************
711 HANDLE iso9660::OpenFile(const char *filename)
713 if (m_info.ISO_HANDLE == NULL) return INVALID_HANDLE_VALUE;
714 HANDLE hContext = AllocFileContext();
715 if (hContext == INVALID_HANDLE_VALUE) return hContext;
717 iso9660::isofile* pContext = GetFileContext(hContext);
719 return INVALID_HANDLE_VALUE;
721 WIN32_FIND_DATA fileinfo;
722 char *pointer, *pointer2;
724 pContext->m_bUseMode2 = false;
725 m_info.curr_filepos = 0;
727 pointer = (char*)filename;
728 while ( strpbrk( pointer, "\\/" ) )
729 pointer = strpbrk( pointer, "\\/" ) + 1;
731 strcpy(work, filename );
734 while ( strpbrk(pointer2 + 1, "\\" ) )
735 pointer2 = strpbrk(pointer2 + 1, "\\" );
739 intptr_t loop = (intptr_t)FindFirstFile( work, &fileinfo );
742 if ( !stricmp(fileinfo.cFileName, pointer ) )
745 loop = FindNextFile( NULL, &fileinfo );
749 FreeFileContext(hContext);
750 return INVALID_HANDLE_VALUE;
753 pContext->m_dwCurrentBlock = m_searchpointer->Location;
754 pContext->m_dwFileSize = m_info.curr_filesize = fileinfo.nFileSizeLow;
755 pContext->m_pBuffer = new uint8_t[CIRC_BUFFER_SIZE * BUFFER_SIZE];
756 pContext->m_dwStartBlock = pContext->m_dwCurrentBlock;
757 pContext->m_dwFilePos = 0;
758 pContext->m_dwCircBuffBegin = 0;
759 pContext->m_dwCircBuffEnd = 0;
760 pContext->m_dwCircBuffSectorStart = 0;
761 pContext->m_bUseMode2 = false;
765 CSingleLock lock(m_critSection);
766 bError = (CIoSupport::ReadSector(m_info.ISO_HANDLE, pContext->m_dwStartBlock, (char*) & (pContext->m_pBuffer[0])) < 0);
769 bError = (CIoSupport::ReadSectorMode2(m_info.ISO_HANDLE, pContext->m_dwStartBlock, (char*) & (pContext->m_pBuffer[0])) < 0);
771 pContext->m_bUseMode2 = true;
773 if (pContext->m_bUseMode2)
774 pContext->m_dwFileSize = (pContext->m_dwFileSize / 2048) * MODE2_DATA_SIZE;
779 //************************************************************************************
780 void iso9660::CloseFile(HANDLE hFile)
782 iso9660::isofile* pContext = GetFileContext(hFile);
785 if (pContext->m_pBuffer)
787 delete [] pContext->m_pBuffer;
788 pContext->m_pBuffer = NULL;
791 FreeFileContext(hFile);
793 //************************************************************************************
794 bool iso9660::ReadSectorFromCache(iso9660::isofile* pContext, DWORD sector, uint8_t** ppBuffer)
797 DWORD StartSectorInCircBuff = pContext->m_dwCircBuffSectorStart;
798 DWORD SectorsInCircBuff;
800 if ( pContext->m_dwCircBuffEnd >= pContext->m_dwCircBuffBegin )
801 SectorsInCircBuff = pContext->m_dwCircBuffEnd - pContext->m_dwCircBuffBegin;
803 SectorsInCircBuff = CIRC_BUFFER_SIZE - (pContext->m_dwCircBuffBegin - pContext->m_dwCircBuffEnd);
805 // If our sector is already in the circular buffer
806 if ( sector >= StartSectorInCircBuff &&
807 sector < (StartSectorInCircBuff + SectorsInCircBuff) &&
808 SectorsInCircBuff > 0 )
811 DWORD SectorInCircBuff = (sector - StartSectorInCircBuff) +
812 pContext->m_dwCircBuffBegin;
813 if ( SectorInCircBuff >= CIRC_BUFFER_SIZE )
814 SectorInCircBuff -= CIRC_BUFFER_SIZE;
816 *ppBuffer = &(pContext->m_pBuffer[SectorInCircBuff]);
820 // Sector is not cache. Read it in.
821 bool SectorIsAdjacentInBuffer =
822 (StartSectorInCircBuff + SectorsInCircBuff) == sector;
823 if ( SectorsInCircBuff == CIRC_BUFFER_SIZE - 1 ||
824 !SectorIsAdjacentInBuffer)
826 // The cache is full. (Or its not an adjacent request in which we'll
827 // also flush the cache)
829 // If its adjacent, just get rid of the first sector.
830 if ( SectorIsAdjacentInBuffer )
832 // Release the first sector in cache
833 pContext->m_dwCircBuffBegin++;
834 if ( pContext->m_dwCircBuffBegin >= CIRC_BUFFER_SIZE )
835 pContext->m_dwCircBuffBegin -= CIRC_BUFFER_SIZE;
836 pContext->m_dwCircBuffSectorStart++;
840 pContext->m_dwCircBuffBegin = pContext->m_dwCircBuffEnd = 0;
841 pContext->m_dwCircBuffSectorStart = 0;
844 // Ok, we're ready to read the sector into the cache
847 CSingleLock lock(m_critSection);
848 if ( pContext->m_bUseMode2 )
850 bError = (CIoSupport::ReadSectorMode2(m_info.ISO_HANDLE, sector, (char*) & (pContext->m_pBuffer[pContext->m_dwCircBuffEnd])) < 0);
854 bError = (CIoSupport::ReadSector(m_info.ISO_HANDLE, sector, (char*) & (pContext->m_pBuffer[pContext->m_dwCircBuffEnd])) < 0);
859 *ppBuffer = &(pContext->m_pBuffer[pContext->m_dwCircBuffEnd]);
860 if ( pContext->m_dwCircBuffEnd == pContext->m_dwCircBuffBegin )
861 pContext->m_dwCircBuffSectorStart = sector;
862 pContext->m_dwCircBuffEnd++;
863 if ( pContext->m_dwCircBuffEnd >= CIRC_BUFFER_SIZE )
864 pContext->m_dwCircBuffEnd -= CIRC_BUFFER_SIZE;
868 //************************************************************************************
869 void iso9660::ReleaseSectorFromCache(iso9660::isofile* pContext, DWORD sector)
872 DWORD StartSectorInCircBuff = pContext->m_dwCircBuffSectorStart;
873 DWORD SectorsInCircBuff;
875 if ( pContext->m_dwCircBuffEnd >= pContext->m_dwCircBuffBegin )
876 SectorsInCircBuff = pContext->m_dwCircBuffEnd - pContext->m_dwCircBuffBegin;
878 SectorsInCircBuff = CIRC_BUFFER_SIZE - (pContext->m_dwCircBuffBegin - pContext->m_dwCircBuffEnd);
880 // If our sector is in the circular buffer
881 if ( sector >= StartSectorInCircBuff &&
882 sector < (StartSectorInCircBuff + SectorsInCircBuff) &&
883 SectorsInCircBuff > 0 )
885 DWORD SectorsToFlush = sector - StartSectorInCircBuff + 1;
886 pContext->m_dwCircBuffBegin += SectorsToFlush;
888 pContext->m_dwCircBuffSectorStart += SectorsToFlush;
889 if ( pContext->m_dwCircBuffBegin >= CIRC_BUFFER_SIZE )
890 pContext->m_dwCircBuffBegin -= CIRC_BUFFER_SIZE;
893 //************************************************************************************
894 long iso9660::ReadFile(HANDLE hFile, uint8_t *pBuffer, long lSize)
898 DWORD sectorSize = 2048;
899 iso9660::isofile* pContext = GetFileContext(hFile);
900 if (!pContext) return -1;
902 if ( pContext->m_bUseMode2 )
903 sectorSize = MODE2_DATA_SIZE;
905 while (lSize > 0 && pContext->m_dwFilePos <= pContext->m_dwFileSize)
907 pContext->m_dwCurrentBlock = (DWORD) (pContext->m_dwFilePos / sectorSize);
908 int64_t iOffsetInBuffer = pContext->m_dwFilePos - (sectorSize * pContext->m_dwCurrentBlock);
909 pContext->m_dwCurrentBlock += pContext->m_dwStartBlock;
912 //sprintf(szBuf,"pos:%i cblk:%i sblk:%i off:%i",(long)m_dwFilePos, (long)m_dwCurrentBlock,(long)m_dwStartBlock,(long)iOffsetInBuffer);
916 bError = !ReadSectorFromCache(pContext, pContext->m_dwCurrentBlock, &pSector);
919 DWORD iBytes2Copy = lSize;
920 if (iBytes2Copy > (sectorSize - iOffsetInBuffer) )
921 iBytes2Copy = (DWORD) (sectorSize - iOffsetInBuffer);
924 memcpy( &pBuffer[iBytesRead], &pSector[iOffsetInBuffer], iBytes2Copy);
925 iBytesRead += iBytes2Copy;
926 lSize -= iBytes2Copy;
927 pContext->m_dwFilePos += iBytes2Copy;
929 if ( iBytes2Copy + iOffsetInBuffer == sectorSize )
930 ReleaseSectorFromCache(pContext, pContext->m_dwCurrentBlock);
932 // Why is this done? It is recalculated at the beginning of the loop
933 pContext->m_dwCurrentBlock += BUFFER_SIZE / MODE2_DATA_SIZE;
938 CLog::Log(LOGDEBUG, "iso9660::ReadFile() hit EOF");
942 if (iBytesRead == 0) return -1;
945 //************************************************************************************
946 int64_t iso9660::Seek(HANDLE hFile, int64_t lOffset, int whence)
948 iso9660::isofile* pContext = GetFileContext(hFile);
949 if (!pContext) return -1;
951 int64_t dwFilePos = pContext->m_dwFilePos;
956 pContext->m_dwFilePos = lOffset;
961 pContext->m_dwFilePos += lOffset;
965 pContext->m_dwFilePos = pContext->m_dwFileSize + lOffset;
971 if (pContext->m_dwFilePos > pContext->m_dwFileSize || pContext->m_dwFilePos < 0)
973 pContext->m_dwFilePos = dwFilePos;
974 return pContext->m_dwFilePos;
978 return pContext->m_dwFilePos;
982 //************************************************************************************
983 int64_t iso9660::GetFileSize(HANDLE hFile)
985 iso9660::isofile* pContext = GetFileContext(hFile);
986 if (!pContext) return -1;
987 return pContext->m_dwFileSize;
990 //************************************************************************************
991 int64_t iso9660::GetFilePosition(HANDLE hFile)
993 iso9660::isofile* pContext = GetFileContext(hFile);
994 if (!pContext) return -1;
995 return pContext->m_dwFilePos;
998 //************************************************************************************
999 void iso9660::FreeFileContext(HANDLE hFile)
1001 intptr_t iFile = (intptr_t)hFile;
1002 if (iFile >= 1 && iFile < MAX_ISO_FILES)
1004 if (m_isoFiles[iFile ]) delete m_isoFiles[iFile ];
1005 m_isoFiles[iFile ] = NULL;
1009 //************************************************************************************
1010 HANDLE iso9660::AllocFileContext()
1012 for (intptr_t i = 1; i < MAX_ISO_FILES; ++i)
1014 if (m_isoFiles[i] == NULL)
1016 m_isoFiles[i] = new isofile;
1020 return INVALID_HANDLE_VALUE;
1023 //************************************************************************************
1024 iso9660::isofile* iso9660::GetFileContext(HANDLE hFile)
1026 intptr_t iFile = (intptr_t)hFile;
1027 if (iFile >= 1 && iFile < MAX_ISO_FILES)
1029 return m_isoFiles[iFile];
1034 //************************************************************************************
1035 bool iso9660::IsScanned()
1037 return (m_hCDROM != NULL);
1040 //************************************************************************************
1041 void iso9660::IsoDateTimeToFileTime(iso9660_Datetime* isoDateTime, FILETIME* filetime)
1044 ZeroMemory(&t, sizeof(tm));
1045 t.tm_year=isoDateTime->year;
1046 t.tm_mon=isoDateTime->month-1;
1047 t.tm_mday=isoDateTime->day;
1048 t.tm_hour=isoDateTime->hour;
1049 t.tm_min=isoDateTime->minute;
1050 t.tm_sec=isoDateTime->second + (isoDateTime->gmtoff * (15 * 60));
1055 time.wYear=t.tm_year+1900;
1056 time.wMonth=t.tm_mon+1;
1057 time.wDayOfWeek=t.tm_wday;
1058 time.wDay=t.tm_mday;
1059 time.wHour=t.tm_hour;
1060 time.wMinute=t.tm_min;
1061 time.wSecond=t.tm_sec;
1062 time.wMilliseconds=0;
1063 SystemTimeToFileTime(&time, filetime);