00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "stdafx.h"
00023 #include "MatroskaFile.h"
00024 #include "..\..\..\DSUtil\DSUtil.h"
00025 #include "..\..\..\zlib\zlib.h"
00026
00027 #define DOCTYPE _T("matroska")
00028 #define DOCTYPEVERSION 2
00029
00030 static void LOG(LPCTSTR fmt, ...)
00031 {
00032 va_list args;
00033 va_start(args, fmt);
00034 if(FILE* f = _tfopen(_T("c:\\matroskasplitterlog.txt"), _T("at")))
00035 {
00036 fseek(f, 0, 2);
00037 _vftprintf(f, fmt, args);
00038 fclose(f);
00039 }
00040 va_end(args);
00041 }
00042
00043 using namespace MatroskaReader;
00044
00045 #define BeginChunk \
00046 CheckPointer(pMN0, E_POINTER); \
00047 \
00048 CAutoPtr<CMatroskaNode> pMN = pMN0->Child(); \
00049 if(!pMN) return S_FALSE; \
00050 \
00051 do \
00052 { \
00053 switch(pMN->m_id) \
00054 { \
00055
00056 #define EndChunk \
00057 } \
00058 } \
00059 while(pMN->Next()); \
00060 \
00061 return S_OK; \
00062
00063 static void bswap(BYTE* s, int len)
00064 {
00065 for(BYTE* d = s + len-1; s < d; s++, d--)
00066 *s ^= *d, *d ^= *s, *s ^= *d;
00067 }
00068
00069
00070
00071
00072
00073 CMatroskaFile::CMatroskaFile(IAsyncReader* pAsyncReader, HRESULT& hr)
00074 : CBaseSplitterFile(pAsyncReader, hr)
00075 , m_rtOffset(0)
00076 {
00077 if(FAILED(hr)) return;
00078 hr = Init();
00079 }
00080
00081 HRESULT CMatroskaFile::Init()
00082 {
00083 DWORD dw;
00084 if(FAILED(Read(dw)) || dw != 0x1A45DFA3)
00085 return E_FAIL;
00086
00087 CMatroskaNode Root(this);
00088 if(FAILED(Parse(&Root)))
00089 return E_FAIL;
00090
00091 CAutoPtr<CMatroskaNode> pSegment, pCluster;
00092 if((pSegment = Root.Child(0x18538067))
00093 && (pCluster = pSegment->Child(0x1F43B675)))
00094 {
00095 Cluster c0;
00096 c0.ParseTimeCode(pCluster);
00097 m_rtOffset = m_segment.GetRefTime(c0.TimeCode);
00098 }
00099
00100 return S_OK;
00101 }
00102
00103 template <class T>
00104 HRESULT CMatroskaFile::Read(T& var)
00105 {
00106 HRESULT hr = Read((BYTE*)&var, sizeof(var));
00107 if(S_OK == hr) bswap((BYTE*)&var, sizeof(var));
00108 return hr;
00109 }
00110
00111 HRESULT CMatroskaFile::Parse(CMatroskaNode* pMN0)
00112 {
00113 BeginChunk
00114 case 0x1A45DFA3:
00115 m_ebml.Parse(pMN);
00116 if(m_ebml.DocType != DOCTYPE || m_ebml.DocTypeReadVersion > DOCTYPEVERSION)
00117 return E_FAIL;
00118 break;
00119 case 0x18538067: if(m_segment.SegmentInfo.SegmentUID.IsEmpty()) m_segment.ParseMinimal(pMN); break;
00120 EndChunk
00121 }
00122
00123
00124
00125 HRESULT EBML::Parse(CMatroskaNode* pMN0)
00126 {
00127 BeginChunk
00128 case 0x4286: EBMLVersion.Parse(pMN); break;
00129 case 0x42F7: EBMLReadVersion.Parse(pMN); break;
00130 case 0x42F2: EBMLMaxIDLength.Parse(pMN); break;
00131 case 0x42F3: EBMLMaxSizeLength.Parse(pMN); break;
00132 case 0x4282: DocType.Parse(pMN); break;
00133 case 0x4287: DocTypeVersion.Parse(pMN); break;
00134 case 0x4285: DocTypeReadVersion.Parse(pMN); break;
00135 EndChunk
00136 }
00137
00138 HRESULT Segment::Parse(CMatroskaNode* pMN0)
00139 {
00140 pos = pMN0->GetPos();
00141
00142 BeginChunk
00143 case 0x1549A966: SegmentInfo.Parse(pMN); break;
00144 case 0x114D9B74: MetaSeekInfo.Parse(pMN); break;
00145 case 0x1654AE6B: Tracks.Parse(pMN); break;
00146 case 0x1F43B675: Clusters.Parse(pMN); break;
00147 case 0x1C53BB6B: Cues.Parse(pMN); break;
00148 case 0x1941A469: Attachments.Parse(pMN); break;
00149 case 0x1043A770: Chapters.Parse(pMN); break;
00150
00151 EndChunk
00152 }
00153
00154 HRESULT Segment::ParseMinimal(CMatroskaNode* pMN0)
00155 {
00156 CheckPointer(pMN0, E_POINTER);
00157
00158 pos = pMN0->GetPos();
00159 len = pMN0->m_len;
00160
00161 CAutoPtr<CMatroskaNode> pMN = pMN0->Child();
00162 if(!pMN) return S_FALSE;
00163
00164 int n = 0;
00165
00166 do
00167 {
00168 switch(pMN->m_id)
00169 {
00170 case 0x1549A966: SegmentInfo.Parse(pMN); n++; break;
00171 case 0x114D9B74: MetaSeekInfo.Parse(pMN); n++; break;
00172 case 0x1654AE6B: Tracks.Parse(pMN); n++; break;
00173 case 0x1C53BB6B: Cues.Parse(pMN); break;
00174 }
00175 }
00176 while(n < 3 && pMN->Next());
00177
00178 while(QWORD pos = pMN->FindPos(0x114D9B74, pMN->GetPos()))
00179 {
00180 pMN->SeekTo(pos);
00181 pMN->Parse();
00182 if(pMN->m_id != 0x114D9B74) {ASSERT(0); break;}
00183 MetaSeekInfo.Parse(pMN);
00184 }
00185
00186 if(n == 3)
00187 {
00188 if(Cues.IsEmpty() && (pMN = pMN0->Child(0x1C53BB6B, false)))
00189 {
00190 do {Cues.Parse(pMN);} while(pMN->Next(true));
00191 }
00192
00193 if(Chapters.IsEmpty() && (pMN = pMN0->Child(0x1043A770, false)))
00194 {
00195 do {Chapters.Parse(pMN); break;} while(pMN->Next(true));
00196 }
00197
00198 if(Attachments.IsEmpty() && (pMN = pMN0->Child(0x1941A469, false)))
00199 {
00200 do {Attachments.Parse(pMN); break;} while (pMN->Next(true));
00201 }
00202 }
00203
00204 return S_OK;
00205 }
00206
00207 UINT64 Segment::GetMasterTrack()
00208 {
00209 UINT64 TrackNumber = 0, AltTrackNumber = 0;
00210
00211 POSITION pos1 = Tracks.GetHeadPosition();
00212 while(pos1 && TrackNumber == 0)
00213 {
00214 Track* pT = Tracks.GetNext(pos1);
00215
00216 POSITION pos2 = pT->TrackEntries.GetHeadPosition();
00217 while(pos2 && TrackNumber == 0)
00218 {
00219 TrackEntry* pTE = pT->TrackEntries.GetNext(pos2);
00220
00221 if(pTE->TrackType == TrackEntry::TypeVideo)
00222 {
00223 TrackNumber = pTE->TrackNumber;
00224 break;
00225 }
00226 else if(pTE->TrackType == TrackEntry::TypeAudio && AltTrackNumber == 0)
00227 {
00228 AltTrackNumber = pTE->TrackNumber;
00229 }
00230 }
00231 }
00232
00233 if(TrackNumber == 0) TrackNumber = AltTrackNumber;
00234 if(TrackNumber == 0) TrackNumber = 1;
00235
00236 return TrackNumber;
00237 }
00238
00239 ChapterAtom* ChapterAtom::FindChapterAtom(UINT64 id)
00240 {
00241 if(ChapterUID == id)
00242 return(this);
00243
00244 POSITION pos = ChapterAtoms.GetHeadPosition();
00245 while(pos)
00246 {
00247 ChapterAtom* ca = ChapterAtoms.GetNext(pos)->FindChapterAtom(id);
00248 if(ca) return ca;
00249 }
00250
00251 return(NULL);
00252 }
00253
00254 ChapterAtom* Segment::FindChapterAtom(UINT64 id, int nEditionEntry)
00255 {
00256 POSITION pos1 = Chapters.GetHeadPosition();
00257 while(pos1)
00258 {
00259 Chapter* c = Chapters.GetNext(pos1);
00260
00261 POSITION pos2 = c->EditionEntries.GetHeadPosition();
00262 while(pos2)
00263 {
00264 EditionEntry* ee = c->EditionEntries.GetNext(pos2);
00265
00266 if(nEditionEntry-- == 0)
00267 {
00268 return id == 0 ? ee : ee->FindChapterAtom(id);
00269 }
00270 }
00271 }
00272
00273 return(NULL);
00274 }
00275
00276 HRESULT Info::Parse(CMatroskaNode* pMN0)
00277 {
00278 BeginChunk
00279 case 0x73A4: SegmentUID.Parse(pMN); break;
00280 case 0x7384: SegmentFilename.Parse(pMN); break;
00281 case 0x3CB923: PrevUID.Parse(pMN); break;
00282 case 0x3C83AB: PrevFilename.Parse(pMN); break;
00283 case 0x3EB923: NextUID.Parse(pMN); break;
00284 case 0x3E83BB: NextFilename.Parse(pMN); break;
00285 case 0x2AD7B1: TimeCodeScale.Parse(pMN); break;
00286 case 0x4489: Duration.Parse(pMN); break;
00287 case 0x4461: DateUTC.Parse(pMN); break;
00288 case 0x7BA9: Title.Parse(pMN); break;
00289 case 0x4D80: MuxingApp.Parse(pMN); break;
00290 case 0x5741: WritingApp.Parse(pMN); break;
00291 EndChunk
00292 }
00293
00294 HRESULT Seek::Parse(CMatroskaNode* pMN0)
00295 {
00296 BeginChunk
00297 case 0x4DBB: SeekHeads.Parse(pMN); break;
00298 EndChunk
00299 }
00300
00301 HRESULT SeekHead::Parse(CMatroskaNode* pMN0)
00302 {
00303 BeginChunk
00304 case 0x53AB: SeekID.Parse(pMN); break;
00305 case 0x53AC: SeekPosition.Parse(pMN); break;
00306 EndChunk
00307 }
00308
00309 HRESULT Track::Parse(CMatroskaNode* pMN0)
00310 {
00311 BeginChunk
00312 case 0xAE: TrackEntries.Parse(pMN); break;
00313 EndChunk
00314 }
00315
00316 HRESULT TrackEntry::Parse(CMatroskaNode* pMN0)
00317 {
00318 BeginChunk
00319 case 0xD7: TrackNumber.Parse(pMN); break;
00320 case 0x73C5: TrackUID.Parse(pMN); break;
00321 case 0x83: TrackType.Parse(pMN); break;
00322 case 0xB9: FlagEnabled.Parse(pMN); break;
00323 case 0x88: FlagDefault.Parse(pMN); break;
00324 case 0x9C: FlagLacing.Parse(pMN); break;
00325 case 0x6DE7: MinCache.Parse(pMN); break;
00326 case 0x6DF8: MaxCache.Parse(pMN); break;
00327 case 0x536E: Name.Parse(pMN); break;
00328 case 0x22B59C: Language.Parse(pMN); break;
00329 case 0x86: CodecID.Parse(pMN); break;
00330 case 0x63A2: CodecPrivate.Parse(pMN); break;
00331 case 0x258688: CodecName.Parse(pMN); break;
00332 case 0x3A9697: CodecSettings.Parse(pMN); break;
00333 case 0x3B4040: CodecInfoURL.Parse(pMN); break;
00334 case 0x26B240: CodecDownloadURL.Parse(pMN); break;
00335 case 0xAA: CodecDecodeAll.Parse(pMN); break;
00336 case 0x6FAB: TrackOverlay.Parse(pMN); break;
00337 case 0x23E383: case 0x2383E3: DefaultDuration.Parse(pMN); break;
00338 case 0x23314F: TrackTimecodeScale.Parse(pMN); break;
00339 case 0xE0: if(S_OK == v.Parse(pMN)) DescType |= DescVideo; break;
00340 case 0xE1: if(S_OK == a.Parse(pMN)) DescType |= DescAudio; break;
00341 case 0x6D80: ces.Parse(pMN); break;
00342 EndChunk
00343 }
00344
00345 static int cesort(const void* a, const void* b)
00346 {
00347 UINT64 ce1 = ((ContentEncoding*)a)->ContentEncodingOrder;
00348 UINT64 ce2 = ((ContentEncoding*)b)->ContentEncodingOrder;
00349
00350 return (int)ce1 - (int)ce2;
00351 }
00352
00353 bool TrackEntry::Expand(CBinary& data, UINT64 Scope)
00354 {
00355 if(ces.ce.GetCount() == 0) return(true);
00356
00357 CArray<ContentEncoding*> cearray;
00358 POSITION pos = ces.ce.GetHeadPosition();
00359 while(pos) cearray.Add(ces.ce.GetNext(pos));
00360 qsort(cearray.GetData(), cearray.GetCount(), sizeof(ContentEncoding*), cesort);
00361
00362 for(int i = cearray.GetCount()-1; i >= 0; i--)
00363 {
00364 ContentEncoding* ce = cearray[i];
00365
00366 if(!(ce->ContentEncodingScope & Scope))
00367 continue;
00368
00369 if(ce->ContentEncodingType == ContentEncoding::Compression)
00370 {
00371 if(!data.Decompress(ce->cc))
00372 return(false);
00373 }
00374 else if(ce->ContentEncodingType == ContentEncoding::Encryption)
00375 {
00376
00377 return(false);
00378 }
00379 }
00380
00381 return(true);
00382 }
00383
00384 HRESULT Video::Parse(CMatroskaNode* pMN0)
00385 {
00386 BeginChunk
00387 case 0x9A: FlagInterlaced.Parse(pMN); break;
00388 case 0x53B8: StereoMode.Parse(pMN); break;
00389 case 0xB0: PixelWidth.Parse(pMN); break;
00390 case 0xBA: PixelHeight.Parse(pMN); break;
00391 case 0x54B0: DisplayWidth.Parse(pMN); break;
00392 case 0x54BA: DisplayHeight.Parse(pMN); break;
00393 case 0x54B2: DisplayUnit.Parse(pMN); break;
00394 case 0x54B3: AspectRatioType.Parse(pMN); break;
00395 case 0x2EB524: ColourSpace.Parse(pMN); break;
00396 case 0x2FB523: GammaValue.Parse(pMN); break;
00397 case 0x2383E3: FramePerSec.Parse(pMN); break;
00398 EndChunk
00399 }
00400
00401 HRESULT Audio::Parse(CMatroskaNode* pMN0)
00402 {
00403 BeginChunk
00404 case 0xB5: SamplingFrequency.Parse(pMN); break;
00405 case 0x78B5: OutputSamplingFrequency.Parse(pMN); break;
00406 case 0x9F: Channels.Parse(pMN); break;
00407 case 0x7D7B: ChannelPositions.Parse(pMN); break;
00408 case 0x6264: BitDepth.Parse(pMN); break;
00409 EndChunk
00410 }
00411
00412 HRESULT ContentEncodings::Parse(CMatroskaNode* pMN0)
00413 {
00414 BeginChunk
00415 case 0x6240: ce.Parse(pMN); break;
00416 EndChunk
00417 }
00418
00419 HRESULT ContentEncoding::Parse(CMatroskaNode* pMN0)
00420 {
00421 BeginChunk
00422 case 0x5031: ContentEncodingOrder.Parse(pMN); break;
00423 case 0x5032: ContentEncodingScope.Parse(pMN); break;
00424 case 0x5033: ContentEncodingType.Parse(pMN); break;
00425 case 0x5034: cc.Parse(pMN); break;
00426 case 0x5035: ce.Parse(pMN); break;
00427 EndChunk
00428 }
00429
00430 HRESULT ContentCompression::Parse(CMatroskaNode* pMN0)
00431 {
00432 BeginChunk
00433 case 0x4254: ContentCompAlgo.Parse(pMN); break;
00434 case 0x4255: ContentCompSettings.Parse(pMN); break;
00435 EndChunk
00436 }
00437
00438 HRESULT ContentEncryption::Parse(CMatroskaNode* pMN0)
00439 {
00440 BeginChunk
00441 case 0x47e1: ContentEncAlgo.Parse(pMN); break;
00442 case 0x47e2: ContentEncKeyID.Parse(pMN); break;
00443 case 0x47e3: ContentSignature.Parse(pMN); break;
00444 case 0x47e4: ContentSigKeyID.Parse(pMN); break;
00445 case 0x47e5: ContentSigAlgo.Parse(pMN); break;
00446 case 0x47e6: ContentSigHashAlgo.Parse(pMN); break;
00447 EndChunk
00448 }
00449
00450 HRESULT Cluster::Parse(CMatroskaNode* pMN0)
00451 {
00452 BeginChunk
00453 case 0xE7: TimeCode.Parse(pMN); break;
00454 case 0xA7: Position.Parse(pMN); break;
00455 case 0xAB: PrevSize.Parse(pMN); break;
00456 case 0xA0: BlockGroups.Parse(pMN, true); break;
00457 case 0xA3: SimpleBlocks.Parse(pMN, true); break;
00458 EndChunk
00459 }
00460
00461 HRESULT Cluster::ParseTimeCode(CMatroskaNode* pMN0)
00462 {
00463 BeginChunk
00464 case 0xE7: TimeCode.Parse(pMN); return S_OK;
00465 EndChunk
00466 }
00467
00468 HRESULT BlockGroup::Parse(CMatroskaNode* pMN0, bool fFull)
00469 {
00470 BeginChunk
00471 case 0xA1: Block.Parse(pMN, fFull); break;
00472 case 0xA2: ; break;
00473 case 0x9B: BlockDuration.Parse(pMN); break;
00474 case 0xFA: ReferencePriority.Parse(pMN); break;
00475 case 0xFB: ReferenceBlock.Parse(pMN); break;
00476 case 0xFD: ReferenceVirtual.Parse(pMN); break;
00477 case 0xA4: CodecState.Parse(pMN); break;
00478 case 0xE8: TimeSlices.Parse(pMN); break;
00479 EndChunk
00480 }
00481
00482 HRESULT SimpleBlock::Parse(CMatroskaNode* pMN, bool fFull)
00483 {
00484 pMN->SeekTo(pMN->m_start);
00485
00486 TrackNumber.Parse(pMN);
00487 CShort s; s.Parse(pMN); TimeCode.Set(s);
00488 Lacing.Parse(pMN);
00489
00490 if(!fFull) return S_OK;
00491
00492 CList<QWORD> lens;
00493 QWORD tlen = 0;
00494 QWORD FrameSize;
00495 BYTE FramesInLaceLessOne;
00496
00497 switch((Lacing & 0x06) >> 1)
00498 {
00499 case 0:
00500
00501 lens.AddTail((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen));
00502 break;
00503 case 1:
00504
00505 BYTE n;
00506 pMN->Read(n);
00507 while(n-- > 0)
00508 {
00509 BYTE b;
00510 QWORD len = 0;
00511 do {pMN->Read(b); len += b;} while(b == 0xff);
00512 lens.AddTail(len);
00513 tlen += len;
00514 }
00515 lens.AddTail((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen));
00516 break;
00517 case 2:
00518
00519 pMN->Read(FramesInLaceLessOne);
00520 FramesInLaceLessOne++;
00521 FrameSize = ((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen)) / FramesInLaceLessOne;
00522 while(FramesInLaceLessOne-- > 0)
00523 lens.AddTail(FrameSize);
00524 break;
00525 case 3:
00526
00527 pMN->Read(FramesInLaceLessOne);
00528
00529 CLength FirstFrameSize;
00530 FirstFrameSize.Parse(pMN);
00531 lens.AddTail(FirstFrameSize);
00532 FramesInLaceLessOne--;
00533 tlen = FirstFrameSize;
00534
00535 CSignedLength DiffSize;
00536 FrameSize = FirstFrameSize;
00537 while(FramesInLaceLessOne--)
00538 {
00539 DiffSize.Parse(pMN);
00540 FrameSize += DiffSize;
00541 lens.AddTail(FrameSize);
00542 tlen += FrameSize;
00543 }
00544 lens.AddTail((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen));
00545 break;
00546 }
00547
00548 POSITION pos = lens.GetHeadPosition();
00549 while(pos)
00550 {
00551 QWORD len = lens.GetNext(pos);
00552 CAutoPtr<CBinary> p(new CBinary());
00553 p->SetSize((INT_PTR)len);
00554 pMN->Read(p->GetData(), len);
00555 BlockData.AddTail(p);
00556 }
00557
00558 return S_OK;
00559 }
00560
00561 HRESULT TimeSlice::Parse(CMatroskaNode* pMN0)
00562 {
00563 BeginChunk
00564 case 0xCC: LaceNumber.Parse(pMN); break;
00565 case 0xCD: FrameNumber.Parse(pMN); break;
00566 case 0xCE: Delay.Parse(pMN); break;
00567 case 0xCF: Duration.Parse(pMN); break;
00568 EndChunk
00569 }
00570
00571 HRESULT Cue::Parse(CMatroskaNode* pMN0)
00572 {
00573 BeginChunk
00574 case 0xBB: CuePoints.Parse(pMN); break;
00575 EndChunk
00576 }
00577
00578 HRESULT CuePoint::Parse(CMatroskaNode* pMN0)
00579 {
00580 BeginChunk
00581 case 0xB3: CueTime.Parse(pMN); break;
00582 case 0xB7: CueTrackPositions.Parse(pMN); break;
00583 EndChunk
00584 }
00585
00586 HRESULT CueTrackPosition::Parse(CMatroskaNode* pMN0)
00587 {
00588 BeginChunk
00589 case 0xF7: CueTrack.Parse(pMN); break;
00590 case 0xF1: CueClusterPosition.Parse(pMN); break;
00591 case 0x5387: CueBlockNumber.Parse(pMN); break;
00592 case 0xEA: CueCodecState.Parse(pMN); break;
00593 case 0xDB: CueReferences.Parse(pMN); break;
00594 EndChunk
00595 }
00596
00597 HRESULT CueReference::Parse(CMatroskaNode* pMN0)
00598 {
00599 BeginChunk
00600 case 0x96: CueRefTime.Parse(pMN); break;
00601 case 0x97: CueRefCluster.Parse(pMN); break;
00602 case 0x535F: CueRefNumber.Parse(pMN); break;
00603 case 0xEB: CueRefCodecState.Parse(pMN); break;
00604 EndChunk
00605 }
00606
00607 HRESULT Attachment::Parse(CMatroskaNode* pMN0)
00608 {
00609 BeginChunk
00610 case 0x61A7: AttachedFiles.Parse(pMN); break;
00611 EndChunk
00612 }
00613
00614 HRESULT AttachedFile::Parse(CMatroskaNode* pMN0)
00615 {
00616 BeginChunk
00617 case 0x467E: FileDescription.Parse(pMN); break;
00618 case 0x466E: FileName.Parse(pMN); break;
00619 case 0x4660: FileMimeType.Parse(pMN); break;
00620 case 0x465C:
00621 FileDataLen = (INT_PTR)pMN->m_len;
00622 FileDataPos = pMN->m_start;
00623 break;
00624 case 0x46AE: FileUID.Parse(pMN); break;
00625 EndChunk
00626 }
00627
00628 HRESULT Chapter::Parse(CMatroskaNode* pMN0)
00629 {
00630 BeginChunk
00631 case 0x45B9: EditionEntries.Parse(pMN); break;
00632 EndChunk
00633 }
00634
00635 HRESULT EditionEntry::Parse(CMatroskaNode* pMN0)
00636 {
00637 BeginChunk
00638 case 0xB6: ChapterAtoms.Parse(pMN); break;
00639 EndChunk
00640 }
00641
00642 HRESULT ChapterAtom::Parse(CMatroskaNode* pMN0)
00643 {
00644 BeginChunk
00645 case 0x73C4: ChapterUID.Parse(pMN); break;
00646 case 0x91: ChapterTimeStart.Parse(pMN); break;
00647 case 0x92: ChapterTimeEnd.Parse(pMN); break;
00648
00649 case 0x80: ChapterDisplays.Parse(pMN); break;
00650 case 0xB6: ChapterAtoms.Parse(pMN); break;
00651 case 0x98: ChapterFlagHidden.Parse(pMN); break;
00652 case 0x4598: ChapterFlagEnabled.Parse(pMN); break;
00653 EndChunk
00654 }
00655
00656 HRESULT ChapterDisplay::Parse(CMatroskaNode* pMN0)
00657 {
00658 BeginChunk
00659 case 0x85: ChapString.Parse(pMN); break;
00660 case 0x437C: ChapLanguage.Parse(pMN); break;
00661 case 0x437E: ChapCountry.Parse(pMN); break;
00662 EndChunk
00663 }
00664
00665
00666
00667 HRESULT CBinary::Parse(CMatroskaNode* pMN)
00668 {
00669 ASSERT(pMN->m_len <= INT_MAX);
00670 SetSize((INT_PTR)pMN->m_len);
00671 return pMN->Read(GetData(), pMN->m_len);
00672 }
00673
00674 bool CBinary::Compress(ContentCompression& cc)
00675 {
00676 if(cc.ContentCompAlgo == ContentCompression::ZLIB)
00677 {
00678 int res;
00679 z_stream c_stream;
00680
00681 c_stream.zalloc = (alloc_func)0;
00682 c_stream.zfree = (free_func)0;
00683 c_stream.opaque = (voidpf)0;
00684
00685 if(Z_OK != (res = deflateInit(&c_stream, 9)))
00686 return(false);
00687
00688 c_stream.next_in = GetData();
00689 c_stream.avail_in = GetSize();
00690
00691 BYTE* dst = NULL;
00692 int n = 0;
00693 do
00694 {
00695 dst = (BYTE*)realloc(dst, ++n*10);
00696 c_stream.next_out = &dst[(n-1)*10];
00697 c_stream.avail_out = 10;
00698 if(Z_OK != (res = deflate(&c_stream, Z_FINISH)) && Z_STREAM_END != res)
00699 {
00700 free(dst);
00701 return(false);
00702 }
00703 }
00704 while(0 == c_stream.avail_out && Z_STREAM_END != res);
00705
00706 deflateEnd(&c_stream);
00707
00708 SetSize(c_stream.total_out);
00709 memcpy(GetData(), dst, GetSize());
00710
00711 free(dst);
00712
00713 return(true);
00714 }
00715
00716 return(false);
00717 }
00718
00719 bool CBinary::Decompress(ContentCompression& cc)
00720 {
00721 if(cc.ContentCompAlgo == ContentCompression::ZLIB)
00722 {
00723 int res;
00724 z_stream d_stream;
00725
00726 d_stream.zalloc = (alloc_func)0;
00727 d_stream.zfree = (free_func)0;
00728 d_stream.opaque = (voidpf)0;
00729
00730 if(Z_OK != (res = inflateInit(&d_stream)))
00731 return(false);
00732
00733 d_stream.next_in = GetData();
00734 d_stream.avail_in = GetSize();
00735
00736 BYTE* dst = NULL;
00737 int n = 0;
00738 do
00739 {
00740 dst = (unsigned char *)realloc(dst, ++n*1000);
00741 d_stream.next_out = &dst[(n-1)*1000];
00742 d_stream.avail_out = 1000;
00743 if(Z_OK != (res = inflate(&d_stream, Z_NO_FLUSH)) && Z_STREAM_END != res)
00744 {
00745 free(dst);
00746 return(false);
00747 }
00748 }
00749 while(0 == d_stream.avail_out && 0 != d_stream.avail_in && Z_STREAM_END != res);
00750
00751 inflateEnd(&d_stream);
00752
00753 SetSize(d_stream.total_out);
00754 memcpy(GetData(), dst, GetSize());
00755
00756 free(dst);
00757
00758 return(true);
00759 }
00760 else if(cc.ContentCompAlgo == ContentCompression::HDRSTRIP)
00761 {
00762 InsertAt(0, &cc.ContentCompSettings);
00763 }
00764
00765 return(false);
00766 }
00767
00768 HRESULT CANSI::Parse(CMatroskaNode* pMN)
00769 {
00770 Empty();
00771
00772 QWORD len = pMN->m_len;
00773 CHAR c;
00774 while(len-- > 0 && SUCCEEDED(pMN->Read(c)))
00775 *this += c;
00776
00777 return(len == -1 ? S_OK : E_FAIL);
00778 }
00779
00780 HRESULT CUTF8::Parse(CMatroskaNode* pMN)
00781 {
00782 Empty();
00783 CAutoVectorPtr<BYTE> buff;
00784 if(!buff.Allocate((UINT)pMN->m_len + 1) || S_OK != pMN->Read(buff, pMN->m_len))
00785 return E_FAIL;
00786 buff[pMN->m_len] = 0;
00787 CStringW::operator = (UTF8To16((LPCSTR)(BYTE*)buff));
00788 return S_OK;
00789 }
00790
00791 HRESULT CUInt::Parse(CMatroskaNode* pMN)
00792 {
00793 m_val = 0;
00794 for(int i = 0; i < (int)pMN->m_len; i++)
00795 {
00796 m_val <<= 8;
00797 HRESULT hr = pMN->Read(*(BYTE*)&m_val);
00798 if(FAILED(hr)) return hr;
00799 }
00800 m_fValid = true;
00801 return S_OK;
00802 }
00803
00804 HRESULT CInt::Parse(CMatroskaNode* pMN)
00805 {
00806 m_val = 0;
00807 for(int i = 0; i < (int)pMN->m_len; i++)
00808 {
00809 HRESULT hr = pMN->Read(*((BYTE*)&m_val+7-i));
00810 if(FAILED(hr)) return hr;
00811 }
00812 m_val >>= (8-pMN->m_len)*8;
00813 m_fValid = true;
00814 return S_OK;
00815 }
00816
00817 HRESULT CFloat::Parse(CMatroskaNode* pMN)
00818 {
00819 HRESULT hr = E_FAIL;
00820 m_val = 0;
00821
00822 if(pMN->m_len == 4)
00823 {
00824 float val = 0;
00825 hr = pMN->Read(val);
00826 m_val = val;
00827 } else if(pMN->m_len == 8) {
00828 hr = pMN->Read(m_val);
00829 }
00830 if(SUCCEEDED(hr))
00831 m_fValid = true;
00832 return hr;
00833 }
00834
00835
00836 template<class T, class BASE>
00837 HRESULT CSimpleVar<T, BASE>::Parse(CMatroskaNode* pMN)
00838 {
00839 m_val = 0;
00840 m_fValid = true;
00841 return pMN->Read(m_val);
00842 }
00843
00844 HRESULT CID::Parse(CMatroskaNode* pMN)
00845 {
00846 m_val = 0;
00847
00848 BYTE b = 0;
00849 HRESULT hr = pMN->Read(b);
00850 if(FAILED(hr)) return hr;
00851
00852 int nMoreBytes = 0;
00853
00854 if((b&0x80) == 0x80) {m_val = b&0xff; nMoreBytes = 0;}
00855 else if((b&0xc0) == 0x40) {m_val = b&0x7f; nMoreBytes = 1;}
00856 else if((b&0xe0) == 0x20) {m_val = b&0x3f; nMoreBytes = 2;}
00857 else if((b&0xf0) == 0x10) {m_val = b&0x1f; nMoreBytes = 3;}
00858 else return E_FAIL;
00859
00860 while(nMoreBytes-- > 0)
00861 {
00862 m_val <<= 8;
00863 hr = pMN->Read(*(BYTE*)&m_val);
00864 if(FAILED(hr)) return hr;
00865 }
00866
00867 m_fValid = true;
00868
00869 return S_OK;
00870 }
00871
00872 HRESULT CLength::Parse(CMatroskaNode* pMN)
00873 {
00874 m_val = 0;
00875
00876 BYTE b = 0;
00877 HRESULT hr = pMN->Read(b);
00878 if(FAILED(hr)) return hr;
00879
00880 int nMoreBytes = 0, nMoreBytesTmp = 0;
00881
00882 if((b&0x80) == 0x80) {m_val = b&0x7f; nMoreBytes = 0;}
00883 else if((b&0xc0) == 0x40) {m_val = b&0x3f; nMoreBytes = 1;}
00884 else if((b&0xe0) == 0x20) {m_val = b&0x1f; nMoreBytes = 2;}
00885 else if((b&0xf0) == 0x10) {m_val = b&0x0f; nMoreBytes = 3;}
00886 else if((b&0xf8) == 0x08) {m_val = b&0x07; nMoreBytes = 4;}
00887 else if((b&0xfc) == 0x04) {m_val = b&0x03; nMoreBytes = 5;}
00888 else if((b&0xfe) == 0x02) {m_val = b&0x01; nMoreBytes = 6;}
00889 else if((b&0xff) == 0x01) {m_val = b&0x00; nMoreBytes = 7;}
00890 else return E_FAIL;
00891
00892 nMoreBytesTmp = nMoreBytes;
00893
00894 QWORD UnknownSize = (1i64<<(7*(nMoreBytes+1)))-1;
00895
00896 while(nMoreBytes-- > 0)
00897 {
00898 m_val <<= 8;
00899 hr = pMN->Read(*(BYTE*)&m_val);
00900 if(FAILED(hr)) return hr;
00901 }
00902
00903 if(m_val == UnknownSize)
00904 {
00905 m_val = pMN->GetLength() - pMN->GetPos();
00906 TRACE(_T("CLength: Unspecified chunk size at %I64d (corrected to %I64d)\n"), pMN->GetPos(), m_val);
00907 }
00908
00909 if(m_fSigned)
00910 m_val -= (UnknownSize >> 1);
00911
00912 m_fValid = true;
00913
00914 return S_OK;
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964 template<class T>
00965 HRESULT CNode<T>::Parse(CMatroskaNode* pMN)
00966 {
00967 CAutoPtr<T> p(new T());
00968 HRESULT hr = E_OUTOFMEMORY;
00969 if(!p || FAILED(hr = p->Parse(pMN))) return hr;
00970 AddTail(p);
00971 return S_OK;
00972 }
00973
00974 HRESULT CBlockGroupNode::Parse(CMatroskaNode* pMN, bool fFull)
00975 {
00976 CAutoPtr<BlockGroup> p(new BlockGroup());
00977 HRESULT hr = E_OUTOFMEMORY;
00978 if(!p || FAILED(hr = p->Parse(pMN, fFull))) return hr;
00979 AddTail(p);
00980 return S_OK;
00981 }
00982
00983 HRESULT CSimpleBlockNode::Parse(CMatroskaNode* pMN, bool fFull)
00984 {
00985 CAutoPtr<SimpleBlock> p(new SimpleBlock());
00986 HRESULT hr = E_OUTOFMEMORY;
00987 if(!p || FAILED(hr = p->Parse(pMN, fFull))) return hr;
00988 AddTail(p);
00989 return S_OK;
00990 }
00991
00993
00994 CMatroskaNode::CMatroskaNode(CMatroskaFile* pMF)
00995 : m_pMF(pMF)
00996 , m_pParent(NULL)
00997 {
00998 ASSERT(m_pMF);
00999 m_start = m_filepos = 0;
01000 m_len.Set(m_pMF ? m_pMF->GetLength() : 0);
01001 }
01002
01003 CMatroskaNode::CMatroskaNode(CMatroskaNode* pParent)
01004 : m_pMF(pParent->m_pMF)
01005 , m_pParent(pParent)
01006 {
01007 Parse();
01008 }
01009
01010 HRESULT CMatroskaNode::Parse()
01011 {
01012 m_filepos = GetPos();
01013 if(FAILED(m_id.Parse(this)) || FAILED(m_len.Parse(this)))
01014 return E_FAIL;
01015 m_start = GetPos();
01016 return S_OK;
01017 }
01018
01019 CAutoPtr<CMatroskaNode> CMatroskaNode::Child(DWORD id, bool fSearch)
01020 {
01021 if(m_len == 0) return CAutoPtr<CMatroskaNode>();
01022 SeekTo(m_start);
01023 CAutoPtr<CMatroskaNode> pMN(new CMatroskaNode(this));
01024 if(id && !pMN->Find(id, fSearch)) pMN.Free();
01025 return pMN;
01026 }
01027
01028 bool CMatroskaNode::Next(bool fSame)
01029 {
01030 if(!m_pParent)
01031 return(false);
01032
01033 CID id = m_id;
01034
01035 while(m_start+m_len < m_pParent->m_start+m_pParent->m_len)
01036 {
01037 SeekTo(m_start+m_len);
01038
01039 if(FAILED(Parse()))
01040 {
01041 if(!Resync())
01042 return(false);
01043 }
01044
01045 if(!fSame || m_id == id)
01046 return(true);
01047 }
01048
01049 return(false);
01050 }
01051
01052 bool CMatroskaNode::Find(DWORD id, bool fSearch)
01053 {
01054 QWORD pos = m_pParent && m_pParent->m_id == 0x18538067
01055 ? FindPos(id)
01056 : 0;
01057
01058 if(pos)
01059 {
01060 SeekTo(pos);
01061 Parse();
01062 }
01063 else if(fSearch)
01064 {
01065 while(m_id != id && Next());
01066 }
01067
01068 return(m_id == id);
01069 }
01070
01071 void CMatroskaNode::SeekTo(QWORD pos) {m_pMF->Seek(pos);}
01072 QWORD CMatroskaNode::GetPos() {return m_pMF->GetPos();}
01073 QWORD CMatroskaNode::GetLength() {return m_pMF->GetLength();}
01074 template <class T>
01075 HRESULT CMatroskaNode::Read(T& var) {return m_pMF->Read(var);}
01076 HRESULT CMatroskaNode::Read(BYTE* pData, QWORD len) {return m_pMF->Read(pData, len);}
01077
01078 QWORD CMatroskaNode::FindPos(DWORD id, QWORD start)
01079 {
01080 Segment& sm = m_pMF->m_segment;
01081
01082 POSITION pos = sm.MetaSeekInfo.GetHeadPosition();
01083 while(pos)
01084 {
01085 Seek* s = sm.MetaSeekInfo.GetNext(pos);
01086
01087 POSITION pos2 = s->SeekHeads.GetHeadPosition();
01088 while(pos2)
01089 {
01090 SeekHead* sh = s->SeekHeads.GetNext(pos2);
01091 if(sh->SeekID == id && sh->SeekPosition+sm.pos >= start)
01092 return sh->SeekPosition+sm.pos;
01093 }
01094 }
01095
01096 return 0;
01097 }
01098
01099 CAutoPtr<CMatroskaNode> CMatroskaNode::Copy()
01100 {
01101 CAutoPtr<CMatroskaNode> pNewNode(new CMatroskaNode(m_pMF));
01102 pNewNode->m_pParent = m_pParent;
01103 pNewNode->m_id.Set(m_id);
01104 pNewNode->m_len.Set(m_len);
01105 pNewNode->m_filepos = m_filepos;
01106 pNewNode->m_start = m_start;
01107 return(pNewNode);
01108 }
01109
01110 CAutoPtr<CMatroskaNode> CMatroskaNode::GetFirstBlock()
01111 {
01112 CAutoPtr<CMatroskaNode> pNode = Child();
01113 do {if(pNode->m_id == 0xA0 || pNode->m_id == 0xA3) return pNode;}
01114 while(pNode->Next());
01115 return CAutoPtr<CMatroskaNode>();
01116 }
01117
01118 bool CMatroskaNode::NextBlock()
01119 {
01120 if(!m_pParent)
01121 return(false);
01122
01123 CID id = m_id;
01124
01125 while(m_start+m_len < m_pParent->m_start+m_pParent->m_len)
01126 {
01127 SeekTo(m_start+m_len);
01128
01129 if(FAILED(Parse()))
01130 {
01131 if(!Resync())
01132 return(false);
01133 }
01134
01135 if(m_id == 0xA0 || m_id == 0xA3)
01136 return(true);
01137 }
01138
01139 return(false);
01140 }
01141
01142 bool CMatroskaNode::Resync()
01143 {
01144 if(m_pParent->m_id == 0x18538067)
01145 {
01146 SeekTo(m_filepos);
01147
01148 for(BYTE b = 0; S_OK == Read(b); b = 0)
01149 {
01150 if((b&0xf0) != 0x10)
01151 continue;
01152
01153 DWORD dw = b;
01154 Read((BYTE*)&dw+1, 3);
01155 bswap((BYTE*)&dw, 4);
01156
01157 switch(dw)
01158 {
01159 case 0x1549A966:
01160 case 0x114D9B74:
01161 case 0x1654AE6B:
01162 case 0x1F43B675:
01163 case 0x1C53BB6B:
01164 case 0x1941A469:
01165 case 0x1043A770:
01166 case 0x1254C367:
01167 SeekTo(GetPos()-4);
01168 return(SUCCEEDED(Parse()));
01169 default:
01170 SeekTo(GetPos()-3);
01171 break;
01172 }
01173 }
01174 }
01175
01176 return(false);
01177 }