bytevectors.c 61 KB

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