bytevectors.c 62 KB

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