2 * Copyright 2010, Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 #include "SubTitlesSRT.h"
14 #include <TextEncoding.h>
16 #include "FileReadWrite.h"
19 SubTitlesSRT::SubTitlesSRT(BFile
* file
, const char* name
)
27 if (file
->InitCheck() != B_OK
)
30 FileReadWrite
lineProvider(file
);
33 EXPECT_SEQUENCE_NUMBER
= 0,
39 int32 lastSequenceNumber
= 0;
40 int32 currentLine
= 0;
42 BPrivate::BTextEncoding
* decoder
= NULL
;
44 int32 state
= EXPECT_SEQUENCE_NUMBER
;
45 while (lineProvider
.Next(line
)) {
49 case EXPECT_SEQUENCE_NUMBER
:
55 int32 sequenceNumber
= atoi(line
.String());
56 if (sequenceNumber
!= lastSequenceNumber
+ 1) {
57 fprintf(stderr
, "Warning: Wrong sequence number in SRT "
58 "file: %" B_PRId32
", expected: %" B_PRId32
", line %"
59 B_PRId32
"\n", sequenceNumber
, lastSequenceNumber
+ 1,
62 state
= EXPECT_TIME_CODE
;
63 lastSequenceNumber
= sequenceNumber
;
67 case EXPECT_TIME_CODE
:
70 int32 separatorPos
= line
.FindFirst(" --> ");
71 if (separatorPos
< 0) {
72 fprintf(stderr
, "Error: Time code expected on line %"
73 B_PRId32
", got '%s'\n", currentLine
, line
.String());
76 BString
timeCode(line
.String(), separatorPos
);
77 if (separatorPos
!= 12) {
78 fprintf(stderr
, "Warning: Time code broken on line %"
79 B_PRId32
" (%s)?\n", currentLine
, timeCode
.String());
85 if (sscanf(timeCode
.String(), "%d:%d:%d,%d", &hours
, &minutes
,
86 &seconds
, &milliSeconds
) != 4) {
87 fprintf(stderr
, "Error: Failed to parse start time on "
88 "line %" B_PRId32
"\n", currentLine
);
91 subTitle
.startTime
= (bigtime_t
)hours
* 60 * 60 * 1000000LL
92 + (bigtime_t
)minutes
* 60 * 1000000LL
93 + (bigtime_t
)seconds
* 1000000LL
94 + (bigtime_t
)milliSeconds
* 1000;
96 int32 endTimePos
= separatorPos
+ 5;
97 timeCode
.SetTo(line
.String() + endTimePos
);
98 if (sscanf(timeCode
.String(), "%d:%d:%d,%d", &hours
, &minutes
,
99 &seconds
, &milliSeconds
) != 4) {
100 fprintf(stderr
, "Error: Failed to parse end time on "
101 "line %" B_PRId32
"\n", currentLine
);
104 bigtime_t endTime
= (bigtime_t
)hours
* 60 * 60 * 1000000LL
105 + (bigtime_t
)minutes
* 60 * 1000000LL
106 + (bigtime_t
)seconds
* 1000000LL
107 + (bigtime_t
)milliSeconds
* 1000;
109 subTitle
.duration
= endTime
- subTitle
.startTime
;
116 if (line
.IsEmpty()) {
117 int32 index
= _IndexFor(subTitle
.startTime
);
118 SubTitle
* clone
= new(std::nothrow
) SubTitle(subTitle
);
119 if (clone
== NULL
|| !fSubTitles
.AddItem(clone
, index
)) {
124 subTitle
.placement
= BPoint(-1, -1);
125 subTitle
.startTime
= 0;
126 subTitle
.duration
= 0;
128 state
= EXPECT_SEQUENCE_NUMBER
;
130 if (decoder
== NULL
) {
131 // We try to guess the encoding from the first line of
132 // text in the subtitle file.
133 decoder
= new BPrivate::BTextEncoding(line
.String(),
136 char buffer
[line
.Length() * 4];
137 size_t inLength
= line
.Length();
138 size_t outLength
= line
.Length() * 4;
139 decoder
->Decode(line
.String(), inLength
, buffer
, outLength
);
140 buffer
[outLength
] = 0;
141 subTitle
.text
<< buffer
<< '\n';
153 SubTitlesSRT::~SubTitlesSRT()
155 for (int32 i
= fSubTitles
.CountItems() - 1; i
>= 0; i
--)
156 delete reinterpret_cast<SubTitle
*>(fSubTitles
.ItemAtFast(i
));
161 SubTitlesSRT::Name() const
163 return fName
.String();
168 SubTitlesSRT::SubTitleAt(bigtime_t time
) const
170 int32 index
= _IndexFor(time
);
172 = reinterpret_cast<SubTitle
*>(fSubTitles
.ItemAt(index
));
173 if (subTitle
!= NULL
&& subTitle
->startTime
> time
)
174 subTitle
= reinterpret_cast<SubTitle
*>(fSubTitles
.ItemAt(index
- 1));
175 if (subTitle
!= NULL
&& subTitle
->startTime
<= time
176 && subTitle
->startTime
+ subTitle
->duration
> time
) {
184 SubTitlesSRT::_IndexFor(bigtime_t startTime
) const
186 // binary search index
188 int32 upper
= fSubTitles
.CountItems();
189 while (lower
< upper
) {
190 int32 mid
= (lower
+ upper
) / 2;
191 SubTitle
* subTitle
= reinterpret_cast<SubTitle
*>(
192 fSubTitles
.ItemAtFast(mid
));
193 if (startTime
< subTitle
->startTime
)