split.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * qrencode - QR Code encoder
  3. *
  4. * Input data splitter.
  5. * Copyright (C) 2006-2013 Kentaro Fukuchi <[email protected]>
  6. *
  7. * The following data / specifications are taken from
  8. * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
  9. * or
  10. * "Automatic identification and data capture techniques --
  11. * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
  12. *
  13. * This library is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU Lesser General Public
  15. * License as published by the Free Software Foundation; either
  16. * version 2.1 of the License, or any later version.
  17. *
  18. * This library is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21. * Lesser General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Lesser General Public
  24. * License along with this library; if not, write to the Free Software
  25. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  26. */
  27. #if HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <errno.h>
  33. #include "qrencode.h"
  34. #include "qrinput.h"
  35. #include "qrspec.h"
  36. #include "split.h"
  37. #define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10)
  38. #define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0)
  39. #if !HAVE_STRDUP
  40. #undef strdup
  41. char *strdup(const char *s)
  42. {
  43. size_t len = strlen(s) + 1;
  44. void *new = malloc(len);
  45. if(new == NULL) return NULL;
  46. return (char *)memcpy(new, s, len);
  47. }
  48. #endif
  49. static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint)
  50. {
  51. unsigned char c, d;
  52. unsigned int word;
  53. c = string[0];
  54. if(c == '\0') return QR_MODE_NUL;
  55. if(isdigit(c)) {
  56. return QR_MODE_NUM;
  57. } else if(isalnum(c)) {
  58. return QR_MODE_AN;
  59. } else if(hint == QR_MODE_KANJI) {
  60. d = string[1];
  61. if(d != '\0') {
  62. word = ((unsigned int)c << 8) | d;
  63. if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) {
  64. return QR_MODE_KANJI;
  65. }
  66. }
  67. }
  68. return QR_MODE_8;
  69. }
  70. static int Split_eatNum(const char *string, QRinput *input, QRencodeMode hint);
  71. static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint);
  72. static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint);
  73. static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint);
  74. static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint)
  75. {
  76. const char *p;
  77. int ret;
  78. int run;
  79. int dif;
  80. int ln;
  81. QRencodeMode mode;
  82. ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
  83. p = string;
  84. while(isdigit(*p)) {
  85. p++;
  86. }
  87. run = p - string;
  88. mode = Split_identifyMode(p, hint);
  89. if(mode == QR_MODE_8) {
  90. dif = QRinput_estimateBitsModeNum(run) + 4 + ln
  91. + QRinput_estimateBitsMode8(1) /* + 4 + l8 */
  92. - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
  93. if(dif > 0) {
  94. return Split_eat8(string, input, hint);
  95. }
  96. }
  97. if(mode == QR_MODE_AN) {
  98. dif = QRinput_estimateBitsModeNum(run) + 4 + ln
  99. + QRinput_estimateBitsModeAn(1) /* + 4 + la */
  100. - QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */;
  101. if(dif > 0) {
  102. return Split_eatAn(string, input, hint);
  103. }
  104. }
  105. ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string);
  106. if(ret < 0) return -1;
  107. return run;
  108. }
  109. static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint)
  110. {
  111. const char *p, *q;
  112. int ret;
  113. int run;
  114. int dif;
  115. int la, ln;
  116. la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
  117. ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
  118. p = string;
  119. while(isalnum(*p)) {
  120. if(isdigit(*p)) {
  121. q = p;
  122. while(isdigit(*q)) {
  123. q++;
  124. }
  125. dif = QRinput_estimateBitsModeAn(p - string) /* + 4 + la */
  126. + QRinput_estimateBitsModeNum(q - p) + 4 + ln
  127. + (isalnum(*q)?(4 + ln):0)
  128. - QRinput_estimateBitsModeAn(q - string) /* - 4 - la */;
  129. if(dif < 0) {
  130. break;
  131. } else {
  132. p = q;
  133. }
  134. } else {
  135. p++;
  136. }
  137. }
  138. run = p - string;
  139. if(*p && !isalnum(*p)) {
  140. dif = QRinput_estimateBitsModeAn(run) + 4 + la
  141. + QRinput_estimateBitsMode8(1) /* + 4 + l8 */
  142. - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */;
  143. if(dif > 0) {
  144. return Split_eat8(string, input, hint);
  145. }
  146. }
  147. ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string);
  148. if(ret < 0) return -1;
  149. return run;
  150. }
  151. static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint)
  152. {
  153. const char *p;
  154. int ret;
  155. int run;
  156. p = string;
  157. while(Split_identifyMode(p, hint) == QR_MODE_KANJI) {
  158. p += 2;
  159. }
  160. run = p - string;
  161. ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string);
  162. if(ret < 0) return -1;
  163. return run;
  164. }
  165. static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint)
  166. {
  167. const char *p, *q;
  168. QRencodeMode mode;
  169. int ret;
  170. int run;
  171. int dif;
  172. int la, ln, l8;
  173. int swcost;
  174. la = QRspec_lengthIndicator(QR_MODE_AN, input->version);
  175. ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version);
  176. l8 = QRspec_lengthIndicator(QR_MODE_8, input->version);
  177. p = string + 1;
  178. while(*p != '\0') {
  179. mode = Split_identifyMode(p, hint);
  180. if(mode == QR_MODE_KANJI) {
  181. break;
  182. }
  183. if(mode == QR_MODE_NUM) {
  184. q = p;
  185. while(isdigit(*q)) {
  186. q++;
  187. }
  188. if(Split_identifyMode(q, hint) == QR_MODE_8) {
  189. swcost = 4 + l8;
  190. } else {
  191. swcost = 0;
  192. }
  193. dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
  194. + QRinput_estimateBitsModeNum(q - p) + 4 + ln
  195. + swcost
  196. - QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
  197. if(dif < 0) {
  198. break;
  199. } else {
  200. p = q;
  201. }
  202. } else if(mode == QR_MODE_AN) {
  203. q = p;
  204. while(isalnum(*q)) {
  205. q++;
  206. }
  207. if(Split_identifyMode(q, hint) == QR_MODE_8) {
  208. swcost = 4 + l8;
  209. } else {
  210. swcost = 0;
  211. }
  212. dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */
  213. + QRinput_estimateBitsModeAn(q - p) + 4 + la
  214. + swcost
  215. - QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */;
  216. if(dif < 0) {
  217. break;
  218. } else {
  219. p = q;
  220. }
  221. } else {
  222. p++;
  223. }
  224. }
  225. run = p - string;
  226. ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string);
  227. if(ret < 0) return -1;
  228. return run;
  229. }
  230. static int Split_splitString(const char *string, QRinput *input,
  231. QRencodeMode hint)
  232. {
  233. int length;
  234. QRencodeMode mode;
  235. if(*string == '\0') return 0;
  236. mode = Split_identifyMode(string, hint);
  237. if(mode == QR_MODE_NUM) {
  238. length = Split_eatNum(string, input, hint);
  239. } else if(mode == QR_MODE_AN) {
  240. length = Split_eatAn(string, input, hint);
  241. } else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) {
  242. length = Split_eatKanji(string, input, hint);
  243. } else {
  244. length = Split_eat8(string, input, hint);
  245. }
  246. if(length == 0) return 0;
  247. if(length < 0) return -1;
  248. return Split_splitString(&string[length], input, hint);
  249. }
  250. static char *dupAndToUpper(const char *str, QRencodeMode hint)
  251. {
  252. char *newstr, *p;
  253. QRencodeMode mode;
  254. newstr = strdup(str);
  255. if(newstr == NULL) return NULL;
  256. p = newstr;
  257. while(*p != '\0') {
  258. mode = Split_identifyMode(p, hint);
  259. if(mode == QR_MODE_KANJI) {
  260. p += 2;
  261. } else {
  262. if (*p >= 'a' && *p <= 'z') {
  263. *p = (char)((int)*p - 32);
  264. }
  265. p++;
  266. }
  267. }
  268. return newstr;
  269. }
  270. int Split_splitStringToQRinput(const char *string, QRinput *input,
  271. QRencodeMode hint, int casesensitive)
  272. {
  273. char *newstr;
  274. int ret;
  275. if(string == NULL || *string == '\0') {
  276. errno = EINVAL;
  277. return -1;
  278. }
  279. if(!casesensitive) {
  280. newstr = dupAndToUpper(string, hint);
  281. if(newstr == NULL) return -1;
  282. ret = Split_splitString(newstr, input, hint);
  283. free(newstr);
  284. } else {
  285. ret = Split_splitString(string, input, hint);
  286. }
  287. return ret;
  288. }