bytevectors.c 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143
  1. /* Copyright 2009-2015,2018-2019
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #ifdef HAVE_LIMITS_H
  19. # include <limits.h>
  20. #endif
  21. #include <byteswap.h>
  22. #include <errno.h>
  23. #include <striconveh.h>
  24. #include <uniconv.h>
  25. #include <unistr.h>
  26. #include <string.h>
  27. #include <alloca.h>
  28. #include <assert.h>
  29. #include <gmp.h>
  30. #include "array-handle.h"
  31. #include "arrays.h"
  32. #include "boolean.h"
  33. #include "dynwind.h"
  34. #include "extensions.h"
  35. #include "generalized-vectors.h"
  36. #include "gsubr.h"
  37. #include "list.h"
  38. #include "numbers.h"
  39. #include "pairs.h"
  40. #include "ports.h"
  41. #include "srfi-4.h"
  42. #include "strings.h"
  43. #include "symbols.h"
  44. #include "uniform.h"
  45. #include "version.h"
  46. #include "bytevectors.h"
  47. /* Utilities. */
  48. /* Convenience macros. These are used by the various templates (macros) that
  49. are parameterized by integer signedness. */
  50. #define INT8_T_signed int8_t
  51. #define INT8_T_unsigned uint8_t
  52. #define INT16_T_signed int16_t
  53. #define INT16_T_unsigned uint16_t
  54. #define INT32_T_signed int32_t
  55. #define INT32_T_unsigned uint32_t
  56. #define is_signed_int8(_x) (((_x) >= -128L) && ((_x) <= 127L))
  57. #define is_unsigned_int8(_x) ((_x) <= 255UL)
  58. #define is_signed_int16(_x) (((_x) >= -32768L) && ((_x) <= 32767L))
  59. #define is_unsigned_int16(_x) ((_x) <= 65535UL)
  60. #define is_signed_int32(_x) (((_x) >= -2147483648L) && ((_x) <= 2147483647L))
  61. #define is_unsigned_int32(_x) ((_x) <= 4294967295UL)
  62. #define SIGNEDNESS_signed 1
  63. #define SIGNEDNESS_unsigned 0
  64. #define INT_TYPE(_size, _sign) INT ## _size ## _T_ ## _sign
  65. #define INT_SWAP(_size) bswap_ ## _size
  66. #define INT_VALID_P(_size, _sign) is_ ## _sign ## _int ## _size
  67. #define SIGNEDNESS(_sign) SIGNEDNESS_ ## _sign
  68. #define INTEGER_ACCESSOR_PROLOGUE(validate, _len, _sign) \
  69. size_t c_len, c_index; \
  70. _sign char *c_bv; \
  71. \
  72. SCM_VALIDATE_##validate (1, bv); \
  73. c_index = scm_to_size_t (index); \
  74. \
  75. c_len = SCM_BYTEVECTOR_LENGTH (bv); \
  76. c_bv = (_sign char *) SCM_BYTEVECTOR_CONTENTS (bv); \
  77. \
  78. if (SCM_UNLIKELY (c_index + ((_len) >> 3UL) - 1 >= c_len)) \
  79. scm_out_of_range (FUNC_NAME, index);
  80. #define INTEGER_GETTER_PROLOGUE(_len, _sign) \
  81. INTEGER_ACCESSOR_PROLOGUE (BYTEVECTOR, _len, _sign)
  82. #define INTEGER_SETTER_PROLOGUE(_len, _sign) \
  83. INTEGER_ACCESSOR_PROLOGUE (MUTABLE_BYTEVECTOR, _len, _sign)
  84. /* Template for fixed-size integer access (only 8, 16 or 32-bit). */
  85. #define INTEGER_REF(_len, _sign) \
  86. SCM result; \
  87. \
  88. INTEGER_GETTER_PROLOGUE (_len, _sign); \
  89. SCM_VALIDATE_SYMBOL (3, endianness); \
  90. \
  91. { \
  92. INT_TYPE (_len, _sign) c_result; \
  93. \
  94. memcpy (&c_result, &c_bv[c_index], (_len) / 8); \
  95. if (!scm_is_eq (endianness, scm_i_native_endianness)) \
  96. c_result = INT_SWAP (_len) (c_result); \
  97. \
  98. result = SCM_I_MAKINUM (c_result); \
  99. } \
  100. \
  101. return result;
  102. /* Template for fixed-size integer access using the native endianness. */
  103. #define INTEGER_NATIVE_REF(_len, _sign) \
  104. SCM result; \
  105. \
  106. INTEGER_GETTER_PROLOGUE (_len, _sign); \
  107. \
  108. { \
  109. INT_TYPE (_len, _sign) c_result; \
  110. \
  111. memcpy (&c_result, &c_bv[c_index], (_len) / 8); \
  112. result = SCM_I_MAKINUM (c_result); \
  113. } \
  114. \
  115. return result;
  116. /* Template for fixed-size integer modification (only 8, 16 or 32-bit). */
  117. #define INTEGER_SET(_len, _sign) \
  118. INTEGER_SETTER_PROLOGUE (_len, _sign); \
  119. SCM_VALIDATE_SYMBOL (3, endianness); \
  120. \
  121. { \
  122. scm_t_signed_bits c_value; \
  123. INT_TYPE (_len, _sign) c_value_short; \
  124. \
  125. if (SCM_UNLIKELY (!SCM_I_INUMP (value))) \
  126. scm_wrong_type_arg (FUNC_NAME, 3, value); \
  127. \
  128. c_value = SCM_I_INUM (value); \
  129. if (SCM_UNLIKELY (!INT_VALID_P (_len, _sign) (c_value))) \
  130. scm_out_of_range (FUNC_NAME, value); \
  131. \
  132. c_value_short = (INT_TYPE (_len, _sign)) c_value; \
  133. if (!scm_is_eq (endianness, scm_i_native_endianness)) \
  134. c_value_short = INT_SWAP (_len) (c_value_short); \
  135. \
  136. memcpy (&c_bv[c_index], &c_value_short, (_len) / 8); \
  137. } \
  138. \
  139. return SCM_UNSPECIFIED;
  140. /* Template for fixed-size integer modification using the native
  141. endianness. */
  142. #define INTEGER_NATIVE_SET(_len, _sign) \
  143. INTEGER_SETTER_PROLOGUE (_len, _sign); \
  144. \
  145. { \
  146. scm_t_signed_bits c_value; \
  147. INT_TYPE (_len, _sign) c_value_short; \
  148. \
  149. if (SCM_UNLIKELY (!SCM_I_INUMP (value))) \
  150. scm_wrong_type_arg (FUNC_NAME, 3, value); \
  151. \
  152. c_value = SCM_I_INUM (value); \
  153. if (SCM_UNLIKELY (!INT_VALID_P (_len, _sign) (c_value))) \
  154. scm_out_of_range (FUNC_NAME, value); \
  155. \
  156. c_value_short = (INT_TYPE (_len, _sign)) c_value; \
  157. \
  158. memcpy (&c_bv[c_index], &c_value_short, (_len) / 8); \
  159. } \
  160. \
  161. return SCM_UNSPECIFIED;
  162. /* Bytevector type. */
  163. #define SCM_BYTEVECTOR_HEADER_BYTES \
  164. (SCM_BYTEVECTOR_HEADER_SIZE * sizeof (scm_t_bits))
  165. #define SCM_BYTEVECTOR_SET_FLAG(bv, flag) \
  166. SCM_SET_BYTEVECTOR_FLAGS ((bv), SCM_BYTEVECTOR_FLAGS (bv) | flag)
  167. #define SCM_BYTEVECTOR_SET_LENGTH(_bv, _len) \
  168. SCM_SET_CELL_WORD_1 ((_bv), (scm_t_bits) (_len))
  169. #define SCM_BYTEVECTOR_SET_CONTENTS(_bv, _contents) \
  170. SCM_SET_CELL_WORD_2 ((_bv), (scm_t_bits) (_contents))
  171. #define SCM_BYTEVECTOR_SET_PARENT(_bv, _parent) \
  172. SCM_SET_CELL_OBJECT_3 ((_bv), (_parent))
  173. #define SCM_VALIDATE_MUTABLE_BYTEVECTOR(pos, v) \
  174. SCM_MAKE_VALIDATE_MSG (pos, v, MUTABLE_BYTEVECTOR_P, "mutable bytevector")
  175. /* The empty bytevector. */
  176. SCM scm_null_bytevector = SCM_UNSPECIFIED;
  177. static inline SCM
  178. make_bytevector (size_t len, scm_t_array_element_type element_type)
  179. {
  180. SCM ret;
  181. size_t c_len;
  182. if (SCM_UNLIKELY (element_type > SCM_ARRAY_ELEMENT_TYPE_LAST
  183. || scm_i_array_element_type_sizes[element_type] < 8
  184. || len >= (((size_t) -1)
  185. / (scm_i_array_element_type_sizes[element_type]/8))))
  186. /* This would be an internal Guile programming error */
  187. abort ();
  188. if (SCM_UNLIKELY (len == 0 && element_type == SCM_ARRAY_ELEMENT_TYPE_VU8
  189. && SCM_BYTEVECTOR_P (scm_null_bytevector)))
  190. ret = scm_null_bytevector;
  191. else
  192. {
  193. signed char *contents;
  194. c_len = len * (scm_i_array_element_type_sizes[element_type] / 8);
  195. contents = scm_gc_malloc_pointerless (SCM_BYTEVECTOR_HEADER_BYTES + c_len,
  196. SCM_GC_BYTEVECTOR);
  197. ret = SCM_PACK_POINTER (contents);
  198. contents += SCM_BYTEVECTOR_HEADER_BYTES;
  199. SCM_SET_BYTEVECTOR_FLAGS (ret,
  200. element_type | SCM_F_BYTEVECTOR_CONTIGUOUS);
  201. SCM_BYTEVECTOR_SET_LENGTH (ret, c_len);
  202. SCM_BYTEVECTOR_SET_CONTENTS (ret, contents);
  203. SCM_BYTEVECTOR_SET_PARENT (ret, SCM_BOOL_F);
  204. }
  205. return ret;
  206. }
  207. /* Return a bytevector of LEN elements of type ELEMENT_TYPE, with element
  208. values taken from CONTENTS. Assume that the storage for CONTENTS will be
  209. automatically reclaimed when it becomes unreachable. */
  210. static inline SCM
  211. make_bytevector_from_buffer (size_t len, void *contents,
  212. scm_t_array_element_type element_type)
  213. {
  214. SCM ret;
  215. if (SCM_UNLIKELY (len == 0))
  216. ret = make_bytevector (len, element_type);
  217. else
  218. {
  219. size_t c_len;
  220. ret = SCM_PACK_POINTER (scm_gc_malloc (SCM_BYTEVECTOR_HEADER_BYTES,
  221. SCM_GC_BYTEVECTOR));
  222. c_len = len * (scm_i_array_element_type_sizes[element_type] / 8);
  223. SCM_SET_BYTEVECTOR_FLAGS (ret, element_type);
  224. SCM_BYTEVECTOR_SET_LENGTH (ret, c_len);
  225. SCM_BYTEVECTOR_SET_CONTENTS (ret, contents);
  226. SCM_BYTEVECTOR_SET_PARENT (ret, SCM_BOOL_F);
  227. }
  228. return ret;
  229. }
  230. /* Return a new bytevector of size LEN octets. */
  231. SCM
  232. scm_c_make_bytevector (size_t len)
  233. {
  234. return make_bytevector (len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  235. }
  236. /* Return a new bytevector of size LEN elements. */
  237. SCM
  238. scm_i_make_typed_bytevector (size_t len, scm_t_array_element_type element_type)
  239. {
  240. return make_bytevector (len, element_type);
  241. }
  242. /* Return a bytevector of size LEN made up of CONTENTS. The area
  243. pointed to by CONTENTS must be protected from GC somehow: either
  244. because it was allocated using `scm_gc_malloc ()', or because it is
  245. part of PARENT. */
  246. SCM
  247. scm_c_take_gc_bytevector (signed char *contents, size_t len, SCM parent)
  248. {
  249. SCM ret;
  250. ret = make_bytevector_from_buffer (len, contents, SCM_ARRAY_ELEMENT_TYPE_VU8);
  251. SCM_BYTEVECTOR_SET_PARENT (ret, parent);
  252. return ret;
  253. }
  254. SCM
  255. scm_c_take_typed_bytevector (signed char *contents, size_t len,
  256. scm_t_array_element_type element_type, SCM parent)
  257. {
  258. SCM ret;
  259. ret = make_bytevector_from_buffer (len, contents, element_type);
  260. SCM_BYTEVECTOR_SET_PARENT (ret, parent);
  261. return ret;
  262. }
  263. /* Shrink BV to C_NEW_LEN (which is assumed to be smaller than its current
  264. size) and return the new bytevector (possibly different from BV). */
  265. SCM
  266. scm_c_shrink_bytevector (SCM bv, size_t c_new_len)
  267. {
  268. SCM new_bv;
  269. size_t c_len;
  270. if (SCM_UNLIKELY (c_new_len % SCM_BYTEVECTOR_TYPE_SIZE (bv)))
  271. /* This would be an internal Guile programming error */
  272. abort ();
  273. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  274. if (SCM_UNLIKELY (c_new_len > c_len))
  275. abort ();
  276. SCM_BYTEVECTOR_SET_LENGTH (bv, c_new_len);
  277. if (SCM_BYTEVECTOR_CONTIGUOUS_P (bv))
  278. {
  279. signed char *c_bv;
  280. c_bv = scm_gc_realloc (SCM2PTR (bv),
  281. c_len + SCM_BYTEVECTOR_HEADER_BYTES,
  282. c_new_len + SCM_BYTEVECTOR_HEADER_BYTES,
  283. SCM_GC_BYTEVECTOR);
  284. new_bv = PTR2SCM (c_bv);
  285. SCM_BYTEVECTOR_SET_CONTENTS (new_bv, c_bv + SCM_BYTEVECTOR_HEADER_BYTES);
  286. }
  287. else
  288. {
  289. signed char *c_bv;
  290. c_bv = scm_gc_realloc (SCM_BYTEVECTOR_CONTENTS (bv),
  291. c_len, c_new_len, SCM_GC_BYTEVECTOR);
  292. SCM_BYTEVECTOR_SET_CONTENTS (bv, c_bv);
  293. new_bv = bv;
  294. }
  295. return new_bv;
  296. }
  297. int
  298. scm_is_bytevector (SCM obj)
  299. {
  300. return SCM_BYTEVECTOR_P (obj);
  301. }
  302. size_t
  303. scm_c_bytevector_length (SCM bv)
  304. #define FUNC_NAME "scm_c_bytevector_length"
  305. {
  306. SCM_VALIDATE_BYTEVECTOR (1, bv);
  307. return SCM_BYTEVECTOR_LENGTH (bv);
  308. }
  309. #undef FUNC_NAME
  310. uint8_t
  311. scm_c_bytevector_ref (SCM bv, size_t index)
  312. #define FUNC_NAME "scm_c_bytevector_ref"
  313. {
  314. size_t c_len;
  315. const uint8_t *c_bv;
  316. SCM_VALIDATE_BYTEVECTOR (1, bv);
  317. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  318. c_bv = (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv);
  319. if (SCM_UNLIKELY (index >= c_len))
  320. scm_out_of_range (FUNC_NAME, scm_from_size_t (index));
  321. return c_bv[index];
  322. }
  323. #undef FUNC_NAME
  324. void
  325. scm_c_bytevector_set_x (SCM bv, size_t index, uint8_t value)
  326. #define FUNC_NAME "scm_c_bytevector_set_x"
  327. {
  328. size_t c_len;
  329. uint8_t *c_bv;
  330. SCM_VALIDATE_MUTABLE_BYTEVECTOR (1, bv);
  331. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  332. c_bv = (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv);
  333. if (SCM_UNLIKELY (index >= c_len))
  334. scm_out_of_range (FUNC_NAME, scm_from_size_t (index));
  335. c_bv[index] = value;
  336. }
  337. #undef FUNC_NAME
  338. int
  339. scm_i_print_bytevector (SCM bv, SCM port, scm_print_state *pstate SCM_UNUSED)
  340. {
  341. ssize_t ubnd, inc, i;
  342. scm_t_array_handle h;
  343. scm_array_get_handle (bv, &h);
  344. scm_putc ('#', port);
  345. scm_write (scm_array_handle_element_type (&h), port);
  346. scm_putc ('(', port);
  347. for (i = h.dims[0].lbnd, ubnd = h.dims[0].ubnd, inc = h.dims[0].inc;
  348. i <= ubnd; i += inc)
  349. {
  350. if (i > 0)
  351. scm_putc (' ', port);
  352. scm_write (scm_array_handle_ref (&h, i), port);
  353. }
  354. scm_putc (')', port);
  355. return 1;
  356. }
  357. /* General operations. */
  358. static SCM sym_big;
  359. static SCM sym_little;
  360. SCM scm_endianness_big, scm_endianness_little;
  361. /* Host endianness (a symbol). */
  362. SCM scm_i_native_endianness = SCM_UNSPECIFIED;
  363. /* Byte-swapping. */
  364. #ifndef bswap_24
  365. # define bswap_24(_x) \
  366. ((((_x) & 0xff0000) >> 16) | \
  367. (((_x) & 0x00ff00)) | \
  368. (((_x) & 0x0000ff) << 16))
  369. #endif
  370. SCM_DEFINE (scm_native_endianness, "native-endianness", 0, 0, 0,
  371. (void),
  372. "Return a symbol denoting the machine's native endianness.")
  373. #define FUNC_NAME s_scm_native_endianness
  374. {
  375. return scm_i_native_endianness;
  376. }
  377. #undef FUNC_NAME
  378. SCM_DEFINE (scm_bytevector_p, "bytevector?", 1, 0, 0,
  379. (SCM obj),
  380. "Return true if @var{obj} is a bytevector.")
  381. #define FUNC_NAME s_scm_bytevector_p
  382. {
  383. return scm_from_bool (scm_is_bytevector (obj));
  384. }
  385. #undef FUNC_NAME
  386. SCM_DEFINE (scm_make_bytevector, "make-bytevector", 1, 1, 0,
  387. (SCM len, SCM fill),
  388. "Return a newly allocated bytevector of @var{len} bytes, "
  389. "optionally filled with @var{fill}.")
  390. #define FUNC_NAME s_scm_make_bytevector
  391. {
  392. SCM bv;
  393. size_t c_len;
  394. uint8_t c_fill = 0;
  395. SCM_VALIDATE_SIZE_COPY (1, len, c_len);
  396. if (!scm_is_eq (fill, SCM_UNDEFINED))
  397. {
  398. int value;
  399. value = scm_to_int (fill);
  400. if (SCM_UNLIKELY ((value < -128) || (value > 255)))
  401. scm_out_of_range (FUNC_NAME, fill);
  402. c_fill = (uint8_t) value;
  403. }
  404. bv = make_bytevector (c_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  405. if (!scm_is_eq (fill, SCM_UNDEFINED))
  406. {
  407. size_t i;
  408. uint8_t *contents;
  409. contents = (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv);
  410. for (i = 0; i < c_len; i++)
  411. contents[i] = c_fill;
  412. }
  413. else
  414. memset (SCM_BYTEVECTOR_CONTENTS (bv), 0, c_len);
  415. return bv;
  416. }
  417. #undef FUNC_NAME
  418. SCM_DEFINE (scm_bytevector_length, "bytevector-length", 1, 0, 0,
  419. (SCM bv),
  420. "Return the length (in bytes) of @var{bv}.")
  421. #define FUNC_NAME s_scm_bytevector_length
  422. {
  423. return scm_from_uint (scm_c_bytevector_length (bv));
  424. }
  425. #undef FUNC_NAME
  426. SCM_DEFINE (scm_bytevector_eq_p, "bytevector=?", 2, 0, 0,
  427. (SCM bv1, SCM bv2),
  428. "Return is @var{bv1} equals to @var{bv2}---i.e., if they "
  429. "have the same length and contents.")
  430. #define FUNC_NAME s_scm_bytevector_eq_p
  431. {
  432. SCM result = SCM_BOOL_F;
  433. size_t c_len1, c_len2;
  434. SCM_VALIDATE_BYTEVECTOR (1, bv1);
  435. SCM_VALIDATE_BYTEVECTOR (2, bv2);
  436. c_len1 = SCM_BYTEVECTOR_LENGTH (bv1);
  437. c_len2 = SCM_BYTEVECTOR_LENGTH (bv2);
  438. if (c_len1 == c_len2 && (SCM_BYTEVECTOR_ELEMENT_TYPE (bv1)
  439. == SCM_BYTEVECTOR_ELEMENT_TYPE (bv2)))
  440. {
  441. signed char *c_bv1, *c_bv2;
  442. c_bv1 = SCM_BYTEVECTOR_CONTENTS (bv1);
  443. c_bv2 = SCM_BYTEVECTOR_CONTENTS (bv2);
  444. result = scm_from_bool (!memcmp (c_bv1, c_bv2, c_len1));
  445. }
  446. return result;
  447. }
  448. #undef FUNC_NAME
  449. SCM_DEFINE (scm_bytevector_fill_x, "bytevector-fill!", 2, 0, 0,
  450. (SCM bv, SCM fill),
  451. "Fill bytevector @var{bv} with @var{fill}, a byte.")
  452. #define FUNC_NAME s_scm_bytevector_fill_x
  453. {
  454. size_t c_len, i;
  455. uint8_t *c_bv, c_fill;
  456. int value;
  457. SCM_VALIDATE_MUTABLE_BYTEVECTOR (1, bv);
  458. value = scm_to_int (fill);
  459. if (SCM_UNLIKELY ((value < -128) || (value > 255)))
  460. scm_out_of_range (FUNC_NAME, fill);
  461. c_fill = (uint8_t) value;
  462. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  463. c_bv = (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv);
  464. for (i = 0; i < c_len; i++)
  465. c_bv[i] = c_fill;
  466. return SCM_UNSPECIFIED;
  467. }
  468. #undef FUNC_NAME
  469. SCM_DEFINE (scm_bytevector_copy_x, "bytevector-copy!", 5, 0, 0,
  470. (SCM source, SCM source_start, SCM target, SCM target_start,
  471. SCM len),
  472. "Copy @var{len} bytes from @var{source} into @var{target}, "
  473. "starting reading from @var{source_start} (a positive index "
  474. "within @var{source}) and start writing at "
  475. "@var{target_start}.")
  476. #define FUNC_NAME s_scm_bytevector_copy_x
  477. {
  478. size_t c_len, c_source_len, c_target_len;
  479. size_t c_source_start, c_target_start;
  480. signed char *c_source, *c_target;
  481. SCM_VALIDATE_BYTEVECTOR (1, source);
  482. SCM_VALIDATE_MUTABLE_BYTEVECTOR (3, target);
  483. c_len = scm_to_size_t (len);
  484. c_source_start = scm_to_size_t (source_start);
  485. c_target_start = scm_to_size_t (target_start);
  486. c_source = SCM_BYTEVECTOR_CONTENTS (source);
  487. c_target = SCM_BYTEVECTOR_CONTENTS (target);
  488. c_source_len = SCM_BYTEVECTOR_LENGTH (source);
  489. c_target_len = SCM_BYTEVECTOR_LENGTH (target);
  490. if (SCM_UNLIKELY (c_source_start + c_len > c_source_len))
  491. scm_out_of_range (FUNC_NAME, source_start);
  492. if (SCM_UNLIKELY (c_target_start + c_len > c_target_len))
  493. scm_out_of_range (FUNC_NAME, target_start);
  494. memmove (c_target + c_target_start,
  495. c_source + c_source_start,
  496. c_len);
  497. return SCM_UNSPECIFIED;
  498. }
  499. #undef FUNC_NAME
  500. SCM_DEFINE (scm_bytevector_copy, "bytevector-copy", 1, 0, 0,
  501. (SCM bv),
  502. "Return a newly allocated copy of @var{bv}.")
  503. #define FUNC_NAME s_scm_bytevector_copy
  504. {
  505. SCM copy;
  506. size_t c_len;
  507. signed char *c_bv, *c_copy;
  508. SCM_VALIDATE_BYTEVECTOR (1, bv);
  509. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  510. c_bv = SCM_BYTEVECTOR_CONTENTS (bv);
  511. copy = make_bytevector (c_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  512. c_copy = SCM_BYTEVECTOR_CONTENTS (copy);
  513. memcpy (c_copy, c_bv, c_len);
  514. return copy;
  515. }
  516. #undef FUNC_NAME
  517. SCM_DEFINE (scm_uniform_array_to_bytevector, "uniform-array->bytevector",
  518. 1, 0, 0, (SCM array),
  519. "Return a newly allocated bytevector whose contents\n"
  520. "will be copied from the uniform array @var{array}.")
  521. #define FUNC_NAME s_scm_uniform_array_to_bytevector
  522. {
  523. SCM contents, ret;
  524. size_t len, sz, byte_len;
  525. scm_t_array_handle h;
  526. const void *elts;
  527. contents = scm_array_contents (array, SCM_BOOL_T);
  528. if (scm_is_false (contents))
  529. scm_wrong_type_arg_msg (FUNC_NAME, 0, array, "uniform contiguous array");
  530. scm_array_get_handle (contents, &h);
  531. assert (h.base == 0);
  532. elts = h.elements;
  533. len = h.dims->inc * (h.dims->ubnd - h.dims->lbnd + 1);
  534. sz = scm_array_handle_uniform_element_bit_size (&h);
  535. if (sz >= 8 && ((sz % 8) == 0))
  536. byte_len = len * (sz / 8);
  537. else if (sz < 8)
  538. /* Elements of sub-byte size (bitvectors) are addressed in 32-bit
  539. units. */
  540. byte_len = ((len * sz + 31) / 32) * 4;
  541. else
  542. /* an internal guile error, really */
  543. SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
  544. ret = make_bytevector (byte_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  545. if (byte_len != 0)
  546. /* Empty arrays may have elements == NULL. We must avoid passing
  547. NULL to memcpy, even if the length is zero, to avoid undefined
  548. behavior. */
  549. memcpy (SCM_BYTEVECTOR_CONTENTS (ret), elts, byte_len);
  550. scm_array_handle_release (&h);
  551. return ret;
  552. }
  553. #undef FUNC_NAME
  554. /* Operations on bytes and octets. */
  555. SCM_DEFINE (scm_bytevector_u8_ref, "bytevector-u8-ref", 2, 0, 0,
  556. (SCM bv, SCM index),
  557. "Return the octet located at @var{index} in @var{bv}.")
  558. #define FUNC_NAME s_scm_bytevector_u8_ref
  559. {
  560. INTEGER_NATIVE_REF (8, unsigned);
  561. }
  562. #undef FUNC_NAME
  563. SCM_DEFINE (scm_bytevector_s8_ref, "bytevector-s8-ref", 2, 0, 0,
  564. (SCM bv, SCM index),
  565. "Return the byte located at @var{index} in @var{bv}.")
  566. #define FUNC_NAME s_scm_bytevector_s8_ref
  567. {
  568. INTEGER_NATIVE_REF (8, signed);
  569. }
  570. #undef FUNC_NAME
  571. SCM_DEFINE (scm_bytevector_u8_set_x, "bytevector-u8-set!", 3, 0, 0,
  572. (SCM bv, SCM index, SCM value),
  573. "Return the octet located at @var{index} in @var{bv}.")
  574. #define FUNC_NAME s_scm_bytevector_u8_set_x
  575. {
  576. INTEGER_NATIVE_SET (8, unsigned);
  577. }
  578. #undef FUNC_NAME
  579. SCM_DEFINE (scm_bytevector_s8_set_x, "bytevector-s8-set!", 3, 0, 0,
  580. (SCM bv, SCM index, SCM value),
  581. "Return the octet located at @var{index} in @var{bv}.")
  582. #define FUNC_NAME s_scm_bytevector_s8_set_x
  583. {
  584. INTEGER_NATIVE_SET (8, signed);
  585. }
  586. #undef FUNC_NAME
  587. SCM_DEFINE (scm_bytevector_to_u8_list, "bytevector->u8-list", 1, 0, 0,
  588. (SCM bv),
  589. "Return a newly allocated list of octets containing the "
  590. "contents of @var{bv}.")
  591. #define FUNC_NAME s_scm_bytevector_to_u8_list
  592. {
  593. SCM lst, pair;
  594. size_t c_len, i;
  595. uint8_t *c_bv;
  596. SCM_VALIDATE_BYTEVECTOR (1, bv);
  597. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  598. c_bv = (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv);
  599. lst = scm_make_list (scm_from_size_t (c_len), SCM_UNSPECIFIED);
  600. for (i = 0, pair = lst;
  601. i < c_len;
  602. i++, pair = SCM_CDR (pair))
  603. {
  604. SCM_SETCAR (pair, SCM_I_MAKINUM (c_bv[i]));
  605. }
  606. return lst;
  607. }
  608. #undef FUNC_NAME
  609. SCM_DEFINE (scm_u8_list_to_bytevector, "u8-list->bytevector", 1, 0, 0,
  610. (SCM lst),
  611. "Turn @var{lst}, a list of octets, into a bytevector.")
  612. #define FUNC_NAME s_scm_u8_list_to_bytevector
  613. {
  614. SCM bv, item;
  615. size_t c_len, i;
  616. uint8_t *c_bv;
  617. SCM_VALIDATE_LIST_COPYLEN (1, lst, c_len);
  618. bv = make_bytevector (c_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  619. c_bv = (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv);
  620. for (i = 0; i < c_len; lst = SCM_CDR (lst), i++)
  621. {
  622. item = SCM_CAR (lst);
  623. if (SCM_LIKELY (SCM_I_INUMP (item)))
  624. {
  625. scm_t_signed_bits c_item;
  626. c_item = SCM_I_INUM (item);
  627. if (SCM_LIKELY ((c_item >= 0) && (c_item < 256)))
  628. c_bv[i] = (uint8_t) c_item;
  629. else
  630. goto type_error;
  631. }
  632. else
  633. goto type_error;
  634. }
  635. return bv;
  636. type_error:
  637. scm_wrong_type_arg (FUNC_NAME, 1, item);
  638. return SCM_BOOL_F;
  639. }
  640. #undef FUNC_NAME
  641. /* Compute the two's complement of VALUE (a positive integer) on SIZE octets
  642. using (2^(SIZE * 8) - VALUE). */
  643. static inline void
  644. twos_complement (mpz_t value, size_t size)
  645. {
  646. unsigned long bit_count;
  647. /* We expect BIT_COUNT to fit in a unsigned long thanks to the range
  648. checking on SIZE performed earlier. */
  649. bit_count = (unsigned long) size << 3UL;
  650. if (SCM_LIKELY (bit_count < sizeof (unsigned long)))
  651. mpz_ui_sub (value, 1UL << bit_count, value);
  652. else
  653. {
  654. mpz_t max;
  655. mpz_init (max);
  656. mpz_ui_pow_ui (max, 2, bit_count);
  657. mpz_sub (value, max, value);
  658. mpz_clear (max);
  659. }
  660. }
  661. static inline SCM
  662. bytevector_large_ref (const char *c_bv, size_t c_size, int signed_p,
  663. SCM endianness)
  664. {
  665. SCM result;
  666. mpz_t c_mpz;
  667. int c_endianness, negative_p = 0;
  668. if (signed_p)
  669. {
  670. if (scm_is_eq (endianness, sym_big))
  671. negative_p = c_bv[0] & 0x80;
  672. else
  673. negative_p = c_bv[c_size - 1] & 0x80;
  674. }
  675. c_endianness = scm_is_eq (endianness, sym_big) ? 1 : -1;
  676. mpz_init (c_mpz);
  677. mpz_import (c_mpz, 1 /* 1 word */, 1 /* word order doesn't matter */,
  678. c_size /* word is C_SIZE-byte long */,
  679. c_endianness,
  680. 0 /* nails */, c_bv);
  681. if (signed_p && negative_p)
  682. {
  683. twos_complement (c_mpz, c_size);
  684. mpz_neg (c_mpz, c_mpz);
  685. }
  686. result = scm_from_mpz (c_mpz);
  687. mpz_clear (c_mpz); /* FIXME: Needed? */
  688. return result;
  689. }
  690. static inline int
  691. bytevector_large_set (char *c_bv, size_t c_size, int signed_p,
  692. SCM value, SCM endianness)
  693. {
  694. mpz_t c_mpz;
  695. int c_endianness, c_sign, err = 0;
  696. c_endianness = scm_is_eq (endianness, sym_big) ? 1 : -1;
  697. mpz_init (c_mpz);
  698. scm_to_mpz (value, c_mpz);
  699. c_sign = mpz_sgn (c_mpz);
  700. if (c_sign < 0)
  701. {
  702. if (SCM_LIKELY (signed_p))
  703. {
  704. mpz_neg (c_mpz, c_mpz);
  705. twos_complement (c_mpz, c_size);
  706. }
  707. else
  708. {
  709. err = -1;
  710. goto finish;
  711. }
  712. }
  713. if (c_sign == 0)
  714. /* Zero. */
  715. memset (c_bv, 0, c_size);
  716. else
  717. {
  718. size_t word_count, value_words;
  719. value_words = ((mpz_sizeinbase (c_mpz, 2) + (8 * c_size) - 1) /
  720. (8 * c_size));
  721. if (SCM_UNLIKELY (value_words > 1))
  722. {
  723. err = -2;
  724. goto finish;
  725. }
  726. mpz_export (c_bv, &word_count, 1 /* word order doesn't matter */,
  727. c_size, c_endianness,
  728. 0 /* nails */, c_mpz);
  729. if (SCM_UNLIKELY (word_count != 1))
  730. /* Shouldn't happen since we already checked with VALUE_SIZE. */
  731. abort ();
  732. }
  733. finish:
  734. mpz_clear (c_mpz);
  735. return err;
  736. }
  737. #define GENERIC_INTEGER_ACCESSOR_PROLOGUE(validate, _sign) \
  738. size_t c_len, c_index, c_size; \
  739. char *c_bv; \
  740. \
  741. SCM_VALIDATE_##validate (1, bv); \
  742. c_index = scm_to_size_t (index); \
  743. c_size = scm_to_size_t (size); \
  744. \
  745. c_len = SCM_BYTEVECTOR_LENGTH (bv); \
  746. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv); \
  747. \
  748. /* C_SIZE must have its 3 higher bits set to zero so that \
  749. multiplying it by 8 yields a number that fits in a \
  750. size_t. */ \
  751. if (SCM_UNLIKELY (c_size == 0 || c_size >= (SIZE_MAX >> 3))) \
  752. scm_out_of_range (FUNC_NAME, size); \
  753. if (SCM_UNLIKELY (c_index + c_size > c_len)) \
  754. scm_out_of_range (FUNC_NAME, index);
  755. #define GENERIC_INTEGER_GETTER_PROLOGUE(_sign) \
  756. GENERIC_INTEGER_ACCESSOR_PROLOGUE (BYTEVECTOR, _sign)
  757. #define GENERIC_INTEGER_SETTER_PROLOGUE(_sign) \
  758. GENERIC_INTEGER_ACCESSOR_PROLOGUE (MUTABLE_BYTEVECTOR, _sign)
  759. /* Template of an integer reference function. */
  760. #define GENERIC_INTEGER_REF(_sign) \
  761. SCM result; \
  762. \
  763. if (c_size < 3) \
  764. { \
  765. int swap; \
  766. _sign int value; \
  767. \
  768. swap = !scm_is_eq (endianness, scm_i_native_endianness); \
  769. switch (c_size) \
  770. { \
  771. case 1: \
  772. { \
  773. _sign char c_value8; \
  774. memcpy (&c_value8, c_bv, 1); \
  775. value = c_value8; \
  776. } \
  777. break; \
  778. case 2: \
  779. { \
  780. INT_TYPE (16, _sign) c_value16; \
  781. memcpy (&c_value16, c_bv, 2); \
  782. if (swap) \
  783. value = (INT_TYPE (16, _sign)) bswap_16 (c_value16); \
  784. else \
  785. value = c_value16; \
  786. } \
  787. break; \
  788. default: \
  789. abort (); \
  790. } \
  791. \
  792. result = SCM_I_MAKINUM ((_sign int) value); \
  793. } \
  794. else \
  795. result = bytevector_large_ref ((char *) c_bv, \
  796. c_size, SIGNEDNESS (_sign), \
  797. endianness); \
  798. \
  799. return result;
  800. static inline SCM
  801. bytevector_signed_ref (const char *c_bv, size_t c_size, SCM endianness)
  802. {
  803. GENERIC_INTEGER_REF (signed);
  804. }
  805. static inline SCM
  806. bytevector_unsigned_ref (const char *c_bv, size_t c_size, SCM endianness)
  807. {
  808. GENERIC_INTEGER_REF (unsigned);
  809. }
  810. /* Template of an integer assignment function. */
  811. #define GENERIC_INTEGER_SET(_sign) \
  812. if (c_size < 3) \
  813. { \
  814. scm_t_signed_bits c_value; \
  815. \
  816. if (SCM_UNLIKELY (!SCM_I_INUMP (value))) \
  817. goto range_error; \
  818. \
  819. c_value = SCM_I_INUM (value); \
  820. switch (c_size) \
  821. { \
  822. case 1: \
  823. if (SCM_LIKELY (INT_VALID_P (8, _sign) (c_value))) \
  824. { \
  825. _sign char c_value8; \
  826. c_value8 = (_sign char) c_value; \
  827. memcpy (c_bv, &c_value8, 1); \
  828. } \
  829. else \
  830. goto range_error; \
  831. break; \
  832. \
  833. case 2: \
  834. if (SCM_LIKELY (INT_VALID_P (16, _sign) (c_value))) \
  835. { \
  836. int swap; \
  837. INT_TYPE (16, _sign) c_value16; \
  838. \
  839. swap = !scm_is_eq (endianness, scm_i_native_endianness); \
  840. \
  841. if (swap) \
  842. c_value16 = (INT_TYPE (16, _sign)) bswap_16 (c_value); \
  843. else \
  844. c_value16 = c_value; \
  845. \
  846. memcpy (c_bv, &c_value16, 2); \
  847. } \
  848. else \
  849. goto range_error; \
  850. break; \
  851. \
  852. default: \
  853. abort (); \
  854. } \
  855. } \
  856. else \
  857. { \
  858. int err; \
  859. \
  860. err = bytevector_large_set (c_bv, c_size, \
  861. SIGNEDNESS (_sign), \
  862. value, endianness); \
  863. if (err) \
  864. goto range_error; \
  865. } \
  866. \
  867. return; \
  868. \
  869. range_error: \
  870. scm_out_of_range (FUNC_NAME, value); \
  871. return;
  872. static inline void
  873. bytevector_signed_set (char *c_bv, size_t c_size,
  874. SCM value, SCM endianness,
  875. const char *func_name)
  876. #define FUNC_NAME func_name
  877. {
  878. GENERIC_INTEGER_SET (signed);
  879. }
  880. #undef FUNC_NAME
  881. static inline void
  882. bytevector_unsigned_set (char *c_bv, size_t c_size,
  883. SCM value, SCM endianness,
  884. const char *func_name)
  885. #define FUNC_NAME func_name
  886. {
  887. GENERIC_INTEGER_SET (unsigned);
  888. }
  889. #undef FUNC_NAME
  890. #undef GENERIC_INTEGER_SET
  891. #undef GENERIC_INTEGER_REF
  892. SCM_DEFINE (scm_bytevector_uint_ref, "bytevector-uint-ref", 4, 0, 0,
  893. (SCM bv, SCM index, SCM endianness, SCM size),
  894. "Return the @var{size}-octet long unsigned integer at index "
  895. "@var{index} in @var{bv}.")
  896. #define FUNC_NAME s_scm_bytevector_uint_ref
  897. {
  898. GENERIC_INTEGER_GETTER_PROLOGUE (unsigned);
  899. return (bytevector_unsigned_ref (&c_bv[c_index], c_size, endianness));
  900. }
  901. #undef FUNC_NAME
  902. SCM_DEFINE (scm_bytevector_sint_ref, "bytevector-sint-ref", 4, 0, 0,
  903. (SCM bv, SCM index, SCM endianness, SCM size),
  904. "Return the @var{size}-octet long unsigned integer at index "
  905. "@var{index} in @var{bv}.")
  906. #define FUNC_NAME s_scm_bytevector_sint_ref
  907. {
  908. GENERIC_INTEGER_GETTER_PROLOGUE (signed);
  909. return (bytevector_signed_ref (&c_bv[c_index], c_size, endianness));
  910. }
  911. #undef FUNC_NAME
  912. SCM_DEFINE (scm_bytevector_uint_set_x, "bytevector-uint-set!", 5, 0, 0,
  913. (SCM bv, SCM index, SCM value, SCM endianness, SCM size),
  914. "Set the @var{size}-octet long unsigned integer at @var{index} "
  915. "to @var{value}.")
  916. #define FUNC_NAME s_scm_bytevector_uint_set_x
  917. {
  918. GENERIC_INTEGER_SETTER_PROLOGUE (unsigned);
  919. bytevector_unsigned_set (&c_bv[c_index], c_size, value, endianness,
  920. FUNC_NAME);
  921. return SCM_UNSPECIFIED;
  922. }
  923. #undef FUNC_NAME
  924. SCM_DEFINE (scm_bytevector_sint_set_x, "bytevector-sint-set!", 5, 0, 0,
  925. (SCM bv, SCM index, SCM value, SCM endianness, SCM size),
  926. "Set the @var{size}-octet long signed integer at @var{index} "
  927. "to @var{value}.")
  928. #define FUNC_NAME s_scm_bytevector_sint_set_x
  929. {
  930. GENERIC_INTEGER_SETTER_PROLOGUE (signed);
  931. bytevector_signed_set (&c_bv[c_index], c_size, value, endianness,
  932. FUNC_NAME);
  933. return SCM_UNSPECIFIED;
  934. }
  935. #undef FUNC_NAME
  936. /* Operations on integers of arbitrary size. */
  937. #define INTEGERS_TO_LIST(_sign) \
  938. SCM lst, pair; \
  939. size_t i, c_len, c_size; \
  940. \
  941. SCM_VALIDATE_BYTEVECTOR (1, bv); \
  942. SCM_VALIDATE_SYMBOL (2, endianness); \
  943. c_size = scm_to_unsigned_integer (size, 1, (size_t) -1); \
  944. \
  945. c_len = SCM_BYTEVECTOR_LENGTH (bv); \
  946. if (SCM_UNLIKELY (c_len % c_size != 0)) \
  947. scm_wrong_type_arg_msg \
  948. (FUNC_NAME, 0, size, \
  949. "an exact positive integer that divides the bytevector length"); \
  950. else if (SCM_UNLIKELY (c_len == 0)) \
  951. lst = SCM_EOL; \
  952. else \
  953. { \
  954. const char *c_bv; \
  955. \
  956. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv); \
  957. \
  958. lst = scm_make_list (scm_from_size_t (c_len / c_size), \
  959. SCM_UNSPECIFIED); \
  960. for (i = 0, pair = lst; \
  961. i <= c_len - c_size; \
  962. i += c_size, c_bv += c_size, pair = SCM_CDR (pair)) \
  963. { \
  964. SCM_SETCAR (pair, \
  965. bytevector_ ## _sign ## _ref (c_bv, c_size, \
  966. endianness)); \
  967. } \
  968. } \
  969. \
  970. return lst;
  971. SCM_DEFINE (scm_bytevector_to_sint_list, "bytevector->sint-list",
  972. 3, 0, 0,
  973. (SCM bv, SCM endianness, SCM size),
  974. "Return a list of signed integers of @var{size} octets "
  975. "representing the contents of @var{bv}.")
  976. #define FUNC_NAME s_scm_bytevector_to_sint_list
  977. {
  978. INTEGERS_TO_LIST (signed);
  979. }
  980. #undef FUNC_NAME
  981. SCM_DEFINE (scm_bytevector_to_uint_list, "bytevector->uint-list",
  982. 3, 0, 0,
  983. (SCM bv, SCM endianness, SCM size),
  984. "Return a list of unsigned integers of @var{size} octets "
  985. "representing the contents of @var{bv}.")
  986. #define FUNC_NAME s_scm_bytevector_to_uint_list
  987. {
  988. INTEGERS_TO_LIST (unsigned);
  989. }
  990. #undef FUNC_NAME
  991. #undef INTEGER_TO_LIST
  992. #define INTEGER_LIST_TO_BYTEVECTOR(_sign) \
  993. SCM bv; \
  994. size_t c_len; \
  995. size_t c_size; \
  996. char *c_bv, *c_bv_ptr; \
  997. \
  998. SCM_VALIDATE_LIST_COPYLEN (1, lst, c_len); \
  999. SCM_VALIDATE_SYMBOL (2, endianness); \
  1000. c_size = scm_to_size_t (size); \
  1001. \
  1002. if (SCM_UNLIKELY (c_size == 0 || c_size >= (SIZE_MAX >> 3))) \
  1003. scm_out_of_range (FUNC_NAME, size); \
  1004. \
  1005. bv = make_bytevector (c_len * c_size, SCM_ARRAY_ELEMENT_TYPE_VU8); \
  1006. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv); \
  1007. \
  1008. for (c_bv_ptr = c_bv; \
  1009. !scm_is_null (lst); \
  1010. lst = SCM_CDR (lst), c_bv_ptr += c_size) \
  1011. { \
  1012. bytevector_ ## _sign ## _set (c_bv_ptr, c_size, \
  1013. SCM_CAR (lst), endianness, \
  1014. FUNC_NAME); \
  1015. } \
  1016. \
  1017. return bv;
  1018. SCM_DEFINE (scm_uint_list_to_bytevector, "uint-list->bytevector",
  1019. 3, 0, 0,
  1020. (SCM lst, SCM endianness, SCM size),
  1021. "Return a bytevector containing the unsigned integers "
  1022. "listed in @var{lst} and encoded on @var{size} octets "
  1023. "according to @var{endianness}.")
  1024. #define FUNC_NAME s_scm_uint_list_to_bytevector
  1025. {
  1026. INTEGER_LIST_TO_BYTEVECTOR (unsigned);
  1027. }
  1028. #undef FUNC_NAME
  1029. SCM_DEFINE (scm_sint_list_to_bytevector, "sint-list->bytevector",
  1030. 3, 0, 0,
  1031. (SCM lst, SCM endianness, SCM size),
  1032. "Return a bytevector containing the signed integers "
  1033. "listed in @var{lst} and encoded on @var{size} octets "
  1034. "according to @var{endianness}.")
  1035. #define FUNC_NAME s_scm_sint_list_to_bytevector
  1036. {
  1037. INTEGER_LIST_TO_BYTEVECTOR (signed);
  1038. }
  1039. #undef FUNC_NAME
  1040. #undef INTEGER_LIST_TO_BYTEVECTOR
  1041. /* Operations on 16-bit integers. */
  1042. SCM_DEFINE (scm_bytevector_u16_ref, "bytevector-u16-ref",
  1043. 3, 0, 0,
  1044. (SCM bv, SCM index, SCM endianness),
  1045. "Return the unsigned 16-bit integer from @var{bv} at "
  1046. "@var{index}.")
  1047. #define FUNC_NAME s_scm_bytevector_u16_ref
  1048. {
  1049. INTEGER_REF (16, unsigned);
  1050. }
  1051. #undef FUNC_NAME
  1052. SCM_DEFINE (scm_bytevector_s16_ref, "bytevector-s16-ref",
  1053. 3, 0, 0,
  1054. (SCM bv, SCM index, SCM endianness),
  1055. "Return the signed 16-bit integer from @var{bv} at "
  1056. "@var{index}.")
  1057. #define FUNC_NAME s_scm_bytevector_s16_ref
  1058. {
  1059. INTEGER_REF (16, signed);
  1060. }
  1061. #undef FUNC_NAME
  1062. SCM_DEFINE (scm_bytevector_u16_native_ref, "bytevector-u16-native-ref",
  1063. 2, 0, 0,
  1064. (SCM bv, SCM index),
  1065. "Return the unsigned 16-bit integer from @var{bv} at "
  1066. "@var{index} using the native endianness.")
  1067. #define FUNC_NAME s_scm_bytevector_u16_native_ref
  1068. {
  1069. INTEGER_NATIVE_REF (16, unsigned);
  1070. }
  1071. #undef FUNC_NAME
  1072. SCM_DEFINE (scm_bytevector_s16_native_ref, "bytevector-s16-native-ref",
  1073. 2, 0, 0,
  1074. (SCM bv, SCM index),
  1075. "Return the unsigned 16-bit integer from @var{bv} at "
  1076. "@var{index} using the native endianness.")
  1077. #define FUNC_NAME s_scm_bytevector_s16_native_ref
  1078. {
  1079. INTEGER_NATIVE_REF (16, signed);
  1080. }
  1081. #undef FUNC_NAME
  1082. SCM_DEFINE (scm_bytevector_u16_set_x, "bytevector-u16-set!",
  1083. 4, 0, 0,
  1084. (SCM bv, SCM index, SCM value, SCM endianness),
  1085. "Store @var{value} in @var{bv} at @var{index} according to "
  1086. "@var{endianness}.")
  1087. #define FUNC_NAME s_scm_bytevector_u16_set_x
  1088. {
  1089. INTEGER_SET (16, unsigned);
  1090. }
  1091. #undef FUNC_NAME
  1092. SCM_DEFINE (scm_bytevector_s16_set_x, "bytevector-s16-set!",
  1093. 4, 0, 0,
  1094. (SCM bv, SCM index, SCM value, SCM endianness),
  1095. "Store @var{value} in @var{bv} at @var{index} according to "
  1096. "@var{endianness}.")
  1097. #define FUNC_NAME s_scm_bytevector_s16_set_x
  1098. {
  1099. INTEGER_SET (16, signed);
  1100. }
  1101. #undef FUNC_NAME
  1102. SCM_DEFINE (scm_bytevector_u16_native_set_x, "bytevector-u16-native-set!",
  1103. 3, 0, 0,
  1104. (SCM bv, SCM index, SCM value),
  1105. "Store the unsigned integer @var{value} at index @var{index} "
  1106. "of @var{bv} using the native endianness.")
  1107. #define FUNC_NAME s_scm_bytevector_u16_native_set_x
  1108. {
  1109. INTEGER_NATIVE_SET (16, unsigned);
  1110. }
  1111. #undef FUNC_NAME
  1112. SCM_DEFINE (scm_bytevector_s16_native_set_x, "bytevector-s16-native-set!",
  1113. 3, 0, 0,
  1114. (SCM bv, SCM index, SCM value),
  1115. "Store the signed integer @var{value} at index @var{index} "
  1116. "of @var{bv} using the native endianness.")
  1117. #define FUNC_NAME s_scm_bytevector_s16_native_set_x
  1118. {
  1119. INTEGER_NATIVE_SET (16, signed);
  1120. }
  1121. #undef FUNC_NAME
  1122. /* Operations on 32-bit integers. */
  1123. /* Unfortunately, on 32-bit machines `SCM' is not large enough to hold
  1124. arbitrary 32-bit integers. Thus we fall back to using the
  1125. `large_{ref,set}' variants on 32-bit machines. */
  1126. #define LARGE_INTEGER_REF(_len, _sign) \
  1127. INTEGER_GETTER_PROLOGUE(_len, _sign); \
  1128. SCM_VALIDATE_SYMBOL (3, endianness); \
  1129. \
  1130. return (bytevector_large_ref ((char *) c_bv + c_index, _len / 8, \
  1131. SIGNEDNESS (_sign), endianness));
  1132. #define LARGE_INTEGER_SET(_len, _sign) \
  1133. int err; \
  1134. INTEGER_SETTER_PROLOGUE (_len, _sign); \
  1135. SCM_VALIDATE_SYMBOL (4, endianness); \
  1136. \
  1137. err = bytevector_large_set ((char *) c_bv + c_index, _len / 8, \
  1138. SIGNEDNESS (_sign), value, endianness); \
  1139. if (SCM_UNLIKELY (err)) \
  1140. scm_out_of_range (FUNC_NAME, value); \
  1141. \
  1142. return SCM_UNSPECIFIED;
  1143. #define LARGE_INTEGER_NATIVE_REF(_len, _sign) \
  1144. INTEGER_GETTER_PROLOGUE(_len, _sign); \
  1145. return (bytevector_large_ref ((char *) c_bv + c_index, _len / 8, \
  1146. SIGNEDNESS (_sign), scm_i_native_endianness));
  1147. #define LARGE_INTEGER_NATIVE_SET(_len, _sign) \
  1148. int err; \
  1149. INTEGER_SETTER_PROLOGUE (_len, _sign); \
  1150. \
  1151. err = bytevector_large_set ((char *) c_bv + c_index, _len / 8, \
  1152. SIGNEDNESS (_sign), value, \
  1153. scm_i_native_endianness); \
  1154. if (SCM_UNLIKELY (err)) \
  1155. scm_out_of_range (FUNC_NAME, value); \
  1156. \
  1157. return SCM_UNSPECIFIED;
  1158. SCM_DEFINE (scm_bytevector_u32_ref, "bytevector-u32-ref",
  1159. 3, 0, 0,
  1160. (SCM bv, SCM index, SCM endianness),
  1161. "Return the unsigned 32-bit integer from @var{bv} at "
  1162. "@var{index}.")
  1163. #define FUNC_NAME s_scm_bytevector_u32_ref
  1164. {
  1165. #if SIZEOF_VOID_P > 4
  1166. INTEGER_REF (32, unsigned);
  1167. #else
  1168. LARGE_INTEGER_REF (32, unsigned);
  1169. #endif
  1170. }
  1171. #undef FUNC_NAME
  1172. SCM_DEFINE (scm_bytevector_s32_ref, "bytevector-s32-ref",
  1173. 3, 0, 0,
  1174. (SCM bv, SCM index, SCM endianness),
  1175. "Return the signed 32-bit integer from @var{bv} at "
  1176. "@var{index}.")
  1177. #define FUNC_NAME s_scm_bytevector_s32_ref
  1178. {
  1179. #if SIZEOF_VOID_P > 4
  1180. INTEGER_REF (32, signed);
  1181. #else
  1182. LARGE_INTEGER_REF (32, signed);
  1183. #endif
  1184. }
  1185. #undef FUNC_NAME
  1186. SCM_DEFINE (scm_bytevector_u32_native_ref, "bytevector-u32-native-ref",
  1187. 2, 0, 0,
  1188. (SCM bv, SCM index),
  1189. "Return the unsigned 32-bit integer from @var{bv} at "
  1190. "@var{index} using the native endianness.")
  1191. #define FUNC_NAME s_scm_bytevector_u32_native_ref
  1192. {
  1193. #if SIZEOF_VOID_P > 4
  1194. INTEGER_NATIVE_REF (32, unsigned);
  1195. #else
  1196. LARGE_INTEGER_NATIVE_REF (32, unsigned);
  1197. #endif
  1198. }
  1199. #undef FUNC_NAME
  1200. SCM_DEFINE (scm_bytevector_s32_native_ref, "bytevector-s32-native-ref",
  1201. 2, 0, 0,
  1202. (SCM bv, SCM index),
  1203. "Return the unsigned 32-bit integer from @var{bv} at "
  1204. "@var{index} using the native endianness.")
  1205. #define FUNC_NAME s_scm_bytevector_s32_native_ref
  1206. {
  1207. #if SIZEOF_VOID_P > 4
  1208. INTEGER_NATIVE_REF (32, signed);
  1209. #else
  1210. LARGE_INTEGER_NATIVE_REF (32, signed);
  1211. #endif
  1212. }
  1213. #undef FUNC_NAME
  1214. SCM_DEFINE (scm_bytevector_u32_set_x, "bytevector-u32-set!",
  1215. 4, 0, 0,
  1216. (SCM bv, SCM index, SCM value, SCM endianness),
  1217. "Store @var{value} in @var{bv} at @var{index} according to "
  1218. "@var{endianness}.")
  1219. #define FUNC_NAME s_scm_bytevector_u32_set_x
  1220. {
  1221. #if SIZEOF_VOID_P > 4
  1222. INTEGER_SET (32, unsigned);
  1223. #else
  1224. LARGE_INTEGER_SET (32, unsigned);
  1225. #endif
  1226. }
  1227. #undef FUNC_NAME
  1228. SCM_DEFINE (scm_bytevector_s32_set_x, "bytevector-s32-set!",
  1229. 4, 0, 0,
  1230. (SCM bv, SCM index, SCM value, SCM endianness),
  1231. "Store @var{value} in @var{bv} at @var{index} according to "
  1232. "@var{endianness}.")
  1233. #define FUNC_NAME s_scm_bytevector_s32_set_x
  1234. {
  1235. #if SIZEOF_VOID_P > 4
  1236. INTEGER_SET (32, signed);
  1237. #else
  1238. LARGE_INTEGER_SET (32, signed);
  1239. #endif
  1240. }
  1241. #undef FUNC_NAME
  1242. SCM_DEFINE (scm_bytevector_u32_native_set_x, "bytevector-u32-native-set!",
  1243. 3, 0, 0,
  1244. (SCM bv, SCM index, SCM value),
  1245. "Store the unsigned integer @var{value} at index @var{index} "
  1246. "of @var{bv} using the native endianness.")
  1247. #define FUNC_NAME s_scm_bytevector_u32_native_set_x
  1248. {
  1249. #if SIZEOF_VOID_P > 4
  1250. INTEGER_NATIVE_SET (32, unsigned);
  1251. #else
  1252. LARGE_INTEGER_NATIVE_SET (32, unsigned);
  1253. #endif
  1254. }
  1255. #undef FUNC_NAME
  1256. SCM_DEFINE (scm_bytevector_s32_native_set_x, "bytevector-s32-native-set!",
  1257. 3, 0, 0,
  1258. (SCM bv, SCM index, SCM value),
  1259. "Store the signed integer @var{value} at index @var{index} "
  1260. "of @var{bv} using the native endianness.")
  1261. #define FUNC_NAME s_scm_bytevector_s32_native_set_x
  1262. {
  1263. #if SIZEOF_VOID_P > 4
  1264. INTEGER_NATIVE_SET (32, signed);
  1265. #else
  1266. LARGE_INTEGER_NATIVE_SET (32, signed);
  1267. #endif
  1268. }
  1269. #undef FUNC_NAME
  1270. /* Operations on 64-bit integers. */
  1271. /* For 64-bit integers, we use only the `large_{ref,set}' variant. */
  1272. SCM_DEFINE (scm_bytevector_u64_ref, "bytevector-u64-ref",
  1273. 3, 0, 0,
  1274. (SCM bv, SCM index, SCM endianness),
  1275. "Return the unsigned 64-bit integer from @var{bv} at "
  1276. "@var{index}.")
  1277. #define FUNC_NAME s_scm_bytevector_u64_ref
  1278. {
  1279. LARGE_INTEGER_REF (64, unsigned);
  1280. }
  1281. #undef FUNC_NAME
  1282. SCM_DEFINE (scm_bytevector_s64_ref, "bytevector-s64-ref",
  1283. 3, 0, 0,
  1284. (SCM bv, SCM index, SCM endianness),
  1285. "Return the signed 64-bit integer from @var{bv} at "
  1286. "@var{index}.")
  1287. #define FUNC_NAME s_scm_bytevector_s64_ref
  1288. {
  1289. LARGE_INTEGER_REF (64, signed);
  1290. }
  1291. #undef FUNC_NAME
  1292. SCM_DEFINE (scm_bytevector_u64_native_ref, "bytevector-u64-native-ref",
  1293. 2, 0, 0,
  1294. (SCM bv, SCM index),
  1295. "Return the unsigned 64-bit integer from @var{bv} at "
  1296. "@var{index} using the native endianness.")
  1297. #define FUNC_NAME s_scm_bytevector_u64_native_ref
  1298. {
  1299. LARGE_INTEGER_NATIVE_REF (64, unsigned);
  1300. }
  1301. #undef FUNC_NAME
  1302. SCM_DEFINE (scm_bytevector_s64_native_ref, "bytevector-s64-native-ref",
  1303. 2, 0, 0,
  1304. (SCM bv, SCM index),
  1305. "Return the unsigned 64-bit integer from @var{bv} at "
  1306. "@var{index} using the native endianness.")
  1307. #define FUNC_NAME s_scm_bytevector_s64_native_ref
  1308. {
  1309. LARGE_INTEGER_NATIVE_REF (64, signed);
  1310. }
  1311. #undef FUNC_NAME
  1312. SCM_DEFINE (scm_bytevector_u64_set_x, "bytevector-u64-set!",
  1313. 4, 0, 0,
  1314. (SCM bv, SCM index, SCM value, SCM endianness),
  1315. "Store @var{value} in @var{bv} at @var{index} according to "
  1316. "@var{endianness}.")
  1317. #define FUNC_NAME s_scm_bytevector_u64_set_x
  1318. {
  1319. LARGE_INTEGER_SET (64, unsigned);
  1320. }
  1321. #undef FUNC_NAME
  1322. SCM_DEFINE (scm_bytevector_s64_set_x, "bytevector-s64-set!",
  1323. 4, 0, 0,
  1324. (SCM bv, SCM index, SCM value, SCM endianness),
  1325. "Store @var{value} in @var{bv} at @var{index} according to "
  1326. "@var{endianness}.")
  1327. #define FUNC_NAME s_scm_bytevector_s64_set_x
  1328. {
  1329. LARGE_INTEGER_SET (64, signed);
  1330. }
  1331. #undef FUNC_NAME
  1332. SCM_DEFINE (scm_bytevector_u64_native_set_x, "bytevector-u64-native-set!",
  1333. 3, 0, 0,
  1334. (SCM bv, SCM index, SCM value),
  1335. "Store the unsigned integer @var{value} at index @var{index} "
  1336. "of @var{bv} using the native endianness.")
  1337. #define FUNC_NAME s_scm_bytevector_u64_native_set_x
  1338. {
  1339. LARGE_INTEGER_NATIVE_SET (64, unsigned);
  1340. }
  1341. #undef FUNC_NAME
  1342. SCM_DEFINE (scm_bytevector_s64_native_set_x, "bytevector-s64-native-set!",
  1343. 3, 0, 0,
  1344. (SCM bv, SCM index, SCM value),
  1345. "Store the signed integer @var{value} at index @var{index} "
  1346. "of @var{bv} using the native endianness.")
  1347. #define FUNC_NAME s_scm_bytevector_s64_native_set_x
  1348. {
  1349. LARGE_INTEGER_NATIVE_SET (64, signed);
  1350. }
  1351. #undef FUNC_NAME
  1352. /* Operations on IEEE-754 numbers. */
  1353. /* There are two possible word endians, visible in glibc's <ieee754.h>.
  1354. However, in R6RS, when the endianness is `little', little endian is
  1355. assumed for both the byte order and the word order. This is clear from
  1356. Section 2.1 of R6RS-lib (in response to
  1357. http://www.r6rs.org/formal-comments/comment-187.txt). */
  1358. union scm_ieee754_float
  1359. {
  1360. float f;
  1361. uint32_t i;
  1362. };
  1363. union scm_ieee754_double
  1364. {
  1365. double d;
  1366. uint64_t i;
  1367. };
  1368. /* Convert to/from a floating-point number with different endianness. This
  1369. method is probably not the most efficient but it should be portable. */
  1370. static inline void
  1371. float_to_foreign_endianness (union scm_ieee754_float *target,
  1372. float source)
  1373. {
  1374. union scm_ieee754_float input;
  1375. input.f = source;
  1376. target->i = bswap_32 (input.i);
  1377. }
  1378. static inline float
  1379. float_from_foreign_endianness (const union scm_ieee754_float *source)
  1380. {
  1381. union scm_ieee754_float result;
  1382. result.i = bswap_32 (source->i);
  1383. return (result.f);
  1384. }
  1385. static inline void
  1386. double_to_foreign_endianness (union scm_ieee754_double *target,
  1387. double source)
  1388. {
  1389. union scm_ieee754_double input;
  1390. input.d = source;
  1391. target->i = bswap_64 (input.i);
  1392. }
  1393. static inline double
  1394. double_from_foreign_endianness (const union scm_ieee754_double *source)
  1395. {
  1396. union scm_ieee754_double result;
  1397. result.i = bswap_64 (source->i);
  1398. return (result.d);
  1399. }
  1400. /* Template macros to abstract over doubles and floats.
  1401. XXX: Guile can only convert to/from doubles. */
  1402. #define IEEE754_UNION(_c_type) union scm_ieee754_ ## _c_type
  1403. #define IEEE754_TO_SCM(_c_type) scm_from_double
  1404. #define IEEE754_FROM_SCM(_c_type) scm_to_double
  1405. #define IEEE754_FROM_FOREIGN_ENDIANNESS(_c_type) \
  1406. _c_type ## _from_foreign_endianness
  1407. #define IEEE754_TO_FOREIGN_ENDIANNESS(_c_type) \
  1408. _c_type ## _to_foreign_endianness
  1409. /* FIXME: SCM_VALIDATE_REAL rejects integers, etc. grrr */
  1410. #define VALIDATE_REAL(pos, v) \
  1411. do { \
  1412. SCM_ASSERT_TYPE (scm_is_real (v), v, pos, FUNC_NAME, "real"); \
  1413. } while (0)
  1414. /* Templace getters and setters. */
  1415. #define IEEE754_GETTER_PROLOGUE(_type) \
  1416. INTEGER_GETTER_PROLOGUE (sizeof (_type) << 3UL, signed);
  1417. #define IEEE754_SETTER_PROLOGUE(_type) \
  1418. INTEGER_SETTER_PROLOGUE (sizeof (_type) << 3UL, signed);
  1419. #define IEEE754_REF(_type) \
  1420. _type c_result; \
  1421. \
  1422. IEEE754_GETTER_PROLOGUE (_type); \
  1423. SCM_VALIDATE_SYMBOL (3, endianness); \
  1424. \
  1425. if (scm_is_eq (endianness, scm_i_native_endianness)) \
  1426. memcpy (&c_result, &c_bv[c_index], sizeof (c_result)); \
  1427. else \
  1428. { \
  1429. IEEE754_UNION (_type) c_raw; \
  1430. \
  1431. memcpy (&c_raw, &c_bv[c_index], sizeof (c_raw)); \
  1432. c_result = \
  1433. IEEE754_FROM_FOREIGN_ENDIANNESS (_type) (&c_raw); \
  1434. } \
  1435. \
  1436. return (IEEE754_TO_SCM (_type) (c_result));
  1437. #define IEEE754_NATIVE_REF(_type) \
  1438. _type c_result; \
  1439. \
  1440. IEEE754_GETTER_PROLOGUE (_type); \
  1441. \
  1442. memcpy (&c_result, &c_bv[c_index], sizeof (c_result)); \
  1443. return (IEEE754_TO_SCM (_type) (c_result));
  1444. #define IEEE754_SET(_type) \
  1445. _type c_value; \
  1446. \
  1447. IEEE754_SETTER_PROLOGUE (_type); \
  1448. VALIDATE_REAL (3, value); \
  1449. SCM_VALIDATE_SYMBOL (4, endianness); \
  1450. c_value = IEEE754_FROM_SCM (_type) (value); \
  1451. \
  1452. if (scm_is_eq (endianness, scm_i_native_endianness)) \
  1453. memcpy (&c_bv[c_index], &c_value, sizeof (c_value)); \
  1454. else \
  1455. { \
  1456. IEEE754_UNION (_type) c_raw; \
  1457. \
  1458. IEEE754_TO_FOREIGN_ENDIANNESS (_type) (&c_raw, c_value); \
  1459. memcpy (&c_bv[c_index], &c_raw, sizeof (c_raw)); \
  1460. } \
  1461. \
  1462. return SCM_UNSPECIFIED;
  1463. #define IEEE754_NATIVE_SET(_type) \
  1464. _type c_value; \
  1465. \
  1466. IEEE754_SETTER_PROLOGUE (_type); \
  1467. VALIDATE_REAL (3, value); \
  1468. c_value = IEEE754_FROM_SCM (_type) (value); \
  1469. \
  1470. memcpy (&c_bv[c_index], &c_value, sizeof (c_value)); \
  1471. return SCM_UNSPECIFIED;
  1472. /* Single precision. */
  1473. SCM_DEFINE (scm_bytevector_ieee_single_ref,
  1474. "bytevector-ieee-single-ref",
  1475. 3, 0, 0,
  1476. (SCM bv, SCM index, SCM endianness),
  1477. "Return the IEEE-754 single from @var{bv} at "
  1478. "@var{index}.")
  1479. #define FUNC_NAME s_scm_bytevector_ieee_single_ref
  1480. {
  1481. IEEE754_REF (float);
  1482. }
  1483. #undef FUNC_NAME
  1484. SCM_DEFINE (scm_bytevector_ieee_single_native_ref,
  1485. "bytevector-ieee-single-native-ref",
  1486. 2, 0, 0,
  1487. (SCM bv, SCM index),
  1488. "Return the IEEE-754 single from @var{bv} at "
  1489. "@var{index} using the native endianness.")
  1490. #define FUNC_NAME s_scm_bytevector_ieee_single_native_ref
  1491. {
  1492. IEEE754_NATIVE_REF (float);
  1493. }
  1494. #undef FUNC_NAME
  1495. SCM_DEFINE (scm_bytevector_ieee_single_set_x,
  1496. "bytevector-ieee-single-set!",
  1497. 4, 0, 0,
  1498. (SCM bv, SCM index, SCM value, SCM endianness),
  1499. "Store real @var{value} in @var{bv} at @var{index} according to "
  1500. "@var{endianness}.")
  1501. #define FUNC_NAME s_scm_bytevector_ieee_single_set_x
  1502. {
  1503. IEEE754_SET (float);
  1504. }
  1505. #undef FUNC_NAME
  1506. SCM_DEFINE (scm_bytevector_ieee_single_native_set_x,
  1507. "bytevector-ieee-single-native-set!",
  1508. 3, 0, 0,
  1509. (SCM bv, SCM index, SCM value),
  1510. "Store the real @var{value} at index @var{index} "
  1511. "of @var{bv} using the native endianness.")
  1512. #define FUNC_NAME s_scm_bytevector_ieee_single_native_set_x
  1513. {
  1514. IEEE754_NATIVE_SET (float);
  1515. }
  1516. #undef FUNC_NAME
  1517. /* Double precision. */
  1518. SCM_DEFINE (scm_bytevector_ieee_double_ref,
  1519. "bytevector-ieee-double-ref",
  1520. 3, 0, 0,
  1521. (SCM bv, SCM index, SCM endianness),
  1522. "Return the IEEE-754 double from @var{bv} at "
  1523. "@var{index}.")
  1524. #define FUNC_NAME s_scm_bytevector_ieee_double_ref
  1525. {
  1526. IEEE754_REF (double);
  1527. }
  1528. #undef FUNC_NAME
  1529. SCM_DEFINE (scm_bytevector_ieee_double_native_ref,
  1530. "bytevector-ieee-double-native-ref",
  1531. 2, 0, 0,
  1532. (SCM bv, SCM index),
  1533. "Return the IEEE-754 double from @var{bv} at "
  1534. "@var{index} using the native endianness.")
  1535. #define FUNC_NAME s_scm_bytevector_ieee_double_native_ref
  1536. {
  1537. IEEE754_NATIVE_REF (double);
  1538. }
  1539. #undef FUNC_NAME
  1540. SCM_DEFINE (scm_bytevector_ieee_double_set_x,
  1541. "bytevector-ieee-double-set!",
  1542. 4, 0, 0,
  1543. (SCM bv, SCM index, SCM value, SCM endianness),
  1544. "Store real @var{value} in @var{bv} at @var{index} according to "
  1545. "@var{endianness}.")
  1546. #define FUNC_NAME s_scm_bytevector_ieee_double_set_x
  1547. {
  1548. IEEE754_SET (double);
  1549. }
  1550. #undef FUNC_NAME
  1551. SCM_DEFINE (scm_bytevector_ieee_double_native_set_x,
  1552. "bytevector-ieee-double-native-set!",
  1553. 3, 0, 0,
  1554. (SCM bv, SCM index, SCM value),
  1555. "Store the real @var{value} at index @var{index} "
  1556. "of @var{bv} using the native endianness.")
  1557. #define FUNC_NAME s_scm_bytevector_ieee_double_native_set_x
  1558. {
  1559. IEEE754_NATIVE_SET (double);
  1560. }
  1561. #undef FUNC_NAME
  1562. #undef IEEE754_UNION
  1563. #undef IEEE754_TO_SCM
  1564. #undef IEEE754_FROM_SCM
  1565. #undef IEEE754_FROM_FOREIGN_ENDIANNESS
  1566. #undef IEEE754_TO_FOREIGN_ENDIANNESS
  1567. #undef IEEE754_REF
  1568. #undef IEEE754_NATIVE_REF
  1569. #undef IEEE754_SET
  1570. #undef IEEE754_NATIVE_SET
  1571. /* Operations on strings. */
  1572. /* Produce a function that returns the length of a UTF-encoded string. */
  1573. #define UTF_STRLEN_FUNCTION(_utf_width) \
  1574. static inline size_t \
  1575. utf ## _utf_width ## _strlen (const uint ## _utf_width ## _t *str) \
  1576. { \
  1577. size_t len = 0; \
  1578. const uint ## _utf_width ## _t *ptr; \
  1579. for (ptr = str; \
  1580. *ptr != 0; \
  1581. ptr++) \
  1582. { \
  1583. len++; \
  1584. } \
  1585. \
  1586. return (len * ((_utf_width) / 8)); \
  1587. }
  1588. UTF_STRLEN_FUNCTION (8)
  1589. /* Return the length (in bytes) of STR, a UTF-(UTF_WIDTH) encoded string. */
  1590. #define UTF_STRLEN(_utf_width, _str) \
  1591. utf ## _utf_width ## _strlen (_str)
  1592. /* Return the "portable" name of the UTF encoding of size UTF_WIDTH and
  1593. ENDIANNESS (Gnulib's `iconv_open' module guarantees the portability of the
  1594. encoding name). */
  1595. static inline void
  1596. utf_encoding_name (char *name, size_t utf_width, SCM endianness)
  1597. {
  1598. strcpy (name, "UTF-");
  1599. strcat (name, ((utf_width == 8)
  1600. ? "8"
  1601. : ((utf_width == 16)
  1602. ? "16"
  1603. : ((utf_width == 32)
  1604. ? "32"
  1605. : "??"))));
  1606. strcat (name,
  1607. ((scm_is_eq (endianness, sym_big))
  1608. ? "BE"
  1609. : ((scm_is_eq (endianness, sym_little))
  1610. ? "LE"
  1611. : "unknown")));
  1612. }
  1613. /* Maximum length of a UTF encoding name. */
  1614. #define MAX_UTF_ENCODING_NAME_LEN 16
  1615. /* Produce the body of a `string->utf' function. */
  1616. #define STRING_TO_UTF(_utf_width) \
  1617. SCM utf; \
  1618. int err; \
  1619. char c_utf_name[MAX_UTF_ENCODING_NAME_LEN]; \
  1620. char *c_utf = NULL; \
  1621. size_t c_strlen, c_utf_len = 0; \
  1622. \
  1623. SCM_VALIDATE_STRING (1, str); \
  1624. if (scm_is_eq (endianness, SCM_UNDEFINED)) \
  1625. endianness = sym_big; \
  1626. else \
  1627. SCM_VALIDATE_SYMBOL (2, endianness); \
  1628. \
  1629. utf_encoding_name (c_utf_name, (_utf_width), endianness); \
  1630. \
  1631. c_strlen = scm_i_string_length (str); \
  1632. if (scm_i_is_narrow_string (str)) \
  1633. { \
  1634. err = mem_iconveh (scm_i_string_chars (str), c_strlen, \
  1635. "ISO-8859-1", c_utf_name, \
  1636. iconveh_question_mark, NULL, \
  1637. &c_utf, &c_utf_len); \
  1638. if (SCM_UNLIKELY (err)) \
  1639. scm_syserror_msg (FUNC_NAME, "failed to convert string: ~A", \
  1640. scm_list_1 (str), err); \
  1641. } \
  1642. else \
  1643. { \
  1644. const scm_t_wchar *wbuf = scm_i_string_wide_chars (str); \
  1645. c_utf = u32_conv_to_encoding (c_utf_name, \
  1646. iconveh_question_mark, \
  1647. (uint32_t *) wbuf, \
  1648. c_strlen, NULL, NULL, &c_utf_len); \
  1649. if (SCM_UNLIKELY (c_utf == NULL)) \
  1650. scm_syserror_msg (FUNC_NAME, "failed to convert string: ~A", \
  1651. scm_list_1 (str), errno); \
  1652. } \
  1653. scm_dynwind_begin (0); \
  1654. scm_dynwind_free (c_utf); \
  1655. utf = make_bytevector (c_utf_len, SCM_ARRAY_ELEMENT_TYPE_VU8); \
  1656. memcpy (SCM_BYTEVECTOR_CONTENTS (utf), c_utf, c_utf_len); \
  1657. scm_dynwind_end (); \
  1658. \
  1659. return (utf);
  1660. SCM_DEFINE (scm_string_to_utf8, "string->utf8",
  1661. 1, 0, 0,
  1662. (SCM str),
  1663. "Return a newly allocated bytevector that contains the UTF-8 "
  1664. "encoding of @var{str}.")
  1665. #define FUNC_NAME s_scm_string_to_utf8
  1666. {
  1667. SCM utf;
  1668. uint8_t *c_utf;
  1669. size_t c_utf_len = 0;
  1670. SCM_VALIDATE_STRING (1, str);
  1671. c_utf = (uint8_t *) scm_to_utf8_stringn (str, &c_utf_len);
  1672. utf = make_bytevector (c_utf_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  1673. memcpy (SCM_BYTEVECTOR_CONTENTS (utf), c_utf, c_utf_len);
  1674. free (c_utf);
  1675. return (utf);
  1676. }
  1677. #undef FUNC_NAME
  1678. SCM_DEFINE (scm_string_to_utf16, "string->utf16",
  1679. 1, 1, 0,
  1680. (SCM str, SCM endianness),
  1681. "Return a newly allocated bytevector that contains the UTF-16 "
  1682. "encoding of @var{str}.")
  1683. #define FUNC_NAME s_scm_string_to_utf16
  1684. {
  1685. STRING_TO_UTF (16);
  1686. }
  1687. #undef FUNC_NAME
  1688. static void
  1689. swap_u32 (scm_t_wchar *vals, size_t len)
  1690. {
  1691. size_t n;
  1692. for (n = 0; n < len; n++)
  1693. vals[n] = bswap_32 (vals[n]);
  1694. }
  1695. SCM_DEFINE (scm_string_to_utf32, "string->utf32",
  1696. 1, 1, 0,
  1697. (SCM str, SCM endianness),
  1698. "Return a newly allocated bytevector that contains the UTF-32 "
  1699. "encoding of @var{str}.")
  1700. #define FUNC_NAME s_scm_string_to_utf32
  1701. {
  1702. SCM bv;
  1703. scm_t_wchar *wchars;
  1704. size_t wchar_len, bytes_len;
  1705. wchars = scm_to_utf32_stringn (str, &wchar_len);
  1706. bytes_len = wchar_len * sizeof (scm_t_wchar);
  1707. if (!scm_is_eq (SCM_UNBNDP (endianness) ? scm_endianness_big : endianness,
  1708. scm_i_native_endianness))
  1709. swap_u32 (wchars, wchar_len);
  1710. bv = make_bytevector (bytes_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
  1711. memcpy (SCM_BYTEVECTOR_CONTENTS (bv), wchars, bytes_len);
  1712. free (wchars);
  1713. return bv;
  1714. }
  1715. #undef FUNC_NAME
  1716. /* Produce the body of a function that converts a UTF-encoded bytevector to a
  1717. string. */
  1718. #define UTF_TO_STRING(_utf_width) \
  1719. SCM str = SCM_BOOL_F; \
  1720. int err; \
  1721. char *c_str = NULL; \
  1722. char c_utf_name[MAX_UTF_ENCODING_NAME_LEN]; \
  1723. char *c_utf; \
  1724. size_t c_strlen = 0, c_utf_len = 0; \
  1725. \
  1726. SCM_VALIDATE_BYTEVECTOR (1, utf); \
  1727. if (scm_is_eq (endianness, SCM_UNDEFINED)) \
  1728. endianness = sym_big; \
  1729. else \
  1730. SCM_VALIDATE_SYMBOL (2, endianness); \
  1731. \
  1732. c_utf_len = SCM_BYTEVECTOR_LENGTH (utf); \
  1733. c_utf = (char *) SCM_BYTEVECTOR_CONTENTS (utf); \
  1734. utf_encoding_name (c_utf_name, (_utf_width), endianness); \
  1735. \
  1736. err = mem_iconveh (c_utf, c_utf_len, \
  1737. c_utf_name, "UTF-8", \
  1738. iconveh_question_mark, NULL, \
  1739. &c_str, &c_strlen); \
  1740. if (SCM_UNLIKELY (err)) \
  1741. scm_syserror_msg (FUNC_NAME, "failed to convert to string: ~A", \
  1742. scm_list_1 (utf), err); \
  1743. else \
  1744. { \
  1745. str = scm_from_utf8_stringn (c_str, c_strlen); \
  1746. free (c_str); \
  1747. } \
  1748. return (str);
  1749. SCM_DEFINE (scm_utf8_to_string, "utf8->string",
  1750. 1, 0, 0,
  1751. (SCM utf),
  1752. "Return a newly allocate string that contains from the UTF-8-"
  1753. "encoded contents of bytevector @var{utf}.")
  1754. #define FUNC_NAME s_scm_utf8_to_string
  1755. {
  1756. SCM str;
  1757. const char *c_utf;
  1758. size_t c_utf_len = 0;
  1759. SCM_VALIDATE_BYTEVECTOR (1, utf);
  1760. c_utf_len = SCM_BYTEVECTOR_LENGTH (utf);
  1761. c_utf = (char *) SCM_BYTEVECTOR_CONTENTS (utf);
  1762. str = scm_from_utf8_stringn (c_utf, c_utf_len);
  1763. return (str);
  1764. }
  1765. #undef FUNC_NAME
  1766. SCM_DEFINE (scm_utf16_to_string, "utf16->string",
  1767. 1, 1, 0,
  1768. (SCM utf, SCM endianness),
  1769. "Return a newly allocate string that contains from the UTF-16-"
  1770. "encoded contents of bytevector @var{utf}.")
  1771. #define FUNC_NAME s_scm_utf16_to_string
  1772. {
  1773. UTF_TO_STRING (16);
  1774. }
  1775. #undef FUNC_NAME
  1776. SCM_DEFINE (scm_utf32_to_string, "utf32->string",
  1777. 1, 1, 0,
  1778. (SCM utf, SCM endianness),
  1779. "Return a newly allocate string that contains from the UTF-32-"
  1780. "encoded contents of bytevector @var{utf}.")
  1781. #define FUNC_NAME s_scm_utf32_to_string
  1782. {
  1783. UTF_TO_STRING (32);
  1784. }
  1785. #undef FUNC_NAME
  1786. /* Initialization. */
  1787. void
  1788. scm_bootstrap_bytevectors (void)
  1789. {
  1790. /* This must be instantiated here because the generalized-vector API may
  1791. want to access bytevectors even though `(rnrs bytevectors)' hasn't been
  1792. loaded. */
  1793. scm_null_bytevector = make_bytevector (0, SCM_ARRAY_ELEMENT_TYPE_VU8);
  1794. scm_endianness_big = sym_big = scm_from_latin1_symbol ("big");
  1795. scm_endianness_little = sym_little = scm_from_latin1_symbol ("little");
  1796. #ifdef WORDS_BIGENDIAN
  1797. scm_i_native_endianness = sym_big;
  1798. #else
  1799. scm_i_native_endianness = sym_little;
  1800. #endif
  1801. scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
  1802. "scm_init_bytevectors",
  1803. (scm_t_extension_init_func) scm_init_bytevectors,
  1804. NULL);
  1805. scm_i_register_vector_constructor
  1806. (scm_i_array_element_types[SCM_ARRAY_ELEMENT_TYPE_VU8],
  1807. scm_make_bytevector);
  1808. }
  1809. void
  1810. scm_init_bytevectors (void)
  1811. {
  1812. #include "bytevectors.x"
  1813. }