btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / mediaplayer / supplier / SubTitlesSRT.cpp
blobbce8f70832efc74dfb6cd2f692bc2653176efb43
1 /*
2 * Copyright 2010, Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "SubTitlesSRT.h"
9 #include <new>
11 #include <stdlib.h>
13 #include <File.h>
14 #include <TextEncoding.h>
16 #include "FileReadWrite.h"
19 SubTitlesSRT::SubTitlesSRT(BFile* file, const char* name)
21 SubTitles(),
22 fName(name),
23 fSubTitles(64)
25 if (file == NULL)
26 return;
27 if (file->InitCheck() != B_OK)
28 return;
30 FileReadWrite lineProvider(file);
31 BString line;
32 enum {
33 EXPECT_SEQUENCE_NUMBER = 0,
34 EXPECT_TIME_CODE,
35 EXPECT_TEXT
38 SubTitle subTitle;
39 int32 lastSequenceNumber = 0;
40 int32 currentLine = 0;
42 BPrivate::BTextEncoding* decoder = NULL;
44 int32 state = EXPECT_SEQUENCE_NUMBER;
45 while (lineProvider.Next(line)) {
46 line.RemoveAll("\n");
47 line.RemoveAll("\r");
48 switch (state) {
49 case EXPECT_SEQUENCE_NUMBER:
51 if (line.IsEmpty())
52 continue;
54 line.Trim();
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,
60 currentLine);
62 state = EXPECT_TIME_CODE;
63 lastSequenceNumber = sequenceNumber;
64 break;
67 case EXPECT_TIME_CODE:
69 line.Trim();
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());
74 return;
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());
81 int hours;
82 int minutes;
83 int seconds;
84 int milliSeconds;
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);
89 return;
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);
102 return;
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;
111 state = EXPECT_TEXT;
112 break;
115 case EXPECT_TEXT:
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)) {
120 delete clone;
121 return;
123 subTitle.text = "";
124 subTitle.placement = BPoint(-1, -1);
125 subTitle.startTime = 0;
126 subTitle.duration = 0;
128 state = EXPECT_SEQUENCE_NUMBER;
129 } else {
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(),
134 line.Length());
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';
143 break;
145 line.SetTo("");
146 currentLine++;
149 delete decoder;
153 SubTitlesSRT::~SubTitlesSRT()
155 for (int32 i = fSubTitles.CountItems() - 1; i >= 0; i--)
156 delete reinterpret_cast<SubTitle*>(fSubTitles.ItemAtFast(i));
160 const char*
161 SubTitlesSRT::Name() const
163 return fName.String();
167 const SubTitle*
168 SubTitlesSRT::SubTitleAt(bigtime_t time) const
170 int32 index = _IndexFor(time);
171 SubTitle* subTitle
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) {
177 return subTitle;
179 return NULL;
183 int32
184 SubTitlesSRT::_IndexFor(bigtime_t startTime) const
186 // binary search index
187 int32 lower = 0;
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)
194 upper = mid;
195 else
196 lower = mid + 1;
198 return lower;