#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
//макс. размер буфера для чтения
#define BUFSIZE 512
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
//кириллическая таблица CP1251
//
const u8 cp1251_cyrillic_table[] = {
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xA8, 0xC6,
0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xB8, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
//кириллическая таблица UTF8
//
const u16 utf8_cyrillic_table[] = {
0xD090, 0xD091, 0xD092, 0xD093, 0xD094, 0xD095, 0xD081, 0xD096,
0xD097, 0xD098, 0xD099, 0xD09A, 0xD09B, 0xD09C, 0xD09D, 0xD09E, 0xD09F,
0xD0A0, 0xD0A1, 0xD0A2, 0xD0A3, 0xD0A4, 0xD0A5, 0xD0A6,
0xD0A7, 0xD0A8, 0xD0A9, 0xD0AA, 0xD0AB, 0xD0AC, 0xD0AD, 0xD0AE, 0xD0AF,
0xD0B0, 0xD0B1, 0xD0B2, 0xD0B3, 0xD0B4, 0xD0B5, 0xD191, 0xD0B6,
0xD0B7, 0xD0B8, 0xD0B9, 0xD0BA, 0xD0BB, 0xD0BC, 0xD0BD, 0xD0BE, 0xD0BF,
0xD180, 0xD181, 0xD182, 0xD183, 0xD184, 0xD185, 0xD186,
0xD187, 0xD188, 0xD189, 0xD18A, 0xD18B, 0xD18C, 0xD18D, 0xD18E, 0xD18F,
};
//буффер для хранения данных
u8 utf8_buffer[BUFSIZE + BUFSIZE];
//общее число символов, предназначенных для записи в файл перед каждым очередным чтением исходного файла
u64 total_utf8_symbols = BUFSIZE;
//
u8* is_cyrillic( u8 code ) {
u8 i;
u8* pos;
if( code != 0xA8 && code != 0xB8 && (code < 0xC0 || code > 0xFF) )
return pos = NULL;
for( i = 0; i < sizeof( cp1251_cyrillic_table ) / sizeof( cp1251_cyrillic_table[0] ); ++i )
if ( code == cp1251_cyrillic_table ) {
pos = &cp1251_cyrillic_table;
}
return pos;
}
void cp1251_to_utf8( u8* cp1251_pointer, u8* to_replace ) {
u8 i;
//так определяем индекс cp1251-кода
for( i = 0; *cp1251_pointer != 0xC0; --cp1251_pointer, ++i );
//вычленяем левый и правый байты utf8-кода, ибо буфер для записи имеет тип элементов u8
u8 utf8_left_code = (utf8_cyrillic_table >> 8);
u8 utf8_right_code = (utf8_cyrillic_table & 0x00ff);
*to_replace = utf8_left_code;
*(to_replace + 1) = utf8_right_code;
}
void replace_array( u8* array, int pos ) {
int i;
for( i = total_utf8_symbols - 1; i >= pos; --i )
*(array + i + 1) = *(array + i);
}
int main( int argc, char* argv[] ) {
u8* CP1251 = cp1251_cyrillic_table;
u16* UTF8 = utf8_cyrillic_table;
//описатель исходного файла
//
int infd;
//описатель формируемого файла
//
int outfd;
//получаем имена файлов, пока без проверки входящих данных
//
const char* infile = argv[1];
char* outfile = argv[2];
//открываем файл для чтения
if( (infd = open(infile, O_RDONLY)) == -1 ) {
fprintf(stderr, "Can't open file for reading...Exiting...\n");
exit( EXIT_FAILURE );
}
//создаём новый файл
outfd = creat(outfile, 0644);
//цикл чтения блоками из файла
while (read( infd, utf8_buffer, BUFSIZE ) > 0) {
u32 i;
//сканируем полученные коды на предмет кириллических
for( i = 0; i < BUFSIZE; ++i ) {
/*
is_cyrillic() проверяет, является ли символ кириллическим. Если да, то возвращает его адрес в таблице кириллических кодов
replace_array() подвигает содержимое буфера на один байт, начиная с позиции, следующей за найденным кириллическим символом, чтобы вместить туда utf-символ, т.к. он занимает на 1 байт больше, чем символ cp1251.
cp1251_to_utf8() собственно, занимается заменой найденного cp1251 кода на код utf8.
++total_utf8_symbols - увеличиваем общее число байт буфера, т.к. с каждым заменённым символом буфер увеличивается на один байт по сравнению с исходным буффером cp1251 символов.
++i - увеличиваем индекс просматриваемого элемента в буфере
*/
if( ( CP1251 = is_cyrillic( utf8_buffer ) ) != NULL ) {
replace_array( utf8_buffer, i + 1 );
cp1251_to_utf8( CP1251, &utf8_buffer );
++total_utf8_symbols;
++i;
}
}
//пишем то, что получилось в файл.
write( outfd, utf8_buffer, total_utf8_symbols );
}
close( infd );
close( outfd );
return 0;
}
Linux: CP1251 to UTF8
Программа получает два аргумента - имя существующего файла(CP1251) и имя создаваемого(UTF8).
Поскольку UTF8 asci-совместима, алгоритм избрал максимально лёгкий:
все символы латиницы оставляем без изменений. Если встречается кириллический символ, мы его код заменяем на соответствующий код utf8. Программа хранит таблицы кодов кириллических символов (каждая таблица - набор кодов символов от 'А' до 'я'). Обратите внимание, что кириллический код utf8 занимает два байта. Таким образом, исходный файл у нас хранит коды символов латиницы(занимают 1 байт) и кириллические коды(2 байта).
Далее код с комментариями:
Код:
Если честно, я уже устал искать грабли. Если мы передаём этой программе маленький файл, содержащий кириллицу CP1251, формируемый файл получается перекодированным до определённого символа. Потом заполняет нулями. Не могу понять, от чего зависит расположение этого символа. Где там ошибка? А если большой файл - то вообще ошибка сегментации. Может быть нужно использовать потоки вместо описателей файлов? Всё-таки с символами же работаем, а не с кодами. Я не нашёл в сети нормальной спецификации рассматриваемых кодировок, и тот алгоритм, который я составил, основывается исключительно на анализе hex-кодов символов в различных кодировках. Так что, если кому-то неохота разбираться с примером, но есть линки, просьба постить. Возможно, ошибка связана с недостаточным пониманием(или непониманием) спецификации кодировок. Короче я запутался и не знаю, куда бежать! Просьба прокомментировать - где неоптимально, где грабли, где низачот!:)
Цитата:
Решил написать консольную утилиту для перекодировки символов.
Хм... а iconv не смотрел? кстати там открытый исходник
Код:
char* in_buf, out_buf;
size_t in_sb, out_sb;
iconv_t cd = iconv_open( "UTF8", "CP1251" );
....
iconv( cd, &in_buf, &in_sb, &out_buf, &out_sb );
....
size_t in_sb, out_sb;
iconv_t cd = iconv_open( "UTF8", "CP1251" );
....
iconv( cd, &in_buf, &in_sb, &out_buf, &out_sb );
....
Кодировки точно правильные, я консольным iconv проверял.
здесь
на это смотрел -
out_buf просто char
русский man по iconv
на это смотрел -
Код:
[COLOR="Red"]char*[/COLOR] in_buf, [COLOR="Red"]out_buf[/COLOR];
out_buf просто char
Цитата: Odissey_
русский man по iconv здесь
на это смотрел -
out_buf просто char
на это смотрел -
Код:
[COLOR="Red"]char*[/COLOR] in_buf, [COLOR="Red"]out_buf[/COLOR];
out_buf просто char
Ну описался я =) ( как тут ударение поставить =)) ) Я же не буду весь свой исходник класть. Сократил чуток и ошибся. За русский ман спасибо, теперь буду знать где если что-то не понятно почитать...