2014-04-28 19:16:28 +02:00
|
|
|
-- Copyright (c) 2007, Niels Martin Hansen, Rodrigo Braz Monteiro
|
2013-04-28 17:42:31 +02:00
|
|
|
-- All rights reserved.
|
|
|
|
--
|
|
|
|
-- Redistribution and use in source and binary forms, with or without
|
|
|
|
-- modification, are permitted provided that the following conditions are met:
|
|
|
|
--
|
|
|
|
-- * Redistributions of source code must retain the above copyright notice,
|
|
|
|
-- this list of conditions and the following disclaimer.
|
|
|
|
-- * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
-- this list of conditions and the following disclaimer in the documentation
|
|
|
|
-- and/or other materials provided with the distribution.
|
|
|
|
-- * Neither the name of the Aegisub Group nor the names of its contributors
|
|
|
|
-- may be used to endorse or promote products derived from this software
|
|
|
|
-- without specific prior written permission.
|
|
|
|
--
|
|
|
|
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
-- POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
-- Unicode (UTF-8) support functions for Aegisub Automation 4 Lua
|
|
|
|
-- http://www.ietf.org/rfc/rfc2279.txt
|
|
|
|
|
2014-05-09 15:41:47 +02:00
|
|
|
impl = require 'aegisub.__unicode_impl'
|
2014-07-22 02:11:55 +02:00
|
|
|
|
|
|
|
check = require 'aegisub.argcheck'
|
2014-07-18 03:04:01 +02:00
|
|
|
ffi = require 'ffi'
|
2014-07-18 19:33:57 +02:00
|
|
|
ffi_util = require 'aegisub.ffi'
|
2014-07-18 03:04:01 +02:00
|
|
|
|
2014-07-18 19:33:57 +02:00
|
|
|
err_buff = ffi.new 'char *[1]'
|
2014-07-22 02:11:55 +02:00
|
|
|
conv_func = (f) -> check'string' (str) ->
|
2014-07-18 19:33:57 +02:00
|
|
|
err_buff[0] = nil
|
|
|
|
result = f str, err_buff
|
|
|
|
errmsg = ffi_util.string err_buff[0]
|
|
|
|
if errmsg
|
|
|
|
error errmsg, 2
|
|
|
|
ffi_util.string result
|
2014-05-09 15:41:47 +02:00
|
|
|
|
2013-04-28 17:42:31 +02:00
|
|
|
local unicode
|
|
|
|
unicode =
|
|
|
|
-- Return the number of bytes occupied by the character starting at the i'th byte in s
|
2014-07-22 02:11:55 +02:00
|
|
|
charwidth: check'string ?number' (s, i) ->
|
2013-04-28 17:42:31 +02:00
|
|
|
b = s\byte i or 1
|
|
|
|
-- FIXME, something in karaskel results in this case, shouldn't happen
|
|
|
|
-- What would "proper" behaviour be? Zero? Or just explode?
|
|
|
|
if not b then 1
|
|
|
|
elseif b < 128 then 1
|
|
|
|
elseif b < 224 then 2
|
|
|
|
elseif b < 240 then 3
|
|
|
|
else 4
|
|
|
|
|
|
|
|
-- Returns an iterator function for iterating over the characters in s
|
2014-07-22 02:11:55 +02:00
|
|
|
chars: check'string' (s) ->
|
2013-04-28 17:42:31 +02:00
|
|
|
curchar, i = 0, 1
|
|
|
|
->
|
|
|
|
return if i > s\len()
|
|
|
|
|
|
|
|
j = i
|
|
|
|
curchar += 1
|
|
|
|
i += unicode.charwidth s, i
|
|
|
|
s\sub(j, i - 1), curchar
|
|
|
|
|
|
|
|
-- Returns the number of characters in s
|
|
|
|
-- Runs in O(s:len()) time!
|
2014-07-22 02:11:55 +02:00
|
|
|
len: check'string' (s) ->
|
2013-04-28 17:42:31 +02:00
|
|
|
n = 0
|
|
|
|
n += 1 for c in unicode.chars s
|
|
|
|
n
|
|
|
|
|
|
|
|
-- Get codepoint of first char in s
|
2014-07-22 02:11:55 +02:00
|
|
|
codepoint: check'string' (s) ->
|
2013-04-28 17:42:31 +02:00
|
|
|
-- Basic case, ASCII
|
|
|
|
b = s\byte 1
|
|
|
|
return b if b < 128
|
|
|
|
|
|
|
|
-- Use a naive decoding algorithm, and assume input is valid
|
|
|
|
local res, w
|
|
|
|
|
|
|
|
if b < 224 then
|
|
|
|
-- prefix byte is 110xxxxx
|
|
|
|
res = b - 192
|
|
|
|
w = 2
|
|
|
|
elseif b < 240 then
|
|
|
|
-- prefix byte is 11100000
|
|
|
|
res = b - 224
|
|
|
|
w = 3
|
|
|
|
else
|
|
|
|
res = b - 240
|
|
|
|
w = 4
|
|
|
|
|
|
|
|
for i = 2, w
|
|
|
|
res = res*64 + s\byte(i) - 128
|
|
|
|
res
|
|
|
|
|
2014-07-18 03:04:01 +02:00
|
|
|
to_upper_case: conv_func impl.to_upper_case
|
|
|
|
to_lower_case: conv_func impl.to_lower_case
|
|
|
|
to_fold_case: conv_func impl.to_fold_case
|
2014-05-09 15:41:47 +02:00
|
|
|
|
2013-04-28 17:42:31 +02:00
|
|
|
return unicode
|