Index: third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc |
diff --git a/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc b/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc |
index 390e192e3d24b678b9bb169b5bdf22b9f6738865..67c6341dd76ebfce2a943fa68428a1534b75fb14 100644 |
--- a/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc |
+++ b/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc |
@@ -121,12 +121,13 @@ bool LibLouisWrapper::Translate(const TranslationParams& params, |
// TODO(jbroman): log this |
return false; |
} |
+ // To avoid unsigned/signed comparison warnings. |
+ int inbufsize = inbuf.size(); |
- int inlen = inbuf.size(); |
- int outlen = inlen * 2; // TODO(jbroman): choose this size more accurately. |
- std::vector<widechar> outbuf(outlen); |
- std::vector<int> text_to_braille(inlen); |
- std::vector<int> braille_to_text(outlen); |
+ std::vector<widechar> outbuf; |
+ std::vector<int> text_to_braille(inbuf.size()); |
+ std::vector<int> braille_to_text; |
+ int outlen; |
// Compute the cursor position pointer to pass to liblouis. |
int out_cursor_position; |
@@ -139,15 +140,36 @@ bool LibLouisWrapper::Translate(const TranslationParams& params, |
out_cursor_position_ptr = &out_cursor_position; |
} |
- // Invoke liblouis. |
- int result = lou_translate(params.table_name.c_str(), |
- &inbuf[0], &inlen, &outbuf[0], &outlen, |
- NULL /* typeform */, NULL /* spacing */, |
- &text_to_braille[0], &braille_to_text[0], |
- out_cursor_position_ptr, dotsIO /* mode */); |
- if (result == 0) { |
- // TODO(jbroman): log this |
- return false; |
+ // Invoke liblouis. Do this in a loop since we can't precalculate the |
+ // translated size. We add an extra slot in the output buffer so that |
+ // common cases like single digits or capital letters won't always trigger |
+ // retranslations (see the comments above the second exit condition inside |
+ // the loop). We also set an arbitrary upper bound for the allocation |
+ // to make sure the loop exits without running out of memory. |
+ for (int outalloc = (inbufsize + 1) * 2, maxoutalloc = (inbufsize + 1) * 8; |
+ outalloc <= maxoutalloc; outalloc *= 2) { |
+ int inlen = inbufsize; |
+ outlen = outalloc; |
+ outbuf.resize(outalloc); |
+ braille_to_text.resize(outalloc); |
+ int result = lou_translate(params.table_name.c_str(), |
+ &inbuf[0], &inlen, &outbuf[0], &outlen, |
+ NULL /* typeform */, NULL /* spacing */, |
+ &text_to_braille[0], &braille_to_text[0], |
+ out_cursor_position_ptr, dotsIO /* mode */); |
+ if (result == 0) { |
+ // TODO(jbroman): log this |
+ return false; |
+ } |
+ // If all of inbuf was not consumed, the output buffer must be too small |
+ // and we have to retry with a larger buffer. |
+ // In addition, if all of outbuf was exhausted, there's no way to know if |
+ // more space was needed, so we'll have to retry the translation in that |
+ // corner case as well. |
+ if (inlen == inbufsize && outlen < outalloc) |
+ break; |
+ outbuf.clear(); |
+ braille_to_text.clear(); |
} |
// Massage the result. |