Update TNG build system
[alexxy/gromacs.git] / src / external / tng_io / src / lib / tng_io.c
1 /* This code is part of the tng binary trajectory format.
2  *
3  * Written by Magnus Lundborg
4  * Copyright (c) 2012-2014, The GROMACS development team.
5  * Check out http://www.gromacs.org for more information.
6  *
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the Revised BSD License.
10  */
11
12 #ifdef USE_STD_INTTYPES_H
13 #include <inttypes.h>
14 #endif
15
16 #include <limits.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20 #include <math.h>
21 #ifdef USE_ZLIB
22 #include <zlib.h>
23 #endif
24
25 #include "tng/tng_io.h"
26 #include "tng/md5.h"
27 #include "compression/tng_compress.h"
28 #include "tng/version.h"
29
30
31 struct tng_bond {
32     /** One of the atoms of the bond */
33     int64_t from_atom_id;
34     /** The other atom of the bond */
35     int64_t to_atom_id;
36 };
37
38 struct tng_atom {
39     /** The residue containing this atom */
40     tng_residue_t residue;
41     /** A unique (per molecule) ID number of the atom */
42     int64_t id;
43     /** The atom_type (depending on the forcefield) */
44     char *atom_type;
45     /** The name of the atom */
46     char *name;
47 };
48
49 struct tng_residue {
50     /** The chain containing this residue */
51     tng_chain_t chain;
52     /** A unique (per chain) ID number of the residue */
53     int64_t id;
54     /** The name of the residue */
55     char *name;
56     /** The number of atoms in the residue */
57     int64_t n_atoms;
58     /** A list of atoms in the residue */
59     int64_t atoms_offset;
60 };
61
62 struct tng_chain {
63     /** The molecule containing this chain */
64     tng_molecule_t molecule;
65     /** A unique (per molecule) ID number of the chain */
66     int64_t id;
67     /** The name of the chain */
68     char *name;
69     /** The number of residues in the chain */
70     int64_t n_residues;
71     /** A list of residues in the chain */
72     tng_residue_t residues;
73 };
74
75 struct tng_molecule {
76     /** A unique ID number of the molecule */
77     int64_t id;
78     /** Quaternary structure of the molecule.
79      *  1 => monomeric
80      *  2 => dimeric
81      *  3 => trimeric
82      *  etc */
83     int64_t quaternary_str;
84     /** The number of chains in the molecule */
85     int64_t n_chains;
86     /** The number of residues in the molecule */
87     int64_t n_residues;
88     /** The number of atoms in the molecule */
89     int64_t n_atoms;
90     /** The number of bonds in the molecule. If the bonds are not specified this
91      * value can be 0. */
92     int64_t n_bonds;
93     /** The name of the molecule */
94     char *name;
95     /** A list of chains in the molecule */
96     tng_chain_t chains;
97     /** A list of residues in the molecule */
98     tng_residue_t residues;
99     /** A list of the atoms in the molecule */
100     tng_atom_t atoms;
101     /** A list of the bonds in the molecule */
102     tng_bond_t bonds;
103 };
104
105 struct tng_gen_block {
106     /** The size of the block header in bytes */
107     int64_t header_contents_size;
108     /** The size of the block contents in bytes */
109     int64_t block_contents_size;
110     /** The ID of the block to determine its type */
111     int64_t id;
112     /** The MD5 hash of the block to verify integrity */
113     char md5_hash[TNG_MD5_HASH_LEN];
114     /** The name of the block */
115     char *name;
116     /** The library version used to write the block */
117     int64_t block_version;
118     int64_t alt_hash_type;
119     int64_t alt_hash_len;
120     char *alt_hash;
121     int64_t signature_type;
122     int64_t signature_len;
123     char *signature;
124     /** The full block header contents */
125     char *header_contents;
126     /** The full block contents */
127     char *block_contents;
128 };
129
130 struct tng_particle_mapping {
131     /** The index number of the first particle in this mapping block */
132     int64_t num_first_particle;
133     /** The number of particles list in this mapping block */
134     int64_t n_particles;
135     /** the mapping of index numbers to the real particle numbers in the
136      * trajectory. real_particle_numbers[0] is the real particle number
137      * (as it is numbered in the molecular system) of the first particle
138      * in the data blocks covered by this particle mapping block */
139     int64_t *real_particle_numbers;
140 };
141
142 struct tng_trajectory_frame_set {
143     /** The number of different particle mapping blocks present. */
144     int64_t n_mapping_blocks;
145     /** The atom mappings of this frame set */
146     struct tng_particle_mapping *mappings;
147     /** The first frame of this frame set */
148     int64_t first_frame;
149     /** The number of frames in this frame set */
150     int64_t n_frames;
151     /** The number of written frames in this frame set (used when writing one
152      * frame at a time). */
153     int64_t n_written_frames;
154     /** The number of frames not yet written to file in this frame set
155      * (used from the utility functions to finish the writing properly. */
156     int64_t n_unwritten_frames;
157
158
159     /** A list of the number of each molecule type - only used when using
160      * variable number of atoms */
161     int64_t *molecule_cnt_list;
162     /** The number of particles/atoms - only used when using variable number
163      * of atoms */
164     int64_t n_particles;
165     /** The file position of the next frame set */
166     int64_t next_frame_set_file_pos;
167     /** The file position of the previous frame set */
168     int64_t prev_frame_set_file_pos;
169     /** The file position of the frame set one long stride step ahead */
170     int64_t medium_stride_next_frame_set_file_pos;
171     /** The file position of the frame set one long stride step behind */
172     int64_t medium_stride_prev_frame_set_file_pos;
173     /** The file position of the frame set one long stride step ahead */
174     int64_t long_stride_next_frame_set_file_pos;
175     /** The file position of the frame set one long stride step behind */
176     int64_t long_stride_prev_frame_set_file_pos;
177     /** Time stamp (in seconds) of first frame in frame set */
178     double first_frame_time;
179
180     /* The data blocks in a frame set are trajectory data blocks */
181     /** The number of trajectory data blocks of particle dependent data */
182     int n_particle_data_blocks;
183     /** A list of data blocks containing particle dependent data */
184     struct tng_particle_data *tr_particle_data;
185     /** The number of trajectory data blocks independent of particles */
186     int n_data_blocks;
187     /** A list of data blocks containing particle indepdendent data */
188     struct tng_non_particle_data *tr_data;
189 };
190
191 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
192 /* FIXME: Make only one data block struct */
193 struct tng_particle_data {
194     /** The block ID of the data block containing this particle data.
195      *  This is used to determine the kind of data that is stored */
196     int64_t block_id;
197     /** The name of the data block. This is used to determine the kind of
198      *  data that is stored */
199     char *block_name;
200     /** The type of data stored. */
201     char datatype;
202     /** The frame number of the first data value */
203     int64_t first_frame_with_data;
204     /** The number of frames in this frame set */
205     int64_t n_frames;
206     /** The number of values stored per frame */
207     int64_t n_values_per_frame;
208     /** The number of frames between each data point - e.g. when
209      *  storing sparse data. */
210     int64_t stride_length;
211     /** ID of the CODEC used for compression 0 == no compression. */
212     int64_t codec_id;
213     /** If reading one frame at a time this is the last read frame */
214     int64_t last_retrieved_frame;
215     /** The multiplier used for getting integer values for compression */
216     double compression_multiplier;
217     /** A 1-dimensional array of values of length
218      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
219     void *values;
220     /** If storing character data store it in a 3-dimensional array */
221     char ****strings;
222 };
223
224 struct tng_non_particle_data {
225     /** The ID of the data block */
226     int64_t block_id;
227     /** The name of the data block. This is used to determine the kind of
228      *  data that is stored */
229     char *block_name;
230     /** The type of data stored. */
231     char datatype;
232     /** The first frame number of the first data value */
233     int64_t first_frame_with_data;
234     /** The number of frames in this data block */
235     int64_t n_frames;
236     /** The number of values stored per frame */
237     int64_t n_values_per_frame;
238     /** The number of frames between each data value, e.g. if storing data
239      *  that is not saved every frame. */
240     int64_t stride_length;
241     /** ID of the CODEC used for compression. 0 == no compression. */
242     int64_t codec_id;
243     /** If reading one frame at a time this is the last read frame */
244     int64_t last_retrieved_frame;
245     /** Compressed data is stored as integers. This compression multiplier is
246      *  the multiplication factor to convert from integer to float/double */
247     double compression_multiplier;
248     /** A 1-dimensional array of values of length
249      *  [sizeof (datatype)] * n_frames * n_values_per_frame */
250     void *values;
251     /** If storing character data store it in a 2-dimensional array */
252     char ***strings;
253 };
254
255
256
257 struct tng_trajectory {
258     /** The path of the input trajectory file */
259     char *input_file_path;
260     /** A handle to the input file */
261     FILE *input_file;
262     /** The length of the input file */
263     long input_file_len;
264     /** The path of the output trajectory file */
265     char *output_file_path;
266     /** A handle to the output file */
267     FILE *output_file;
268     /** Function to swap 32 bit values to and from the endianness of the
269      * input file */
270     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
271     /** Function to swap 64 bit values to and from the endianness of the
272      * input file */
273     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
274     /** Function to swap 32 bit values to and from the endianness of the
275      * input file */
276     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
277     /** Function to swap 64 bit values to and from the endianness of the
278      * input file */
279     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
280     /** The endianness of 32 bit values of the current computer */
281     char endianness_32;
282     /** The endianness of 64 bit values of the current computer */
283     char endianness_64;
284
285     /** The name of the program producing this trajectory */
286     char *first_program_name;
287     /** The forcefield used in the simulations */
288     char *forcefield_name;
289     /** The name of the user running the simulations */
290     char *first_user_name;
291     /** The name of the computer on which the simulations were performed */
292     char *first_computer_name;
293     /** The PGP signature of the user creating the file. */
294     char *first_pgp_signature;
295     /** The name of the program used when making last modifications to the
296      *  file */
297     char *last_program_name;
298     /** The name of the user making the last modifications to the file */
299     char *last_user_name;
300     /** The name of the computer on which the last modifications were made */
301     char *last_computer_name;
302     /** The PGP signature of the user making the last modifications to the
303      *  file. */
304     char *last_pgp_signature;
305     /** The time (n seconds since 1970) when the file was created */
306     int64_t time;
307     /** The exponential of the value of the distance unit used. The default
308      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
309      * the measurements are in Ã… the distance_unit_exponential = -10. */
310     int64_t distance_unit_exponential;
311
312     /** A flag indicating if the number of atoms can vary throughout the
313      *  simulation, e.g. using a grand canonical ensemble */
314     char var_num_atoms_flag;
315     /** The number of frames in a frame set. It is allowed to have frame sets
316      *  with fewer frames, but this will help searching for specific frames */
317     int64_t frame_set_n_frames;
318     /** The number of frame sets in a medium stride step */
319     int64_t medium_stride_length;
320     /** The number of frame sets in a long stride step */
321     int64_t long_stride_length;
322     /** The current (can change from one frame set to another) time length
323      *  (in seconds) of one frame */
324     double time_per_frame;
325
326     /** The number of different kinds of molecules in the trajectory */
327     int64_t n_molecules;
328     /** A list of molecules in the trajectory */
329     tng_molecule_t molecules;
330     /** A list of the count of each molecule - if using variable number of
331      *  particles this will be specified in each frame set */
332     int64_t *molecule_cnt_list;
333     /** The total number of particles/atoms. If using variable number of
334      *  particles this will be specified in each frame set */
335     int64_t n_particles;
336
337      /** The pos in the src file of the first frame set */
338     int64_t first_trajectory_frame_set_input_file_pos;
339     /** The pos in the dest file of the first frame set */
340     int64_t first_trajectory_frame_set_output_file_pos;
341     /** The pos in the src file of the last frame set */
342     int64_t last_trajectory_frame_set_input_file_pos;
343     /** The pos in the dest file of the last frame set */
344     int64_t last_trajectory_frame_set_output_file_pos;
345     /** The currently active frame set */
346     struct tng_trajectory_frame_set current_trajectory_frame_set;
347     /** The pos in the src file of the current frame set */
348     long current_trajectory_frame_set_input_file_pos;
349     /** The pos in the dest file of the current frame set */
350     long current_trajectory_frame_set_output_file_pos;
351     /** The number of frame sets in the trajectory N.B. Not saved in file and
352      *  cannot be trusted to be up-to-date */
353     int64_t n_trajectory_frame_sets;
354
355     /* These data blocks are non-trajectory data blocks */
356     /** The number of non-frame dependent particle dependent data blocks */
357     int n_particle_data_blocks;
358     /** A list of data blocks containing particle dependent data */
359     struct tng_particle_data *non_tr_particle_data;
360
361     /** The number of frame and particle independent data blocks */
362     int n_data_blocks;
363     /** A list of frame and particle indepdendent data blocks */
364     struct tng_non_particle_data *non_tr_data;
365
366     /** TNG compression algorithm for compressing positions */
367     int *compress_algo_pos;
368     /** TNG compression algorithm for compressing velocities */
369     int *compress_algo_vel;
370     /** The precision used for lossy compression */
371     double compression_precision;
372 };
373
374 #ifndef USE_WINDOWS
375 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
376 #define USE_WINDOWS
377 #endif /* win32... */
378 #endif /* not defined USE_WINDOWS */
379
380 #ifdef USE_WINDOWS
381 #define TNG_INLINE __inline
382 #define TNG_SNPRINTF _snprintf
383 #else
384 #define TNG_INLINE inline
385 #define TNG_SNPRINTF snprintf
386 #endif
387
388 static TNG_INLINE int tng_min_i(int a, int b)
389 {
390     return (a < b ? a : b);
391 }
392
393 /*
394 static TNG_INLINE int tng_max_i(int a, int b)
395 {
396     return (a > b ? a : b);
397 }
398 */
399 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
400 {
401     return (a < b ? a : b);
402 }
403
404 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
405 {
406     return (a > b ? a : b);
407 }
408
409 /*
410 static TNG_INLINE float tng_min_f(float a, float b)
411 {
412     return (a < b ? a : b);
413 }
414
415 static TNG_INLINE float tng_max_f(float a, float b)
416 {
417     return (a > b ? a : b);
418 }
419
420 static TNG_INLINE double tng_min_d(double a, double b)
421 {
422     return (a < b ? a : b);
423 }
424
425 static TNG_INLINE double tng_max_d(double a, double b)
426 {
427     return (a > b ? a : b);
428 }
429 */
430
431 /** This function swaps the byte order of a 32 bit numerical variable
432  * to big endian.
433  * It does not only work with integer, but e.g. floats need casting.
434  * If the byte order is already big endian no change is needed.
435  * @param tng_data is a trajectory data container.
436  * @param v is a pointer to a 32 bit numerical value (float or integer).
437  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
438  * byte order is not recognised.
439  */
440 static tng_function_status tng_swap_byte_order_big_endian_32
441                 (const tng_trajectory_t tng_data, int32_t *v)
442 {
443     switch(tng_data->endianness_32)
444     {
445     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
446         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
447              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
448              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
449              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
450
451         return(TNG_SUCCESS);
452
453     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
454         *v = ((*v & 0xFFFF0000) >> 16) |
455              ((*v & 0x0000FFFF) << 16);
456
457         return(TNG_SUCCESS);
458
459     case TNG_BIG_ENDIAN_32: /* Already correct */
460         return(TNG_SUCCESS);
461
462     default:
463         return(TNG_FAILURE);
464     }
465 }
466
467 /** This function swaps the byte order of a 64 bit numerical variable
468  * to big endian.
469  * It does not only work with integer, but e.g. floats need casting.
470  * The byte order swapping routine can convert four different byte
471  * orders to big endian.
472  * If the byte order is already big endian no change is needed.
473  * @param tng_data is a trajectory data container.
474  * @param v is a pointer to a 64 bit numerical value (double or integer).
475  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
476  * byte order is not recognised.
477  */
478 static tng_function_status tng_swap_byte_order_big_endian_64
479                 (const tng_trajectory_t tng_data, int64_t *v)
480 {
481     switch(tng_data->endianness_64)
482     {
483     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
484         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
485              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
486              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
487              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
488              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
489              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
490              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
491              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
492
493         return(TNG_SUCCESS);
494
495     case TNG_QUAD_SWAP_64: /* Byte quad swap */
496         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
497              ((*v & 0x00000000FFFFFFFFLL) << 32);
498
499         return(TNG_SUCCESS);
500
501     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
502         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
503              ((*v & 0x0000FFFF0000FFFFLL) << 16);
504
505         return(TNG_SUCCESS);
506
507     case TNG_BYTE_SWAP_64: /* Byte swap */
508         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
509              ((*v & 0x00FF00FF00FF00FFLL) << 8);
510
511         return(TNG_SUCCESS);
512
513     case TNG_BIG_ENDIAN_64: /* Already correct */
514         return(TNG_SUCCESS);
515
516     default:
517         return(TNG_FAILURE);
518     }
519 }
520
521 /** This function swaps the byte order of a 32 bit numerical variable
522  * to little endian.
523  * It does not only work with integer, but e.g. floats need casting.
524  * If the byte order is already little endian no change is needed.
525  * @param tng_data is a trajectory data container.
526  * @param v is a pointer to a 32 bit numerical value (float or integer).
527  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
528  * byte order is not recognised.
529  */
530 static tng_function_status tng_swap_byte_order_little_endian_32
531                 (const tng_trajectory_t tng_data, int32_t *v)
532 {
533     switch(tng_data->endianness_32)
534     {
535     case TNG_LITTLE_ENDIAN_32: /* Already correct */
536         return(TNG_SUCCESS);
537
538     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
539         *v = ((*v & 0xFF00FF00) >> 8) |
540              ((*v & 0x00FF00FF) << 8);
541
542         return(TNG_SUCCESS);
543
544     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
545         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
546              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
547              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
548              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
549
550         return(TNG_SUCCESS);
551
552     default:
553         return(TNG_FAILURE);
554     }
555 }
556
557 /** This function swaps the byte order of a 64 bit numerical variable
558  * to little endian.
559  * It does not only work with integer, but e.g. floats need casting.
560  * The byte order swapping routine can convert four different byte
561  * orders to little endian.
562  * If the byte order is already little endian no change is needed.
563  * @param tng_data is a trajectory data container.
564  * @param v is a pointer to a 64 bit numerical value (double or integer).
565  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
566  * byte order is not recognised.
567  */
568 static tng_function_status tng_swap_byte_order_little_endian_64
569                 (const tng_trajectory_t tng_data, int64_t *v)
570 {
571     switch(tng_data->endianness_64)
572     {
573     case TNG_LITTLE_ENDIAN_64: /* Already correct */
574         return(TNG_SUCCESS);
575
576     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
577         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
578              ((*v & 0x00FF000000FF0000LL) >> 8) |
579              ((*v & 0x0000FF000000FF00LL) << 8) |
580              ((*v & 0x000000FF000000FFLL) << 24);
581
582         return(TNG_SUCCESS);
583
584     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
585         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
586              ((*v & 0x00FF00FF00000000LL) >> 24) |
587              ((*v & 0x00000000FF00FF00LL) << 24) |
588              ((*v & 0x0000000000FF00FFLL) << 40);
589
590         return(TNG_SUCCESS);
591
592     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
593         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
594              ((*v & 0x0000FFFF00000000LL) >> 16) |
595              ((*v & 0x00000000FFFF0000LL) << 16) |
596              ((*v & 0x000000000000FFFFLL) << 48);
597
598         return(TNG_SUCCESS);
599
600     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
601         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
602              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
603              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
604              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
605              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
606              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
607              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
608              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
609
610         return(TNG_SUCCESS);
611
612     default:
613         return(TNG_FAILURE);
614     }
615 }
616 /** Generate the md5 hash of a block.
617  * The hash is created based on the actual block contents.
618  * @param block is a general block container.
619  * @return TNG_SUCCESS (0) if successful.
620  */
621 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
622 {
623     md5_state_t md5_state;
624
625     md5_init(&md5_state);
626     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
627                (int)block->block_contents_size);
628     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
629
630     return(TNG_SUCCESS);
631 }
632
633 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
634  * calculated from the current contents.
635  * If the current md5 hash is not set skip the comparison.
636  * @param block is a general block container.
637  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
638  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
639  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
640  * set.
641  */
642 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
643                                                      tng_bool *results)
644 {
645     md5_state_t md5_state;
646     char hash[TNG_MD5_HASH_LEN];
647
648     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
649
650     *results = TNG_TRUE;
651     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
652     {
653         return(TNG_FAILURE);
654     }
655     md5_init(&md5_state);
656     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
657                (int)block->block_contents_size);
658     md5_finish(&md5_state, (md5_byte_t *)hash);
659
660     if(strncmp(block->md5_hash, hash, 16) != 0)
661     {
662         *results = TNG_FALSE;
663     }
664
665     return(TNG_SUCCESS);
666 }
667
668 /** Open the input file if it is not already opened.
669  * @param tng_data is a trajectory data container.
670  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
671  * error has occured.
672  */
673 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
674 {
675     if(!tng_data->input_file)
676     {
677         if(!tng_data->input_file_path)
678         {
679             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
680                    __FILE__, __LINE__);
681             return(TNG_CRITICAL);
682         }
683         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
684         if(!tng_data->input_file)
685         {
686             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
687                    tng_data->input_file_path, __FILE__, __LINE__);
688             return(TNG_CRITICAL);
689         }
690     }
691     return(TNG_SUCCESS);
692 }
693
694 /** Open the output file if it is not already opened
695  * @param tng_data is a trajectory data container.
696  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
697  * error has occured.
698  */
699 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
700 {
701     if(!tng_data->output_file)
702     {
703         if(!tng_data->output_file_path)
704         {
705             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
706                    __FILE__, __LINE__);
707             return(TNG_CRITICAL);
708         }
709
710         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
711
712         if(!tng_data->output_file)
713         {
714             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
715                    tng_data->output_file_path, __FILE__, __LINE__);
716             return(TNG_CRITICAL);
717         }
718     }
719     return(TNG_SUCCESS);
720 }
721
722 /** Setup a file block container.
723  * @param block_p a pointer to memory to initialise as a file block container.
724  * @details Memory is allocated during initialisation.
725  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
726  * error has occured.
727  */
728 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
729 {
730     tng_gen_block_t block;
731
732     *block_p = malloc(sizeof(struct tng_gen_block));
733     if(!*block_p)
734     {
735         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
736                sizeof(struct tng_gen_block), __FILE__, __LINE__);
737         return(TNG_CRITICAL);
738     }
739
740     block = *block_p;
741
742     block->id = -1;
743     /* Reset the md5_hash */
744     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
745     block->name = 0;
746     block->block_version = TNG_API_VERSION;
747     block->header_contents = 0;
748     block->header_contents_size = 0;
749     block->block_contents = 0;
750     block->block_contents_size = 0;
751
752     return(TNG_SUCCESS);
753 }
754
755 /**
756  * @brief Clean up a file block container.
757  * @param block_p a pointer to the file block container to destroy.
758  * @details All allocated memory in the data structure is freed, as well as
759  * block_p itself.
760  * @return TNG_SUCCESS (0) if successful.
761  */
762 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
763 {
764     tng_gen_block_t block = *block_p;
765
766     if(!*block_p)
767     {
768         return(TNG_SUCCESS);
769     }
770
771 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
772     if(block->name)
773     {
774         free(block->name);
775         block->name = 0;
776     }
777     if(block->header_contents)
778     {
779         free(block->header_contents);
780         block->header_contents = 0;
781     }
782     if(block->block_contents)
783     {
784         free(block->block_contents);
785         block->block_contents = 0;
786     }
787
788     free(*block_p);
789     *block_p = 0;
790
791     return(TNG_SUCCESS);
792 }
793
794 /** Read the header of a data block, regardless of its type
795  * @param tng_data is a trajectory data container.
796  * @param block is a general block container.
797  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
798  * error has occured (not able to read the header size, thus skipping
799  * the block) or TNG_CRITICAL (2) if a major error has occured.
800  */
801 static tng_function_status tng_block_header_read
802                 (tng_trajectory_t tng_data, tng_gen_block_t block)
803 {
804     int len, offset = 0;
805
806     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
807
808     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
809     {
810         return(TNG_CRITICAL);
811     }
812
813     /* First read the header size to be able to read the whole header. */
814     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
815         1, tng_data->input_file) == 0)
816     {
817         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
818                __FILE__, __LINE__);
819         return(TNG_CRITICAL);
820     }
821
822     if(block->header_contents_size == 0)
823     {
824         block->id = -1;
825         return(TNG_FAILURE);
826     }
827
828     /* If this was the size of the general info block check the endianness */
829     if(ftell(tng_data->input_file) < 9)
830     {
831         /* File is little endian */
832         if ( *((const char*)&block->header_contents_size) != 0x00 &&
833              *((const char*)(&block->header_contents_size) + 7) == 0x00)
834         {
835             /* If the architecture endianness is little endian no byte swap
836              * will be needed. Otherwise use the functions to swap to little
837              * endian */
838             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
839             {
840                 tng_data->input_endianness_swap_func_32 = 0;
841             }
842             else
843             {
844                 tng_data->input_endianness_swap_func_32 =
845                 &tng_swap_byte_order_little_endian_32;
846             }
847             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
848             {
849                 tng_data->input_endianness_swap_func_64 = 0;
850             }
851             else
852             {
853                 tng_data->input_endianness_swap_func_64 =
854                 &tng_swap_byte_order_little_endian_64;
855             }
856         }
857         /* File is big endian */
858         else
859         {
860             /* If the architecture endianness is big endian no byte swap
861              * will be needed. Otherwise use the functions to swap to big
862              * endian */
863             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
864             {
865                 tng_data->input_endianness_swap_func_32 = 0;
866             }
867             else
868             {
869                 tng_data->input_endianness_swap_func_32 =
870                 &tng_swap_byte_order_big_endian_32;
871             }
872             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
873             {
874                 tng_data->input_endianness_swap_func_64 = 0;
875             }
876             else
877             {
878                 tng_data->input_endianness_swap_func_64 =
879                 &tng_swap_byte_order_big_endian_64;
880             }
881         }
882     }
883
884     if(tng_data->input_endianness_swap_func_64)
885     {
886         if(tng_data->input_endianness_swap_func_64(tng_data,
887                                                    &block->header_contents_size)
888             != TNG_SUCCESS)
889         {
890             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
891                     __FILE__, __LINE__);
892         }
893     }
894
895     /* Move the reading position to the beginning of the header. */
896     fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
897           SEEK_CUR);
898
899     /* If there is already memory allocated for the contents free it (we do not
900      * know if the size is correct). */
901     if(block->header_contents)
902     {
903         free(block->header_contents);
904     }
905
906     block->header_contents = malloc(block->header_contents_size);
907     if(!block->header_contents)
908     {
909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
910                block->header_contents_size, __FILE__, __LINE__);
911         return(TNG_CRITICAL);
912     }
913
914     /* Read the whole header into header_contents. This way it can be saved
915      * even if it cannot be interpreted
916      * for one reason or another. */
917     if(fread(block->header_contents, block->header_contents_size, 1,
918         tng_data->input_file) == 0)
919     {
920         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
921         return(TNG_CRITICAL);
922     }
923
924     /* The header contents size has already been read. Skip ahead. */
925     offset = sizeof(block->header_contents_size);
926
927
928     /* Copy the respective parameters from the header contents block */
929     memcpy(&block->block_contents_size, block->header_contents+offset,
930            sizeof(block->block_contents_size));
931     if(tng_data->input_endianness_swap_func_64)
932     {
933         if(tng_data->input_endianness_swap_func_64(tng_data,
934                                                    &block->block_contents_size)
935             != TNG_SUCCESS)
936         {
937             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
938                     __FILE__, __LINE__);
939         }
940     }
941
942     offset += sizeof(block->block_contents_size);
943
944     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
945     if(tng_data->input_endianness_swap_func_64)
946     {
947         if(tng_data->input_endianness_swap_func_64(tng_data,
948                                                    &block->id)
949             != TNG_SUCCESS)
950         {
951             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
952                     __FILE__, __LINE__);
953         }
954     }
955
956     offset += sizeof(block->id);
957
958     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
959     offset += TNG_MD5_HASH_LEN;
960
961     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
962     {
963         free(block->name);
964         block->name = 0;
965     }
966     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
967     if(!block->name)
968     {
969         block->name = malloc(len);
970         if(!block->name)
971         {
972             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
973                     __FILE__, __LINE__);
974             return(TNG_CRITICAL);
975         }
976         strncpy(block->name, block->header_contents+offset, len);
977     }
978     offset += len;
979
980     memcpy(&block->block_version, block->header_contents+offset,
981            sizeof(block->block_version));
982     if(tng_data->input_endianness_swap_func_64)
983     {
984         if(tng_data->input_endianness_swap_func_64(tng_data,
985                                                    &block->block_version)
986             != TNG_SUCCESS)
987         {
988             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
989                     __FILE__, __LINE__);
990         }
991     }
992
993     return(TNG_SUCCESS);
994 }
995
996 /** Write a whole block, both header and contents, regardless of it type
997  * @param tng_data is a trajectory data container.
998  * @param block is a general block container.
999  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1000  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1001  */
1002 /* Disabled until it is used.*/
1003 /*
1004 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1005 //                                                     tng_gen_block_t block)
1006 // {
1007 //     if(!block->header_contents)
1008 //     {
1009 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1010 //         return(TNG_FAILURE);
1011 //     }
1012 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1013 //                 tng_data->output_file) != 1)
1014 //     {
1015 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1016 //                 __FILE__, __LINE__);
1017 //         return(TNG_CRITICAL);
1018 //     }
1019 //
1020 //     if(!block->block_contents)
1021 //     {
1022 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1023 //                 __FILE__, __LINE__);
1024 //         return(TNG_FAILURE);
1025 //     }
1026 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1027 //                 tng_data->output_file) != 1)
1028 //     {
1029 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1030 //                 __FILE__, __LINE__);
1031 //         return(TNG_CRITICAL);
1032 //     }
1033 //     return(TNG_SUCCESS);
1034 // }
1035 */
1036
1037 /** Update the md5 hash of a block already written to the file
1038  * @param tng_data is a trajectory data container.
1039  * @param block is the block, of which to update the md5 hash.
1040  * @param header_start_pos is the file position where the block header starts.
1041  * @param contents_start_pos is the file position where the block contents
1042  * start.
1043  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1044  * error has occured.
1045  */
1046 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
1047                                                tng_gen_block_t block,
1048                                                const int64_t header_start_pos,
1049                                                const int64_t contents_start_pos)
1050 {
1051     if(block->block_contents)
1052     {
1053         free(block->block_contents);
1054     }
1055
1056     block->block_contents = malloc(block->block_contents_size);
1057     if(!block->block_contents)
1058     {
1059         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1060                block->block_contents_size, __FILE__, __LINE__);
1061         return(TNG_CRITICAL);
1062     }
1063
1064     fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
1065     if(fread(block->block_contents, block->block_contents_size, 1,
1066             tng_data->output_file) == 0)
1067     {
1068         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1069         return(TNG_CRITICAL);
1070     }
1071
1072     tng_block_md5_hash_generate(block);
1073
1074     fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
1075           SEEK_SET);
1076     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1077
1078     return(TNG_SUCCESS);
1079 }
1080
1081 /** Update the frame set pointers in the file header (general info block),
1082  * already written to disk
1083  * @param tng_data is a trajectory data container.
1084  * @param hash_mode specifies whether to update the block md5 hash when
1085  * updating the pointers.
1086  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1087  * error has occured.
1088  */
1089 static tng_function_status tng_header_pointers_update
1090                 (tng_trajectory_t tng_data, const char hash_mode)
1091 {
1092     tng_gen_block_t block;
1093     FILE *temp = tng_data->input_file;
1094     int64_t output_file_pos, pos, contents_start_pos;
1095
1096     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1097     {
1098         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1099                __FILE__, __LINE__);
1100         return(TNG_CRITICAL);
1101     }
1102
1103     tng_data->input_file = tng_data->output_file;
1104
1105     tng_block_init(&block);
1106
1107     output_file_pos = ftell(tng_data->output_file);
1108     fseek(tng_data->output_file, 0, SEEK_SET);
1109
1110     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1111     {
1112         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1113                __FILE__, __LINE__);
1114         tng_data->input_file = temp;
1115         tng_block_destroy(&block);
1116         return(TNG_CRITICAL);
1117     }
1118
1119     contents_start_pos = ftell(tng_data->output_file);
1120
1121     fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
1122           sizeof(int64_t), SEEK_CUR);
1123
1124     tng_data->input_file = temp;
1125
1126     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1127
1128     if(tng_data->input_endianness_swap_func_64)
1129     {
1130         if(tng_data->input_endianness_swap_func_64(tng_data,
1131                                                     &pos)
1132             != TNG_SUCCESS)
1133         {
1134             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1135                     __FILE__, __LINE__);
1136         }
1137     }
1138
1139     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1140     {
1141         tng_block_destroy(&block);
1142         return(TNG_CRITICAL);
1143     }
1144
1145     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1146
1147     if(tng_data->input_endianness_swap_func_64)
1148     {
1149         if(tng_data->input_endianness_swap_func_64(tng_data,
1150                                                     &pos)
1151             != TNG_SUCCESS)
1152         {
1153             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1154                     __FILE__, __LINE__);
1155         }
1156     }
1157
1158     if(fwrite(&pos,
1159         sizeof(int64_t), 1, tng_data->output_file) != 1)
1160     {
1161         tng_block_destroy(&block);
1162         return(TNG_CRITICAL);
1163     }
1164
1165     if(hash_mode == TNG_USE_HASH)
1166     {
1167         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1168     }
1169
1170     tng_block_destroy(&block);
1171
1172     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1173
1174     return(TNG_SUCCESS);
1175 }
1176
1177 /** Update the frame set pointers in the current frame set block, already
1178  * written to disk. It also updates the pointers of the blocks pointing to
1179  * the current frame set block.
1180  * @param tng_data is a trajectory data container.
1181  * @param hash_mode specifies whether to update the block md5 hash when
1182  * updating the pointers.
1183  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1184  * error has occured.
1185  */
1186 static tng_function_status tng_frame_set_pointers_update
1187                 (tng_trajectory_t tng_data, const char hash_mode)
1188 {
1189     tng_gen_block_t block;
1190     tng_trajectory_frame_set_t frame_set;
1191     FILE *temp = tng_data->input_file;
1192     int64_t pos, output_file_pos, contents_start_pos;
1193
1194     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1195     {
1196         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1197                __FILE__, __LINE__);
1198         return(TNG_CRITICAL);
1199     }
1200
1201     tng_block_init(&block);
1202     output_file_pos = ftell(tng_data->output_file);
1203
1204     tng_data->input_file = tng_data->output_file;
1205
1206     frame_set = &tng_data->current_trajectory_frame_set;
1207
1208     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1209
1210     /* Update next frame set */
1211     if(frame_set->next_frame_set_file_pos > 0)
1212     {
1213         fseek(tng_data->output_file, (long)frame_set->next_frame_set_file_pos,
1214               SEEK_SET);
1215
1216         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1217         {
1218             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1219                 __FILE__, __LINE__);
1220             tng_data->input_file = temp;
1221             tng_block_destroy(&block);
1222             return(TNG_CRITICAL);
1223         }
1224
1225         contents_start_pos = ftell(tng_data->output_file);
1226
1227         fseek(tng_data->output_file, (long)block->block_contents_size - (5 *
1228             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1229
1230         if(tng_data->input_endianness_swap_func_64)
1231         {
1232             if(tng_data->input_endianness_swap_func_64(tng_data,
1233                                                         &pos)
1234                 != TNG_SUCCESS)
1235             {
1236                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1237                         __FILE__, __LINE__);
1238             }
1239         }
1240
1241         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1242         {
1243             tng_data->input_file = temp;
1244             tng_block_destroy(&block);
1245             return(TNG_CRITICAL);
1246         }
1247
1248         if(hash_mode == TNG_USE_HASH)
1249         {
1250             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1251                                 contents_start_pos);
1252         }
1253         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1254     }
1255     /* Update previous frame set */
1256     if(frame_set->prev_frame_set_file_pos > 0)
1257     {
1258         fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
1259               SEEK_SET);
1260
1261         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1262         {
1263             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1264                 __FILE__, __LINE__);
1265             tng_data->input_file = temp;
1266             tng_block_destroy(&block);
1267             return(TNG_CRITICAL);
1268         }
1269
1270         contents_start_pos = ftell(tng_data->output_file);
1271
1272         fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
1273             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1274
1275         if(tng_data->input_endianness_swap_func_64)
1276         {
1277             if(tng_data->input_endianness_swap_func_64(tng_data,
1278                                                         &pos)
1279                 != TNG_SUCCESS)
1280             {
1281                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1282                         __FILE__, __LINE__);
1283             }
1284         }
1285
1286         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1287         {
1288             tng_data->input_file = temp;
1289             tng_block_destroy(&block);
1290             return(TNG_CRITICAL);
1291         }
1292
1293         if(hash_mode == TNG_USE_HASH)
1294         {
1295             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1296                                 contents_start_pos);
1297         }
1298         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1299     }
1300
1301     /* Update the frame set one medium stride step after */
1302     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1303     {
1304         fseek(tng_data->output_file,
1305               (long)frame_set->medium_stride_next_frame_set_file_pos,
1306               SEEK_SET);
1307
1308         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1309         {
1310             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1311                 __FILE__, __LINE__);
1312             tng_data->input_file = temp;
1313             tng_block_destroy(&block);
1314             return(TNG_CRITICAL);
1315         }
1316
1317         contents_start_pos = ftell(tng_data->output_file);
1318
1319         fseek(tng_data->output_file, (long)block->block_contents_size - (3 *
1320             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1321
1322         if(tng_data->input_endianness_swap_func_64)
1323         {
1324             if(tng_data->input_endianness_swap_func_64(tng_data,
1325                                                         &pos)
1326                 != TNG_SUCCESS)
1327             {
1328                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1329                         __FILE__, __LINE__);
1330             }
1331         }
1332
1333         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1334         {
1335             tng_data->input_file = temp;
1336             tng_block_destroy(&block);
1337             return(TNG_CRITICAL);
1338         }
1339
1340         if(hash_mode == TNG_USE_HASH)
1341         {
1342             tng_md5_hash_update(tng_data, block,
1343                                 frame_set->medium_stride_next_frame_set_file_pos,
1344                                 contents_start_pos);
1345         }
1346     }
1347     /* Update the frame set one medium stride step before */
1348     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1349     {
1350         fseek(tng_data->output_file,
1351               (long)frame_set->medium_stride_prev_frame_set_file_pos,
1352               SEEK_SET);
1353
1354         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1355         {
1356             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1357                 __FILE__, __LINE__);
1358             tng_data->input_file = temp;
1359             tng_block_destroy(&block);
1360             return(TNG_CRITICAL);
1361         }
1362
1363         contents_start_pos = ftell(tng_data->output_file);
1364
1365         fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
1366             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1367
1368         if(tng_data->input_endianness_swap_func_64)
1369         {
1370             if(tng_data->input_endianness_swap_func_64(tng_data,
1371                                                         &pos)
1372                 != TNG_SUCCESS)
1373             {
1374                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1375                         __FILE__, __LINE__);
1376             }
1377         }
1378
1379         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1380         {
1381             tng_data->input_file = temp;
1382             tng_block_destroy(&block);
1383             return(TNG_CRITICAL);
1384         }
1385
1386         if(hash_mode == TNG_USE_HASH)
1387         {
1388             tng_md5_hash_update(tng_data, block,
1389                                 frame_set->medium_stride_prev_frame_set_file_pos,
1390                                 contents_start_pos);
1391         }
1392     }
1393
1394     /* Update the frame set one long stride step after */
1395     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1396     {
1397         fseek(tng_data->output_file,
1398               (long)frame_set->long_stride_next_frame_set_file_pos,
1399               SEEK_SET);
1400
1401         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1402         {
1403             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1404                 __FILE__, __LINE__);
1405             tng_data->input_file = temp;
1406             tng_block_destroy(&block);
1407             return(TNG_CRITICAL);
1408         }
1409
1410         contents_start_pos = ftell(tng_data->output_file);
1411
1412         fseek(tng_data->output_file, (long)block->block_contents_size - (1 *
1413             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1414
1415         if(tng_data->input_endianness_swap_func_64)
1416         {
1417             if(tng_data->input_endianness_swap_func_64(tng_data,
1418                                                         &pos)
1419                 != TNG_SUCCESS)
1420             {
1421                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1422                         __FILE__, __LINE__);
1423             }
1424         }
1425
1426         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1427         {
1428             tng_data->input_file = temp;
1429             tng_block_destroy(&block);
1430             return(TNG_CRITICAL);
1431         }
1432
1433         if(hash_mode == TNG_USE_HASH)
1434         {
1435             tng_md5_hash_update(tng_data, block,
1436                                 frame_set->long_stride_next_frame_set_file_pos,
1437                                 contents_start_pos);
1438         }
1439     }
1440     /* Update the frame set one long stride step before */
1441     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1442     {
1443         fseek(tng_data->output_file,
1444               (long)frame_set->long_stride_prev_frame_set_file_pos,
1445               SEEK_SET);
1446
1447         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1448         {
1449             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1450                 __FILE__, __LINE__);
1451             tng_data->input_file = temp;
1452             tng_block_destroy(&block);
1453             return(TNG_CRITICAL);
1454         }
1455
1456         contents_start_pos = ftell(tng_data->output_file);
1457
1458         fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
1459             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1460
1461         if(tng_data->input_endianness_swap_func_64)
1462         {
1463             if(tng_data->input_endianness_swap_func_64(tng_data,
1464                                                         &pos)
1465                 != TNG_SUCCESS)
1466             {
1467                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1468                         __FILE__, __LINE__);
1469             }
1470         }
1471
1472         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1473         {
1474             tng_data->input_file = temp;
1475             tng_block_destroy(&block);
1476             return(TNG_CRITICAL);
1477         }
1478
1479         if(hash_mode == TNG_USE_HASH)
1480         {
1481             tng_md5_hash_update(tng_data, block,
1482                                 frame_set->long_stride_prev_frame_set_file_pos,
1483                                 contents_start_pos);
1484         }
1485     }
1486
1487     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1488
1489     tng_data->input_file = temp;
1490
1491     tng_block_destroy(&block);
1492
1493     return(TNG_SUCCESS);
1494 }
1495
1496 static tng_function_status tng_reread_frame_set_at_file_pos
1497                 (tng_trajectory_t tng_data,
1498                  const int64_t pos)
1499 {
1500     tng_gen_block_t block;
1501     tng_function_status stat;
1502
1503     tng_block_init(&block);
1504
1505     fseek(tng_data->input_file, pos, SEEK_SET);
1506     if(pos > 0)
1507     {
1508         stat = tng_block_header_read(tng_data, block);
1509         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1510         {
1511             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1512                     __FILE__, __LINE__);
1513             tng_block_destroy(&block);
1514             return(TNG_FAILURE);
1515         }
1516
1517         if(tng_block_read_next(tng_data, block,
1518                                TNG_SKIP_HASH) != TNG_SUCCESS)
1519         {
1520             tng_block_destroy(&block);
1521             return(TNG_CRITICAL);
1522         }
1523     }
1524
1525     tng_block_destroy(&block);
1526
1527     return(TNG_SUCCESS);
1528 }
1529
1530 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1531                 (tng_trajectory_t tng_data,
1532                  int64_t *pos)
1533 {
1534     int64_t orig_pos, curr_frame_set_pos;
1535     tng_gen_block_t block;
1536     tng_function_status stat;
1537     tng_trajectory_frame_set_t frame_set =
1538     &tng_data->current_trajectory_frame_set;
1539
1540     orig_pos = ftell(tng_data->input_file);
1541     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1542
1543     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1544
1545     if(*pos <= 0)
1546     {
1547         return(TNG_SUCCESS);
1548     }
1549
1550     fseek(tng_data->input_file, *pos, SEEK_SET);
1551
1552     tng_block_init(&block);
1553     /* Read block headers first to see that a frame set block is found. */
1554     stat = tng_block_header_read(tng_data, block);
1555     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1556     {
1557         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1558                 __FILE__, __LINE__);
1559         tng_block_destroy(&block);
1560         return(TNG_FAILURE);
1561     }
1562
1563     if(tng_block_read_next(tng_data, block,
1564                            TNG_SKIP_HASH) != TNG_SUCCESS)
1565     {
1566         tng_block_destroy(&block);
1567         return(TNG_CRITICAL);
1568     }
1569
1570     /* Read all frame set blocks (not the blocks between them) */
1571     while(frame_set->next_frame_set_file_pos > 0)
1572     {
1573         fseek(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1574         stat = tng_block_header_read(tng_data, block);
1575         if(stat == TNG_CRITICAL)
1576         {
1577             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1578                     __FILE__, __LINE__);
1579             tng_block_destroy(&block);
1580             return(TNG_CRITICAL);
1581         }
1582         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1583         {
1584             return(TNG_FAILURE);
1585         }
1586
1587         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1588         if(stat != TNG_SUCCESS)
1589         {
1590             tng_block_destroy(&block);
1591             return(stat);
1592         }
1593         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1594         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1595            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1596         {
1597             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1598         }
1599     }
1600
1601     /* Re-read the frame set that used to be the current one */
1602     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1603
1604     fseek(tng_data->input_file, orig_pos, SEEK_SET);
1605
1606     tng_block_destroy(&block);
1607
1608     return(TNG_SUCCESS);
1609 }
1610
1611 static tng_function_status tng_frame_set_complete_migrate
1612                 (tng_trajectory_t tng_data,
1613                  int64_t block_start_pos,
1614                  int64_t block_len,
1615                  int64_t new_pos)
1616 {
1617     int64_t i;
1618     tng_bool updated = TNG_FALSE;
1619
1620     char *contents;
1621
1622     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1623     {
1624         return(TNG_CRITICAL);
1625     }
1626
1627     fseek(tng_data->input_file, block_start_pos, SEEK_SET);
1628
1629     contents = malloc(block_len);
1630     if(!contents)
1631     {
1632         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1633                 block_len, __FILE__, __LINE__);
1634         return(TNG_CRITICAL);
1635     }
1636
1637     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1638     {
1639         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1640                __FILE__, __LINE__);
1641         free(contents);
1642         return(TNG_CRITICAL);
1643     }
1644     fseek(tng_data->output_file, new_pos, SEEK_SET);
1645
1646     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1647     {
1648         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1649                 __FILE__, __LINE__);
1650         free(contents);
1651         return(TNG_CRITICAL);
1652     }
1653
1654     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1655
1656     tng_frame_set_pointers_update(tng_data, TNG_USE_HASH);
1657
1658     /* Update the general info block if needed */
1659     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1660     {
1661         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1662         updated = TNG_TRUE;
1663     }
1664     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1665     {
1666         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1667         updated = TNG_TRUE;
1668     }
1669     if(updated)
1670     {
1671         tng_header_pointers_update(tng_data, TNG_USE_HASH);
1672     }
1673
1674     /* Fill the block with NULL to avoid confusion. */
1675     for(i = 0; i < block_len; i++)
1676     {
1677         contents[i] = '\0';
1678     }
1679     fseek(tng_data->output_file, block_start_pos, SEEK_SET);
1680
1681     /* FIXME: casting block_len to size_t is dangerous */
1682     fwrite(contents, 1, block_len, tng_data->output_file);
1683
1684     free(contents);
1685
1686     return(TNG_SUCCESS);
1687 }
1688
1689 static tng_function_status tng_length_of_current_frame_set_contents_get
1690                 (tng_trajectory_t tng_data,
1691                  int64_t *len)
1692 {
1693     int64_t orig_pos, pos, curr_frame_set_pos;
1694     tng_gen_block_t block;
1695     tng_function_status stat;
1696
1697     orig_pos = ftell(tng_data->input_file);
1698     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1699
1700     *len = 0;
1701
1702     fseek(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1703
1704     tng_block_init(&block);
1705     /* Read block headers first to see that a frame set block is found. */
1706     stat = tng_block_header_read(tng_data, block);
1707     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1708     {
1709         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
1710                 curr_frame_set_pos, __FILE__, __LINE__);
1711         tng_block_destroy(&block);
1712         return(TNG_FAILURE);
1713     }
1714
1715     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1716     while(stat == TNG_SUCCESS)
1717     {
1718         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1719         *len += block->header_contents_size + block->block_contents_size;
1720         pos += block->header_contents_size + block->block_contents_size;
1721         if(pos >= tng_data->input_file_len)
1722         {
1723             break;
1724         }
1725         stat = tng_block_header_read(tng_data, block);
1726         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1727         {
1728             break;
1729         }
1730     }
1731
1732     /* Re-read the frame set that used to be the current one */
1733     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1734
1735     fseek(tng_data->input_file, orig_pos, SEEK_SET);
1736
1737     tng_block_destroy(&block);
1738
1739     return(TNG_SUCCESS);
1740 }
1741
1742 /** Migrate blocks in the file to make room for new data in a block. This
1743  * is required e.g. when adding data to a block or extending strings in a
1744  * block.
1745  * @param tng_data is a trajectory data container.
1746  * @param start_pos is the position from which to start moving data, usually
1747  * the byte after the end of the block to which data was added.
1748  * @param offset is the number of bytes that were inserted.
1749  * @details Trajectory blocks (frame sets and their related blocks) are moved
1750  * to the end of the file (if needed) in order to make room for non-trajectory
1751  * data.
1752  */
1753 static tng_function_status tng_migrate_data_in_file
1754                 (tng_trajectory_t tng_data,
1755                  int64_t start_pos,
1756                  int64_t offset)
1757 {
1758     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1759     tng_gen_block_t block;
1760     tng_function_status stat;
1761     FILE *temp;
1762
1763     if(offset <= 0)
1764     {
1765         return(TNG_SUCCESS);
1766     }
1767
1768     temp = tng_data->input_file;
1769
1770     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1771     if(stat != TNG_SUCCESS)
1772     {
1773         tng_data->input_file = temp;
1774         return(stat);
1775     }
1776
1777     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1778
1779     empty_space = traj_start_pos - (start_pos - 1);
1780
1781     if(empty_space >= offset)
1782     {
1783         return(TNG_SUCCESS);
1784     }
1785
1786     orig_file_pos = ftell(tng_data->input_file);
1787     tng_block_init(&block);
1788
1789     while(empty_space < offset)
1790     {
1791         fseek(tng_data->input_file, traj_start_pos, SEEK_SET);
1792         stat = tng_block_header_read(tng_data, block);
1793         if(stat == TNG_CRITICAL)
1794         {
1795             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1796                     __FILE__, __LINE__);
1797             tng_block_destroy(&block);
1798             tng_data->input_file = temp;
1799             return(TNG_CRITICAL);
1800         }
1801         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1802         {
1803             tng_data->input_file = temp;
1804             tng_block_destroy(&block);
1805             return(TNG_FAILURE);
1806         }
1807         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1808         if(stat != TNG_SUCCESS)
1809         {
1810             tng_data->input_file = temp;
1811             tng_block_destroy(&block);
1812             return(stat);
1813         }
1814         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1815                                               frame_set_length, tng_data->input_file_len);
1816         if(stat != TNG_SUCCESS)
1817         {
1818             tng_data->input_file = temp;
1819             tng_block_destroy(&block);
1820             return(stat);
1821         }
1822
1823         empty_space += frame_set_length;
1824     }
1825     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
1826     tng_block_destroy(&block);
1827
1828     return(TNG_SUCCESS);
1829 }
1830
1831 static tng_function_status tng_block_header_len_calculate
1832                 (const tng_trajectory_t tng_data,
1833                  tng_gen_block_t block,
1834                  int64_t *len)
1835 {
1836     int name_len;
1837     (void)tng_data;
1838
1839     /* If the string is unallocated allocate memory for just string
1840      * termination */
1841     if(!block->name)
1842     {
1843         block->name = malloc(1);
1844         if(!block->name)
1845         {
1846             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1847                    __FILE__, __LINE__);
1848             return(TNG_CRITICAL);
1849         }
1850         block->name[0] = 0;
1851     }
1852
1853     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1854
1855     /* Calculate the size of the header to write */
1856     *len = sizeof(block->header_contents_size) +
1857                   sizeof(block->block_contents_size) +
1858                   sizeof(block->id) +
1859                   sizeof(block->block_version) +
1860                   TNG_MD5_HASH_LEN +
1861                   name_len;
1862
1863     return (TNG_SUCCESS);
1864 }
1865
1866 /** Write the header of a data block, regardless of its type
1867  * @param tng_data is a trajectory data container.
1868  * @param block is a general block container.
1869  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1870  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1871  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1872  * error has occured.
1873  */
1874 static tng_function_status tng_block_header_write
1875                 (tng_trajectory_t tng_data,
1876                  tng_gen_block_t block,
1877                  const char hash_mode)
1878 {
1879     int name_len, offset = 0;
1880
1881     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1882
1883     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1884     {
1885         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1886                __FILE__, __LINE__);
1887         return(TNG_CRITICAL);
1888     }
1889
1890     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
1891         TNG_SUCCESS)
1892     {
1893         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
1894                 __FILE__, __LINE__);
1895         return(TNG_CRITICAL);
1896     }
1897
1898     if(hash_mode == TNG_USE_HASH)
1899     {
1900         tng_block_md5_hash_generate(block);
1901     }
1902
1903     if(block->header_contents)
1904     {
1905         free(block->header_contents);
1906     }
1907
1908     block->header_contents = malloc(block->header_contents_size);
1909     if(!block->header_contents)
1910     {
1911         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1912                block->header_contents_size, __FILE__, __LINE__);
1913         return(TNG_CRITICAL);
1914     }
1915
1916     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1917
1918     /* First copy all data into the header_contents block and finally write
1919      * the whole block at once. */
1920     memcpy(block->header_contents, &block->header_contents_size,
1921            sizeof(block->header_contents_size));
1922     if(tng_data->output_endianness_swap_func_64)
1923     {
1924         if(tng_data->output_endianness_swap_func_64(tng_data,
1925                                       (int64_t *)block->header_contents+offset)
1926             != TNG_SUCCESS)
1927         {
1928             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1929                     __FILE__, __LINE__);
1930         }
1931     }
1932     offset += sizeof(block->header_contents_size);
1933
1934     memcpy(block->header_contents+offset, &block->block_contents_size,
1935            sizeof(block->block_contents_size));
1936     if(tng_data->output_endianness_swap_func_64)
1937     {
1938         if(tng_data->output_endianness_swap_func_64(tng_data,
1939                                       (int64_t *)block->header_contents+offset)
1940             != TNG_SUCCESS)
1941         {
1942             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1943                     __FILE__, __LINE__);
1944         }
1945     }
1946     offset += sizeof(block->block_contents_size);
1947
1948     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1949     if(tng_data->output_endianness_swap_func_64)
1950     {
1951         if(tng_data->output_endianness_swap_func_64(tng_data,
1952                                       (int64_t *)block->header_contents+offset)
1953             != TNG_SUCCESS)
1954         {
1955             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1956                     __FILE__, __LINE__);
1957         }
1958     }
1959     offset += sizeof(block->id);
1960
1961     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1962     offset += TNG_MD5_HASH_LEN;
1963
1964     strncpy(block->header_contents+offset, block->name, name_len);
1965     offset += name_len;
1966
1967     memcpy(block->header_contents+offset, &block->block_version,
1968            sizeof(block->block_version));
1969     if(tng_data->output_endianness_swap_func_64)
1970     {
1971         if(tng_data->output_endianness_swap_func_64(tng_data,
1972                                       (int64_t *)block->header_contents+offset)
1973             != TNG_SUCCESS)
1974         {
1975             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1976                     __FILE__, __LINE__);
1977         }
1978     }
1979
1980     if(fwrite(block->header_contents, block->header_contents_size,
1981        1, tng_data->output_file) != 1)
1982     {
1983         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1984         return(TNG_CRITICAL);
1985     }
1986     return(TNG_SUCCESS);
1987 }
1988
1989 static tng_function_status tng_general_info_block_len_calculate
1990                 (tng_trajectory_t tng_data,
1991                  int64_t *len)
1992 {
1993     int first_program_name_len, first_user_name_len;
1994     int first_computer_name_len, first_pgp_signature_len;
1995     int last_program_name_len, last_user_name_len;
1996     int last_computer_name_len, last_pgp_signature_len;
1997     int forcefield_name_len;
1998
1999     /* If the strings are unallocated allocate memory for just string
2000      * termination */
2001     if(!tng_data->first_program_name)
2002     {
2003         tng_data->first_program_name = malloc(1);
2004         if(!tng_data->first_program_name)
2005         {
2006             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2007                    __FILE__, __LINE__);
2008             return(TNG_CRITICAL);
2009         }
2010         tng_data->first_program_name[0] = 0;
2011     }
2012     if(!tng_data->last_program_name)
2013     {
2014         tng_data->last_program_name = malloc(1);
2015         if(!tng_data->last_program_name)
2016         {
2017             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2018                    __FILE__, __LINE__);
2019             return(TNG_CRITICAL);
2020         }
2021         tng_data->last_program_name[0] = 0;
2022     }
2023     if(!tng_data->first_user_name)
2024     {
2025         tng_data->first_user_name = malloc(1);
2026         if(!tng_data->first_user_name)
2027         {
2028             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2029                    __FILE__, __LINE__);
2030             return(TNG_CRITICAL);
2031         }
2032         tng_data->first_user_name[0] = 0;
2033     }
2034     if(!tng_data->last_user_name)
2035     {
2036         tng_data->last_user_name = malloc(1);
2037         if(!tng_data->last_user_name)
2038         {
2039             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2040                    __FILE__, __LINE__);
2041             return(TNG_CRITICAL);
2042         }
2043         tng_data->last_user_name[0] = 0;
2044     }
2045     if(!tng_data->first_computer_name)
2046     {
2047         tng_data->first_computer_name = malloc(1);
2048         if(!tng_data->first_computer_name)
2049         {
2050             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2051                    __FILE__, __LINE__);
2052             return(TNG_CRITICAL);
2053         }
2054         tng_data->first_computer_name[0] = 0;
2055     }
2056     if(!tng_data->last_computer_name)
2057     {
2058         tng_data->last_computer_name = malloc(1);
2059         if(!tng_data->last_computer_name)
2060         {
2061             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2062                    __FILE__, __LINE__);
2063             return(TNG_CRITICAL);
2064         }
2065         tng_data->last_computer_name[0] = 0;
2066     }
2067     if(!tng_data->first_pgp_signature)
2068     {
2069         tng_data->first_pgp_signature = malloc(1);
2070         if(!tng_data->first_pgp_signature)
2071         {
2072             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2073                    __FILE__, __LINE__);
2074             return(TNG_CRITICAL);
2075         }
2076         tng_data->first_pgp_signature[0] = 0;
2077     }
2078     if(!tng_data->last_pgp_signature)
2079     {
2080         tng_data->last_pgp_signature = malloc(1);
2081         if(!tng_data->last_pgp_signature)
2082         {
2083             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2084                    __FILE__, __LINE__);
2085             return(TNG_CRITICAL);
2086         }
2087         tng_data->last_pgp_signature[0] = 0;
2088     }
2089     if(!tng_data->forcefield_name)
2090     {
2091         tng_data->forcefield_name = malloc(1);
2092         if(!tng_data->forcefield_name)
2093         {
2094             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2095                    __FILE__, __LINE__);
2096             return(TNG_CRITICAL);
2097         }
2098         tng_data->forcefield_name[0] = 0;
2099     }
2100
2101     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2102                            TNG_MAX_STR_LEN);
2103     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2104                            TNG_MAX_STR_LEN);
2105     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2106                         TNG_MAX_STR_LEN);
2107     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2108                         TNG_MAX_STR_LEN);
2109     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2110                             TNG_MAX_STR_LEN);
2111     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2112                             TNG_MAX_STR_LEN);
2113     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2114                             TNG_MAX_STR_LEN);
2115     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2116                             TNG_MAX_STR_LEN);
2117     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2118                               TNG_MAX_STR_LEN);
2119
2120     *len = sizeof(tng_data->time) +
2121                   sizeof(tng_data->var_num_atoms_flag) +
2122                   sizeof(tng_data->frame_set_n_frames) +
2123                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2124                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2125                   sizeof(tng_data->medium_stride_length) +
2126                   sizeof(tng_data->long_stride_length) +
2127                   sizeof(tng_data->distance_unit_exponential) +
2128                   first_program_name_len +
2129                   last_program_name_len +
2130                   first_user_name_len +
2131                   last_user_name_len +
2132                   first_computer_name_len +
2133                   last_computer_name_len +
2134                   first_pgp_signature_len +
2135                   last_pgp_signature_len +
2136                   forcefield_name_len;
2137
2138     return(TNG_SUCCESS);
2139 }
2140
2141 /** Read a general info block. This is the first block of a TNG file.
2142  *  Populate the fields in tng_data.
2143  * @param tng_data is a trajectory data container.
2144  * @param block is a general block container.
2145  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2146  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2147  * compared to the md5 hash of the read contents to ensure valid data.
2148  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2149  * error has occured.
2150  */
2151 static tng_function_status tng_general_info_block_read
2152                 (tng_trajectory_t tng_data, tng_gen_block_t block,
2153                  const char hash_mode)
2154 {
2155     int len, offset = 0;
2156     tng_bool same_hash;
2157
2158     void *temp;
2159
2160     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2161
2162     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2163     {
2164         return(TNG_CRITICAL);
2165     }
2166
2167     temp = realloc(block->block_contents, block->block_contents_size);
2168     if(!temp)
2169     {
2170         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2171                block->block_contents_size, __FILE__, __LINE__);
2172         free(block->block_contents);
2173         block->block_contents = 0;
2174         return(TNG_CRITICAL);
2175     }
2176     block->block_contents = temp;
2177
2178     /* Read the whole block into block_contents to be able to write it to disk
2179      * even if it cannot be interpreted. */
2180     if(fread(block->block_contents, block->block_contents_size, 1,
2181              tng_data->input_file) == 0)
2182     {
2183         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2184         return(TNG_CRITICAL);
2185     }
2186
2187     /* FIXME: Does not check if the size of the contents matches the expected
2188      * size or if the contents can be read. */
2189
2190     if(hash_mode == TNG_USE_HASH)
2191     {
2192         tng_md5_hash_match_verify(block, &same_hash);
2193         if(same_hash != TNG_TRUE)
2194         {
2195             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2196                 "%s: %d\n",
2197                 __FILE__, __LINE__);
2198     /*         return(TNG_FAILURE); */
2199         }
2200     }
2201
2202     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
2203     temp = realloc(tng_data->first_program_name, len);
2204     if(!temp)
2205     {
2206         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2207                __FILE__, __LINE__);
2208         free(tng_data->first_program_name);
2209         tng_data->first_program_name = 0;
2210         return(TNG_CRITICAL);
2211     }
2212     tng_data->first_program_name = temp;
2213     strncpy(tng_data->first_program_name, block->block_contents, len);
2214     offset += len;
2215
2216     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
2217     temp = realloc(tng_data->last_program_name, len);
2218     if(!temp)
2219     {
2220         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2221                __FILE__, __LINE__);
2222         free(tng_data->last_program_name);
2223         tng_data->last_program_name = 0;
2224         return(TNG_CRITICAL);
2225     }
2226     tng_data->last_program_name = temp;
2227     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
2228     offset += len;
2229
2230     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2231     temp = realloc(tng_data->first_user_name, len);
2232     if(!temp)
2233     {
2234         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2235                __FILE__, __LINE__);
2236         free(tng_data->first_user_name);
2237         tng_data->first_user_name = 0;
2238         return(TNG_CRITICAL);
2239     }
2240     tng_data->first_user_name = temp;
2241     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
2242     offset += len;
2243
2244     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2245     temp = realloc(tng_data->last_user_name, len);
2246     if(!temp)
2247     {
2248         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2249                __FILE__, __LINE__);
2250         free(tng_data->last_user_name);
2251         tng_data->last_user_name = 0;
2252         return(TNG_CRITICAL);
2253     }
2254     tng_data->last_user_name = temp;
2255     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
2256     offset += len;
2257
2258     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2259     temp = realloc(tng_data->first_computer_name, len);
2260     if(!temp)
2261     {
2262         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2263                __FILE__, __LINE__);
2264         free(tng_data->first_computer_name);
2265         tng_data->first_computer_name = 0;
2266         return(TNG_CRITICAL);
2267     }
2268     tng_data->first_computer_name = temp;
2269     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
2270     offset += len;
2271
2272     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2273     temp = realloc(tng_data->last_computer_name, len);
2274     if(!temp)
2275     {
2276         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2277                __FILE__, __LINE__);
2278         free(tng_data->last_computer_name);
2279         tng_data->last_computer_name = 0;
2280         return(TNG_CRITICAL);
2281     }
2282     tng_data->last_computer_name = temp;
2283     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
2284     offset += len;
2285
2286     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2287     temp = realloc(tng_data->first_pgp_signature, len);
2288     if(!temp)
2289     {
2290         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2291                __FILE__, __LINE__);
2292         free(tng_data->first_pgp_signature);
2293         tng_data->first_pgp_signature = 0;
2294         return(TNG_CRITICAL);
2295     }
2296     tng_data->first_pgp_signature = temp;
2297     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
2298     offset += len;
2299
2300     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2301     temp = realloc(tng_data->last_pgp_signature, len);
2302     if(!temp)
2303     {
2304         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2305                __FILE__, __LINE__);
2306         free(tng_data->last_pgp_signature);
2307         tng_data->last_pgp_signature = 0;
2308         return(TNG_CRITICAL);
2309     }
2310     tng_data->last_pgp_signature = temp;
2311     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
2312     offset += len;
2313
2314     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2315     temp = realloc(tng_data->forcefield_name, len);
2316     if(!temp)
2317     {
2318         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2319                __FILE__, __LINE__);
2320         free(tng_data->forcefield_name);
2321         tng_data->forcefield_name = 0;
2322         return(TNG_CRITICAL);
2323     }
2324     tng_data->forcefield_name = temp;
2325     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
2326     offset += len;
2327
2328     memcpy(&tng_data->time, block->block_contents+offset,
2329            sizeof(tng_data->time));
2330     if(tng_data->input_endianness_swap_func_64)
2331     {
2332         if(tng_data->input_endianness_swap_func_64(tng_data,
2333                                                    &tng_data->time)
2334             != TNG_SUCCESS)
2335         {
2336             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2337                     __FILE__, __LINE__);
2338         }
2339     }
2340     offset += sizeof(tng_data->time);
2341
2342     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
2343            sizeof(tng_data->var_num_atoms_flag));
2344     offset += sizeof(tng_data->var_num_atoms_flag);
2345
2346     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
2347            sizeof(tng_data->frame_set_n_frames));
2348     if(tng_data->input_endianness_swap_func_64)
2349     {
2350         if(tng_data->input_endianness_swap_func_64(tng_data,
2351                                                  &tng_data->frame_set_n_frames)
2352             != TNG_SUCCESS)
2353         {
2354             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2355                     __FILE__, __LINE__);
2356         }
2357     }
2358     offset += sizeof(tng_data->frame_set_n_frames);
2359
2360     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
2361            block->block_contents+offset,
2362            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
2363     if(tng_data->input_endianness_swap_func_64)
2364     {
2365         if(tng_data->input_endianness_swap_func_64(tng_data,
2366                           &tng_data->first_trajectory_frame_set_input_file_pos)
2367             != TNG_SUCCESS)
2368         {
2369             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2370                     __FILE__, __LINE__);
2371         }
2372     }
2373     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
2374
2375     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2376     tng_data->first_trajectory_frame_set_input_file_pos;
2377
2378
2379     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
2380            block->block_contents+offset,
2381            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
2382     if(tng_data->input_endianness_swap_func_64)
2383     {
2384         if(tng_data->input_endianness_swap_func_64(tng_data,
2385                           &tng_data->last_trajectory_frame_set_input_file_pos)
2386             != TNG_SUCCESS)
2387         {
2388             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2389                     __FILE__, __LINE__);
2390         }
2391     }
2392     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
2393
2394     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
2395            sizeof(tng_data->medium_stride_length));
2396     if(tng_data->input_endianness_swap_func_64)
2397     {
2398         if(tng_data->input_endianness_swap_func_64(tng_data,
2399                                                &tng_data->medium_stride_length)
2400             != TNG_SUCCESS)
2401         {
2402             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2403                     __FILE__, __LINE__);
2404         }
2405     }
2406     offset += sizeof(tng_data->medium_stride_length);
2407
2408     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
2409            sizeof(tng_data->long_stride_length));
2410     if(tng_data->input_endianness_swap_func_64)
2411     {
2412         if(tng_data->input_endianness_swap_func_64(tng_data,
2413                                                  &tng_data->long_stride_length)
2414             != TNG_SUCCESS)
2415         {
2416             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2417                     __FILE__, __LINE__);
2418         }
2419     }
2420     offset += sizeof(tng_data->long_stride_length);
2421
2422     if(block->block_version >= 3)
2423     {
2424         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
2425             sizeof(tng_data->distance_unit_exponential));
2426         if(tng_data->input_endianness_swap_func_64)
2427         {
2428             if(tng_data->input_endianness_swap_func_64(tng_data,
2429                                           &tng_data->distance_unit_exponential)
2430                 != TNG_SUCCESS)
2431             {
2432                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2433                         __FILE__, __LINE__);
2434             }
2435         }
2436     }
2437
2438     return(TNG_SUCCESS);
2439 }
2440
2441 /** Write a general info block. This is the first block of a TNG file.
2442  * @param tng_data is a trajectory data container.
2443  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2444  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2445  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2446  * error has occured.
2447  */
2448 static tng_function_status tng_general_info_block_write
2449                 (tng_trajectory_t tng_data,
2450                  const char hash_mode)
2451 {
2452     int first_program_name_len, first_user_name_len;
2453     int first_computer_name_len, first_pgp_signature_len;
2454     int last_program_name_len, last_user_name_len;
2455     int last_computer_name_len, last_pgp_signature_len;
2456     int forcefield_name_len, name_len;
2457     int offset = 0;
2458     tng_gen_block_t block;
2459
2460     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2461     {
2462         return(TNG_CRITICAL);
2463     }
2464
2465     fseek(tng_data->output_file, 0, SEEK_SET);
2466
2467     tng_block_init(&block);
2468
2469     name_len = (int)strlen("GENERAL INFO");
2470
2471     block->name = malloc(name_len + 1);
2472     if(!block->name)
2473     {
2474         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2475                 name_len+1, __FILE__, __LINE__);
2476         tng_block_destroy(&block);
2477         return(TNG_CRITICAL);
2478     }
2479
2480     strcpy(block->name, "GENERAL INFO");
2481     block->id = TNG_GENERAL_INFO;
2482
2483     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2484         TNG_SUCCESS)
2485     {
2486         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2487                 __FILE__, __LINE__);
2488         tng_block_destroy(&block);
2489         return(TNG_CRITICAL);
2490     }
2491
2492     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2493                            TNG_MAX_STR_LEN);
2494     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2495                            TNG_MAX_STR_LEN);
2496     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2497                         TNG_MAX_STR_LEN);
2498     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2499                         TNG_MAX_STR_LEN);
2500     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2501                             TNG_MAX_STR_LEN);
2502     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2503                             TNG_MAX_STR_LEN);
2504     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2505                             TNG_MAX_STR_LEN);
2506     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2507                             TNG_MAX_STR_LEN);
2508     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2509                               TNG_MAX_STR_LEN);
2510
2511     if(block->block_contents)
2512     {
2513         free(block->block_contents);
2514     }
2515     block->block_contents = malloc(block->block_contents_size);
2516     if(!block->block_contents)
2517     {
2518         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2519                block->block_contents_size, __FILE__, __LINE__);
2520         tng_block_destroy(&block);
2521         return(TNG_CRITICAL);
2522     }
2523
2524     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
2525     offset += first_program_name_len;
2526
2527     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
2528     offset += last_program_name_len;
2529
2530     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
2531     offset += first_user_name_len;
2532
2533     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
2534     offset += last_user_name_len;
2535
2536     strncpy(block->block_contents+offset, tng_data->first_computer_name,
2537             first_computer_name_len);
2538     offset += first_computer_name_len;
2539
2540     strncpy(block->block_contents+offset, tng_data->last_computer_name,
2541             last_computer_name_len);
2542     offset += last_computer_name_len;
2543
2544     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
2545             first_pgp_signature_len);
2546     offset += first_pgp_signature_len;
2547
2548     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
2549             last_pgp_signature_len);
2550     offset += last_pgp_signature_len;
2551
2552     strncpy(block->block_contents+offset, tng_data->forcefield_name,
2553             forcefield_name_len);
2554     offset += forcefield_name_len;
2555
2556     memcpy(block->block_contents+offset, &tng_data->time,
2557            sizeof(tng_data->time));
2558     if(tng_data->output_endianness_swap_func_64)
2559     {
2560         if(tng_data->output_endianness_swap_func_64(tng_data,
2561                                       (int64_t *)block->header_contents+offset)
2562             != TNG_SUCCESS)
2563         {
2564             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2565                     __FILE__, __LINE__);
2566         }
2567     }
2568     offset += sizeof(tng_data->time);
2569
2570     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
2571            sizeof(tng_data->var_num_atoms_flag));
2572     offset += sizeof(tng_data->var_num_atoms_flag);
2573
2574     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
2575            sizeof(tng_data->frame_set_n_frames));
2576     if(tng_data->output_endianness_swap_func_64)
2577     {
2578         if(tng_data->output_endianness_swap_func_64(tng_data,
2579                                       (int64_t *)block->header_contents+offset)
2580             != TNG_SUCCESS)
2581         {
2582             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2583                     __FILE__, __LINE__);
2584         }
2585     }
2586     offset += sizeof(tng_data->frame_set_n_frames);
2587
2588     memcpy(block->block_contents+offset,
2589            &tng_data->first_trajectory_frame_set_output_file_pos,
2590            sizeof(tng_data->first_trajectory_frame_set_output_file_pos));
2591     if(tng_data->output_endianness_swap_func_64)
2592     {
2593         if(tng_data->output_endianness_swap_func_64(tng_data,
2594                                       (int64_t *)block->header_contents+offset)
2595             != TNG_SUCCESS)
2596         {
2597             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2598                     __FILE__, __LINE__);
2599         }
2600     }
2601     offset += sizeof(tng_data->first_trajectory_frame_set_output_file_pos);
2602
2603     memcpy(block->block_contents+offset,
2604            &tng_data->last_trajectory_frame_set_output_file_pos,
2605            sizeof(tng_data->last_trajectory_frame_set_output_file_pos));
2606     if(tng_data->output_endianness_swap_func_64)
2607     {
2608         if(tng_data->output_endianness_swap_func_64(tng_data,
2609                                       (int64_t *)block->header_contents+offset)
2610             != TNG_SUCCESS)
2611         {
2612             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2613                     __FILE__, __LINE__);
2614         }
2615     }
2616     offset += sizeof(tng_data->last_trajectory_frame_set_output_file_pos);
2617
2618     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
2619            sizeof(tng_data->medium_stride_length));
2620     if(tng_data->output_endianness_swap_func_64)
2621     {
2622         if(tng_data->output_endianness_swap_func_64(tng_data,
2623                                       (int64_t *)block->header_contents+offset)
2624             != TNG_SUCCESS)
2625         {
2626             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2627                     __FILE__, __LINE__);
2628         }
2629     }
2630     offset += sizeof(tng_data->medium_stride_length);
2631
2632     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
2633            sizeof(tng_data->long_stride_length));
2634     if(tng_data->output_endianness_swap_func_64)
2635     {
2636         if(tng_data->output_endianness_swap_func_64(tng_data,
2637                                       (int64_t *)block->header_contents+offset)
2638             != TNG_SUCCESS)
2639         {
2640             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2641                     __FILE__, __LINE__);
2642         }
2643     }
2644     offset += sizeof(tng_data->long_stride_length);
2645
2646     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
2647            sizeof(tng_data->distance_unit_exponential));
2648     if(tng_data->output_endianness_swap_func_64)
2649     {
2650         if(tng_data->output_endianness_swap_func_64(tng_data,
2651                                       (int64_t *)block->header_contents+offset)
2652             != TNG_SUCCESS)
2653         {
2654             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2655                     __FILE__, __LINE__);
2656         }
2657     }
2658
2659     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2660     {
2661         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2662                tng_data->output_file_path, __FILE__, __LINE__);
2663         tng_block_destroy(&block);
2664         return(TNG_CRITICAL);
2665     }
2666
2667     if(fwrite(block->block_contents, block->block_contents_size, 1,
2668         tng_data->output_file) != 1)
2669     {
2670         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
2671         tng_block_destroy(&block);
2672         return(TNG_CRITICAL);
2673     }
2674
2675     tng_block_destroy(&block);
2676
2677     return(TNG_SUCCESS);
2678 }
2679
2680 /** Read the chain data of a molecules block.
2681  * @param tng_data is a trajectory data container.
2682  * @param block is a general block container.
2683  * @param chain is the chain data container.
2684  * @param offset is the offset of the block input and is updated when reading.
2685  * @return TNG_SUCCESS(0) is successful.
2686  */
2687 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
2688                                                tng_gen_block_t block,
2689                                                tng_chain_t chain,
2690                                                int *offset)
2691 {
2692     int len;
2693
2694     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2695
2696     memcpy(&chain->id, block->block_contents+*offset,
2697             sizeof(chain->id));
2698     if(tng_data->input_endianness_swap_func_64)
2699     {
2700         if(tng_data->input_endianness_swap_func_64(tng_data,
2701                                                    &chain->id)
2702             != TNG_SUCCESS)
2703         {
2704             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2705                     __FILE__, __LINE__);
2706         }
2707     }
2708     *offset += sizeof(chain->id);
2709
2710     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2711             TNG_MAX_STR_LEN);
2712     chain->name = malloc(len);
2713     strncpy(chain->name,
2714             block->block_contents+*offset, len);
2715     *offset += len;
2716
2717     memcpy(&chain->n_residues, block->block_contents+*offset,
2718         sizeof(chain->n_residues));
2719     if(tng_data->input_endianness_swap_func_64)
2720     {
2721         if(tng_data->input_endianness_swap_func_64(tng_data,
2722                                                    &chain->n_residues)
2723             != TNG_SUCCESS)
2724         {
2725             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2726                     __FILE__, __LINE__);
2727         }
2728     }
2729     *offset += sizeof(chain->n_residues);
2730
2731     return(TNG_SUCCESS);
2732 }
2733
2734 /** Write the chain data of a molecules block.
2735  * @param tng_data is a trajectory data container.
2736  * @param block is a general block container.
2737  * @param chain is the chain data container.
2738  * @param offset is the offset of the block output and is updated when writing.
2739  * @return TNG_SUCCESS(0) is successful.
2740  */
2741 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
2742                                                 tng_gen_block_t block,
2743                                                 tng_chain_t chain,
2744                                                 int *offset)
2745 {
2746     int len;
2747
2748     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2749
2750     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
2751     if(tng_data->output_endianness_swap_func_64)
2752     {
2753         if(tng_data->output_endianness_swap_func_64(tng_data,
2754                                     (int64_t *)block->header_contents+*offset)
2755             != TNG_SUCCESS)
2756         {
2757             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2758                     __FILE__, __LINE__);
2759         }
2760     }
2761     *offset += sizeof(chain->id);
2762
2763     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2764     strncpy(block->block_contents + *offset, chain->name, len);
2765     *offset += len;
2766
2767     memcpy(block->block_contents+*offset, &chain->n_residues,
2768         sizeof(chain->n_residues));
2769     if(tng_data->output_endianness_swap_func_64)
2770     {
2771         if(tng_data->output_endianness_swap_func_64(tng_data,
2772                                     (int64_t *)block->header_contents+*offset)
2773             != TNG_SUCCESS)
2774         {
2775             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2776                     __FILE__, __LINE__);
2777         }
2778     }
2779     *offset += sizeof(chain->n_residues);
2780
2781     return(TNG_SUCCESS);
2782 }
2783
2784 /** Read the residue data of a molecules block.
2785  * @param tng_data is a trajectory data container.
2786  * @param block is a general block container.
2787  * @param residue is the residue data container.
2788  * @param offset is the offset of the block input and is updated when reading.
2789  * @return TNG_SUCCESS(0) is successful.
2790  */
2791 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
2792                                                  tng_gen_block_t block,
2793                                                  tng_residue_t residue,
2794                                                  int *offset)
2795 {
2796     int len;
2797
2798     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2799
2800     memcpy(&residue->id, block->block_contents+*offset,
2801         sizeof(residue->id));
2802     if(tng_data->input_endianness_swap_func_64)
2803     {
2804         if(tng_data->input_endianness_swap_func_64(tng_data,
2805                                                    &residue->id)
2806             != TNG_SUCCESS)
2807         {
2808             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2809                     __FILE__, __LINE__);
2810         }
2811     }
2812     *offset += sizeof(residue->id);
2813
2814     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2815             TNG_MAX_STR_LEN);
2816     residue->name = malloc(len);
2817     strncpy(residue->name,
2818             block->block_contents+*offset, len);
2819     *offset += len;
2820
2821     memcpy(&residue->n_atoms, block->block_contents+*offset,
2822             sizeof(residue->n_atoms));
2823     if(tng_data->input_endianness_swap_func_64)
2824     {
2825         if(tng_data->input_endianness_swap_func_64(tng_data,
2826                                                    &residue->n_atoms)
2827             != TNG_SUCCESS)
2828         {
2829             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2830                     __FILE__, __LINE__);
2831         }
2832     }
2833     *offset += sizeof(residue->n_atoms);
2834
2835     return(TNG_SUCCESS);
2836 }
2837
2838 /** Write the residue data of a molecules block.
2839  * @param tng_data is a trajectory data container.
2840  * @param block is a general block container.
2841  * @param residue is the residue data container.
2842  * @param offset is the offset of the block output and is updated when writing.
2843  * @return TNG_SUCCESS(0) is successful.
2844  */
2845 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
2846                                                   tng_gen_block_t block,
2847                                                   tng_residue_t residue,
2848                                                   int *offset)
2849 {
2850     int len;
2851
2852     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2853
2854     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
2855     if(tng_data->output_endianness_swap_func_64)
2856     {
2857         if(tng_data->output_endianness_swap_func_64(tng_data,
2858                                     (int64_t *)block->header_contents+*offset)
2859             != TNG_SUCCESS)
2860         {
2861             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2862                     __FILE__, __LINE__);
2863         }
2864     }
2865     *offset += sizeof(residue->id);
2866
2867     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2868     strncpy(block->block_contents + *offset, residue->name, len);
2869     *offset += len;
2870
2871     memcpy(block->block_contents+*offset, &residue->n_atoms,
2872         sizeof(residue->n_atoms));
2873     if(tng_data->output_endianness_swap_func_64)
2874     {
2875         if(tng_data->output_endianness_swap_func_64(tng_data,
2876                                     (int64_t *)block->header_contents+*offset)
2877             != TNG_SUCCESS)
2878         {
2879             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2880                     __FILE__, __LINE__);
2881         }
2882     }
2883     *offset += sizeof(residue->n_atoms);
2884
2885     return(TNG_SUCCESS);
2886 }
2887
2888 /** Read the atom data of a molecules block.
2889  * @param tng_data is a trajectory data container.
2890  * @param block is a general block container.
2891  * @param atom is the atom data container.
2892  * @param offset is the offset of the block input and is updated when reading.
2893  * @return TNG_SUCCESS(0) is successful.
2894  */
2895 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2896                                               tng_gen_block_t block,
2897                                               tng_atom_t atom,
2898                                               int *offset)
2899 {
2900     int len;
2901
2902     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2903
2904     memcpy(&atom->id, block->block_contents+*offset,
2905         sizeof(atom->id));
2906     if(tng_data->input_endianness_swap_func_64)
2907     {
2908         if(tng_data->input_endianness_swap_func_64(tng_data,
2909                                                     &atom->id)
2910             != TNG_SUCCESS)
2911         {
2912             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2913                     __FILE__, __LINE__);
2914         }
2915     }
2916     *offset += sizeof(atom->id);
2917
2918     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2919             TNG_MAX_STR_LEN);
2920     atom->name = malloc(len);
2921     strncpy(atom->name,
2922             block->block_contents+*offset, len);
2923     *offset += len;
2924
2925     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2926             TNG_MAX_STR_LEN);
2927     atom->atom_type = malloc(len);
2928     strncpy(atom->atom_type,
2929             block->block_contents+*offset, len);
2930     *offset += len;
2931
2932     return(TNG_SUCCESS);
2933 }
2934
2935 /** Write the atom data of a molecules block.
2936  * @param tng_data is a trajectory data container.
2937  * @param block is a general block container.
2938  * @param atom is the atom data container.
2939  * @param offset is the offset of the block output and is updated when writing.
2940  * @return TNG_SUCCESS(0) is successful.
2941  */
2942 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2943                                                tng_gen_block_t block,
2944                                                tng_atom_t atom,
2945                                                int *offset)
2946 {
2947     int len;
2948
2949     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2950
2951     memcpy(block->block_contents+*offset, &atom->id,
2952             sizeof(atom->id));
2953     if(tng_data->output_endianness_swap_func_64)
2954     {
2955         if(tng_data->output_endianness_swap_func_64(tng_data,
2956                                     (int64_t *)block->header_contents+*offset)
2957             != TNG_SUCCESS)
2958         {
2959             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2960                     __FILE__, __LINE__);
2961         }
2962     }
2963     *offset += sizeof(atom->id);
2964
2965     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2966     strncpy(block->block_contents + *offset, atom->name, len);
2967     *offset += len;
2968
2969     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2970     strncpy(block->block_contents + *offset, atom->atom_type, len);
2971     *offset += len;
2972
2973     return(TNG_SUCCESS);
2974 }
2975
2976 static tng_function_status tng_molecules_block_len_calculate
2977                 (const tng_trajectory_t tng_data,
2978                  int64_t *len)
2979 {
2980     int64_t i, j;
2981     tng_molecule_t molecule;
2982     tng_chain_t chain;
2983     tng_residue_t residue;
2984     tng_atom_t atom;
2985     tng_bond_t bond;
2986
2987     *len = 0;
2988
2989     for(i = 0; i < tng_data->n_molecules; i++)
2990     {
2991         molecule = &tng_data->molecules[i];
2992         if(!molecule->name)
2993         {
2994             molecule->name = malloc(1);
2995             if(!molecule->name)
2996             {
2997                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2998                        __FILE__, __LINE__);
2999                 return(TNG_CRITICAL);
3000             }
3001             molecule->name[0] = 0;
3002         }
3003         *len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3004
3005         chain = molecule->chains;
3006         for(j = 0; j < molecule->n_chains; j++)
3007         {
3008             *len += sizeof(chain->id);
3009
3010             if(!chain->name)
3011             {
3012                 chain->name = malloc(1);
3013                 if(!chain->name)
3014                 {
3015                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3016                            __FILE__, __LINE__);
3017                     return(TNG_CRITICAL);
3018                 }
3019                 chain->name[0] = 0;
3020             }
3021             *len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
3022
3023             *len += sizeof(chain->n_residues);
3024
3025             chain++;
3026         }
3027
3028         residue = molecule->residues;
3029         for(j = 0; j < molecule->n_residues; j++)
3030         {
3031             *len += sizeof(residue->id);
3032
3033             if(!residue->name)
3034             {
3035                 residue->name = malloc(1);
3036                 if(!residue->name)
3037                 {
3038                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3039                            __FILE__, __LINE__);
3040                     return(TNG_CRITICAL);
3041                 }
3042                 residue->name[0] = 0;
3043             }
3044             *len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
3045
3046             *len += sizeof(residue->n_atoms);
3047
3048             residue++;
3049         }
3050
3051         atom = molecule->atoms;
3052         for(j = 0; j < molecule->n_atoms; j++)
3053         {
3054             *len += sizeof(atom->id);
3055             if(!atom->name)
3056             {
3057                 atom->name = malloc(1);
3058                 if(!atom->name)
3059                 {
3060                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3061                            __FILE__, __LINE__);
3062                     return(TNG_CRITICAL);
3063                 }
3064                 atom->name[0] = 0;
3065             }
3066             *len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
3067
3068             if(!atom->atom_type)
3069             {
3070                 atom->atom_type = malloc(1);
3071                 if(!atom->atom_type)
3072                 {
3073                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3074                            __FILE__, __LINE__);
3075                     return(TNG_CRITICAL);
3076                 }
3077                 atom->atom_type[0] = 0;
3078             }
3079             *len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
3080
3081             atom++;
3082         }
3083
3084         for(j = 0; j < molecule->n_bonds; j++)
3085         {
3086             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
3087         }
3088     }
3089     *len += sizeof(tng_data->n_molecules) +
3090             (sizeof(molecule->id) +
3091             sizeof(molecule->quaternary_str) +
3092             sizeof(molecule->n_chains) +
3093             sizeof(molecule->n_residues) +
3094             sizeof(molecule->n_atoms) +
3095             sizeof(molecule->n_bonds)) *
3096             tng_data->n_molecules;
3097
3098     if(!tng_data->var_num_atoms_flag)
3099     {
3100         *len += tng_data->n_molecules * sizeof(int64_t);
3101     }
3102
3103     return(TNG_SUCCESS);
3104 }
3105
3106 /** Read a molecules block. Contains chain, residue and atom data
3107  * @param tng_data is a trajectory data container.
3108  * @param block is a general block container.
3109  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3110  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3111  * compared to the md5 hash of the read contents to ensure valid data.
3112  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3113  * error has occured.
3114  */
3115 static tng_function_status tng_molecules_block_read
3116                 (tng_trajectory_t tng_data,
3117                  tng_gen_block_t block,
3118                  const char hash_mode)
3119 {
3120     int64_t i, j, k, l;
3121     int len, offset = 0;
3122     tng_molecule_t molecule;
3123     tng_chain_t chain;
3124     tng_residue_t residue;
3125     tng_atom_t atom;
3126     tng_bond_t bond;
3127     tng_bool same_hash;
3128
3129     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3130     {
3131         return(TNG_CRITICAL);
3132     }
3133
3134     if(block->block_contents)
3135     {
3136         free(block->block_contents);
3137     }
3138
3139     block->block_contents = malloc(block->block_contents_size);
3140     if(!block->block_contents)
3141     {
3142         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3143                block->block_contents_size, __FILE__, __LINE__);
3144         return(TNG_CRITICAL);
3145     }
3146
3147     /* Read the whole block into block_contents to be able to write it to disk
3148      * even if it cannot be interpreted. */
3149     if(fread(block->block_contents, block->block_contents_size, 1,
3150              tng_data->input_file) == 0)
3151     {
3152         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3153     }
3154
3155     /* FIXME: Does not check if the size of the contents matches the expected
3156      * size or if the contents can be read. */
3157
3158     if(hash_mode == TNG_USE_HASH)
3159     {
3160         tng_md5_hash_match_verify(block, &same_hash);
3161         if(same_hash != TNG_TRUE)
3162         {
3163             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3164                 "%s: %d\n",
3165                 __FILE__, __LINE__);
3166         }
3167     }
3168
3169     if(tng_data->molecules)
3170     {
3171         for(i=0; i<tng_data->n_molecules; i++)
3172         {
3173             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
3174         }
3175         free(tng_data->molecules);
3176         tng_data->molecules = 0;
3177         tng_data->n_molecules = 0;
3178     }
3179
3180     memcpy(&tng_data->n_molecules, block->block_contents,
3181            sizeof(tng_data->n_molecules));
3182     if(tng_data->input_endianness_swap_func_64)
3183     {
3184         if(tng_data->input_endianness_swap_func_64(tng_data,
3185                                                    &tng_data->n_molecules)
3186             != TNG_SUCCESS)
3187         {
3188             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3189                     __FILE__, __LINE__);
3190         }
3191     }
3192     offset += sizeof(tng_data->n_molecules);
3193
3194     if(tng_data->molecules)
3195     {
3196         free(tng_data->molecules);
3197     }
3198
3199     tng_data->n_particles = 0;
3200
3201     tng_data->molecules = malloc(tng_data->n_molecules *
3202                           sizeof(struct tng_molecule));
3203     if(!tng_data->molecules)
3204     {
3205         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3206                tng_data->n_molecules * sizeof(struct tng_molecule),
3207                __FILE__, __LINE__);
3208         return(TNG_CRITICAL);
3209     }
3210
3211     if(!tng_data->var_num_atoms_flag)
3212     {
3213         if(tng_data->molecule_cnt_list)
3214         {
3215             free(tng_data->molecule_cnt_list);
3216         }
3217         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
3218                                       tng_data->n_molecules);
3219         if(!tng_data->molecule_cnt_list)
3220         {
3221             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3222                    tng_data->n_molecules * sizeof(struct tng_molecule),
3223                    __FILE__, __LINE__);
3224             return(TNG_CRITICAL);
3225         }
3226     }
3227
3228     /* Read each molecule from file */
3229     for(i=0; i < tng_data->n_molecules; i++)
3230     {
3231         molecule = &tng_data->molecules[i];
3232
3233         memcpy(&molecule->id, block->block_contents+offset,
3234                sizeof(molecule->id));
3235         if(tng_data->input_endianness_swap_func_64)
3236         {
3237             if(tng_data->input_endianness_swap_func_64(tng_data,
3238                                                        &molecule->id)
3239                 != TNG_SUCCESS)
3240             {
3241                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3242                         __FILE__, __LINE__);
3243             }
3244         }
3245         offset += sizeof(molecule->id);
3246
3247 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
3248         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
3249         molecule->name = malloc(len);
3250         strncpy(molecule->name, block->block_contents+offset, len);
3251         offset += len;
3252
3253         memcpy(&molecule->quaternary_str, block->block_contents+offset,
3254                sizeof(molecule->quaternary_str));
3255         if(tng_data->input_endianness_swap_func_64)
3256         {
3257             if(tng_data->input_endianness_swap_func_64(tng_data,
3258                                                      &molecule->quaternary_str)
3259                 != TNG_SUCCESS)
3260             {
3261                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3262                         __FILE__, __LINE__);
3263             }
3264         }
3265         offset += sizeof(molecule->quaternary_str);
3266
3267         if(!tng_data->var_num_atoms_flag)
3268         {
3269             memcpy(&tng_data->molecule_cnt_list[i],
3270                    block->block_contents+offset,
3271                    sizeof(int64_t));
3272             if(tng_data->input_endianness_swap_func_64)
3273             {
3274                 if(tng_data->input_endianness_swap_func_64(tng_data,
3275                                                &tng_data->molecule_cnt_list[i])
3276                     != TNG_SUCCESS)
3277                 {
3278                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3279                             __FILE__, __LINE__);
3280                 }
3281             }
3282             offset += sizeof(int64_t);
3283         }
3284
3285
3286         memcpy(&molecule->n_chains, block->block_contents+offset,
3287                sizeof(molecule->n_chains));
3288         if(tng_data->input_endianness_swap_func_64)
3289         {
3290             if(tng_data->input_endianness_swap_func_64(tng_data,
3291                                                        &molecule->n_chains)
3292                 != TNG_SUCCESS)
3293             {
3294                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3295                         __FILE__, __LINE__);
3296             }
3297         }
3298         offset += sizeof(molecule->n_chains);
3299
3300         memcpy(&molecule->n_residues, block->block_contents+offset,
3301                sizeof(molecule->n_residues));
3302         if(tng_data->input_endianness_swap_func_64)
3303         {
3304             if(tng_data->input_endianness_swap_func_64(tng_data,
3305                                                        &molecule->n_residues)
3306                 != TNG_SUCCESS)
3307             {
3308                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3309                         __FILE__, __LINE__);
3310             }
3311         }
3312         offset += sizeof(molecule->n_residues);
3313
3314         memcpy(&molecule->n_atoms, block->block_contents+offset,
3315                sizeof(molecule->n_atoms));
3316         if(tng_data->input_endianness_swap_func_64)
3317         {
3318             if(tng_data->input_endianness_swap_func_64(tng_data,
3319                                                        &molecule->n_atoms)
3320                 != TNG_SUCCESS)
3321             {
3322                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3323                         __FILE__, __LINE__);
3324             }
3325         }
3326         offset += sizeof(molecule->n_atoms);
3327
3328         tng_data->n_particles += molecule->n_atoms *
3329                                  tng_data->molecule_cnt_list[i];
3330
3331         if(molecule->n_chains > 0)
3332         {
3333             molecule->chains = malloc(molecule->n_chains *
3334                                     sizeof(struct tng_chain));
3335             if(!molecule->chains)
3336             {
3337                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3338                     molecule->n_chains * sizeof(struct tng_chain),
3339                     __FILE__, __LINE__);
3340                 return(TNG_CRITICAL);
3341             }
3342
3343             chain = molecule->chains;
3344         }
3345         else
3346         {
3347             chain = 0;
3348         }
3349
3350         if(molecule->n_residues > 0)
3351         {
3352             molecule->residues = malloc(molecule->n_residues *
3353                                 sizeof(struct tng_residue));
3354             if(!molecule->residues)
3355             {
3356                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3357                     molecule->n_residues * sizeof(struct tng_residue),
3358                     __FILE__, __LINE__);
3359                 if(molecule->chains)
3360                 {
3361                     free(molecule->chains);
3362                     molecule->chains = 0;
3363                 }
3364                 return(TNG_CRITICAL);
3365             }
3366
3367             residue = molecule->residues;
3368         }
3369         else
3370         {
3371             residue = 0;
3372         }
3373
3374         molecule->atoms = malloc(molecule->n_atoms *
3375                                  sizeof(struct tng_atom));
3376         if(!molecule->atoms)
3377         {
3378             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3379                    molecule->n_atoms * sizeof(struct tng_atom),
3380                    __FILE__, __LINE__);
3381             if(molecule->chains)
3382             {
3383                 free(molecule->chains);
3384                 molecule->chains = 0;
3385             }
3386             if(molecule->residues)
3387             {
3388                 free(molecule->residues);
3389                 molecule->residues = 0;
3390             }
3391             return(TNG_CRITICAL);
3392         }
3393
3394         atom = molecule->atoms;
3395
3396         if(molecule->n_chains > 0)
3397         {
3398             /* Read the chains of the molecule */
3399             for(j=0; j<molecule->n_chains; j++)
3400             {
3401                 chain->molecule = molecule;
3402
3403                 tng_chain_data_read(tng_data, block, chain, &offset);
3404
3405                 chain->residues = molecule->residues;
3406                 residue = chain->residues;
3407
3408                 /* Read the residues of the chain */
3409                 for(k=0; k<chain->n_residues; k++)
3410                 {
3411                     residue->chain = chain;
3412
3413                     tng_residue_data_read(tng_data, block, residue, &offset);
3414
3415                     residue->atoms_offset = atom - molecule->atoms;
3416                     /* Read the atoms of the residue */
3417                     for(l=0; l<residue->n_atoms; l++)
3418                     {
3419                         atom->residue = residue;
3420
3421                         tng_atom_data_read(tng_data, block, atom, &offset);
3422
3423                         atom++;
3424                     }
3425                     residue++;
3426                 }
3427                 chain++;
3428             }
3429         }
3430         else
3431         {
3432             if(molecule->n_residues > 0)
3433             {
3434                 for(k=0; k<molecule->n_residues; k++)
3435                 {
3436                     residue->chain = 0;
3437
3438                     tng_residue_data_read(tng_data, block, residue, &offset);
3439
3440                     residue->atoms_offset = atom - molecule->atoms;
3441                     /* Read the atoms of the residue */
3442                     for(l=0; l<residue->n_atoms; l++)
3443                     {
3444                         atom->residue = residue;
3445
3446                         tng_atom_data_read(tng_data, block, atom, &offset);
3447
3448                         atom++;
3449                     }
3450                     residue++;
3451                 }
3452             }
3453             else
3454             {
3455                 for(l=0; l<molecule->n_atoms; l++)
3456                 {
3457                     atom->residue = 0;
3458
3459                     tng_atom_data_read(tng_data, block, atom, &offset);
3460
3461                     atom++;
3462                 }
3463             }
3464         }
3465
3466         memcpy(&molecule->n_bonds, block->block_contents+offset,
3467                sizeof(molecule->n_bonds));
3468         if(tng_data->input_endianness_swap_func_64)
3469         {
3470             if(tng_data->input_endianness_swap_func_64(tng_data,
3471                                                        &molecule->n_bonds)
3472                 != TNG_SUCCESS)
3473             {
3474                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3475                         __FILE__, __LINE__);
3476             }
3477         }
3478         offset += sizeof(molecule->n_bonds);
3479
3480         if(molecule->n_bonds > 0)
3481         {
3482             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
3483                                            sizeof(struct tng_bond));
3484             if(!molecule->bonds)
3485             {
3486                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3487                        molecule->n_bonds * sizeof(struct tng_bond),
3488                        __FILE__, __LINE__);
3489                 if(molecule->chains)
3490                 {
3491                     free(molecule->chains);
3492                     molecule->chains = 0;
3493                 }
3494                 if(molecule->residues)
3495                 {
3496                     free(molecule->residues);
3497                     molecule->residues = 0;
3498                 }
3499                 if(molecule->atoms)
3500                 {
3501                     free(molecule->atoms);
3502                     molecule->atoms = 0;
3503                 }
3504                 return(TNG_CRITICAL);
3505             }
3506
3507             bond = molecule->bonds;
3508
3509             for(j=0; j<molecule->n_bonds; j++)
3510             {
3511                 memcpy(&bond->from_atom_id, block->block_contents+offset,
3512                     sizeof(bond->from_atom_id));
3513                 if(tng_data->input_endianness_swap_func_64)
3514                 {
3515                     if(tng_data->input_endianness_swap_func_64(tng_data,
3516                                                                &bond->from_atom_id)
3517                         != TNG_SUCCESS)
3518                     {
3519                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3520                                 __FILE__, __LINE__);
3521                     }
3522                 }
3523                 offset += sizeof(bond->from_atom_id);
3524
3525                 memcpy(&bond->to_atom_id, block->block_contents+offset,
3526                     sizeof(bond->to_atom_id));
3527                 if(tng_data->input_endianness_swap_func_64)
3528                 {
3529                     if(tng_data->input_endianness_swap_func_64(tng_data,
3530                                                                &bond->to_atom_id)
3531                         != TNG_SUCCESS)
3532                     {
3533                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3534                                 __FILE__, __LINE__);
3535                     }
3536                 }
3537                 offset += sizeof(bond->to_atom_id);
3538
3539                 bond++;
3540             }
3541         }
3542         else
3543         {
3544             molecule->bonds = 0;
3545         }
3546     }
3547
3548     return(TNG_SUCCESS);
3549 }
3550
3551 /** Write a molecules block.
3552  * @param tng_data is a trajectory data container.
3553  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3554  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3555  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3556  * error has occured.
3557  */
3558 static tng_function_status tng_molecules_block_write
3559                 (tng_trajectory_t tng_data,
3560                  const char hash_mode)
3561 {
3562     int len = 0, name_len, offset = 0;
3563     int64_t i, j, k, l;
3564     tng_molecule_t molecule;
3565     tng_chain_t chain;
3566     tng_residue_t residue;
3567     tng_atom_t atom;
3568     tng_bond_t bond;
3569     tng_gen_block_t block;
3570
3571     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3572     {
3573         return(TNG_CRITICAL);
3574     }
3575
3576     tng_block_init(&block);
3577
3578     name_len = (int)strlen("MOLECULES");
3579
3580     block->name = malloc(name_len + 1);
3581     if(!block->name)
3582     {
3583         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3584                 name_len+1, __FILE__, __LINE__);
3585         tng_block_destroy(&block);
3586         return(TNG_CRITICAL);
3587     }
3588
3589     strcpy(block->name, "MOLECULES");
3590     block->id = TNG_MOLECULES;
3591
3592     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3593         TNG_SUCCESS)
3594     {
3595         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3596                 __FILE__, __LINE__);
3597         tng_block_destroy(&block);
3598         return(TNG_CRITICAL);
3599     }
3600
3601     block->block_contents = malloc(block->block_contents_size);
3602     if(!block->block_contents)
3603     {
3604         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3605                block->block_contents_size, __FILE__, __LINE__);
3606         tng_block_destroy(&block);
3607         return(TNG_CRITICAL);
3608     }
3609
3610     memcpy(block->block_contents+offset, &tng_data->n_molecules,
3611            sizeof(tng_data->n_molecules));
3612     if(tng_data->output_endianness_swap_func_64)
3613     {
3614         if(tng_data->output_endianness_swap_func_64(tng_data,
3615                                       (int64_t *)block->header_contents+offset)
3616             != TNG_SUCCESS)
3617         {
3618             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3619                     __FILE__, __LINE__);
3620         }
3621     }
3622     offset += sizeof(tng_data->n_molecules);
3623
3624     for(i = 0; i < tng_data->n_molecules; i++)
3625     {
3626         molecule = &tng_data->molecules[i];
3627         memcpy(block->block_contents+offset, &molecule->id,
3628                sizeof(molecule->id));
3629         if(tng_data->output_endianness_swap_func_64)
3630         {
3631             if(tng_data->output_endianness_swap_func_64(tng_data,
3632                                         (int64_t *)block->header_contents+offset)
3633                 != TNG_SUCCESS)
3634             {
3635                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3636                         __FILE__, __LINE__);
3637             }
3638         }
3639         offset += sizeof(molecule->id);
3640
3641 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
3642         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3643         strncpy(block->block_contents + offset, molecule->name, len);
3644         offset += len;
3645
3646         memcpy(block->block_contents+offset, &molecule->quaternary_str,
3647                sizeof(molecule->quaternary_str));
3648         if(tng_data->output_endianness_swap_func_64)
3649         {
3650             if(tng_data->output_endianness_swap_func_64(tng_data,
3651                                         (int64_t *)block->header_contents+offset)
3652                 != TNG_SUCCESS)
3653             {
3654                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3655                         __FILE__, __LINE__);
3656             }
3657         }
3658         offset += sizeof(molecule->quaternary_str);
3659
3660         if(!tng_data->var_num_atoms_flag)
3661         {
3662             memcpy(block->block_contents+offset,
3663                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
3664             if(tng_data->output_endianness_swap_func_64)
3665             {
3666                 if(tng_data->output_endianness_swap_func_64(tng_data,
3667                                             (int64_t *)block->header_contents+offset)
3668                     != TNG_SUCCESS)
3669                 {
3670                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3671                             __FILE__, __LINE__);
3672                 }
3673             }
3674             offset += sizeof(int64_t);
3675         }
3676
3677         memcpy(block->block_contents+offset, &molecule->n_chains,
3678                sizeof(molecule->n_chains));
3679         if(tng_data->output_endianness_swap_func_64)
3680         {
3681             if(tng_data->output_endianness_swap_func_64(tng_data,
3682                                         (int64_t *)block->header_contents+offset)
3683                 != TNG_SUCCESS)
3684             {
3685                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3686                         __FILE__, __LINE__);
3687             }
3688         }
3689         offset += sizeof(molecule->n_chains);
3690
3691         memcpy(block->block_contents+offset, &molecule->n_residues,
3692                sizeof(molecule->n_residues));
3693         if(tng_data->output_endianness_swap_func_64)
3694         {
3695             if(tng_data->output_endianness_swap_func_64(tng_data,
3696                                         (int64_t *)block->header_contents+offset)
3697                 != TNG_SUCCESS)
3698             {
3699                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3700                         __FILE__, __LINE__);
3701             }
3702         }
3703         offset += sizeof(molecule->n_residues);
3704
3705         memcpy(block->block_contents+offset, &molecule->n_atoms,
3706                sizeof(molecule->n_atoms));
3707         if(tng_data->output_endianness_swap_func_64)
3708         {
3709             if(tng_data->output_endianness_swap_func_64(tng_data,
3710                                         (int64_t *)block->header_contents+offset)
3711                 != TNG_SUCCESS)
3712             {
3713                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3714                         __FILE__, __LINE__);
3715             }
3716         }
3717         offset += sizeof(molecule->n_atoms);
3718
3719         if(molecule->n_chains > 0)
3720         {
3721             chain = molecule->chains;
3722             for(j = 0; j < molecule->n_chains; j++)
3723             {
3724                 tng_chain_data_write(tng_data, block, chain, &offset);
3725
3726                 residue = chain->residues;
3727                 for(k = 0; k < chain->n_residues; k++)
3728                 {
3729                     tng_residue_data_write(tng_data, block, residue, &offset);
3730
3731                     atom = molecule->atoms + residue->atoms_offset;
3732                     for(l = 0; l < residue->n_atoms; l++)
3733                     {
3734                         tng_atom_data_write(tng_data, block, atom, &offset);
3735
3736                         atom++;
3737                     }
3738                     residue++;
3739                 }
3740                 chain++;
3741             }
3742         }
3743         else
3744         {
3745             if(molecule->n_residues > 0)
3746             {
3747                 residue = molecule->residues;
3748                 for(k = 0; k < molecule->n_residues; k++)
3749                 {
3750                     tng_residue_data_write(tng_data, block, residue, &offset);
3751
3752                     atom = molecule->atoms + residue->atoms_offset;
3753                     for(l = 0; l < residue->n_atoms; l++)
3754                     {
3755                         tng_atom_data_write(tng_data, block, atom, &offset);
3756
3757                         atom++;
3758                     }
3759                     residue++;
3760                 }
3761             }
3762             else
3763             {
3764                 atom = molecule->atoms;
3765                 for(l = 0; l < molecule->n_atoms; l++)
3766                 {
3767                     tng_atom_data_write(tng_data, block, atom, &offset);
3768
3769                     atom++;
3770                 }
3771             }
3772         }
3773
3774         memcpy(block->block_contents+offset, &molecule->n_bonds,
3775                sizeof(molecule->n_bonds));
3776         if(tng_data->output_endianness_swap_func_64)
3777         {
3778             if(tng_data->output_endianness_swap_func_64(tng_data,
3779                                         (int64_t *)block->header_contents+offset)
3780                 != TNG_SUCCESS)
3781             {
3782                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3783                         __FILE__, __LINE__);
3784             }
3785         }
3786         offset += sizeof(molecule->n_bonds);
3787
3788         bond = molecule->bonds;
3789         for(j = 0; j < molecule->n_bonds; j++)
3790         {
3791             memcpy(block->block_contents+offset, &bond->from_atom_id,
3792                    sizeof(bond->from_atom_id));
3793             if(tng_data->output_endianness_swap_func_64)
3794             {
3795                 if(tng_data->output_endianness_swap_func_64(tng_data,
3796                                             (int64_t *)block->header_contents+offset)
3797                     != TNG_SUCCESS)
3798                 {
3799                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3800                             __FILE__, __LINE__);
3801                 }
3802             }
3803             offset += sizeof(bond->from_atom_id);
3804
3805             memcpy(block->block_contents+offset, &bond->to_atom_id,
3806                    sizeof(bond->to_atom_id));
3807             if(tng_data->output_endianness_swap_func_64)
3808             {
3809                 if(tng_data->output_endianness_swap_func_64(tng_data,
3810                                             (int64_t *)block->header_contents+offset)
3811                     != TNG_SUCCESS)
3812                 {
3813                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3814                             __FILE__, __LINE__);
3815                 }
3816             }
3817             offset += sizeof(bond->to_atom_id);
3818
3819             bond++;
3820         }
3821     }
3822
3823     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3824     {
3825         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3826                tng_data->output_file_path, __FILE__, __LINE__);
3827         tng_block_destroy(&block);
3828         return(TNG_CRITICAL);
3829     }
3830
3831     if(fwrite(block->block_contents, block->block_contents_size, 1,
3832               tng_data->output_file) != 1)
3833     {
3834         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
3835                __FILE__, __LINE__);
3836         tng_block_destroy(&block);
3837         return(TNG_CRITICAL);
3838     }
3839
3840     tng_block_destroy(&block);
3841
3842     return(TNG_SUCCESS);
3843 }
3844
3845 static tng_function_status tng_frame_set_block_len_calculate
3846                 (const tng_trajectory_t tng_data,
3847                  int64_t *len)
3848 {
3849     *len = sizeof(int64_t) * 8;
3850     *len += sizeof(double) * 2;
3851
3852     if(tng_data->var_num_atoms_flag)
3853     {
3854         *len += sizeof(int64_t) * tng_data->n_molecules;
3855     }
3856     return(TNG_SUCCESS);
3857 }
3858
3859 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
3860  * @param tng_data is a trajectory data container.
3861  * @param block is a general block container.
3862  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3863  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3864  * compared to the md5 hash of the read contents to ensure valid data.
3865  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3866  * error has occured.
3867  */
3868 static tng_function_status tng_frame_set_block_read
3869                 (tng_trajectory_t tng_data,
3870                  tng_gen_block_t block,
3871                  const char hash_mode)
3872 {
3873     long file_pos;
3874     int offset = 0;
3875     int64_t i, prev_n_particles;
3876     tng_bool same_hash;
3877     tng_trajectory_frame_set_t frame_set =
3878     &tng_data->current_trajectory_frame_set;
3879
3880     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3881     {
3882         return(TNG_CRITICAL);
3883     }
3884
3885     if(block->block_contents)
3886     {
3887         free(block->block_contents);
3888     }
3889
3890     block->block_contents = malloc(block->block_contents_size);
3891     if(!block->block_contents)
3892     {
3893         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3894                block->block_contents_size, __FILE__, __LINE__);
3895         return(TNG_CRITICAL);
3896     }
3897
3898     /* Read the whole block into block_contents to be able to write it to
3899      * disk even if it cannot be interpreted. */
3900     if(fread(block->block_contents, block->block_contents_size, 1,
3901              tng_data->input_file) == 0)
3902     {
3903         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3904         return(TNG_CRITICAL);
3905     }
3906
3907     /* FIXME: Does not check if the size of the contents matches the expected
3908      * size or if the contents can be read. */
3909
3910     file_pos = (int64_t)ftell(tng_data->input_file) -
3911                (long)(block->block_contents_size + block->header_contents_size);
3912
3913     if(hash_mode == TNG_USE_HASH)
3914     {
3915         tng_md5_hash_match_verify(block, &same_hash);
3916         if(same_hash != TNG_TRUE)
3917         {
3918             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
3919                 "%s: %d\n",
3920                 file_pos, __FILE__, __LINE__);
3921     /*         return(TNG_FAILURE); */
3922         }
3923     }
3924
3925     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3926
3927     tng_frame_set_particle_mapping_free(tng_data);
3928
3929     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3930     {
3931         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3932     }
3933     /* FIXME: Should check the frame number instead of the file_pos, in case
3934      * frame sets are not in order */
3935     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3936     {
3937         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3938     }
3939
3940     memcpy(&frame_set->first_frame, block->block_contents,
3941            sizeof(frame_set->first_frame));
3942     if(tng_data->input_endianness_swap_func_64)
3943     {
3944         if(tng_data->input_endianness_swap_func_64(tng_data,
3945                                                    &frame_set->first_frame)
3946             != TNG_SUCCESS)
3947         {
3948             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3949                     __FILE__, __LINE__);
3950         }
3951     }
3952     offset += sizeof(frame_set->first_frame);
3953
3954     memcpy(&frame_set->n_frames, block->block_contents + offset,
3955            sizeof(frame_set->n_frames));
3956     if(tng_data->input_endianness_swap_func_64)
3957     {
3958         if(tng_data->input_endianness_swap_func_64(tng_data,
3959                                                    &frame_set->n_frames)
3960             != TNG_SUCCESS)
3961         {
3962             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3963                     __FILE__, __LINE__);
3964         }
3965     }
3966     offset += sizeof(frame_set->n_frames);
3967
3968     if(tng_data->var_num_atoms_flag)
3969     {
3970         prev_n_particles = frame_set->n_particles;
3971         frame_set->n_particles = 0;
3972         /* If the list of molecule counts has already been created assume that
3973          * it is of correct size. */
3974         if(!frame_set->molecule_cnt_list)
3975         {
3976                 frame_set->molecule_cnt_list =
3977                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3978
3979                 if(!frame_set->molecule_cnt_list)
3980                 {
3981                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3982                            sizeof(int64_t) * tng_data->n_molecules,
3983                            __FILE__, __LINE__);
3984                     return(TNG_CRITICAL);
3985                 }
3986         }
3987         for(i = 0; i < tng_data->n_molecules; i++)
3988         {
3989             memcpy(&frame_set->molecule_cnt_list[i],
3990                    block->block_contents + offset,
3991                    sizeof(int64_t));
3992             if(tng_data->input_endianness_swap_func_64)
3993             {
3994                 if(tng_data->input_endianness_swap_func_64(tng_data,
3995                                               &frame_set->molecule_cnt_list[i])
3996                     != TNG_SUCCESS)
3997                 {
3998                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3999                             __FILE__, __LINE__);
4000                 }
4001             }
4002             offset += sizeof(int64_t);
4003             frame_set->n_particles += tng_data->molecules[i].n_atoms *
4004                                       frame_set->molecule_cnt_list[i];
4005         }
4006         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
4007         {
4008             /* FIXME: Particle dependent data memory management */
4009         }
4010     }
4011
4012     memcpy(&frame_set->next_frame_set_file_pos,
4013            block->block_contents + offset,
4014            sizeof(frame_set->next_frame_set_file_pos));
4015     if(tng_data->input_endianness_swap_func_64)
4016     {
4017         if(tng_data->input_endianness_swap_func_64(tng_data,
4018                                            &frame_set->next_frame_set_file_pos)
4019             != TNG_SUCCESS)
4020         {
4021             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4022                     __FILE__, __LINE__);
4023         }
4024     }
4025     offset += sizeof(frame_set->next_frame_set_file_pos);
4026
4027     memcpy(&frame_set->prev_frame_set_file_pos,
4028            block->block_contents + offset,
4029            sizeof(frame_set->prev_frame_set_file_pos));
4030     if(tng_data->input_endianness_swap_func_64)
4031     {
4032         if(tng_data->input_endianness_swap_func_64(tng_data,
4033                                            &frame_set->prev_frame_set_file_pos)
4034             != TNG_SUCCESS)
4035         {
4036             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4037                     __FILE__, __LINE__);
4038         }
4039     }
4040     offset += sizeof(frame_set->prev_frame_set_file_pos);
4041
4042     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
4043            block->block_contents + offset,
4044            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4045     if(tng_data->input_endianness_swap_func_64)
4046     {
4047         if(tng_data->input_endianness_swap_func_64(tng_data,
4048                              &frame_set->medium_stride_next_frame_set_file_pos)
4049             != TNG_SUCCESS)
4050         {
4051             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4052                     __FILE__, __LINE__);
4053         }
4054     }
4055     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4056
4057     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
4058            block->block_contents + offset,
4059            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4060     if(tng_data->input_endianness_swap_func_64)
4061     {
4062         if(tng_data->input_endianness_swap_func_64(tng_data,
4063                              &frame_set->medium_stride_prev_frame_set_file_pos)
4064             != TNG_SUCCESS)
4065         {
4066             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4067                     __FILE__, __LINE__);
4068         }
4069     }
4070     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4071
4072     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
4073            block->block_contents + offset,
4074            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4075     if(tng_data->input_endianness_swap_func_64)
4076     {
4077         if(tng_data->input_endianness_swap_func_64(tng_data,
4078                                &frame_set->long_stride_next_frame_set_file_pos)
4079             != TNG_SUCCESS)
4080         {
4081             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4082                     __FILE__, __LINE__);
4083         }
4084     }
4085     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4086
4087     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
4088            block->block_contents + offset,
4089            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4090     if(tng_data->input_endianness_swap_func_64)
4091     {
4092         if(tng_data->input_endianness_swap_func_64(tng_data,
4093                                &frame_set->long_stride_prev_frame_set_file_pos)
4094             != TNG_SUCCESS)
4095         {
4096             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4097                     __FILE__, __LINE__);
4098         }
4099     }
4100     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4101
4102     if(block->block_version >= 3)
4103     {
4104         memcpy(&frame_set->first_frame_time,
4105             block->block_contents + offset,
4106             sizeof(frame_set->first_frame_time));
4107         if(tng_data->input_endianness_swap_func_64)
4108         {
4109             if(tng_data->input_endianness_swap_func_64(tng_data,
4110                                 (int64_t *)&frame_set->first_frame_time)
4111                 != TNG_SUCCESS)
4112             {
4113                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4114                         __FILE__, __LINE__);
4115             }
4116         }
4117         offset += sizeof(frame_set->first_frame_time);
4118
4119         memcpy(&tng_data->time_per_frame,
4120             block->block_contents + offset,
4121             sizeof(tng_data->time_per_frame));
4122         if(tng_data->input_endianness_swap_func_64)
4123         {
4124             if(tng_data->input_endianness_swap_func_64(tng_data,
4125                                 (int64_t *)&tng_data->time_per_frame)
4126                 != TNG_SUCCESS)
4127             {
4128                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4129                         __FILE__, __LINE__);
4130             }
4131         }
4132     }
4133     else
4134     {
4135         frame_set->first_frame_time = -1;
4136         tng_data->time_per_frame = -1;
4137     }
4138
4139     /* If the output file and the input files are the same the number of
4140      * frames in the file are the same number as has just been read.
4141      * This is updated here to later on see if there have been new frames
4142      * added and thereby the frame set needs to be rewritten. */
4143     if(tng_data->output_file == tng_data->input_file)
4144     {
4145         frame_set->n_written_frames = frame_set->n_frames;
4146     }
4147
4148     return(TNG_SUCCESS);
4149 }
4150
4151 /** Write tng_data->current_trajectory_frame_set to file
4152  * @param tng_data is a trajectory data container.
4153  * @param block is a general block container.
4154  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4155  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4156  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4157  * error has occured.
4158  */
4159 static tng_function_status tng_frame_set_block_write
4160                 (tng_trajectory_t tng_data,
4161                  tng_gen_block_t block,
4162                  const char hash_mode)
4163 {
4164     char *temp_name;
4165     int64_t i;
4166     int offset = 0;
4167     unsigned int name_len;
4168     tng_trajectory_frame_set_t frame_set =
4169     &tng_data->current_trajectory_frame_set;
4170
4171     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4172     {
4173         return(TNG_CRITICAL);
4174     }
4175
4176     name_len = (int)strlen("TRAJECTORY FRAME SET");
4177
4178     if(!block->name || strlen(block->name) < name_len)
4179     {
4180         temp_name = realloc(block->name, name_len + 1);
4181         if(!temp_name)
4182         {
4183             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4184                    name_len+1, __FILE__, __LINE__);
4185             free(block->name);
4186             block->name = 0;
4187             return(TNG_CRITICAL);
4188         }
4189         block->name = temp_name;
4190     }
4191     strcpy(block->name, "TRAJECTORY FRAME SET");
4192     block->id = TNG_TRAJECTORY_FRAME_SET;
4193
4194     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
4195         TNG_SUCCESS)
4196     {
4197         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
4198                 __FILE__, __LINE__);
4199         return(TNG_CRITICAL);
4200     }
4201
4202     if(block->block_contents)
4203     {
4204         free(block->block_contents);
4205     }
4206     block->block_contents = malloc(block->block_contents_size);
4207     if(!block->block_contents)
4208     {
4209         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4210                block->block_contents_size, __FILE__, __LINE__);
4211         return(TNG_CRITICAL);
4212     }
4213
4214     memcpy(block->block_contents, &frame_set->first_frame,
4215            sizeof(frame_set->first_frame));
4216     if(tng_data->output_endianness_swap_func_64)
4217     {
4218         if(tng_data->output_endianness_swap_func_64(tng_data,
4219                                       (int64_t *)block->header_contents+offset)
4220             != TNG_SUCCESS)
4221         {
4222             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4223                     __FILE__, __LINE__);
4224         }
4225     }
4226     offset += sizeof(frame_set->first_frame);
4227
4228     memcpy(block->block_contents+offset, &frame_set->n_frames,
4229            sizeof(frame_set->n_frames));
4230     if(tng_data->output_endianness_swap_func_64)
4231     {
4232         if(tng_data->output_endianness_swap_func_64(tng_data,
4233                                       (int64_t *)block->header_contents+offset)
4234             != TNG_SUCCESS)
4235         {
4236             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4237                     __FILE__, __LINE__);
4238         }
4239     }
4240     offset += sizeof(frame_set->n_frames);
4241
4242     if(tng_data->var_num_atoms_flag)
4243     {
4244         for(i = 0; i < tng_data->n_molecules; i++)
4245         {
4246             memcpy(block->block_contents+offset,
4247                    &frame_set->molecule_cnt_list[i],
4248                    sizeof(int64_t));
4249             if(tng_data->output_endianness_swap_func_64)
4250             {
4251                 if(tng_data->output_endianness_swap_func_64(tng_data,
4252                                             (int64_t *)block->header_contents+offset)
4253                     != TNG_SUCCESS)
4254                 {
4255                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4256                             __FILE__, __LINE__);
4257                 }
4258             }
4259             offset += sizeof(int64_t);
4260         }
4261     }
4262
4263
4264     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
4265            sizeof(frame_set->next_frame_set_file_pos));
4266     if(tng_data->output_endianness_swap_func_64)
4267     {
4268         if(tng_data->output_endianness_swap_func_64(tng_data,
4269                                       (int64_t *)block->header_contents+offset)
4270             != TNG_SUCCESS)
4271         {
4272             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4273                     __FILE__, __LINE__);
4274         }
4275     }
4276     offset += sizeof(frame_set->next_frame_set_file_pos);
4277
4278     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
4279            sizeof(frame_set->prev_frame_set_file_pos));
4280     if(tng_data->output_endianness_swap_func_64)
4281     {
4282         if(tng_data->output_endianness_swap_func_64(tng_data,
4283                                       (int64_t *)block->header_contents+offset)
4284             != TNG_SUCCESS)
4285         {
4286             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4287                     __FILE__, __LINE__);
4288         }
4289     }
4290     offset += sizeof(frame_set->prev_frame_set_file_pos);
4291
4292     memcpy(block->block_contents+offset,
4293            &frame_set->medium_stride_next_frame_set_file_pos,
4294            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4295     if(tng_data->output_endianness_swap_func_64)
4296     {
4297         if(tng_data->output_endianness_swap_func_64(tng_data,
4298                                       (int64_t *)block->header_contents+offset)
4299             != TNG_SUCCESS)
4300         {
4301             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4302                     __FILE__, __LINE__);
4303         }
4304     }
4305     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4306
4307     memcpy(block->block_contents+offset,
4308            &frame_set->medium_stride_prev_frame_set_file_pos,
4309            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4310     if(tng_data->output_endianness_swap_func_64)
4311     {
4312         if(tng_data->output_endianness_swap_func_64(tng_data,
4313                                       (int64_t *)block->header_contents+offset)
4314             != TNG_SUCCESS)
4315         {
4316             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4317                     __FILE__, __LINE__);
4318         }
4319     }
4320     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4321
4322     memcpy(block->block_contents+offset,
4323            &frame_set->long_stride_next_frame_set_file_pos,
4324            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4325     if(tng_data->output_endianness_swap_func_64)
4326     {
4327         if(tng_data->output_endianness_swap_func_64(tng_data,
4328                                       (int64_t *)block->header_contents+offset)
4329             != TNG_SUCCESS)
4330         {
4331             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4332                     __FILE__, __LINE__);
4333         }
4334     }
4335     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4336
4337     memcpy(block->block_contents+offset,
4338            &frame_set->long_stride_prev_frame_set_file_pos,
4339            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4340     if(tng_data->output_endianness_swap_func_64)
4341     {
4342         if(tng_data->output_endianness_swap_func_64(tng_data,
4343                                       (int64_t *)block->header_contents+offset)
4344             != TNG_SUCCESS)
4345         {
4346             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4347                     __FILE__, __LINE__);
4348         }
4349     }
4350     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4351
4352     memcpy(block->block_contents+offset,
4353            &frame_set->first_frame_time,
4354            sizeof(frame_set->first_frame_time));
4355     if(tng_data->output_endianness_swap_func_64)
4356     {
4357         if(tng_data->output_endianness_swap_func_64(tng_data,
4358                                       (int64_t *)block->header_contents+offset)
4359             != TNG_SUCCESS)
4360         {
4361             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4362                     __FILE__, __LINE__);
4363         }
4364     }
4365     offset += sizeof(frame_set->first_frame_time);
4366
4367     memcpy(block->block_contents+offset,
4368            &tng_data->time_per_frame,
4369            sizeof(tng_data->time_per_frame));
4370     if(tng_data->output_endianness_swap_func_64)
4371     {
4372         if(tng_data->output_endianness_swap_func_64(tng_data,
4373                                       (int64_t *)block->header_contents+offset)
4374             != TNG_SUCCESS)
4375         {
4376             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4377                     __FILE__, __LINE__);
4378         }
4379     }
4380
4381     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4382     {
4383         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4384                tng_data->output_file_path, __FILE__, __LINE__);
4385         return(TNG_CRITICAL);
4386     }
4387
4388     if(fwrite(block->block_contents, block->block_contents_size, 1,
4389               tng_data->output_file) != 1)
4390     {
4391         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4392         return(TNG_CRITICAL);
4393     }
4394
4395     return(TNG_SUCCESS);
4396 }
4397
4398 static tng_function_status tng_trajectory_mapping_block_len_calculate
4399                 (const tng_trajectory_t tng_data,
4400                  const int64_t n_particles,
4401                  int64_t *len)
4402 {
4403     (void)tng_data;
4404     *len = sizeof(int64_t) * (2 + n_particles);
4405
4406     return(TNG_SUCCESS);
4407 }
4408
4409 /** Read an atom mappings block (translating between real atom indexes and how
4410  *  the atom info is written in this frame set).
4411  * @param tng_data is a trajectory data container.
4412  * @param block is a general block container.
4413  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4414  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
4415  * compared to the md5 hash of the read contents to ensure valid data.
4416  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4417  * error has occured.
4418  */
4419 static tng_function_status tng_trajectory_mapping_block_read
4420                 (tng_trajectory_t tng_data,
4421                  tng_gen_block_t block,
4422                  const char hash_mode)
4423 {
4424     int64_t i;
4425     int offset = 0;
4426     tng_bool same_hash;
4427     tng_trajectory_frame_set_t frame_set =
4428     &tng_data->current_trajectory_frame_set;
4429
4430     tng_particle_mapping_t mapping, mappings;
4431
4432     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
4433     {
4434         return(TNG_CRITICAL);
4435     }
4436
4437     if(block->block_contents)
4438     {
4439         free(block->block_contents);
4440     }
4441
4442     block->block_contents = malloc(block->block_contents_size);
4443     if(!block->block_contents)
4444     {
4445         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4446                block->block_contents_size, __FILE__, __LINE__);
4447         return(TNG_CRITICAL);
4448     }
4449
4450     /* Read the whole block into block_contents to be able to write it to disk
4451      *  even if it cannot be interpreted. */
4452     if(fread(block->block_contents, block->block_contents_size, 1,
4453         tng_data->input_file) == 0)
4454     {
4455         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
4456         return(TNG_CRITICAL);
4457     }
4458
4459     /* FIXME: Does not check if the size of the contents matches the expected
4460      * size or if the contents can be read. */
4461
4462     if(hash_mode == TNG_USE_HASH)
4463     {
4464         tng_md5_hash_match_verify(block, &same_hash);
4465         if(same_hash != TNG_TRUE)
4466         {
4467             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4468                 "%s: %d\n",
4469                 __FILE__, __LINE__);
4470     /*         return(TNG_FAILURE); */
4471         }
4472     }
4473
4474     frame_set->n_mapping_blocks++;
4475     mappings = realloc(frame_set->mappings,
4476                        sizeof(struct tng_particle_mapping) *
4477                        frame_set->n_mapping_blocks);
4478     if(!mappings)
4479     {
4480         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4481                block->block_contents_size, __FILE__, __LINE__);
4482         free(frame_set->mappings);
4483         frame_set->mappings = 0;
4484         return(TNG_CRITICAL);
4485     }
4486     frame_set->mappings = mappings;
4487     mapping = &mappings[frame_set->n_mapping_blocks - 1];
4488
4489
4490     memcpy(&mapping->num_first_particle, block->block_contents+offset,
4491            sizeof(mapping->num_first_particle));
4492     if(tng_data->input_endianness_swap_func_64)
4493     {
4494         if(tng_data->input_endianness_swap_func_64(tng_data,
4495                                                    &mapping->num_first_particle)
4496             != TNG_SUCCESS)
4497         {
4498             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4499                     __FILE__, __LINE__);
4500         }
4501     }
4502     offset += sizeof(mapping->num_first_particle);
4503
4504     memcpy(&mapping->n_particles, block->block_contents+offset,
4505            sizeof(mapping->n_particles));
4506     if(tng_data->input_endianness_swap_func_64)
4507     {
4508         if(tng_data->input_endianness_swap_func_64(tng_data,
4509                                                    &mapping->n_particles)
4510             != TNG_SUCCESS)
4511         {
4512             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4513                     __FILE__, __LINE__);
4514         }
4515     }
4516     offset += sizeof(mapping->n_particles);
4517
4518     mapping->real_particle_numbers = malloc(mapping->n_particles *
4519                                             sizeof(int64_t));
4520     if(!mapping->real_particle_numbers)
4521     {
4522         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4523                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
4524         return(TNG_CRITICAL);
4525     }
4526
4527     /* If the byte order needs to be swapped the data must be read one value at
4528      * a time and swapped */
4529     if(tng_data->input_endianness_swap_func_64)
4530     {
4531         for(i = 0; i < mapping->n_particles; i++)
4532         {
4533             memcpy(&mapping->real_particle_numbers[i],
4534                     block->block_contents + offset,
4535                     sizeof(int64_t));
4536             if(tng_data->input_endianness_swap_func_64(tng_data,
4537                                             &mapping->real_particle_numbers[i])
4538                 != TNG_SUCCESS)
4539             {
4540                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4541                         __FILE__, __LINE__);
4542             }
4543             offset += sizeof(int64_t);
4544         }
4545     }
4546     /* Otherwise the data can be read all at once */
4547     else
4548     {
4549         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
4550                mapping->n_particles * sizeof(int64_t));
4551     }
4552
4553
4554     return(TNG_SUCCESS);
4555 }
4556
4557 /** Write the atom mappings of the current trajectory frame set
4558  * @param tng_data is a trajectory data container.
4559  * @param block is a general block container.
4560  * @param mapping_block_nr is the index of the mapping block to write.
4561  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4562  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4563  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4564  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4565  */
4566 static tng_function_status tng_trajectory_mapping_block_write
4567                 (tng_trajectory_t tng_data,
4568                  tng_gen_block_t block,
4569                  int mapping_block_nr,
4570                  const char hash_mode)
4571 {
4572     char *temp_name;
4573     int i, offset = 0;
4574     unsigned int name_len;
4575     tng_particle_mapping_t mapping =
4576     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4577
4578     if(mapping_block_nr >=
4579        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4580     {
4581         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4582                __FILE__, __LINE__);
4583         return(TNG_FAILURE);
4584     }
4585
4586     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4587     {
4588         return(TNG_CRITICAL);
4589     }
4590
4591     name_len = (int)strlen("PARTICLE MAPPING");
4592
4593     if(!block->name || strlen(block->name) < name_len)
4594     {
4595         temp_name = realloc(block->name, name_len + 1);
4596         if(!temp_name)
4597         {
4598             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4599                    name_len+1, __FILE__, __LINE__);
4600             free(block->name);
4601             block->name = 0;
4602             return(TNG_CRITICAL);
4603         }
4604         block->name = temp_name;
4605     }
4606     strcpy(block->name, "PARTICLE MAPPING");
4607     block->id = TNG_PARTICLE_MAPPING;
4608
4609     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4610                                                   mapping->n_particles,
4611                                                   &block->block_contents_size) !=
4612         TNG_SUCCESS)
4613     {
4614         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4615                 __FILE__, __LINE__);
4616         return(TNG_CRITICAL);
4617     }
4618
4619     if(block->block_contents)
4620     {
4621         free(block->block_contents);
4622     }
4623     block->block_contents = malloc(block->block_contents_size);
4624     if(!block->block_contents)
4625     {
4626         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4627                block->block_contents_size, __FILE__, __LINE__);
4628         return(TNG_CRITICAL);
4629     }
4630
4631     memcpy(block->block_contents, &mapping->num_first_particle,
4632            sizeof(mapping->num_first_particle));
4633     if(tng_data->output_endianness_swap_func_64)
4634     {
4635         if(tng_data->output_endianness_swap_func_64(tng_data,
4636                                       (int64_t *)block->header_contents+offset)
4637             != TNG_SUCCESS)
4638         {
4639             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4640                     __FILE__, __LINE__);
4641         }
4642     }
4643     offset += sizeof(mapping->num_first_particle);
4644
4645     memcpy(block->block_contents+offset, &mapping->n_particles,
4646            sizeof(mapping->n_particles));
4647     if(tng_data->output_endianness_swap_func_64)
4648     {
4649         if(tng_data->output_endianness_swap_func_64(tng_data,
4650                                       (int64_t *)block->header_contents+offset)
4651             != TNG_SUCCESS)
4652         {
4653             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4654                     __FILE__, __LINE__);
4655         }
4656     }
4657     offset += sizeof(mapping->n_particles);
4658
4659     if(tng_data->output_endianness_swap_func_64)
4660     {
4661         for(i = 0; i < mapping->n_particles; i++)
4662         {
4663             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
4664                 sizeof(int64_t));
4665             if(tng_data->output_endianness_swap_func_64(tng_data,
4666                                         (int64_t *)block->header_contents+offset)
4667                 != TNG_SUCCESS)
4668             {
4669                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4670                         __FILE__, __LINE__);
4671             }
4672             offset += sizeof(int64_t);
4673         }
4674     }
4675     else
4676     {
4677         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
4678                mapping->n_particles * sizeof(int64_t));
4679     }
4680
4681
4682     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4683     {
4684         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4685                tng_data->output_file_path, __FILE__, __LINE__);
4686         return(TNG_CRITICAL);
4687     }
4688
4689     if(fwrite(block->block_contents, block->block_contents_size, 1,
4690               tng_data->output_file) != 1)
4691     {
4692         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4693         return(TNG_CRITICAL);
4694     }
4695
4696     return(TNG_SUCCESS);
4697 }
4698
4699 /** Prepare a block for storing particle data
4700  * @param tng_data is a trajectory data container.
4701  * @param block_type_flag specifies if this is a trajectory block or a
4702  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4703  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4704  * error has occured.
4705  */
4706 static tng_function_status tng_particle_data_block_create
4707                 (tng_trajectory_t tng_data,
4708                  const char block_type_flag)
4709 {
4710     tng_trajectory_frame_set_t frame_set =
4711     &tng_data->current_trajectory_frame_set;
4712
4713     tng_particle_data_t data;
4714
4715     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4716     {
4717         frame_set->n_particle_data_blocks++;
4718         data = realloc(frame_set->tr_particle_data,
4719                     sizeof(struct tng_particle_data) *
4720                     frame_set->n_particle_data_blocks);
4721         if(!data)
4722         {
4723             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4724                 sizeof(struct tng_particle_data) *
4725                 frame_set->n_particle_data_blocks,
4726                 __FILE__, __LINE__);
4727             free(frame_set->tr_particle_data);
4728             frame_set->tr_particle_data = 0;
4729             return(TNG_CRITICAL);
4730         }
4731         frame_set->tr_particle_data = data;
4732     }
4733     else
4734     {
4735         tng_data->n_particle_data_blocks++;
4736         data = realloc(tng_data->non_tr_particle_data,
4737                         sizeof(struct tng_particle_data) *
4738                         tng_data->n_particle_data_blocks);
4739         if(!data)
4740         {
4741             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4742                     sizeof(struct tng_particle_data) *
4743                     tng_data->n_particle_data_blocks,
4744                     __FILE__, __LINE__);
4745             free(tng_data->non_tr_particle_data);
4746             tng_data->non_tr_particle_data = 0;
4747             return(TNG_CRITICAL);
4748         }
4749         tng_data->non_tr_particle_data = data;
4750     }
4751
4752     return(TNG_SUCCESS);
4753 }
4754
4755 static tng_function_status tng_compress(tng_trajectory_t tng_data,
4756                                         tng_gen_block_t block,
4757                                         const int64_t n_frames,
4758                                         const int64_t n_particles,
4759                                         const char type,
4760                                         void *start_pos)
4761 {
4762     int nalgo;
4763     int new_len;
4764     int *alt_algo = 0;
4765     char *dest, *temp;
4766     int64_t algo_find_n_frames;
4767     unsigned long offset;
4768     float f_precision;
4769     double d_precision;
4770
4771     if(block->id != TNG_TRAJ_POSITIONS &&
4772        block->id != TNG_TRAJ_VELOCITIES)
4773     {
4774         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4775                "TNG method. %s: %d\n", __FILE__, __LINE__);
4776         return(TNG_FAILURE);
4777     }
4778     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4779     {
4780         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4781         return(TNG_FAILURE);
4782     }
4783
4784     if(n_frames <= 0 || n_particles <= 0)
4785     {
4786         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4787                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4788         return(TNG_FAILURE);
4789     }
4790
4791     f_precision = 1/(float)tng_data->compression_precision;
4792     d_precision = 1/tng_data->compression_precision;
4793
4794     if(block->id == TNG_TRAJ_POSITIONS)
4795     {
4796         /* If there is only one frame in this frame set and there might be more
4797          * do not store the algorithm as the compression algorithm, but find
4798          * the best one without storing it */
4799         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4800         {
4801             nalgo = tng_compress_nalgo();
4802             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4803             if(type == TNG_FLOAT_DATA)
4804             {
4805                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
4806                                                         (int)n_frames,
4807                                                         f_precision,
4808                                                         0, alt_algo,
4809                                                         &new_len);
4810
4811             }
4812             else
4813             {
4814                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
4815                                            (int)n_frames,
4816                                            d_precision,
4817                                            0, alt_algo,
4818                                            &new_len);
4819             }
4820         }
4821         else if(!tng_data->compress_algo_pos)
4822         {
4823             if(n_frames > 10)
4824             {
4825                 algo_find_n_frames = 5;
4826             }
4827             else
4828             {
4829                 algo_find_n_frames = n_frames;
4830             }
4831
4832             nalgo = tng_compress_nalgo();
4833             tng_data->compress_algo_pos=malloc(nalgo *
4834                                            sizeof *tng_data->compress_algo_pos);
4835             if(type == TNG_FLOAT_DATA)
4836             {
4837                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
4838                                                         (int)algo_find_n_frames,
4839                                                         f_precision,
4840                                                         0, tng_data->
4841                                                         compress_algo_pos,
4842                                                         &new_len);
4843
4844                 if(algo_find_n_frames < n_frames)
4845                 {
4846                     dest = tng_compress_pos_float(start_pos, (int)n_particles,
4847                                                   (int)n_frames,
4848                                                   f_precision,
4849                                                   0, tng_data->compress_algo_pos,
4850                                                   &new_len);
4851                 }
4852             }
4853             else
4854             {
4855                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
4856                                            (int)algo_find_n_frames,
4857                                            d_precision,
4858                                            0, tng_data->
4859                                            compress_algo_pos,
4860                                            &new_len);
4861
4862                 if(algo_find_n_frames < n_frames)
4863                 {
4864                     dest = tng_compress_pos(start_pos, (int)n_particles,
4865                                             (int)n_frames,
4866                                             d_precision, 0,
4867                                             tng_data->compress_algo_pos,
4868                                             &new_len);
4869                 }
4870             }
4871         }
4872         else
4873         {
4874             if(type == TNG_FLOAT_DATA)
4875             {
4876                 dest = tng_compress_pos_float(start_pos, (int)n_particles,
4877                                               (int)n_frames,
4878                                               f_precision, 0,
4879                                               tng_data->compress_algo_pos, &new_len);
4880             }
4881             else
4882             {
4883                 dest = tng_compress_pos(start_pos, (int)n_particles,
4884                                         (int)n_frames,
4885                                         d_precision, 0,
4886                                         tng_data->compress_algo_pos,
4887                                         &new_len);
4888             }
4889         }
4890     }
4891     else if(block->id == TNG_TRAJ_VELOCITIES)
4892     {
4893         /* If there is only one frame in this frame set and there might be more
4894          * do not store the algorithm as the compression algorithm, but find
4895          * the best one without storing it */
4896         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4897         {
4898             nalgo = tng_compress_nalgo();
4899             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4900             if(type == TNG_FLOAT_DATA)
4901             {
4902                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4903                                                         (int)n_frames,
4904                                                         f_precision,
4905                                                         0, alt_algo,
4906                                                         &new_len);
4907
4908             }
4909             else
4910             {
4911                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4912                                                   (int)n_frames,
4913                                                   d_precision,
4914                                                   0, alt_algo,
4915                                                   &new_len);
4916             }
4917         }
4918         else if(!tng_data->compress_algo_vel)
4919         {
4920             if(n_frames > 10)
4921             {
4922                 algo_find_n_frames = 5;
4923             }
4924             else
4925             {
4926                 algo_find_n_frames = n_frames;
4927             }
4928
4929             nalgo = tng_compress_nalgo();
4930             tng_data->compress_algo_vel=malloc(nalgo *
4931                                            sizeof *tng_data->compress_algo_vel);
4932
4933             if(type == TNG_FLOAT_DATA)
4934             {
4935                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4936                                                         (int)algo_find_n_frames,
4937                                                         f_precision,
4938                                                         0, tng_data->
4939                                                         compress_algo_vel,
4940                                                         &new_len);
4941                 if(algo_find_n_frames < n_frames)
4942                 {
4943                     dest = tng_compress_vel_float(start_pos, (int)n_particles,
4944                                                   (int)n_frames,
4945                                                   f_precision,
4946                                                   0, tng_data->compress_algo_vel,
4947                                                   &new_len);
4948                 }
4949             }
4950             else
4951             {
4952                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4953                                                   (int)algo_find_n_frames,
4954                                                   d_precision,
4955                                                   0, tng_data->
4956                                                   compress_algo_vel,
4957                                                   &new_len);
4958                 if(algo_find_n_frames < n_frames)
4959                 {
4960                     dest = tng_compress_vel(start_pos, (int)n_particles,
4961                                             (int)n_frames,
4962                                             d_precision,
4963                                             0, tng_data->compress_algo_vel,
4964                                             &new_len);
4965                 }
4966             }
4967         }
4968         else
4969         {
4970             if(type == TNG_FLOAT_DATA)
4971             {
4972                 dest = tng_compress_vel_float(start_pos, (int)n_particles,
4973                                               (int)n_frames,
4974                                               f_precision,
4975                                               0, tng_data->
4976                                               compress_algo_vel,
4977                                               &new_len);
4978             }
4979             else
4980             {
4981                 dest = tng_compress_vel(start_pos, (int)n_particles,
4982                                         (int)n_frames,
4983                                         d_precision,
4984                                         0, tng_data->
4985                                         compress_algo_vel,
4986                                         &new_len);
4987             }
4988         }
4989     }
4990     else
4991     {
4992         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4993         return(TNG_FAILURE);
4994     }
4995
4996     offset = (unsigned long)((char *)start_pos - block->block_contents);
4997
4998     if(alt_algo)
4999     {
5000         free(alt_algo);
5001     }
5002
5003     block->block_contents_size = new_len + offset;
5004
5005     temp = realloc(block->block_contents, block->block_contents_size);
5006     if(!temp)
5007     {
5008         free(block->block_contents);
5009         block->block_contents = 0;
5010         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5011                block->block_contents_size, __FILE__, __LINE__);
5012         return(TNG_CRITICAL);
5013     }
5014     block->block_contents = temp;
5015     if(dest)
5016     {
5017         memcpy(temp + offset, dest, new_len);
5018         free(dest);
5019     }
5020     else
5021     {
5022         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
5023         return(TNG_FAILURE);
5024     }
5025
5026     return(TNG_SUCCESS);
5027 }
5028
5029 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
5030                                           tng_gen_block_t block,
5031                                           const char type,
5032                                           void *start_pos,
5033                                           const unsigned long uncompressed_len)
5034 {
5035     char *temp;
5036     double *d_dest = 0;
5037     float *f_dest = 0;
5038     unsigned long offset;
5039     int result;
5040     (void)tng_data;
5041
5042     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5043
5044     if(block->id != TNG_TRAJ_POSITIONS &&
5045        block->id != TNG_TRAJ_VELOCITIES)
5046     {
5047         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5048                "TNG method.\n");
5049         return(TNG_FAILURE);
5050     }
5051     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5052     {
5053         fprintf(stderr, "TNG library: Data type not supported.\n");
5054         return(TNG_FAILURE);
5055     }
5056
5057     if(type == TNG_FLOAT_DATA)
5058     {
5059         f_dest = malloc(uncompressed_len);
5060         if(!f_dest)
5061         {
5062             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5063                 uncompressed_len, __FILE__, __LINE__);
5064             return(TNG_CRITICAL);
5065         }
5066         result = tng_compress_uncompress_float(start_pos, f_dest);
5067     }
5068     else
5069     {
5070         d_dest = malloc(uncompressed_len);
5071         if(!d_dest)
5072         {
5073             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5074                 uncompressed_len, __FILE__, __LINE__);
5075             return(TNG_CRITICAL);
5076         }
5077         result = tng_compress_uncompress(start_pos, d_dest);
5078     }
5079
5080     if(result == 1)
5081     {
5082         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5083         return(TNG_FAILURE);
5084     }
5085
5086     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5087
5088     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5089
5090     temp = realloc(block->block_contents, uncompressed_len + offset);
5091     if(!temp)
5092     {
5093         free(block->block_contents);
5094         block->block_contents = 0;
5095         if(d_dest)
5096         {
5097             free(d_dest);
5098         }
5099         if(f_dest)
5100         {
5101             free(f_dest);
5102         }
5103         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5104                block->block_contents_size, __FILE__, __LINE__);
5105         return(TNG_CRITICAL);
5106     }
5107
5108     if(type == TNG_FLOAT_DATA)
5109     {
5110         memcpy(temp + offset, f_dest, uncompressed_len);
5111     }
5112     else
5113     {
5114         memcpy(temp + offset, d_dest, uncompressed_len);
5115     }
5116
5117     block->block_contents = temp;
5118
5119     if(d_dest)
5120     {
5121         free(d_dest);
5122     }
5123     if(f_dest)
5124     {
5125         free(f_dest);
5126     }
5127     return(TNG_SUCCESS);
5128 }
5129
5130 #ifdef USE_ZLIB
5131 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5132                                              tng_gen_block_t block,
5133                                              void *start_pos, const int len)
5134 {
5135     Bytef *dest;
5136     char *temp;
5137     unsigned long max_len, stat, offset;
5138     (void)tng_data;
5139
5140     max_len = compressBound(len);
5141     dest = malloc(max_len);
5142     if(!dest)
5143     {
5144         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
5145                max_len, __FILE__, __LINE__);
5146         return(TNG_CRITICAL);
5147     }
5148
5149     stat = compress(dest, &max_len, start_pos, len);
5150     if(stat != (unsigned long)Z_OK)
5151     {
5152         free(dest);
5153         if(stat == (unsigned long)Z_MEM_ERROR)
5154         {
5155             fprintf(stderr, "TNG library: Not enough memory. ");
5156         }
5157         else if(stat == (unsigned long)Z_BUF_ERROR)
5158         {
5159             fprintf(stderr, "TNG library: Destination buffer too small. ");
5160         }
5161         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5162         return(TNG_FAILURE);
5163     }
5164
5165     offset = (char *)start_pos - block->block_contents;
5166
5167     block->block_contents_size = max_len + offset;
5168
5169     temp = realloc(block->block_contents, block->block_contents_size);
5170     if(!temp)
5171     {
5172         free(block->block_contents);
5173         free(dest);
5174         block->block_contents = 0;
5175         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5176                block->block_contents_size, __FILE__, __LINE__);
5177         return(TNG_CRITICAL);
5178     }
5179
5180     block->block_contents = temp;
5181
5182     memcpy(temp + offset, dest, max_len);
5183
5184     free(dest);
5185
5186     return(TNG_SUCCESS);
5187 }
5188
5189 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5190                                                tng_gen_block_t block,
5191                                                void *start_pos,
5192                                                unsigned long uncompressed_len)
5193 {
5194     Bytef *dest;
5195     char *temp;
5196     unsigned long stat;
5197     int offset;
5198     (void)tng_data;
5199
5200     offset = (char *)start_pos - (char *)block->block_contents;
5201
5202     dest = malloc(uncompressed_len);
5203     if(!dest)
5204     {
5205         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5206                uncompressed_len, __FILE__, __LINE__);
5207         return(TNG_CRITICAL);
5208     }
5209
5210     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5211                       block->block_contents_size - offset);
5212
5213     if(stat != Z_OK)
5214     {
5215         free(dest);
5216         if(stat == (unsigned long)Z_MEM_ERROR)
5217         {
5218             fprintf(stderr, "TNG library: Not enough memory. ");
5219         }
5220         else if(stat == (unsigned long)Z_BUF_ERROR)
5221         {
5222             fprintf(stderr, "TNG library: Destination buffer too small. ");
5223         }
5224         else if(stat == (unsigned long)Z_DATA_ERROR)
5225         {
5226             fprintf(stderr, "TNG library: Data corrupt. ");
5227         }
5228         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5229                __LINE__);
5230         return(TNG_FAILURE);
5231     }
5232
5233
5234     block->block_contents_size = uncompressed_len + offset;
5235
5236     temp = realloc(block->block_contents, uncompressed_len + offset);
5237     if(!temp)
5238     {
5239         free(block->block_contents);
5240         block->block_contents = 0;
5241         free(dest);
5242         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5243                block->block_contents_size, __FILE__, __LINE__);
5244         return(TNG_CRITICAL);
5245     }
5246
5247     memcpy(temp + offset, dest, uncompressed_len);
5248
5249     block->block_contents = temp;
5250
5251     free(dest);
5252     return(TNG_SUCCESS);
5253 }
5254 #endif
5255
5256 /** Allocate memory for storing particle data.
5257  * The allocated block will be refered to by data->values.
5258  * @param tng_data is a trajectory data container.
5259  * @param data is the data struct, which will contain the allocated memory in
5260  * data->values.
5261  * @param n_frames is the number of frames of data to store.
5262  * @param n_particles is the number of particles with data.
5263  * @param n_values_per_frame is the number of data values per particle and
5264  * frame.
5265  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5266  * error has occured.
5267  */
5268 static tng_function_status tng_allocate_particle_data_mem
5269                 (tng_trajectory_t tng_data,
5270                  tng_particle_data_t data,
5271                  int64_t n_frames,
5272                  int64_t stride_length,
5273                  const int64_t n_particles,
5274                  const int64_t n_values_per_frame)
5275 {
5276     void ***values;
5277     int64_t i, j, k, size, frame_alloc;
5278     (void)tng_data;
5279
5280     if(n_particles == 0 || n_values_per_frame == 0)
5281     {
5282         return(TNG_FAILURE);
5283     }
5284
5285     if(data->strings && data->datatype == TNG_CHAR_DATA)
5286     {
5287         for(i = 0; i < data->n_frames; i++)
5288         {
5289             for(j = 0; j < n_particles; j++)
5290             {
5291                 for(k = 0; k < data->n_values_per_frame; k++)
5292                 {
5293                     if(data->strings[i][j][k])
5294                     {
5295                         free(data->strings[i][j][k]);
5296                     }
5297                 }
5298                 free(data->strings[i][j]);
5299             }
5300             free(data->strings[i]);
5301         }
5302         free(data->strings);
5303     }
5304     data->n_frames = n_frames;
5305     n_frames = tng_max_i64(1, n_frames);
5306     data->stride_length = tng_max_i64(1, stride_length);
5307     data->n_values_per_frame = n_values_per_frame;
5308     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5309
5310     if(data->datatype == TNG_CHAR_DATA)
5311     {
5312         data->strings = malloc(sizeof(char ***) * frame_alloc);
5313         for(i = 0; i < frame_alloc; i++)
5314         {
5315             data->strings[i] = malloc(sizeof(char **) *
5316                                     n_particles);
5317             if(!data->strings[i])
5318             {
5319                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5320                     sizeof(union data_values *) * n_particles,
5321                     __FILE__, __LINE__);
5322                 return(TNG_CRITICAL);
5323             }
5324             for(j = 0; j < n_particles; j++)
5325             {
5326                 data->strings[i][j] = malloc(sizeof(char *) *
5327                                             n_values_per_frame);
5328                 if(!data->strings[i][j])
5329                 {
5330                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5331                         sizeof(union data_values) * n_values_per_frame,
5332                         __FILE__, __LINE__);
5333                     return(TNG_CRITICAL);
5334                 }
5335                 for(k = 0; k < n_values_per_frame; k++)
5336                 {
5337                     data->strings[i][j][k] = 0;
5338                 }
5339             }
5340         }
5341     }
5342     else
5343     {
5344         switch(data->datatype)
5345         {
5346         case TNG_INT_DATA:
5347             size = sizeof(int64_t);
5348             break;
5349         case TNG_FLOAT_DATA:
5350             size = sizeof(float);
5351             break;
5352         case TNG_DOUBLE_DATA:
5353         default:
5354             size = sizeof(double);
5355         }
5356
5357         values = realloc(data->values,
5358                          size * frame_alloc *
5359                          n_particles * n_values_per_frame);
5360         if(!values)
5361         {
5362             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5363                    size * frame_alloc *
5364                    n_particles * n_values_per_frame,
5365                    __FILE__, __LINE__);
5366             free(data->values);
5367             data->values = 0;
5368             return(TNG_CRITICAL);
5369         }
5370         data->values = values;
5371     }
5372     return(TNG_SUCCESS);
5373 }
5374
5375 static tng_function_status tng_particle_data_find
5376                 (tng_trajectory_t tng_data,
5377                  const int64_t id,
5378                  tng_particle_data_t *data)
5379 {
5380     int64_t block_index, i;
5381     tng_trajectory_frame_set_t frame_set = &tng_data->
5382                                            current_trajectory_frame_set;
5383     char block_type_flag;
5384
5385     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5386        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5387     {
5388         block_type_flag = TNG_TRAJECTORY_BLOCK;
5389     }
5390     else
5391     {
5392         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5393     }
5394
5395     block_index = -1;
5396     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5397     {
5398         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5399         {
5400             *data = &frame_set->tr_particle_data[i];
5401             if((*data)->block_id == id)
5402             {
5403                 block_index = i;
5404                 break;
5405             }
5406         }
5407     }
5408     else
5409     {
5410         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5411         {
5412             *data = &tng_data->non_tr_particle_data[i];
5413             if((*data)->block_id == id)
5414             {
5415                 block_index = i;
5416                 break;
5417             }
5418         }
5419     }
5420     if(block_index == -1)
5421     {
5422         return(TNG_FAILURE);
5423     }
5424     return(TNG_SUCCESS);
5425 }
5426
5427 static tng_function_status tng_data_find
5428                 (tng_trajectory_t tng_data,
5429                  const int64_t id,
5430                  tng_non_particle_data_t *data)
5431 {
5432     int64_t block_index, i;
5433     tng_trajectory_frame_set_t frame_set = &tng_data->
5434                                            current_trajectory_frame_set;
5435     char block_type_flag;
5436
5437     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5438        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5439     {
5440         block_type_flag = TNG_TRAJECTORY_BLOCK;
5441     }
5442     else
5443     {
5444         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5445     }
5446
5447     block_index = -1;
5448     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5449     {
5450         for(i = 0; i < frame_set->n_data_blocks; i++)
5451         {
5452             *data = &frame_set->tr_data[i];
5453             if((*data)->block_id == id)
5454             {
5455                 block_index = i;
5456                 break;
5457             }
5458         }
5459         if(block_index == -1)
5460         {
5461             for(i = 0; i < tng_data->n_data_blocks; i++)
5462             {
5463                 *data = &tng_data->non_tr_data[i];
5464                 if((*data)->block_id == id)
5465                 {
5466                     block_index = i;
5467                     break;
5468                 }
5469             }
5470         }
5471     }
5472     else
5473     {
5474         for(i = 0; i < tng_data->n_data_blocks; i++)
5475         {
5476             *data = &tng_data->non_tr_data[i];
5477             if((*data)->block_id == id)
5478             {
5479                 block_index = i;
5480                 break;
5481             }
5482         }
5483     }
5484     if(block_index == -1)
5485     {
5486         return(TNG_FAILURE);
5487     }
5488     return(TNG_SUCCESS);
5489 }
5490
5491 static tng_function_status tng_data_block_len_calculate
5492                 (const tng_trajectory_t tng_data,
5493                  const tng_particle_data_t data,
5494                  const tng_bool is_particle_data,
5495                  const int64_t n_frames,
5496                  const int64_t frame_step,
5497                  const int64_t stride_length,
5498                  const int64_t num_first_particle,
5499                  const int64_t n_particles,
5500                  const char dependency,
5501                  int64_t *data_start_pos,
5502                  int64_t *len)
5503 {
5504     int size;
5505     int64_t i, j, k;
5506     char ***first_dim_values, **second_dim_values;
5507     (void)tng_data;
5508
5509     if(data == 0)
5510     {
5511         return(TNG_SUCCESS);
5512     }
5513
5514     switch(data->datatype)
5515     {
5516     case TNG_CHAR_DATA:
5517         size = 1;
5518         break;
5519     case TNG_INT_DATA:
5520         size = sizeof(int64_t);
5521         break;
5522     case TNG_FLOAT_DATA:
5523         size = sizeof(float);
5524         break;
5525     case TNG_DOUBLE_DATA:
5526     default:
5527         size = sizeof(double);
5528     }
5529
5530     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5531            sizeof(data->codec_id);
5532     if(is_particle_data)
5533     {
5534         *len += sizeof(num_first_particle) + sizeof(n_particles);
5535     }
5536
5537     if(stride_length > 1)
5538     {
5539         *len += sizeof(data->first_frame_with_data) +
5540                 sizeof(data->stride_length);
5541     }
5542
5543     if(data->codec_id != TNG_UNCOMPRESSED)
5544     {
5545         *len += sizeof(data->compression_multiplier);
5546     }
5547
5548     if(dependency & TNG_FRAME_DEPENDENT)
5549     {
5550         *len += sizeof(char);
5551     }
5552
5553     *data_start_pos = *len;
5554
5555     if(data->datatype == TNG_CHAR_DATA)
5556     {
5557         if(is_particle_data)
5558         {
5559             for(i = 0; i < n_frames; i++)
5560             {
5561                 first_dim_values = data->strings[i];
5562                 for(j = num_first_particle; j < num_first_particle + n_particles;
5563                     j++)
5564                 {
5565                     second_dim_values = first_dim_values[j];
5566                     for(k = 0; k < data->n_values_per_frame; k++)
5567                     {
5568                         *len += strlen(second_dim_values[k]) + 1;
5569                     }
5570                 }
5571             }
5572         }
5573         else
5574         {
5575             for(i = 0; i < n_frames; i++)
5576             {
5577                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5578                 for(j = 0; j < data->n_values_per_frame; j++)
5579                 {
5580                     *len += strlen(second_dim_values[j]) + 1;
5581                 }
5582             }
5583         }
5584     }
5585     else
5586     {
5587         *len += size * frame_step * n_particles * data->n_values_per_frame;
5588     }
5589
5590     return(TNG_SUCCESS);
5591 }
5592
5593 /** Read the values of a particle data block
5594  * @param tng_data is a trajectory data container.
5595  * @param block is the block to store the data (should already contain
5596  * the block headers and the block contents).
5597  * @param offset is the reading offset to point at the place where the actual
5598  * values are stored, starting from the beginning of the block_contents. The
5599  * offset is changed during the reading.
5600  * @param datatype is the type of data of the data block (char, int, float or
5601  * double).
5602  * @param num_first_particle is the number of the first particle in the data
5603  * block. This should be the same as in the corresponding particle mapping
5604  * block.
5605  * @param n_particles is the number of particles in the data block. This should
5606  * be the same as in the corresponding particle mapping block.
5607  * @param first_frame_with_data is the frame number of the first frame with data
5608  * in this data block.
5609  * @param stride_length is the number of frames between each data entry.
5610  * @param n_frames is the number of frames in this data block.
5611  * @param n_values is the number of values per particle and frame stored in this
5612  * data block.
5613  * @param codec_id is the ID of the codec to compress the data.
5614  * @param multiplier is the multiplication factor applied to each data value
5615  * before compression. This factor is applied since some compression algorithms
5616  * work only on integers.
5617  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5618  * error has occured.
5619  */
5620 static tng_function_status tng_particle_data_read
5621                 (tng_trajectory_t tng_data,
5622                  tng_gen_block_t block,
5623                  int *offset,
5624                  const char datatype,
5625                  const int64_t num_first_particle,
5626                  const int64_t n_particles,
5627                  const int64_t first_frame_with_data,
5628                  const int64_t stride_length,
5629                  int64_t n_frames,
5630                  const int64_t n_values,
5631                  const int64_t codec_id,
5632                  const double multiplier)
5633 {
5634     int64_t i, j, k, tot_n_particles, n_frames_div;
5635     int size, len;
5636     unsigned long data_size;
5637     char ***first_dim_values, **second_dim_values;
5638     tng_particle_data_t data;
5639     tng_trajectory_frame_set_t frame_set =
5640     &tng_data->current_trajectory_frame_set;
5641     char block_type_flag;
5642
5643     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5644
5645     switch(datatype)
5646     {
5647     case TNG_CHAR_DATA:
5648         size = 1;
5649         break;
5650     case TNG_INT_DATA:
5651         size = sizeof(int64_t);
5652         break;
5653     case TNG_FLOAT_DATA:
5654         size = sizeof(float);
5655         break;
5656     case TNG_DOUBLE_DATA:
5657     default:
5658         size = sizeof(double);
5659     }
5660
5661     /* If the block does not exist, create it */
5662     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5663     {
5664         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5665         {
5666             block_type_flag = TNG_TRAJECTORY_BLOCK;
5667         }
5668         else
5669         {
5670             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5671         }
5672
5673         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5674            TNG_SUCCESS)
5675         {
5676             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5677                    __FILE__, __LINE__);
5678             return(TNG_CRITICAL);
5679         }
5680         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5681         {
5682             data = &frame_set->tr_particle_data[frame_set->
5683                                                 n_particle_data_blocks - 1];
5684         }
5685         else
5686         {
5687             data = &tng_data->non_tr_particle_data[tng_data->
5688                                                    n_particle_data_blocks - 1];
5689         }
5690         data->block_id = block->id;
5691
5692         data->block_name = malloc(strlen(block->name) + 1);
5693         if(!data->block_name)
5694         {
5695             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5696                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5697             return(TNG_CRITICAL);
5698         }
5699         strcpy(data->block_name, block->name);
5700
5701         data->datatype = datatype;
5702
5703         data->values = 0;
5704         /* FIXME: Memory leak from strings. */
5705         data->strings = 0;
5706         data->n_frames = 0;
5707         data->codec_id = codec_id;
5708         data->compression_multiplier = multiplier;
5709         data->last_retrieved_frame = -1;
5710     }
5711
5712     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5713        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5714        tng_data->var_num_atoms_flag)
5715     {
5716         tot_n_particles = frame_set->n_particles;
5717     }
5718     else
5719     {
5720         tot_n_particles = tng_data->n_particles;
5721     }
5722
5723     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5724
5725     if(codec_id != TNG_UNCOMPRESSED)
5726     {
5727         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5728         switch(codec_id)
5729         {
5730         case TNG_XTC_COMPRESSION:
5731             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5732             break;
5733         case TNG_TNG_COMPRESSION:
5734 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5735             if(tng_uncompress(tng_data, block, datatype,
5736                               block->block_contents + *offset,
5737                               data_size) != TNG_SUCCESS)
5738             {
5739                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5740                        __FILE__, __LINE__);
5741                 return(TNG_CRITICAL);
5742             }
5743 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5744             break;
5745 #ifdef USE_ZLIB
5746         case TNG_GZIP_COMPRESSION:
5747 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5748             if(tng_gzip_uncompress(tng_data, block,
5749                                    block->block_contents + *offset,
5750                                    data_size) != TNG_SUCCESS)
5751             {
5752                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5753                     __LINE__);
5754                 return(TNG_CRITICAL);
5755             }
5756 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5757             break;
5758 #endif
5759         }
5760     }
5761     /* Allocate memory */
5762     if(!data->values || data->n_frames != n_frames ||
5763        data->n_values_per_frame != n_values)
5764     {
5765         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5766                                           stride_length,
5767                                           tot_n_particles, n_values) !=
5768            TNG_SUCCESS)
5769         {
5770             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5771                    __FILE__, __LINE__);
5772             return(TNG_CRITICAL);
5773         }
5774     }
5775
5776     data->first_frame_with_data = first_frame_with_data;
5777
5778     if(datatype == TNG_CHAR_DATA)
5779     {
5780         for(i = 0; i < n_frames_div; i++)
5781         {
5782             first_dim_values = data->strings[i];
5783             for(j = num_first_particle; j < num_first_particle + n_particles;
5784                 j++)
5785             {
5786                 second_dim_values = first_dim_values[j];
5787                 for(k = 0; k < n_values; k++)
5788                 {
5789                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5790                               TNG_MAX_STR_LEN);
5791                     if(second_dim_values[k])
5792                     {
5793                         free(second_dim_values[k]);
5794                     }
5795                     second_dim_values[k] = malloc(len);
5796                     if(!second_dim_values[k])
5797                     {
5798                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5799                             len, __FILE__, __LINE__);
5800                         return(TNG_CRITICAL);
5801                     }
5802                     strncpy(second_dim_values[k],
5803                             block->block_contents+*offset, len);
5804                     *offset += len;
5805                 }
5806             }
5807         }
5808     }
5809     else
5810     {
5811         memcpy((char *)data->values + n_frames_div * size * n_values *
5812                num_first_particle,
5813                block->block_contents + *offset,
5814                block->block_contents_size - *offset);
5815         switch(datatype)
5816         {
5817         case TNG_FLOAT_DATA:
5818             if(tng_data->input_endianness_swap_func_32)
5819             {
5820                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5821                 {
5822                     if(tng_data->input_endianness_swap_func_32(tng_data,
5823                         (int32_t *)((char *)data->values + i))
5824                         != TNG_SUCCESS)
5825                     {
5826                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5827                                 __FILE__, __LINE__);
5828                     }
5829                 }
5830             }
5831             break;
5832         case TNG_INT_DATA:
5833         case TNG_DOUBLE_DATA:
5834             if(tng_data->input_endianness_swap_func_64)
5835             {
5836                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5837                 {
5838                     if(tng_data->input_endianness_swap_func_64(tng_data,
5839                         (int64_t *)((char *)data->values + i))
5840                         != TNG_SUCCESS)
5841                     {
5842                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5843                                 __FILE__, __LINE__);
5844                     }
5845                 }
5846             }
5847             break;
5848         case TNG_CHAR_DATA:
5849             break;
5850         }
5851     }
5852     return(TNG_SUCCESS);
5853 }
5854
5855 /** Write a particle data block
5856  * @param tng_data is a trajectory data container.
5857  * @param block is the block to store the data (should already contain
5858  * the block headers and the block contents).
5859  * @param block_index is the index number of the data block in the frame set.
5860  * @param mapping is the particle mapping that is relevant for the data block.
5861  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5862  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5863  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5864  * error has occured.
5865  */
5866 static tng_function_status tng_particle_data_block_write
5867                 (tng_trajectory_t tng_data,
5868                  tng_gen_block_t block,
5869                  const int64_t block_index,
5870                  const tng_particle_mapping_t mapping,
5871                  const char hash_mode)
5872 {
5873     int64_t n_particles, num_first_particle, n_frames, stride_length;
5874     int64_t frame_step, data_start_pos;
5875     int64_t i, j, k;
5876     int size;
5877     size_t len, offset = 0;
5878     char dependency, temp, *temp_name;
5879     double multiplier;
5880     char ***first_dim_values, **second_dim_values;
5881     tng_trajectory_frame_set_t frame_set;
5882     tng_function_status stat;
5883
5884     tng_particle_data_t data;
5885     char block_type_flag;
5886
5887     frame_set = &tng_data->current_trajectory_frame_set;
5888
5889     /* If we have already started writing frame sets it is too late to write
5890      * non-trajectory data blocks */
5891     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5892     {
5893         block_type_flag = TNG_TRAJECTORY_BLOCK;
5894     }
5895     else
5896     {
5897         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5898     }
5899
5900     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5901     {
5902         return(TNG_CRITICAL);
5903     }
5904
5905     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5906     {
5907         data = &frame_set->tr_particle_data[block_index];
5908
5909         /* If this data block has not had any data added in this frame set
5910          * do not write it. */
5911         if(data->first_frame_with_data < frame_set->first_frame)
5912         {
5913             return(TNG_SUCCESS);
5914         }
5915
5916         stride_length = tng_max_i64(1, data->stride_length);
5917     }
5918     else
5919     {
5920         data = &tng_data->non_tr_particle_data[block_index];
5921         stride_length = 1;
5922     }
5923
5924     switch(data->datatype)
5925     {
5926     case TNG_CHAR_DATA:
5927         size = 1;
5928         break;
5929     case TNG_INT_DATA:
5930         size = sizeof(int64_t);
5931         break;
5932     case TNG_FLOAT_DATA:
5933         size = sizeof(float);
5934         break;
5935     case TNG_DOUBLE_DATA:
5936     default:
5937         size = sizeof(double);
5938     }
5939
5940     len = strlen(data->block_name) + 1;
5941
5942     if(!block->name || strlen(block->name) < len)
5943     {
5944         temp_name = realloc(block->name, len);
5945         if(!temp_name)
5946         {
5947             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
5948                    __FILE__, __LINE__);
5949             free(block->name);
5950             block->name = 0;
5951             return(TNG_CRITICAL);
5952         }
5953         block->name = temp_name;
5954     }
5955     strncpy(block->name, data->block_name, len);
5956     block->id = data->block_id;
5957
5958     /* If writing frame independent data data->n_frames is 0, but n_frames
5959        is used for the loop writing the data (and reserving memory) and needs
5960        to be at least 1 */
5961     n_frames = tng_max_i64(1, data->n_frames);
5962
5963     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5964     {
5965         /* If the frame set is finished before writing the full number of frames
5966            make sure the data block is not longer than the frame set. */
5967         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5968
5969         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5970     }
5971
5972     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5973                  n_frames / stride_length;
5974
5975     /* TNG compression will use compression precision to get integers from
5976      * floating point data. The compression multiplier stores that information
5977      * to be able to return the precision of the compressed data. */
5978     if(data->codec_id == TNG_TNG_COMPRESSION)
5979     {
5980         data->compression_multiplier = tng_data->compression_precision;
5981     }
5982     /* Uncompressed data blocks do not use compression multipliers at all.
5983      * GZip compression does not need it either. */
5984     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5985     {
5986         data->compression_multiplier = 1.0;
5987     }
5988
5989     if(mapping && mapping->n_particles != 0)
5990     {
5991         n_particles = mapping->n_particles;
5992         num_first_particle = mapping->num_first_particle;
5993     }
5994     else
5995     {
5996         num_first_particle = 0;
5997         if(tng_data->var_num_atoms_flag)
5998         {
5999             n_particles = frame_set->n_particles;
6000         }
6001         else
6002         {
6003             n_particles = tng_data->n_particles;
6004         }
6005     }
6006
6007     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6008     {
6009         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6010     }
6011     else
6012     {
6013         dependency = TNG_PARTICLE_DEPENDENT;
6014     }
6015
6016     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6017                                     frame_step, stride_length, num_first_particle,
6018                                     n_particles, dependency, &data_start_pos,
6019                                     &block->block_contents_size) != TNG_SUCCESS)
6020     {
6021         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6022                 __FILE__, __LINE__);
6023         return(TNG_CRITICAL);
6024     }
6025
6026     if(block->block_contents)
6027     {
6028         free(block->block_contents);
6029     }
6030     block->block_contents = malloc(block->block_contents_size);
6031     if(!block->block_contents)
6032     {
6033         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6034                block->block_contents_size, __FILE__, __LINE__);
6035         return(TNG_CRITICAL);
6036     }
6037
6038
6039     memcpy(block->block_contents, &data->datatype, sizeof(char));
6040     offset += sizeof(char);
6041
6042     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6043     offset += sizeof(char);
6044
6045     if(dependency & TNG_FRAME_DEPENDENT)
6046     {
6047         if(stride_length > 1)
6048         {
6049             temp = 1;
6050         }
6051         else
6052         {
6053             temp = 0;
6054         }
6055         memcpy(block->block_contents+offset, &temp, sizeof(char));
6056         offset += sizeof(char);
6057     }
6058
6059     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6060            sizeof(data->n_values_per_frame));
6061     if(tng_data->output_endianness_swap_func_64)
6062     {
6063         if(tng_data->output_endianness_swap_func_64(tng_data,
6064            (int64_t *)block->header_contents+offset)
6065             != TNG_SUCCESS)
6066         {
6067             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6068                     __FILE__, __LINE__);
6069         }
6070     }
6071     offset += sizeof(data->n_values_per_frame);
6072
6073     memcpy(block->block_contents+offset, &data->codec_id,
6074            sizeof(data->codec_id));
6075     if(tng_data->output_endianness_swap_func_64)
6076     {
6077         if(tng_data->output_endianness_swap_func_64(tng_data,
6078            (int64_t *)block->header_contents+offset)
6079             != TNG_SUCCESS)
6080         {
6081             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6082                     __FILE__, __LINE__);
6083         }
6084     }
6085     offset += sizeof(data->codec_id);
6086
6087     if(data->codec_id != TNG_UNCOMPRESSED)
6088     {
6089         memcpy(block->block_contents+offset, &data->compression_multiplier,
6090                sizeof(data->compression_multiplier));
6091         if(tng_data->output_endianness_swap_func_64)
6092         {
6093             if(tng_data->output_endianness_swap_func_64(tng_data,
6094                (int64_t *)block->header_contents+offset)
6095                 != TNG_SUCCESS)
6096             {
6097                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6098                         __FILE__, __LINE__);
6099             }
6100         }
6101         offset += sizeof(data->compression_multiplier);
6102     }
6103
6104     if(data->n_frames > 0 && stride_length > 1)
6105     {
6106         /* FIXME: first_frame_with_data is not reliably set */
6107         if(data->first_frame_with_data == 0)
6108         {
6109             data->first_frame_with_data = frame_set->first_frame;
6110         }
6111         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6112                sizeof(data->first_frame_with_data));
6113         if(tng_data->output_endianness_swap_func_64)
6114         {
6115             if(tng_data->output_endianness_swap_func_64(tng_data,
6116                (int64_t *)block->header_contents+offset)
6117                 != TNG_SUCCESS)
6118             {
6119                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6120                         __FILE__, __LINE__);
6121             }
6122         }
6123         offset += sizeof(data->first_frame_with_data);
6124
6125         memcpy(block->block_contents+offset, &stride_length,
6126                sizeof(stride_length));
6127         if(tng_data->output_endianness_swap_func_64)
6128         {
6129             if(tng_data->output_endianness_swap_func_64(tng_data,
6130                (int64_t *)block->header_contents+offset)
6131                 != TNG_SUCCESS)
6132             {
6133                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6134                         __FILE__, __LINE__);
6135             }
6136         }
6137         offset += sizeof(stride_length);
6138     }
6139
6140
6141     memcpy(block->block_contents+offset, &num_first_particle,
6142            sizeof(num_first_particle));
6143     if(tng_data->output_endianness_swap_func_64)
6144     {
6145         if(tng_data->output_endianness_swap_func_64(tng_data,
6146            (int64_t *)block->header_contents+offset)
6147             != TNG_SUCCESS)
6148         {
6149             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6150                     __FILE__, __LINE__);
6151         }
6152     }
6153     offset += sizeof(num_first_particle);
6154
6155     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6156     if(tng_data->output_endianness_swap_func_64)
6157     {
6158         if(tng_data->output_endianness_swap_func_64(tng_data,
6159            (int64_t *)block->header_contents+offset)
6160             != TNG_SUCCESS)
6161         {
6162             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6163                     __FILE__, __LINE__);
6164         }
6165     }
6166     offset += sizeof(n_particles);
6167
6168     if(data->datatype == TNG_CHAR_DATA)
6169     {
6170         if(data->strings)
6171         {
6172             for(i = 0; i < frame_step; i++)
6173             {
6174                 first_dim_values = data->strings[i];
6175                 for(j = num_first_particle; j < num_first_particle + n_particles;
6176                     j++)
6177                 {
6178                     second_dim_values = first_dim_values[j];
6179                     for(k = 0; k < data->n_values_per_frame; k++)
6180                     {
6181                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6182                         strncpy(block->block_contents+offset,
6183                                 second_dim_values[k], len);
6184                         offset += len;
6185                     }
6186                 }
6187             }
6188         }
6189     }
6190     else if(data->values)
6191     {
6192         memcpy(block->block_contents + offset, data->values,
6193                block->block_contents_size - offset);
6194
6195         switch(data->datatype)
6196         {
6197         case TNG_FLOAT_DATA:
6198             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6199                data->codec_id == TNG_TNG_COMPRESSION)
6200             {
6201                 if(tng_data->input_endianness_swap_func_32)
6202                 {
6203                     for(i = offset; i < block->block_contents_size; i+=size)
6204                     {
6205                         if(tng_data->input_endianness_swap_func_32(tng_data,
6206                            (int32_t *)(block->block_contents + i))
6207                            != TNG_SUCCESS)
6208                         {
6209                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6210                                     __FILE__, __LINE__);
6211                         }
6212                     }
6213                 }
6214             }
6215             else
6216             {
6217                 multiplier = data->compression_multiplier;
6218                 if(fabs(multiplier - 1.0) > 0.00001 ||
6219                    tng_data->input_endianness_swap_func_32)
6220                 {
6221                     for(i = offset; i < block->block_contents_size; i+=size)
6222                     {
6223                         *(float *)(block->block_contents + i) *= (float)multiplier;
6224                         if(tng_data->input_endianness_swap_func_32 &&
6225                         tng_data->input_endianness_swap_func_32(tng_data,
6226                         (int32_t *)(block->block_contents + i))
6227                         != TNG_SUCCESS)
6228                         {
6229                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6230                                     __FILE__, __LINE__);
6231                         }
6232                     }
6233                 }
6234             }
6235             break;
6236         case TNG_INT_DATA:
6237             if(tng_data->input_endianness_swap_func_64)
6238             {
6239                 for(i = offset; i < block->block_contents_size; i+=size)
6240                 {
6241                     if(tng_data->input_endianness_swap_func_64(tng_data,
6242                        (int64_t *)(block->block_contents + i))
6243                        != TNG_SUCCESS)
6244                     {
6245                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6246                                 __FILE__, __LINE__);
6247                     }
6248                 }
6249             }
6250             break;
6251         case TNG_DOUBLE_DATA:
6252             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6253                data->codec_id == TNG_TNG_COMPRESSION)
6254             {
6255                 if(tng_data->input_endianness_swap_func_64)
6256                 {
6257                     for(i = offset; i < block->block_contents_size; i+=size)
6258                     {
6259                         if(tng_data->input_endianness_swap_func_64(tng_data,
6260                            (int64_t *)(block->block_contents + i))
6261                            != TNG_SUCCESS)
6262                         {
6263                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6264                                     __FILE__, __LINE__);
6265                         }
6266                     }
6267                 }
6268             }
6269             else
6270             {
6271                 multiplier = data->compression_multiplier;
6272                 if(fabs(multiplier - 1.0) > 0.00001 ||
6273                    tng_data->input_endianness_swap_func_64)
6274                 {
6275                     for(i = offset; i < block->block_contents_size; i+=size)
6276                     {
6277                         *(double *)(block->block_contents + i) *= multiplier;
6278                         if(tng_data->input_endianness_swap_func_64 &&
6279                         tng_data->input_endianness_swap_func_64(tng_data,
6280                         (int64_t *)(block->block_contents + i))
6281                         != TNG_SUCCESS)
6282                         {
6283                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6284                                     __FILE__, __LINE__);
6285                         }
6286                     }
6287                 }
6288             }
6289             break;
6290         case TNG_CHAR_DATA:
6291             break;
6292         }
6293     }
6294     else
6295     {
6296         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6297     }
6298
6299     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6300     frame_set->n_unwritten_frames = 0;
6301
6302     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6303     {
6304         switch(data->codec_id)
6305         {
6306         case TNG_XTC_COMPRESSION:
6307             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6308             data->codec_id = TNG_UNCOMPRESSED;
6309             break;
6310         case TNG_TNG_COMPRESSION:
6311             stat = tng_compress(tng_data, block, frame_step,
6312                                 n_particles, data->datatype,
6313                                 block->block_contents + data_start_pos);
6314             if(stat != TNG_SUCCESS)
6315             {
6316                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6317                     __FILE__, __LINE__);
6318                 if(stat == TNG_CRITICAL)
6319                 {
6320                     return(TNG_CRITICAL);
6321                 }
6322                 /* Set the data again, but with no compression (to write only
6323                  * the relevant data) */
6324                 data->codec_id = TNG_UNCOMPRESSED;
6325                 stat = tng_particle_data_block_write(tng_data, block,
6326                                                      block_index, mapping,
6327                                                      hash_mode);
6328                 return(stat);
6329             }
6330             break;
6331 #ifdef USE_ZLIB
6332         case TNG_GZIP_COMPRESSION:
6333     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6334             stat = tng_gzip_compress(tng_data, block,
6335                                      block->block_contents + data_start_pos,
6336                                      block->block_contents_size - data_start_pos);
6337             if(stat != TNG_SUCCESS)
6338             {
6339                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6340                     __LINE__);
6341                 if(stat == TNG_CRITICAL)
6342                 {
6343                     return(TNG_CRITICAL);
6344                 }
6345                 /* Set the data again, but with no compression (to write only
6346                  * the relevant data) */
6347                 data->codec_id = TNG_UNCOMPRESSED;
6348                 stat = tng_particle_data_block_write(tng_data, block,
6349                                                      block_index, mapping,
6350                                                      hash_mode);
6351                 return(stat);
6352             }
6353     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6354             break;
6355 #endif
6356         }
6357     }
6358
6359     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6360     {
6361         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6362                tng_data->output_file_path, __FILE__, __LINE__);
6363         return(TNG_CRITICAL);
6364     }
6365
6366     if(fwrite(block->block_contents, block->block_contents_size, 1,
6367         tng_data->output_file) != 1)
6368     {
6369         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6370                 __LINE__);
6371         return(TNG_CRITICAL);
6372     }
6373
6374     return(TNG_SUCCESS);
6375 }
6376
6377 /* TEST: */
6378 /** Create a non-particle data block
6379  * @param tng_data is a trajectory data container.
6380  * @param block_type_flag specifies if this is a trajectory block or a
6381  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6382  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6383  * error has occured.
6384  */
6385 static tng_function_status tng_data_block_create
6386                 (tng_trajectory_t tng_data,
6387                  const char block_type_flag)
6388 {
6389     tng_trajectory_frame_set_t frame_set =
6390     &tng_data->current_trajectory_frame_set;
6391
6392     tng_non_particle_data_t data;
6393
6394     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6395     {
6396         frame_set->n_data_blocks++;
6397         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6398                        frame_set->n_data_blocks);
6399         if(!data)
6400         {
6401             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6402                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6403                 __FILE__, __LINE__);
6404             free(frame_set->tr_data);
6405             frame_set->tr_data = 0;
6406             return(TNG_CRITICAL);
6407         }
6408         frame_set->tr_data = data;
6409     }
6410     else
6411     {
6412         tng_data->n_data_blocks++;
6413         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6414                         tng_data->n_data_blocks);
6415         if(!data)
6416         {
6417             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6418                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6419                 __FILE__, __LINE__);
6420             free(tng_data->non_tr_data);
6421             tng_data->non_tr_data = 0;
6422             return(TNG_CRITICAL);
6423         }
6424         tng_data->non_tr_data = data;
6425     }
6426
6427     return(TNG_SUCCESS);
6428 }
6429
6430 /* TEST: */
6431 /** Allocate memory for storing non-particle data.
6432  * The allocated block will be refered to by data->values.
6433  * @param tng_data is a trajectory data container.
6434  * @param data is the data struct, which will contain the allocated memory in
6435  * data->values.
6436  * @param n_frames is the number of frames of data to store.
6437  * @param n_values_per_frame is the number of data values per frame.
6438  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6439  * error has occured.
6440  */
6441 static tng_function_status tng_allocate_data_mem
6442                 (tng_trajectory_t tng_data,
6443                  tng_non_particle_data_t data,
6444                  int64_t n_frames,
6445                  int64_t stride_length,
6446                  const int64_t n_values_per_frame)
6447 {
6448     void **values;
6449     int64_t i, j, size, frame_alloc;
6450     (void)tng_data;
6451
6452     if(n_values_per_frame == 0)
6453     {
6454         return(TNG_FAILURE);
6455     }
6456
6457     if(data->strings && data->datatype == TNG_CHAR_DATA)
6458     {
6459         for(i = 0; i < data->n_frames; i++)
6460         {
6461             for(j = 0; j < data->n_values_per_frame; j++)
6462             {
6463                 if(data->strings[i][j])
6464                 {
6465                     free(data->strings[i][j]);
6466                     data->strings[i][j] = 0;
6467                 }
6468             }
6469             free(data->strings[i]);
6470             data->strings[i] = 0;
6471         }
6472         free(data->strings);
6473     }
6474     data->n_frames = n_frames;
6475     data->stride_length = tng_max_i64(1, stride_length);
6476     n_frames = tng_max_i64(1, n_frames);
6477     data->n_values_per_frame = n_values_per_frame;
6478     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6479
6480     if(data->datatype == TNG_CHAR_DATA)
6481     {
6482         data->strings = malloc(sizeof(char **) * frame_alloc);
6483         for(i = 0; i < frame_alloc; i++)
6484         {
6485             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6486             if(!data->strings[i])
6487             {
6488                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6489                        n_values_per_frame,
6490                        __FILE__, __LINE__);
6491                 return(TNG_CRITICAL);
6492             }
6493             for(j = 0; j < n_values_per_frame; j++)
6494             {
6495                 data->strings[i][j] = 0;
6496             }
6497         }
6498     }
6499     else
6500     {
6501         switch(data->datatype)
6502         {
6503         case TNG_INT_DATA:
6504             size = sizeof(int64_t);
6505             break;
6506         case TNG_FLOAT_DATA:
6507             size = sizeof(float);
6508             break;
6509         case TNG_DOUBLE_DATA:
6510         default:
6511             size = sizeof(double);
6512         }
6513
6514         values = realloc(data->values,
6515                          size * frame_alloc *
6516                          n_values_per_frame);
6517         if(!values)
6518         {
6519             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6520                    size * frame_alloc *
6521                    n_values_per_frame,
6522                    __FILE__, __LINE__);
6523             free(data->values);
6524             data->values = 0;
6525             return(TNG_CRITICAL);
6526         }
6527         data->values = values;
6528     }
6529
6530     return(TNG_SUCCESS);
6531 }
6532
6533 /** Read the values of a non-particle data block
6534  * @param tng_data is a trajectory data container.
6535  * @param block is the block to store the data (should already contain
6536  * the block headers and the block contents).
6537  * @param offset is the reading offset to point at the place where the actual
6538  * values are stored, starting from the beginning of the block_contents. The
6539  * offset is changed during the reading.
6540  * @param datatype is the type of data of the data block (char, int, float or
6541  * double).
6542  * @param first_frame_with_data is the frame number of the first frame with data
6543  * in this data block.
6544  * @param stride_length is the number of frames between each data entry.
6545  * @param n_frames is the number of frames in this data block.
6546  * @param n_values is the number of values per frame stored in this data block.
6547  * @param codec_id is the ID of the codec to compress the data.
6548  * @param multiplier is the multiplication factor applied to each data value
6549  * before compression. This factor is applied since some compression algorithms
6550  * work only on integers.
6551  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6552  * error has occured.
6553  */
6554 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6555                                          tng_gen_block_t block,
6556                                          int *offset,
6557                                          const char datatype,
6558                                          const int64_t first_frame_with_data,
6559                                          const int64_t stride_length,
6560                                          int64_t n_frames,
6561                                          const int64_t n_values,
6562                                          const int64_t codec_id,
6563                                          const double multiplier)
6564 {
6565     int64_t i, j, n_frames_div;
6566     int size, len;
6567 #ifdef USE_ZLIB
6568     unsigned long data_size;
6569 #endif
6570     tng_non_particle_data_t data;
6571     tng_trajectory_frame_set_t frame_set =
6572     &tng_data->current_trajectory_frame_set;
6573     char block_type_flag;
6574
6575     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6576
6577 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6578
6579     switch(datatype)
6580     {
6581     case TNG_CHAR_DATA:
6582         size = 1;
6583         break;
6584     case TNG_INT_DATA:
6585         size = sizeof(int64_t);
6586         break;
6587     case TNG_FLOAT_DATA:
6588         size = sizeof(float);
6589         break;
6590     case TNG_DOUBLE_DATA:
6591     default:
6592         size = sizeof(double);
6593     }
6594
6595     /* If the block does not exist, create it */
6596     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6597     {
6598         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6599         {
6600             block_type_flag = TNG_TRAJECTORY_BLOCK;
6601         }
6602         else
6603         {
6604             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6605         }
6606
6607         if(tng_data_block_create(tng_data, block_type_flag) !=
6608             TNG_SUCCESS)
6609         {
6610             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6611                    __FILE__, __LINE__);
6612             return(TNG_CRITICAL);
6613         }
6614         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6615         {
6616             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6617         }
6618         else
6619         {
6620             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6621         }
6622         data->block_id = block->id;
6623
6624         data->block_name = malloc(strlen(block->name) + 1);
6625         if(!data->block_name)
6626         {
6627             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6628                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6629             return(TNG_CRITICAL);
6630         }
6631         strcpy(data->block_name, block->name);
6632
6633         data->datatype = datatype;
6634
6635         data->values = 0;
6636         /* FIXME: Memory leak from strings. */
6637         data->strings = 0;
6638         data->n_frames = 0;
6639         data->codec_id = codec_id;
6640         data->compression_multiplier = multiplier;
6641         data->last_retrieved_frame = -1;
6642     }
6643
6644     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6645
6646     if(codec_id != TNG_UNCOMPRESSED)
6647     {
6648         switch(codec_id)
6649         {
6650 #ifdef USE_ZLIB
6651         case TNG_GZIP_COMPRESSION:
6652             data_size = n_frames_div * size * n_values;
6653     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6654             if(tng_gzip_uncompress(tng_data, block,
6655                                    block->block_contents + *offset,
6656                                    data_size) != TNG_SUCCESS)
6657             {
6658                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6659                     __LINE__);
6660                 return(TNG_CRITICAL);
6661             }
6662     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6663             break;
6664 #endif
6665         }
6666     }
6667
6668     /* Allocate memory */
6669     if(!data->values || data->n_frames != n_frames ||
6670        data->n_values_per_frame != n_values)
6671     {
6672         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6673                                  n_values) !=
6674            TNG_SUCCESS)
6675         {
6676             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6677                    __FILE__, __LINE__);
6678             return(TNG_CRITICAL);
6679         }
6680     }
6681
6682     data->first_frame_with_data = first_frame_with_data;
6683
6684     if(datatype == TNG_CHAR_DATA)
6685     {
6686         for(i = 0; i < n_frames_div; i++)
6687         {
6688             for(j = 0; j < n_values; j++)
6689             {
6690                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6691                               TNG_MAX_STR_LEN);
6692                 if(data->strings[i][j])
6693                 {
6694                     free(data->strings[i][j]);
6695                 }
6696                 data->strings[i][j] = malloc(len);
6697                 if(!data->strings[i][j])
6698                 {
6699                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6700                            len, __FILE__, __LINE__);
6701                     return(TNG_CRITICAL);
6702                 }
6703                 strncpy(data->strings[i][j], block->block_contents+*offset,
6704                         len);
6705                 *offset += len;
6706             }
6707         }
6708     }
6709     else
6710     {
6711         memcpy(data->values, block->block_contents + *offset,
6712                block->block_contents_size - *offset);
6713         switch(datatype)
6714         {
6715         case TNG_FLOAT_DATA:
6716             if(tng_data->input_endianness_swap_func_32)
6717             {
6718                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6719                 {
6720                     if(tng_data->input_endianness_swap_func_32(tng_data,
6721                         (int32_t *)((char *)data->values + i))
6722                         != TNG_SUCCESS)
6723                     {
6724                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6725                                 __FILE__, __LINE__);
6726                     }
6727                 }
6728             }
6729             break;
6730         case TNG_INT_DATA:
6731         case TNG_DOUBLE_DATA:
6732             if(tng_data->input_endianness_swap_func_64)
6733             {
6734                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6735                 {
6736                     if(tng_data->input_endianness_swap_func_64(tng_data,
6737                         (int64_t *)((char *)data->values + i))
6738                         != TNG_SUCCESS)
6739                     {
6740                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6741                                 __FILE__, __LINE__);
6742                     }
6743                 }
6744             }
6745             break;
6746         case TNG_CHAR_DATA:
6747             break;
6748         }
6749     }
6750     return(TNG_SUCCESS);
6751 }
6752
6753 /** Write a non-particle data block
6754  * @param tng_data is a trajectory data container.
6755  * @param block is the block to store the data (should already contain
6756  * the block headers and the block contents).
6757  * @param block_index is the index number of the data block in the frame set.
6758  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6759  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6760  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6761  * error has occured.
6762  */
6763 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6764                                                 tng_gen_block_t block,
6765                                                 const int64_t block_index,
6766                                                 const char hash_mode)
6767 {
6768     int64_t n_frames, stride_length, frame_step, data_start_pos;
6769     int64_t i, j;
6770     int offset = 0, size;
6771     unsigned int len;
6772 #ifdef USE_ZLIB
6773     tng_function_status stat;
6774 #endif
6775     char temp, dependency, *temp_name;
6776     double multiplier;
6777     tng_trajectory_frame_set_t frame_set =
6778     &tng_data->current_trajectory_frame_set;
6779
6780     tng_non_particle_data_t data;
6781     char block_type_flag;
6782
6783     /* If we have already started writing frame sets it is too late to write
6784      * non-trajectory data blocks */
6785     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6786     {
6787         block_type_flag = TNG_TRAJECTORY_BLOCK;
6788     }
6789     else
6790     {
6791         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6792     }
6793
6794     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6795     {
6796         return(TNG_CRITICAL);
6797     }
6798
6799     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6800     {
6801         data = &frame_set->tr_data[block_index];
6802
6803         /* If this data block has not had any data added in this frame set
6804          * do not write it. */
6805         if(data->first_frame_with_data < frame_set->first_frame)
6806         {
6807             return(TNG_SUCCESS);
6808         }
6809
6810         stride_length = tng_max_i64(1, data->stride_length);
6811     }
6812     else
6813     {
6814         data = &tng_data->non_tr_data[block_index];
6815         stride_length = 1;
6816     }
6817
6818     switch(data->datatype)
6819     {
6820     case TNG_CHAR_DATA:
6821         size = 1;
6822         break;
6823     case TNG_INT_DATA:
6824         size = sizeof(int64_t);
6825         break;
6826     case TNG_FLOAT_DATA:
6827         size = sizeof(float);
6828         break;
6829     case TNG_DOUBLE_DATA:
6830     default:
6831         size = sizeof(double);
6832     }
6833
6834     len = (unsigned int)strlen(data->block_name) + 1;
6835
6836     if(!block->name || strlen(block->name) < len)
6837     {
6838         temp_name = realloc(block->name, len);
6839         if(!temp_name)
6840         {
6841             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
6842                    __FILE__, __LINE__);
6843             free(block->name);
6844             block->name = 0;
6845             return(TNG_CRITICAL);
6846         }
6847         block->name = temp_name;
6848     }
6849     strncpy(block->name, data->block_name, len);
6850     block->id = data->block_id;
6851
6852     /* If writing frame independent data data->n_frames is 0, but n_frames
6853        is used for the loop writing the data (and reserving memory) and needs
6854        to be at least 1 */
6855     n_frames = tng_max_i64(1, data->n_frames);
6856
6857     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6858     {
6859         /* If the frame set is finished before writing the full number of frames
6860            make sure the data block is not longer than the frame set. */
6861         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6862
6863         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6864     }
6865
6866     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6867                  n_frames / stride_length;
6868
6869     /* TNG compression will use compression precision to get integers from
6870      * floating point data. The compression multiplier stores that information
6871      * to be able to return the precision of the compressed data. */
6872     if(data->codec_id == TNG_TNG_COMPRESSION)
6873     {
6874         data->compression_multiplier = tng_data->compression_precision;
6875     }
6876     /* Uncompressed data blocks do not use compression multipliers at all.
6877      * GZip compression does not need it either. */
6878     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6879     {
6880         data->compression_multiplier = 1.0;
6881     }
6882
6883     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6884     {
6885         dependency = TNG_FRAME_DEPENDENT;
6886     }
6887     else
6888     {
6889         dependency = 0;
6890     }
6891
6892     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6893                                     frame_step, stride_length, 0,
6894                                     1, dependency, &data_start_pos,
6895                                     &block->block_contents_size) != TNG_SUCCESS)
6896     {
6897         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6898                 __FILE__, __LINE__);
6899         return(TNG_CRITICAL);
6900     }
6901
6902     if(block->block_contents)
6903     {
6904         free(block->block_contents);
6905     }
6906     block->block_contents = malloc(block->block_contents_size);
6907     if(!block->block_contents)
6908     {
6909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6910                block->block_contents_size, __FILE__, __LINE__);
6911         return(TNG_CRITICAL);
6912     }
6913
6914
6915     memcpy(block->block_contents, &data->datatype, sizeof(char));
6916     offset += sizeof(char);
6917
6918     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6919     offset += sizeof(char);
6920
6921     if(dependency & TNG_FRAME_DEPENDENT)
6922     {
6923         if(stride_length > 1)
6924         {
6925             temp = 1;
6926         }
6927         else
6928         {
6929             temp = 0;
6930         }
6931         memcpy(block->block_contents+offset, &temp, sizeof(char));
6932         offset += sizeof(char);
6933     }
6934
6935     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6936            sizeof(data->n_values_per_frame));
6937     if(tng_data->output_endianness_swap_func_64)
6938     {
6939         if(tng_data->output_endianness_swap_func_64(tng_data,
6940            (int64_t *)block->header_contents+offset)
6941             != TNG_SUCCESS)
6942         {
6943             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6944                     __FILE__, __LINE__);
6945         }
6946     }
6947     offset += sizeof(data->n_values_per_frame);
6948
6949     memcpy(block->block_contents+offset, &data->codec_id,
6950            sizeof(data->codec_id));
6951     if(tng_data->output_endianness_swap_func_64)
6952     {
6953         if(tng_data->output_endianness_swap_func_64(tng_data,
6954            (int64_t *)block->header_contents+offset)
6955             != TNG_SUCCESS)
6956         {
6957             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6958                     __FILE__, __LINE__);
6959         }
6960     }
6961     offset += sizeof(data->codec_id);
6962
6963     if(data->codec_id != TNG_UNCOMPRESSED)
6964     {
6965         memcpy(block->block_contents+offset, &data->compression_multiplier,
6966                sizeof(data->compression_multiplier));
6967         if(tng_data->output_endianness_swap_func_64)
6968         {
6969             if(tng_data->output_endianness_swap_func_64(tng_data,
6970             (int64_t *)block->header_contents+offset)
6971                 != TNG_SUCCESS)
6972             {
6973                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6974                         __FILE__, __LINE__);
6975             }
6976         }
6977         offset += sizeof(data->compression_multiplier);
6978     }
6979
6980     if(data->n_frames > 0 && stride_length > 1)
6981     {
6982         /* FIXME: first_frame_with_data is not reliably set */
6983         if(data->first_frame_with_data == 0)
6984         {
6985             data->first_frame_with_data = frame_set->first_frame;
6986         }
6987         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6988                sizeof(data->first_frame_with_data));
6989         if(tng_data->output_endianness_swap_func_64)
6990         {
6991             if(tng_data->output_endianness_swap_func_64(tng_data,
6992             (int64_t *)block->header_contents+offset)
6993                 != TNG_SUCCESS)
6994             {
6995                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6996                         __FILE__, __LINE__);
6997             }
6998         }
6999         offset += sizeof(data->first_frame_with_data);
7000
7001         memcpy(block->block_contents+offset, &stride_length,
7002                sizeof(data->stride_length));
7003         if(tng_data->output_endianness_swap_func_64)
7004         {
7005             if(tng_data->output_endianness_swap_func_64(tng_data,
7006             (int64_t *)block->header_contents+offset)
7007                 != TNG_SUCCESS)
7008             {
7009                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7010                         __FILE__, __LINE__);
7011             }
7012         }
7013         offset += sizeof(data->stride_length);
7014     }
7015
7016     if(data->datatype == TNG_CHAR_DATA)
7017     {
7018         if(data->strings)
7019         {
7020             for(i = 0; i < frame_step; i++)
7021             {
7022                 for(j = 0; j < data->n_values_per_frame; j++)
7023                 {
7024                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7025                     strncpy(block->block_contents+offset, data->strings[i][j],
7026                             len);
7027                     offset += len;
7028                 }
7029             }
7030         }
7031     }
7032     else if(data->values)
7033     {
7034         memcpy(block->block_contents + offset, data->values,
7035                block->block_contents_size - offset);
7036         switch(data->datatype)
7037         {
7038         case TNG_FLOAT_DATA:
7039             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7040                data->codec_id == TNG_TNG_COMPRESSION)
7041             {
7042                 if(tng_data->input_endianness_swap_func_32)
7043                 {
7044                     for(i = offset; i < block->block_contents_size; i+=size)
7045                     {
7046                         if(tng_data->input_endianness_swap_func_32(tng_data,
7047                            (int32_t *)(block->block_contents + i))
7048                            != TNG_SUCCESS)
7049                         {
7050                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7051                                     __FILE__, __LINE__);
7052                         }
7053                     }
7054                 }
7055             }
7056             else
7057             {
7058                 multiplier = data->compression_multiplier;
7059                 if(fabs(multiplier - 1.0) > 0.00001 ||
7060                    tng_data->input_endianness_swap_func_32)
7061                 {
7062                     for(i = offset; block->block_contents_size; i+=size)
7063                     {
7064                         *(float *)(block->block_contents + i) *= (float)multiplier;
7065                         if(tng_data->input_endianness_swap_func_32 &&
7066                         tng_data->input_endianness_swap_func_32(tng_data,
7067                         (int32_t *)(block->block_contents + i))
7068                         != TNG_SUCCESS)
7069                         {
7070                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7071                                     __FILE__, __LINE__);
7072                         }
7073                     }
7074                 }
7075             }
7076             break;
7077         case TNG_INT_DATA:
7078             if(tng_data->input_endianness_swap_func_64)
7079             {
7080                 for(i = offset; i < block->block_contents_size; i+=size)
7081                 {
7082                     if(tng_data->input_endianness_swap_func_64(tng_data,
7083                        (int64_t *)(block->block_contents + i))
7084                        != TNG_SUCCESS)
7085                     {
7086                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7087                                 __FILE__, __LINE__);
7088                     }
7089                 }
7090             }
7091             break;
7092         case TNG_DOUBLE_DATA:
7093             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7094                data->codec_id == TNG_TNG_COMPRESSION)
7095             {
7096                 if(tng_data->input_endianness_swap_func_64)
7097                 {
7098                     for(i = offset; i < block->block_contents_size; i+=size)
7099                     {
7100                         if(tng_data->input_endianness_swap_func_64(tng_data,
7101                            (int64_t *)(block->block_contents + i))
7102                            != TNG_SUCCESS)
7103                         {
7104                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7105                                     __FILE__, __LINE__);
7106                         }
7107                     }
7108                 }
7109             }
7110             else
7111             {
7112                 multiplier = data->compression_multiplier;
7113                 if(fabs(multiplier - 1.0) > 0.00001 ||
7114                    tng_data->input_endianness_swap_func_64)
7115                 {
7116                     for(i = offset; i < block->block_contents_size; i+=size)
7117                     {
7118                         *(double *)(block->block_contents + i) *= multiplier;
7119                         if(tng_data->input_endianness_swap_func_64 &&
7120                         tng_data->input_endianness_swap_func_64(tng_data,
7121                         (int64_t *)(block->block_contents + i))
7122                         != TNG_SUCCESS)
7123                         {
7124                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7125                                     __FILE__, __LINE__);
7126                         }
7127                     }
7128                 }
7129             }
7130             break;
7131         case TNG_CHAR_DATA:
7132             break;
7133         }
7134     }
7135     else
7136     {
7137         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7138     }
7139
7140     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7141     frame_set->n_unwritten_frames = 0;
7142
7143     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7144     {
7145         switch(data->codec_id)
7146         {
7147 #ifdef USE_ZLIB
7148         case TNG_GZIP_COMPRESSION:
7149     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7150             stat = tng_gzip_compress(tng_data, block,
7151                                      block->block_contents + data_start_pos,
7152                                      block->block_contents_size - data_start_pos);
7153             if(stat != TNG_SUCCESS)
7154             {
7155                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7156                     __LINE__);
7157                 if(stat == TNG_CRITICAL)
7158                 {
7159                     return(TNG_CRITICAL);
7160                 }
7161                 data->codec_id = TNG_UNCOMPRESSED;
7162             }
7163     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7164             break;
7165 #endif
7166         }
7167     }
7168
7169     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7170     {
7171         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7172                tng_data->output_file_path, __FILE__, __LINE__);
7173         return(TNG_CRITICAL);
7174     }
7175
7176     if(fwrite(block->block_contents, block->block_contents_size, 1,
7177               tng_data->output_file) != 1)
7178     {
7179         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7180                __FILE__, __LINE__);
7181         return(TNG_CRITICAL);
7182     }
7183
7184     return(TNG_SUCCESS);
7185 }
7186
7187 /** Read the meta information of a data block (particle or non-particle data).
7188  * @param tng_data is a trajectory data container.
7189  * @param block is the block to store the data (should already contain
7190  * the block headers).
7191  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7192  * error has occured.
7193  */
7194 static tng_function_status tng_data_block_meta_information_read
7195                 (tng_trajectory_t tng_data,
7196                  tng_gen_block_t block,
7197                  int *offset,
7198                  char *datatype,
7199                  char *dependency,
7200                  char *sparse_data,
7201                  int64_t *n_values,
7202                  int64_t *codec_id,
7203                  int64_t *first_frame_with_data,
7204                  int64_t *stride_length,
7205                  int64_t *n_frames,
7206                  int64_t *num_first_particle,
7207                  int64_t *block_n_particles,
7208                  double *multiplier)
7209 {
7210     int meta_size;
7211     char *contents;
7212
7213     if(block->block_contents)
7214     {
7215         contents = block->block_contents;
7216     }
7217     else
7218     {
7219         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7220         contents = malloc(meta_size);
7221         if(!contents)
7222         {
7223             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7224                meta_size, __FILE__, __LINE__);
7225         }
7226
7227         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7228         {
7229             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7230             free(contents);
7231             return(TNG_CRITICAL);
7232         }
7233     }
7234
7235     memcpy(datatype, contents+*offset,
7236            sizeof(*datatype));
7237     *offset += sizeof(*datatype);
7238
7239     memcpy(dependency, contents+*offset,
7240            sizeof(*dependency));
7241     *offset += sizeof(*dependency);
7242
7243     if(*dependency & TNG_FRAME_DEPENDENT)
7244     {
7245         memcpy(sparse_data, contents+*offset,
7246                sizeof(*sparse_data));
7247         *offset += sizeof(*sparse_data);
7248     }
7249
7250     memcpy(n_values, contents+*offset,
7251         sizeof(*n_values));
7252     if(tng_data->input_endianness_swap_func_64)
7253     {
7254         if(tng_data->input_endianness_swap_func_64(tng_data,
7255                                                    n_values)
7256             != TNG_SUCCESS)
7257         {
7258             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7259                     __FILE__, __LINE__);
7260         }
7261     }
7262     *offset += sizeof(*n_values);
7263
7264     memcpy(codec_id, contents+*offset,
7265         sizeof(*codec_id));
7266     if(tng_data->input_endianness_swap_func_64)
7267     {
7268         if(tng_data->input_endianness_swap_func_64(tng_data,
7269                                                    codec_id)
7270             != TNG_SUCCESS)
7271         {
7272             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7273                     __FILE__, __LINE__);
7274         }
7275     }
7276     *offset += sizeof(*codec_id);
7277
7278     if(*codec_id != TNG_UNCOMPRESSED)
7279     {
7280         memcpy(multiplier, contents+*offset,
7281             sizeof(*multiplier));
7282         if(tng_data->input_endianness_swap_func_64)
7283         {
7284             if(tng_data->input_endianness_swap_func_64(tng_data,
7285                                                        (int64_t *) multiplier)
7286                 != TNG_SUCCESS)
7287             {
7288                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7289                         __FILE__, __LINE__);
7290             }
7291         }
7292         *offset += sizeof(*multiplier);
7293     }
7294     else
7295     {
7296         *multiplier = 1;
7297     }
7298
7299     if(*dependency & TNG_FRAME_DEPENDENT)
7300     {
7301         if(*sparse_data)
7302         {
7303             memcpy(first_frame_with_data, contents+*offset,
7304                 sizeof(*first_frame_with_data));
7305             if(tng_data->input_endianness_swap_func_64)
7306             {
7307                 if(tng_data->input_endianness_swap_func_64(tng_data,
7308                                                            first_frame_with_data)
7309                     != TNG_SUCCESS)
7310                 {
7311                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7312                             __FILE__, __LINE__);
7313                 }
7314             }
7315             *offset += sizeof(*first_frame_with_data);
7316
7317             memcpy(stride_length, contents+*offset,
7318                 sizeof(*stride_length));
7319             if(tng_data->input_endianness_swap_func_64)
7320             {
7321                 if(tng_data->input_endianness_swap_func_64(tng_data,
7322                                                            stride_length)
7323                     != TNG_SUCCESS)
7324                 {
7325                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7326                             __FILE__, __LINE__);
7327                 }
7328             }
7329             *offset += sizeof(*stride_length);
7330             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7331                         (*first_frame_with_data -
7332                         tng_data->current_trajectory_frame_set.first_frame);
7333         }
7334         else
7335         {
7336             *first_frame_with_data = 0;
7337             *stride_length = 1;
7338             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7339         }
7340     }
7341     else
7342     {
7343         *first_frame_with_data = 0;
7344         *stride_length = 1;
7345         *n_frames = 1;
7346     }
7347
7348     if (*dependency & TNG_PARTICLE_DEPENDENT)
7349     {
7350         memcpy(num_first_particle, contents+*offset,
7351                sizeof(*num_first_particle));
7352         if(tng_data->input_endianness_swap_func_64)
7353         {
7354             if(tng_data->input_endianness_swap_func_64(tng_data,
7355                                                        num_first_particle)
7356                 != TNG_SUCCESS)
7357             {
7358                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7359                         __FILE__, __LINE__);
7360             }
7361         }
7362         *offset += sizeof(*num_first_particle);
7363
7364         memcpy(block_n_particles, contents+*offset,
7365             sizeof(*block_n_particles));
7366         if(tng_data->input_endianness_swap_func_64)
7367         {
7368             if(tng_data->input_endianness_swap_func_64(tng_data,
7369                                                        block_n_particles)
7370                 != TNG_SUCCESS)
7371             {
7372                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7373                         __FILE__, __LINE__);
7374             }
7375         }
7376         *offset += sizeof(*block_n_particles);
7377     }
7378
7379     if(!block->block_contents)
7380     {
7381         free(contents);
7382     }
7383     return(TNG_SUCCESS);
7384 }
7385
7386 /** Read the contents of a data block (particle or non-particle data).
7387  * @param tng_data is a trajectory data container.
7388  * @param block is the block to store the data (should already contain
7389  * the block headers).
7390  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7391  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7392  * compared to the md5 hash of the read contents to ensure valid data.
7393  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7394  * error has occured.
7395  */
7396 static tng_function_status tng_data_block_contents_read
7397                 (tng_trajectory_t tng_data,
7398                  tng_gen_block_t block,
7399                  const char hash_mode)
7400 {
7401     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7402     int64_t stride_length, block_n_particles, num_first_particle;
7403     double multiplier;
7404     char datatype, dependency, sparse_data;
7405     int offset = 0;
7406     tng_bool same_hash;
7407
7408     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7409     {
7410         return(TNG_CRITICAL);
7411     }
7412
7413     if(block->block_contents)
7414     {
7415         free(block->block_contents);
7416     }
7417
7418     block->block_contents = malloc(block->block_contents_size);
7419     if(!block->block_contents)
7420     {
7421         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7422                block->block_contents_size, __FILE__, __LINE__);
7423         return(TNG_CRITICAL);
7424     }
7425
7426     /* Read the whole block into block_contents to be able to write it to
7427      * disk even if it cannot be interpreted. */
7428     if(fread(block->block_contents, block->block_contents_size, 1,
7429              tng_data->input_file) == 0)
7430     {
7431         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7432         return(TNG_CRITICAL);
7433     }
7434
7435     /* FIXME: Does not check if the size of the contents matches the expected
7436      * size or if the contents can be read. */
7437
7438     if(hash_mode == TNG_USE_HASH)
7439     {
7440         tng_md5_hash_match_verify(block, &same_hash);
7441         if(same_hash != TNG_TRUE)
7442         {
7443             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7444                 block->name, __FILE__, __LINE__);
7445     /*         return(TNG_FAILURE); */
7446         }
7447     }
7448
7449     if(tng_data_block_meta_information_read(tng_data, block,
7450                                             &offset, &datatype,
7451                                             &dependency, &sparse_data,
7452                                             &n_values, &codec_id,
7453                                             &first_frame_with_data,
7454                                             &stride_length, &n_frames,
7455                                             &num_first_particle,
7456                                             &block_n_particles,
7457                                             &multiplier) == TNG_CRITICAL)
7458     {
7459         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7460             block->name, __FILE__, __LINE__);
7461         return(TNG_CRITICAL);
7462     }
7463
7464     if (dependency & TNG_PARTICLE_DEPENDENT)
7465     {
7466         return(tng_particle_data_read(tng_data, block,
7467                                       &offset, datatype,
7468                                       num_first_particle,
7469                                       block_n_particles,
7470                                       first_frame_with_data,
7471                                       stride_length,
7472                                       n_frames, n_values,
7473                                       codec_id, multiplier));
7474     }
7475     else
7476     {
7477         return(tng_data_read(tng_data, block,
7478                              &offset, datatype,
7479                              first_frame_with_data,
7480                              stride_length,
7481                              n_frames, n_values,
7482                              codec_id, multiplier));
7483     }
7484 }
7485
7486 /*
7487 // ** Move the blocks in a frame set so that there is no unused space between
7488 //  * them. This can only be done on the last frame set in the file and should
7489 //  * be done e.g. if the last frame set in the file has fewer frames than
7490 //  * default or after compressing data blocks in a frame set.
7491 //  * @param tng_data is a trajectory data container.
7492 //  * @details the current_trajectory_frame_set is the one that will be modified.
7493 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7494 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7495 //  * FIXME: This function is not finished!!!
7496 //  *
7497 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7498 // {
7499 //     tng_gen_block_t block;
7500 //     tng_trajectory_frame_set_t frame_set;
7501 //     FILE *temp = tng_data->input_file;
7502 //     int64_t pos, contents_start_pos, output_file_len;
7503 //
7504 //     frame_set = &tng_data->current_trajectory_frame_set;
7505 //
7506 //     if(frame_set->n_written_frames == frame_set->n_frames)
7507 //     {
7508 //         return(TNG_SUCCESS);
7509 //     }
7510 //
7511 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7512 //        tng_data->last_trajectory_frame_set_output_file_pos)
7513 //     {
7514 //     }
7515 //
7516 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7517 //     {
7518 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7519 //                __FILE__, __LINE__);
7520 //         return(TNG_CRITICAL);
7521 //     }
7522 //
7523 //     tng_block_init(&block);
7524 // //     output_file_pos = ftell(tng_data->output_file);
7525 //
7526 //     tng_data->input_file = tng_data->output_file;
7527 //
7528 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7529 //
7530 //     fseek(tng_data->output_file, pos, SEEK_SET);
7531 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7532 //     {
7533 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7534 //             __FILE__, __LINE__);
7535 //         tng_data->input_file = temp;
7536 //         tng_block_destroy(&block);
7537 //         return(TNG_CRITICAL);
7538 //     }
7539 //
7540 //     contents_start_pos = ftell(tng_data->output_file);
7541 //
7542 //     fseek(tng_data->output_file, 0, SEEK_END);
7543 //     output_file_len = ftell(tng_data->output_file);
7544 //     pos = contents_start_pos + block->block_contents_size;
7545 //     fseek(tng_data->output_file, pos,
7546 //           SEEK_SET);
7547 //
7548 //     while(pos < output_file_len)
7549 //     {
7550 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7551 //         {
7552 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7553 //                    __FILE__, __LINE__);
7554 //             tng_data->input_file = temp;
7555 //             tng_block_destroy(&block);
7556 //             return(TNG_CRITICAL);
7557 //         }
7558 //         pos += block->header_contents_size + block->block_contents_size;
7559 //         fseek(tng_data->output_file, pos, SEEK_SET);
7560 //     }
7561 //
7562 //     return(TNG_SUCCESS);
7563 // }
7564 */
7565 /** Finish writing the current frame set. Update the number of frames
7566  * and the hashes of the frame set and all its data blocks (if hash_mode
7567  * == TNG_USE_HASH).
7568  * @param tng_data is a trajectory data container.
7569  * @param hash_mode specifies whether to update the block md5 hash when
7570  * updating the pointers.
7571  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7572  * error has occured.
7573  */
7574 static tng_function_status tng_frame_set_finalize
7575                 (tng_trajectory_t tng_data, const char hash_mode)
7576 {
7577     tng_gen_block_t block;
7578     tng_trajectory_frame_set_t frame_set;
7579     FILE *temp = tng_data->input_file;
7580     int64_t pos, contents_start_pos, output_file_len;
7581
7582     frame_set = &tng_data->current_trajectory_frame_set;
7583
7584     if(frame_set->n_written_frames == frame_set->n_frames)
7585     {
7586         return(TNG_SUCCESS);
7587     }
7588
7589     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7590     {
7591         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7592                __FILE__, __LINE__);
7593         return(TNG_CRITICAL);
7594     }
7595
7596     tng_block_init(&block);
7597 /*     output_file_pos = ftell(tng_data->output_file); */
7598
7599     tng_data->input_file = tng_data->output_file;
7600
7601     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7602
7603     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7604
7605     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7606     {
7607         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7608             __FILE__, __LINE__);
7609         tng_data->input_file = temp;
7610         tng_block_destroy(&block);
7611         return(TNG_CRITICAL);
7612     }
7613
7614     contents_start_pos = ftell(tng_data->output_file);
7615
7616     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7617     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7618               1, tng_data->output_file) != 1)
7619     {
7620         tng_data->input_file = temp;
7621         tng_block_destroy(&block);
7622         return(TNG_CRITICAL);
7623     }
7624
7625
7626     if(hash_mode == TNG_USE_HASH)
7627     {
7628         tng_md5_hash_update(tng_data, block, pos,
7629                             pos + block->header_contents_size);
7630     }
7631
7632     fseek(tng_data->output_file, 0, SEEK_END);
7633     output_file_len = ftell(tng_data->output_file);
7634     pos = contents_start_pos + block->block_contents_size;
7635     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7636
7637     while(pos < output_file_len)
7638     {
7639         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7640         {
7641             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7642                    __FILE__, __LINE__);
7643             tng_data->input_file = temp;
7644             tng_block_destroy(&block);
7645             return(TNG_CRITICAL);
7646         }
7647
7648         if(hash_mode == TNG_USE_HASH)
7649         {
7650             tng_md5_hash_update(tng_data, block, pos,
7651                                 pos + block->header_contents_size);
7652         }
7653         pos += block->header_contents_size + block->block_contents_size;
7654         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7655     }
7656
7657     tng_data->input_file = temp;
7658     tng_block_destroy(&block);
7659     return(TNG_SUCCESS);
7660 }
7661
7662 /*
7663 // ** Sets the name of a file contents block
7664 //  * @param tng_data is a trajectory data container.
7665 //  * @param block is the block, of which to change names.
7666 //  * @param new_name is the new name of the block.
7667 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7668 //  * error has occured.
7669 //
7670 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7671 //                                               tng_gen_block_t block,
7672 //                                               const char *new_name)
7673 // {
7674 //     int len;
7675 //
7676 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7677 //
7678 //      * If the currently stored string length is not enough to store the new
7679 //      * string it is freed and reallocated. *
7680 //     if(block->name && strlen(block->name) < len)
7681 //     {
7682 //         free(block->name);
7683 //         block->name = 0;
7684 //     }
7685 //     if(!block->name)
7686 //     {
7687 //         block->name = malloc(len);
7688 //         if(!block->name)
7689 //         {
7690 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7691 //                    __FILE__, __LINE__);
7692 //             return(TNG_CRITICAL);
7693 //         }
7694 //     }
7695 //
7696 //     strncpy(block->name, new_name, len);
7697 //
7698 //     return(TNG_SUCCESS);
7699 // }
7700 */
7701
7702 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7703                                          const tng_atom_t atom,
7704                                          tng_residue_t *residue)
7705 {
7706     (void) tng_data;
7707
7708     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7709
7710     *residue = atom->residue;
7711
7712     return(TNG_SUCCESS);
7713 }
7714
7715 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7716                                       const tng_atom_t atom,
7717                                       char *name,
7718                                       const int max_len)
7719 {
7720     (void) tng_data;
7721     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7722     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7723
7724     strncpy(name, atom->name, max_len - 1);
7725     name[max_len - 1] = 0;
7726
7727     if(strlen(atom->name) > (unsigned int)max_len - 1)
7728     {
7729         return(TNG_FAILURE);
7730     }
7731     return(TNG_SUCCESS);
7732 }
7733
7734 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7735                                       tng_atom_t atom,
7736                                       const char *new_name)
7737 {
7738     unsigned int len;
7739     (void)tng_data;
7740
7741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7742     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7743
7744     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7745
7746     /* If the currently stored string length is not enough to store the new
7747      * string it is freed and reallocated. */
7748     if(atom->name && strlen(atom->name) < len)
7749     {
7750         free(atom->name);
7751         atom->name = 0;
7752     }
7753     if(!atom->name)
7754     {
7755         atom->name = malloc(len);
7756         if(!atom->name)
7757         {
7758             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7759                    __FILE__, __LINE__);
7760             return(TNG_CRITICAL);
7761         }
7762     }
7763
7764     strncpy(atom->name, new_name, len);
7765
7766     return(TNG_SUCCESS);
7767 }
7768
7769 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7770                                       const tng_atom_t atom,
7771                                       char *type,
7772                                       const int max_len)
7773 {
7774     (void) tng_data;
7775     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7776     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7777
7778     strncpy(type, atom->atom_type, max_len - 1);
7779     type[max_len - 1] = 0;
7780
7781     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7782     {
7783         return(TNG_FAILURE);
7784     }
7785     return(TNG_SUCCESS);
7786 }
7787
7788 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7789                                       tng_atom_t atom,
7790                                       const char *new_type)
7791 {
7792     unsigned int len;
7793     (void)tng_data;
7794
7795     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7796     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7797
7798     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7799
7800     /* If the currently stored string length is not enough to store the new
7801      * string it is freed and reallocated. */
7802     if(atom->atom_type && strlen(atom->atom_type) < len)
7803     {
7804         free(atom->atom_type);
7805         atom->atom_type = 0;
7806     }
7807     if(!atom->atom_type)
7808     {
7809         atom->atom_type = malloc(len);
7810         if(!atom->atom_type)
7811         {
7812             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7813                    __FILE__, __LINE__);
7814             return(TNG_CRITICAL);
7815         }
7816     }
7817
7818     strncpy(atom->atom_type, new_type, len);
7819
7820     return(TNG_SUCCESS);
7821 }
7822
7823 /** Initialise an atom struct
7824  * @param atom is the atom to initialise.
7825  * @return TNG_SUCCESS (0) if successful.
7826  */
7827 static tng_function_status tng_atom_init(tng_atom_t atom)
7828 {
7829     atom->name = 0;
7830     atom->atom_type = 0;
7831
7832     return(TNG_SUCCESS);
7833 }
7834
7835 /** Free the memory in an atom struct
7836  * @param atom is the atom to destroy.
7837  * @return TNG_SUCCESS (0) if successful.
7838  */
7839 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7840 {
7841     if(atom->name)
7842     {
7843         free(atom->name);
7844         atom->name = 0;
7845     }
7846     if(atom->atom_type)
7847     {
7848         free(atom->atom_type);
7849         atom->atom_type = 0;
7850     }
7851
7852     return(TNG_SUCCESS);
7853 }
7854
7855 tng_function_status DECLSPECDLLEXPORT tng_version_major
7856                 (const tng_trajectory_t tng_data,
7857                  int *version)
7858 {
7859     (void)tng_data;
7860
7861     *version = TNG_VERSION_MAJOR;
7862
7863     return(TNG_SUCCESS);
7864 }
7865
7866 tng_function_status DECLSPECDLLEXPORT tng_version_minor
7867                 (const tng_trajectory_t tng_data,
7868                  int *version)
7869 {
7870     (void)tng_data;
7871
7872     *version = TNG_VERSION_MINOR;
7873
7874     return(TNG_SUCCESS);
7875 }
7876
7877 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
7878                 (const tng_trajectory_t tng_data,
7879                  int *patch_level)
7880 {
7881     (void)tng_data;
7882
7883     *patch_level = TNG_VERSION_PATCHLEVEL;
7884
7885     return(TNG_SUCCESS);
7886 }
7887
7888 tng_function_status DECLSPECDLLEXPORT tng_version
7889                 (const tng_trajectory_t tng_data,
7890                  char *version,
7891                  const int max_len)
7892 {
7893     (void)tng_data;
7894     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
7895
7896     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
7897
7898     return(TNG_SUCCESS);
7899 }
7900
7901 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7902                 (tng_trajectory_t tng_data,
7903                  const char *name,
7904                  tng_molecule_t *molecule)
7905 {
7906     int64_t id;
7907
7908     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7909     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7910
7911     /* Set ID to the ID of the last molecule + 1 */
7912     if(tng_data->n_molecules)
7913     {
7914         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7915     }
7916     else
7917     {
7918         id = 1;
7919     }
7920
7921     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7922 }
7923
7924 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7925                 (tng_trajectory_t tng_data,
7926                  const char *name,
7927                  const int64_t id,
7928                  tng_molecule_t *molecule)
7929 {
7930     tng_molecule_t new_molecules;
7931     int64_t *new_molecule_cnt_list;
7932     tng_function_status stat = TNG_SUCCESS;
7933
7934     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7935     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7936
7937     new_molecules = realloc(tng_data->molecules,
7938                             sizeof(struct tng_molecule) *
7939                             (tng_data->n_molecules + 1));
7940
7941     if(!new_molecules)
7942     {
7943         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7944                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7945                __FILE__, __LINE__);
7946         free(tng_data->molecules);
7947         tng_data->molecules = 0;
7948         return(TNG_CRITICAL);
7949     }
7950
7951     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7952                                     sizeof(int64_t) *
7953                                     (tng_data->n_molecules + 1));
7954
7955     if(!new_molecule_cnt_list)
7956     {
7957         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7958                sizeof(int64_t) * (tng_data->n_molecules + 1),
7959                __FILE__, __LINE__);
7960         free(tng_data->molecule_cnt_list);
7961         tng_data->molecule_cnt_list = 0;
7962         free(new_molecules);
7963         return(TNG_CRITICAL);
7964     }
7965
7966     tng_data->molecules = new_molecules;
7967     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7968
7969     *molecule = &new_molecules[tng_data->n_molecules];
7970
7971     tng_molecule_init(tng_data, *molecule);
7972     tng_molecule_name_set(tng_data, *molecule, name);
7973
7974     /* FIXME: Should this be a function argument instead? */
7975     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7976
7977     (*molecule)->id = id;
7978
7979     tng_data->n_molecules++;
7980
7981     return(stat);
7982 }
7983
7984 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7985                 (tng_trajectory_t tng_data,
7986                  tng_molecule_t *molecule_p)
7987 {
7988     int64_t *new_molecule_cnt_list, id;
7989     tng_molecule_t new_molecules, molecule;
7990
7991     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7992
7993     /* Set ID to the ID of the last molecule + 1 */
7994     if(tng_data->n_molecules)
7995     {
7996         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7997     }
7998     else
7999     {
8000         id = 1;
8001     }
8002
8003     new_molecules = realloc(tng_data->molecules,
8004                             sizeof(struct tng_molecule) *
8005                             (tng_data->n_molecules + 1));
8006
8007     if(!new_molecules)
8008     {
8009         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8010                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8011                __FILE__, __LINE__);
8012         free(tng_data->molecules);
8013         tng_data->molecules = 0;
8014         return(TNG_CRITICAL);
8015     }
8016
8017     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8018                                     sizeof(int64_t) *
8019                                     (tng_data->n_molecules + 1));
8020
8021     if(!new_molecule_cnt_list)
8022     {
8023         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8024                sizeof(int64_t) * (tng_data->n_molecules + 1),
8025                __FILE__, __LINE__);
8026         free(tng_data->molecule_cnt_list);
8027         tng_data->molecule_cnt_list = 0;
8028         free(new_molecules);
8029         return(TNG_CRITICAL);
8030     }
8031
8032     molecule = *molecule_p;
8033
8034     tng_data->molecules = new_molecules;
8035     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8036
8037     new_molecules[tng_data->n_molecules] = *molecule;
8038
8039     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8040
8041     free(*molecule_p);
8042
8043     molecule = &new_molecules[tng_data->n_molecules];
8044
8045     *molecule_p = molecule;
8046
8047     molecule->id = id;
8048
8049     tng_data->n_molecules++;
8050
8051     return(TNG_SUCCESS);
8052 }
8053
8054 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8055                                           const tng_molecule_t molecule,
8056                                           char *name,
8057                                           const int max_len)
8058 {
8059     (void) tng_data;
8060     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8061     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8062
8063     strncpy(name, molecule->name, max_len - 1);
8064     name[max_len - 1] = 0;
8065
8066     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8067     {
8068         return(TNG_FAILURE);
8069     }
8070     return(TNG_SUCCESS);
8071 }
8072
8073 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8074                 (tng_trajectory_t tng_data,
8075                  tng_molecule_t molecule,
8076                  const char *new_name)
8077 {
8078     unsigned int len;
8079     (void)tng_data;
8080
8081     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8082     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8083
8084     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8085
8086     /* If the currently stored string length is not enough to store the new
8087      * string it is freed and reallocated. */
8088     if(molecule->name && strlen(molecule->name) < len)
8089     {
8090         free(molecule->name);
8091         molecule->name = 0;
8092     }
8093     if(!molecule->name)
8094     {
8095         molecule->name = malloc(len);
8096         if(!molecule->name)
8097         {
8098             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8099                    __FILE__, __LINE__);
8100             return(TNG_CRITICAL);
8101         }
8102     }
8103
8104     strncpy(molecule->name, new_name, len);
8105
8106     return(TNG_SUCCESS);
8107 }
8108
8109 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8110                 (const tng_trajectory_t tng_data,
8111                  const tng_molecule_t molecule,
8112                  int64_t *cnt)
8113 {
8114     int64_t i, index = -1;
8115
8116     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8117     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8118
8119     for(i = 0; i < tng_data->n_molecules; i++)
8120     {
8121         if(&tng_data->molecules[i] == molecule)
8122         {
8123             index = i;
8124             break;
8125         }
8126     }
8127     if(index == -1)
8128     {
8129         return(TNG_FAILURE);
8130     }
8131     *cnt = tng_data->molecule_cnt_list[index];
8132
8133     return(TNG_SUCCESS);
8134 }
8135
8136 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8137                 (tng_trajectory_t tng_data,
8138                  tng_molecule_t molecule,
8139                  const int64_t cnt)
8140 {
8141     int64_t i, old_cnt, index = -1;
8142
8143     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8144
8145     for(i = 0; i < tng_data->n_molecules; i++)
8146     {
8147         if(&tng_data->molecules[i] == molecule)
8148         {
8149             index = i;
8150             break;
8151         }
8152     }
8153     if(index == -1)
8154     {
8155         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8156                __FILE__, __LINE__);
8157         return(TNG_FAILURE);
8158     }
8159     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8160     {
8161         old_cnt = tng_data->molecule_cnt_list[index];
8162         tng_data->molecule_cnt_list[index] = cnt;
8163
8164         tng_data->n_particles += (cnt-old_cnt) *
8165                                  tng_data->molecules[index].n_atoms;
8166     }
8167     else
8168     {
8169         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8170         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8171
8172         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8173                 tng_data->molecules[index].n_atoms;
8174     }
8175
8176     return(TNG_SUCCESS);
8177 }
8178
8179 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8180                 (tng_trajectory_t tng_data,
8181                  const char *name,
8182                  int64_t nr,
8183                  tng_molecule_t *molecule)
8184 {
8185     int64_t i, n_molecules;
8186
8187     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8188     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8189     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8190
8191     n_molecules = tng_data->n_molecules;
8192
8193     for(i = n_molecules - 1; i >= 0; i--)
8194     {
8195         *molecule = &tng_data->molecules[i];
8196         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8197         {
8198             if(nr == -1 || nr == (*molecule)->id)
8199             {
8200                 return(TNG_SUCCESS);
8201             }
8202         }
8203     }
8204
8205     *molecule = 0;
8206
8207     return(TNG_FAILURE);
8208 }
8209
8210 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8211                 (tng_trajectory_t tng_data,
8212                  int64_t index,
8213                  tng_molecule_t *molecule)
8214 {
8215     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8216     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8217
8218     if(index >= tng_data->n_molecules)
8219     {
8220         *molecule = 0;
8221         return(TNG_FAILURE);
8222     }
8223     *molecule = &tng_data->molecules[index];
8224     return(TNG_SUCCESS);
8225 }
8226
8227 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8228                                                                tng_trajectory_t tng_data_dest)
8229 {
8230     tng_molecule_t molecule, molecule_temp;
8231     tng_chain_t chain, chain_temp;
8232     tng_residue_t residue, residue_temp;
8233     tng_atom_t atom, atom_temp;
8234     tng_bond_t bond_temp;
8235     tng_function_status stat;
8236     int64_t i, j, k, l, *list_temp;
8237
8238     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8239     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8240
8241     for(i = 0; i < tng_data_dest->n_molecules; i++)
8242     {
8243         molecule = &tng_data_dest->molecules[i];
8244         tng_molecule_destroy(tng_data_dest, molecule);
8245     }
8246
8247     tng_data_dest->n_molecules = 0;
8248     tng_data_dest->n_particles = 0;
8249
8250     molecule_temp = realloc(tng_data_dest->molecules,
8251                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8252     if(!molecule_temp)
8253     {
8254         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8255                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8256                __FILE__, __LINE__);
8257         free(tng_data_dest->molecules);
8258         tng_data_dest->molecules = 0;
8259         return(TNG_CRITICAL);
8260     }
8261     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8262                                      sizeof(int64_t) * tng_data_src->n_molecules);
8263     if(!list_temp)
8264     {
8265         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8266                sizeof(int64_t) * tng_data_src->n_molecules,
8267                __FILE__, __LINE__);
8268         free(tng_data_dest->molecule_cnt_list);
8269         tng_data_dest->molecule_cnt_list = 0;
8270         free(molecule_temp);
8271         return(TNG_CRITICAL);
8272     }
8273
8274     tng_data_dest->molecules = molecule_temp;
8275     tng_data_dest->molecule_cnt_list = list_temp;
8276
8277     for(i = 0; i < tng_data_src->n_molecules; i++)
8278     {
8279         molecule = &tng_data_src->molecules[i];
8280         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8281                                      &molecule_temp);
8282         if(stat != TNG_SUCCESS)
8283         {
8284             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8285                    __FILE__, __LINE__);
8286             return(stat);
8287         }
8288         molecule_temp->quaternary_str = molecule->quaternary_str;
8289         for(j = 0; j < molecule->n_chains; j++)
8290         {
8291             chain = &molecule->chains[j];
8292             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8293                                                chain->name, chain->id,
8294                                                &chain_temp);
8295             if(stat != TNG_SUCCESS)
8296             {
8297                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8298                        __FILE__, __LINE__);
8299                 return(stat);
8300             }
8301             for(k = 0; k < chain->n_residues; k++)
8302             {
8303                 residue = &chain->residues[k];
8304                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8305                                                   residue->name, residue->id,
8306                                                   &residue_temp);
8307                 if(stat != TNG_SUCCESS)
8308                 {
8309                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8310                            __FILE__, __LINE__);
8311                     return(stat);
8312                 }
8313                 for(l = 0; l < residue->n_atoms; l++)
8314                 {
8315                     atom = &molecule->atoms[residue->atoms_offset + l];
8316                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8317                                                      atom->name, atom->atom_type,
8318                                                      atom->id, &atom_temp);
8319                     if(stat != TNG_SUCCESS)
8320                     {
8321                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8322                            __FILE__, __LINE__);
8323                         return(stat);
8324                     }
8325                 }
8326             }
8327         }
8328         molecule_temp->n_bonds = molecule->n_bonds;
8329         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8330                             molecule->n_bonds);
8331         if(!bond_temp)
8332         {
8333             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8334                    sizeof(struct tng_bond) * molecule->n_bonds,
8335                    __FILE__, __LINE__);
8336             free(molecule_temp->bonds);
8337             molecule_temp->n_bonds = 0;
8338             return(TNG_CRITICAL);
8339         }
8340         molecule_temp->bonds = bond_temp;
8341         for(j = 0; j < molecule->n_bonds; j++)
8342         {
8343             molecule_temp->bonds[j] = molecule->bonds[j];
8344         }
8345         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8346                                     tng_data_src->molecule_cnt_list[i]);
8347         if(stat != TNG_SUCCESS)
8348         {
8349             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8350                    __FILE__, __LINE__);
8351             return(stat);
8352         }
8353     }
8354     return(TNG_SUCCESS);
8355 }
8356
8357 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8358                 (const tng_trajectory_t tng_data,
8359                  const tng_molecule_t molecule,
8360                  int64_t *n)
8361 {
8362     (void) tng_data;
8363     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8364     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8365
8366     *n = molecule->n_chains;
8367
8368     return(TNG_SUCCESS);
8369 }
8370
8371 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8372                 (tng_trajectory_t tng_data,
8373                  tng_molecule_t molecule,
8374                  int64_t index,
8375                  tng_chain_t *chain)
8376 {
8377     (void) tng_data;
8378     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8379     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8380
8381     if(index >= molecule->n_chains)
8382     {
8383         *chain = 0;
8384         return(TNG_FAILURE);
8385     }
8386     *chain = &molecule->chains[index];
8387     return(TNG_SUCCESS);
8388 }
8389
8390 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8391                 (const tng_trajectory_t tng_data,
8392                  const tng_molecule_t molecule,
8393                  int64_t *n)
8394 {
8395     (void) tng_data;
8396     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8397     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8398
8399     *n = molecule->n_residues;
8400
8401     return(TNG_SUCCESS);
8402 }
8403
8404 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8405                 (const tng_trajectory_t tng_data,
8406                  const tng_molecule_t molecule,
8407                  const int64_t index,
8408                  tng_residue_t *residue)
8409 {
8410     (void) tng_data;
8411     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8412     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8413
8414     if(index >= molecule->n_residues)
8415     {
8416         *residue = 0;
8417         return(TNG_FAILURE);
8418     }
8419     *residue = &molecule->residues[index];
8420     return(TNG_SUCCESS);
8421 }
8422
8423 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8424                 (const tng_trajectory_t tng_data,
8425                  const tng_molecule_t molecule,
8426                  int64_t *n)
8427 {
8428     (void) tng_data;
8429     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8430     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8431
8432     *n = molecule->n_atoms;
8433
8434     return(TNG_SUCCESS);
8435 }
8436
8437 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8438                 (const tng_trajectory_t tng_data,
8439                  const tng_molecule_t molecule,
8440                  const int64_t index,
8441                  tng_atom_t *atom)
8442 {
8443     (void) tng_data;
8444     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8445     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8446
8447     if(index >= molecule->n_atoms)
8448     {
8449         *atom = 0;
8450         return(TNG_FAILURE);
8451     }
8452     *atom = &molecule->atoms[index];
8453     return(TNG_SUCCESS);
8454 }
8455
8456 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8457                 (tng_trajectory_t tng_data,
8458                  tng_molecule_t molecule,
8459                  const char *name,
8460                  int64_t nr,
8461                  tng_chain_t *chain)
8462 {
8463     int64_t i, n_chains;
8464     (void)tng_data;
8465
8466     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8467     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8468
8469     n_chains = molecule->n_chains;
8470
8471     for(i = n_chains - 1; i >= 0; i--)
8472     {
8473         *chain = &molecule->chains[i];
8474         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8475         {
8476             if(nr == -1 || nr == (*chain)->id)
8477             {
8478                 return(TNG_SUCCESS);
8479             }
8480         }
8481     }
8482
8483     *chain = 0;
8484
8485     return(TNG_FAILURE);
8486 }
8487
8488 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8489                 (tng_trajectory_t tng_data,
8490                  tng_molecule_t molecule,
8491                  const char *name,
8492                  tng_chain_t *chain)
8493 {
8494     int64_t id;
8495
8496     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8497     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8498
8499     /* Set ID to the ID of the last chain + 1 */
8500     if(molecule->n_chains)
8501     {
8502         id = molecule->chains[molecule->n_chains-1].id + 1;
8503     }
8504     else
8505     {
8506         id = 1;
8507     }
8508
8509     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8510                                        id, chain));
8511 }
8512
8513 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8514                 (tng_trajectory_t tng_data,
8515                  tng_molecule_t molecule,
8516                  const char *name,
8517                  const int64_t id,
8518                  tng_chain_t *chain)
8519 {
8520     tng_chain_t new_chains;
8521     tng_function_status stat = TNG_SUCCESS;
8522
8523     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8524     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8525
8526     new_chains = realloc(molecule->chains,
8527                          sizeof(struct tng_chain) *
8528                          (molecule->n_chains + 1));
8529
8530     if(!new_chains)
8531     {
8532         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8533                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8534                __FILE__, __LINE__);
8535         free(molecule->chains);
8536         molecule->chains = 0;
8537         return(TNG_CRITICAL);
8538     }
8539
8540     molecule->chains = new_chains;
8541
8542     *chain = &new_chains[molecule->n_chains];
8543     (*chain)->name = 0;
8544
8545     tng_chain_name_set(tng_data, *chain, name);
8546
8547     (*chain)->molecule = molecule;
8548     (*chain)->n_residues = 0;
8549
8550     molecule->n_chains++;
8551
8552     (*chain)->id = id;
8553
8554     return(stat);
8555 }
8556
8557 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8558                 (const tng_trajectory_t tng_data,
8559                  tng_molecule_t molecule,
8560                  const int64_t from_atom_id,
8561                  const int64_t to_atom_id,
8562                  tng_bond_t *bond)
8563 {
8564     tng_bond_t new_bonds;
8565     (void)tng_data;
8566
8567     new_bonds = realloc(molecule->bonds,
8568                         sizeof(struct tng_bond) *
8569                         (molecule->n_bonds + 1));
8570
8571     if(!new_bonds)
8572     {
8573         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8574                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8575                __FILE__, __LINE__);
8576         *bond = 0;
8577         free(molecule->bonds);
8578         molecule->bonds = 0;
8579         return(TNG_CRITICAL);
8580     }
8581
8582     molecule->bonds = new_bonds;
8583
8584     *bond = &new_bonds[molecule->n_bonds];
8585
8586     (*bond)->from_atom_id = from_atom_id;
8587     (*bond)->to_atom_id = to_atom_id;
8588
8589     molecule->n_bonds++;
8590
8591     return(TNG_SUCCESS);
8592 }
8593
8594 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8595                 (tng_trajectory_t tng_data,
8596                  tng_molecule_t molecule,
8597                  const char *name,
8598                  int64_t id,
8599                  tng_atom_t *atom)
8600 {
8601     int64_t i, n_atoms;
8602     (void)tng_data;
8603
8604     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8605
8606     n_atoms = molecule->n_atoms;
8607
8608     for(i = n_atoms - 1; i >= 0; i--)
8609     {
8610         *atom = &molecule->atoms[i];
8611         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8612         {
8613             if(id == -1 || id == (*atom)->id)
8614             {
8615                 return(TNG_SUCCESS);
8616             }
8617         }
8618     }
8619
8620     *atom = 0;
8621
8622     return(TNG_FAILURE);
8623 }
8624
8625 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8626                                        const tng_chain_t chain,
8627                                        char *name,
8628                                        const int max_len)
8629 {
8630     (void) tng_data;
8631     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8632     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8633
8634     strncpy(name, chain->name, max_len - 1);
8635     name[max_len - 1] = 0;
8636
8637     if(strlen(chain->name) > (unsigned int)max_len - 1)
8638     {
8639         return(TNG_FAILURE);
8640     }
8641     return(TNG_SUCCESS);
8642 }
8643
8644 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8645                 (tng_trajectory_t tng_data,
8646                  tng_chain_t chain,
8647                  const char *new_name)
8648 {
8649     unsigned int len;
8650     (void)tng_data;
8651
8652     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8653
8654     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8655
8656     /* If the currently stored string length is not enough to store the new
8657      * string it is freed and reallocated. */
8658     if(chain->name && strlen(chain->name) < len)
8659     {
8660         free(chain->name);
8661         chain->name = 0;
8662     }
8663     if(!chain->name)
8664     {
8665         chain->name = malloc(len);
8666         if(!chain->name)
8667         {
8668             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8669                    __FILE__, __LINE__);
8670             return(TNG_CRITICAL);
8671         }
8672     }
8673
8674     strncpy(chain->name, new_name, len);
8675
8676     return(TNG_SUCCESS);
8677 }
8678
8679 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8680                 (const tng_trajectory_t tng_data,
8681                  const tng_chain_t chain,
8682                  int64_t *n)
8683 {
8684     (void) tng_data;
8685     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8686     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8687
8688     *n = chain->n_residues;
8689
8690     return(TNG_SUCCESS);
8691 }
8692
8693 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8694                 (const tng_trajectory_t tng_data,
8695                  const tng_chain_t chain,
8696                  const int64_t index,
8697                  tng_residue_t *residue)
8698 {
8699     (void) tng_data;
8700     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8701     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8702
8703     if(index >= chain->n_residues)
8704     {
8705         *residue = 0;
8706         return(TNG_FAILURE);
8707     }
8708     *residue = &chain->residues[index];
8709     return(TNG_SUCCESS);
8710 }
8711
8712 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8713                 (tng_trajectory_t tng_data,
8714                  tng_chain_t chain,
8715                  const char *name,
8716                  int64_t id,
8717                  tng_residue_t *residue)
8718 {
8719     int64_t i, n_residues;
8720     (void)tng_data;
8721
8722     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8723
8724     n_residues = chain->n_residues;
8725
8726     for(i = n_residues - 1; i >= 0; i--)
8727     {
8728         *residue = &chain->residues[i];
8729         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8730         {
8731             if(id == -1 || id == (*residue)->id)
8732             {
8733                 return(TNG_SUCCESS);
8734             }
8735         }
8736     }
8737
8738     *residue = 0;
8739
8740     return(TNG_FAILURE);
8741 }
8742
8743 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8744                 (tng_trajectory_t tng_data,
8745                  tng_chain_t chain,
8746                  const char *name,
8747                  tng_residue_t *residue)
8748 {
8749     int64_t id;
8750
8751     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8752     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8753
8754     /* Set ID to the ID of the last residue + 1 */
8755     if(chain->n_residues)
8756     {
8757         id = chain->residues[chain->n_residues-1].id + 1;
8758     }
8759     else
8760     {
8761         id = 0;
8762     }
8763
8764     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8765                                       id, residue));
8766 }
8767
8768 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8769                 (tng_trajectory_t tng_data,
8770                  tng_chain_t chain,
8771                  const char *name,
8772                  const int64_t id,
8773                  tng_residue_t *residue)
8774 {
8775     int64_t curr_index;
8776     tng_residue_t new_residues, temp_residue, last_residue;
8777     tng_molecule_t molecule = chain->molecule;
8778     tng_function_status stat = TNG_SUCCESS;
8779
8780     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8781     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8782
8783     if(chain->n_residues)
8784     {
8785         curr_index = chain->residues - molecule->residues;
8786     }
8787     else
8788     {
8789         curr_index = -1;
8790     }
8791
8792     new_residues = realloc(molecule->residues,
8793                            sizeof(struct tng_residue) *
8794                            (molecule->n_residues + 1));
8795
8796     if(!new_residues)
8797     {
8798         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8799                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8800                __FILE__, __LINE__);
8801         free(molecule->residues);
8802         molecule->residues = 0;
8803         return(TNG_CRITICAL);
8804     }
8805
8806     molecule->residues = new_residues;
8807
8808     if(curr_index != -1)
8809     {
8810         chain->residues = new_residues + curr_index;
8811         if(molecule->n_residues)
8812         {
8813             last_residue = &new_residues[molecule->n_residues - 1];
8814
8815             temp_residue = chain->residues + (chain->n_residues - 1);
8816             /* Make space in list of residues to add the new residues together with the other
8817             * residues of this chain */
8818             if(temp_residue != last_residue)
8819             {
8820                 ++temp_residue;
8821                 memmove(temp_residue + 1, temp_residue,
8822                         last_residue - temp_residue);
8823             }
8824         }
8825     }
8826     else
8827     {
8828         curr_index = molecule->n_residues;
8829     }
8830
8831     *residue = &molecule->residues[curr_index + chain->n_residues];
8832
8833     if(!chain->n_residues)
8834     {
8835         chain->residues = *residue;
8836     }
8837     else
8838     {
8839         chain->residues = &molecule->residues[curr_index];
8840     }
8841
8842     (*residue)->name = 0;
8843     tng_residue_name_set(tng_data, *residue, name);
8844
8845     (*residue)->chain = chain;
8846     (*residue)->n_atoms = 0;
8847     (*residue)->atoms_offset = 0;
8848
8849     chain->n_residues++;
8850     molecule->n_residues++;
8851
8852     (*residue)->id = id;
8853
8854     return(stat);
8855 }
8856
8857 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8858                                          const tng_residue_t residue,
8859                                          char *name,
8860                                          const int max_len)
8861 {
8862     (void) tng_data;
8863     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8864     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8865
8866     strncpy(name, residue->name, max_len - 1);
8867     name[max_len - 1] = 0;
8868
8869     if(strlen(residue->name) > (unsigned int)max_len - 1)
8870     {
8871         return(TNG_FAILURE);
8872     }
8873     return(TNG_SUCCESS);
8874 }
8875
8876 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8877                                                            tng_residue_t residue,
8878                                                            const char *new_name)
8879 {
8880     unsigned int len;
8881     (void)tng_data;
8882
8883     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8884     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8885
8886     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8887
8888     /* If the currently stored string length is not enough to store the new
8889      * string it is freed and reallocated. */
8890     if(residue->name && strlen(residue->name) < len)
8891     {
8892         free(residue->name);
8893         residue->name = 0;
8894     }
8895     if(!residue->name)
8896     {
8897         residue->name = malloc(len);
8898         if(!residue->name)
8899         {
8900             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8901                    __FILE__, __LINE__);
8902             return(TNG_CRITICAL);
8903         }
8904     }
8905
8906     strncpy(residue->name, new_name, len);
8907
8908     return(TNG_SUCCESS);
8909 }
8910
8911 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8912                 (const tng_trajectory_t tng_data,
8913                  const tng_residue_t residue,
8914                  int64_t *n)
8915 {
8916     (void) tng_data;
8917     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8918     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8919
8920     *n = residue->n_atoms;
8921
8922     return(TNG_SUCCESS);
8923 }
8924
8925 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8926                 (const tng_trajectory_t tng_data,
8927                  const tng_residue_t residue,
8928                  const int64_t index,
8929                  tng_atom_t *atom)
8930 {
8931     tng_chain_t chain;
8932     tng_molecule_t molecule;
8933
8934     (void) tng_data;
8935     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8936     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8937
8938     if(index >= residue->n_atoms)
8939     {
8940         *atom = 0;
8941         return(TNG_FAILURE);
8942     }
8943     chain = residue->chain;
8944     molecule = chain->molecule;
8945
8946     if(index + residue->atoms_offset >= molecule->n_atoms)
8947     {
8948         *atom = 0;
8949         return(TNG_FAILURE);
8950     }
8951
8952     *atom = &molecule->atoms[residue->atoms_offset + index];
8953     return(TNG_SUCCESS);
8954 }
8955
8956 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8957                 (tng_trajectory_t tng_data,
8958                  tng_residue_t residue,
8959                  const char *atom_name,
8960                  const char *atom_type,
8961                  tng_atom_t *atom)
8962 {
8963     int64_t id;
8964
8965     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8966     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8967     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8968
8969     /* Set ID to the ID of the last atom + 1 */
8970     if(residue->chain->molecule->n_atoms)
8971     {
8972         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
8973     }
8974     else
8975     {
8976         id = 0;
8977     }
8978
8979     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
8980                                      id, atom));
8981 }
8982
8983 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
8984                 (tng_trajectory_t tng_data,
8985                  tng_residue_t residue,
8986                  const char *atom_name,
8987                  const char *atom_type,
8988                  const int64_t id,
8989                  tng_atom_t *atom)
8990 {
8991     tng_atom_t new_atoms;
8992     tng_molecule_t molecule = residue->chain->molecule;
8993     tng_function_status stat = TNG_SUCCESS;
8994
8995     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8996     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8997     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8998
8999     if(!residue->n_atoms)
9000     {
9001         residue->atoms_offset = molecule->n_atoms;
9002     }
9003
9004     new_atoms = realloc(molecule->atoms,
9005                         sizeof(struct tng_atom) *
9006                         (molecule->n_atoms + 1));
9007
9008     if(!new_atoms)
9009     {
9010         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9011                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
9012                __FILE__, __LINE__);
9013         free(molecule->atoms);
9014         molecule->atoms = 0;
9015         return(TNG_CRITICAL);
9016     }
9017
9018     molecule->atoms = new_atoms;
9019
9020     *atom = &new_atoms[molecule->n_atoms];
9021
9022     tng_atom_init(*atom);
9023     tng_atom_name_set(tng_data, *atom, atom_name);
9024     tng_atom_type_set(tng_data, *atom, atom_type);
9025
9026     (*atom)->residue = residue;
9027
9028     residue->n_atoms++;
9029     molecule->n_atoms++;
9030
9031     (*atom)->id = id;
9032
9033     return(stat);
9034 }
9035
9036 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
9037                                                          tng_molecule_t *molecule_p)
9038 {
9039     *molecule_p = malloc(sizeof(struct tng_molecule));
9040     if(!*molecule_p)
9041     {
9042         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9043                sizeof(struct tng_molecule), __FILE__, __LINE__);
9044         return(TNG_CRITICAL);
9045     }
9046
9047     tng_molecule_init(tng_data, *molecule_p);
9048
9049     return(TNG_SUCCESS);
9050 }
9051
9052 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9053                                                         tng_molecule_t *molecule_p)
9054 {
9055     if(!*molecule_p)
9056     {
9057         return(TNG_SUCCESS);
9058     }
9059
9060     tng_molecule_destroy(tng_data, *molecule_p);
9061
9062     free(*molecule_p);
9063     *molecule_p = 0;
9064
9065     return(TNG_SUCCESS);
9066 }
9067
9068 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9069                                                         tng_molecule_t molecule)
9070 {
9071     (void)tng_data;
9072     molecule->quaternary_str = 1;
9073     molecule->name = 0;
9074     molecule->n_chains = 0;
9075     molecule->chains = 0;
9076     molecule->n_residues = 0;
9077     molecule->residues = 0;
9078     molecule->n_atoms = 0;
9079     molecule->atoms = 0;
9080     molecule->n_bonds = 0;
9081     molecule->bonds = 0;
9082
9083     return(TNG_SUCCESS);
9084 }
9085
9086 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9087                                                            tng_molecule_t molecule)
9088 {
9089     int64_t i;
9090     (void)tng_data;
9091
9092     if(molecule->name)
9093     {
9094         free(molecule->name);
9095         molecule->name = 0;
9096     }
9097
9098     if(molecule->chains)
9099     {
9100         for(i = 0; i < molecule->n_chains; i++)
9101         {
9102             if(molecule->chains[i].name)
9103             {
9104                 free(molecule->chains[i].name);
9105                 molecule->chains[i].name = 0;
9106             }
9107         }
9108         free(molecule->chains);
9109         molecule->chains = 0;
9110     }
9111     molecule->n_chains = 0;
9112
9113     if(molecule->residues)
9114     {
9115         for(i = 0; i < molecule->n_residues; i++)
9116         {
9117             if(molecule->residues[i].name)
9118             {
9119                 free(molecule->residues[i].name);
9120                 molecule->residues[i].name = 0;
9121             }
9122         }
9123         free(molecule->residues);
9124         molecule->residues = 0;
9125     }
9126     molecule->n_residues = 0;
9127
9128     if(molecule->atoms)
9129     {
9130         for(i = 0; i < molecule->n_atoms; i++)
9131         {
9132             tng_atom_destroy(&molecule->atoms[i]);
9133         }
9134         free(molecule->atoms);
9135         molecule->atoms = 0;
9136     }
9137     molecule->n_atoms = 0;
9138
9139     if(molecule->bonds)
9140     {
9141         free(molecule->bonds);
9142         molecule->bonds = 0;
9143     }
9144     molecule->n_bonds = 0;
9145
9146     return(TNG_SUCCESS);
9147 }
9148
9149 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9150                 (const tng_trajectory_t tng_data,
9151                  const int64_t nr,
9152                  char *name,
9153                  int max_len)
9154 {
9155     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9156     tng_molecule_t mol;
9157     tng_bool found = TNG_FALSE;
9158
9159     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9160     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9161
9162     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9163
9164     if(!molecule_cnt_list)
9165     {
9166         return(TNG_FAILURE);
9167     }
9168
9169     for(i = 0; i < tng_data->n_molecules; i++)
9170     {
9171         mol = &tng_data->molecules[i];
9172         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9173         {
9174             cnt += mol->n_atoms * molecule_cnt_list[i];
9175             continue;
9176         }
9177         found = TNG_TRUE;
9178         break;
9179     }
9180     if(!found)
9181     {
9182         return(TNG_FAILURE);
9183     }
9184
9185     strncpy(name, mol->name, max_len - 1);
9186     name[max_len - 1] = 0;
9187
9188     if(strlen(mol->name) > (unsigned int)max_len - 1)
9189     {
9190         return(TNG_FAILURE);
9191     }
9192     return(TNG_SUCCESS);
9193 }
9194
9195 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9196                 (const tng_trajectory_t tng_data,
9197                  const int64_t nr,
9198                  int64_t *id)
9199 {
9200     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9201     tng_molecule_t mol;
9202     tng_bool found = TNG_FALSE;
9203
9204     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9205     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9206
9207     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9208
9209     if(!molecule_cnt_list)
9210     {
9211         return(TNG_FAILURE);
9212     }
9213
9214     for(i = 0; i < tng_data->n_molecules; i++)
9215     {
9216         mol = &tng_data->molecules[i];
9217         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9218         {
9219             cnt += mol->n_atoms * molecule_cnt_list[i];
9220             continue;
9221         }
9222         found = TNG_TRUE;
9223         break;
9224     }
9225     if(!found)
9226     {
9227         return(TNG_FAILURE);
9228     }
9229
9230     *id = mol->id;
9231
9232     return(TNG_SUCCESS);
9233 }
9234
9235 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9236                 (const tng_trajectory_t tng_data,
9237                  int64_t *n_bonds,
9238                  int64_t **from_atoms,
9239                  int64_t **to_atoms)
9240 {
9241     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9242     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9243     tng_molecule_t mol;
9244     tng_bond_t bond;
9245
9246     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9247     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9248     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9249     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9250
9251     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9252
9253     if(!molecule_cnt_list)
9254     {
9255         return(TNG_FAILURE);
9256     }
9257
9258     *n_bonds = 0;
9259     /* First count the total number of bonds to allocate memory */
9260     for(i = 0; i < tng_data->n_molecules; i++)
9261     {
9262         mol = &tng_data->molecules[i];
9263         mol_cnt = molecule_cnt_list[i];
9264         *n_bonds += mol_cnt * mol->n_bonds;
9265     }
9266     if(*n_bonds == 0)
9267     {
9268         return(TNG_SUCCESS);
9269     }
9270
9271     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9272     if(!*from_atoms)
9273     {
9274         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9275                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9276         return(TNG_CRITICAL);
9277     }
9278     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9279     if(!*to_atoms)
9280     {
9281         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9282                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9283         free(*from_atoms);
9284         *from_atoms = 0;
9285         return(TNG_CRITICAL);
9286     }
9287
9288     cnt = 0;
9289     for(i = 0; i < tng_data->n_molecules; i++)
9290     {
9291         mol = &tng_data->molecules[i];
9292         mol_cnt = molecule_cnt_list[i];
9293         for(j = 0; j < mol_cnt; j++)
9294         {
9295             for(k = 0; k < mol->n_bonds; k++)
9296             {
9297                 bond = &mol->bonds[k];
9298                 from_atom = atom_cnt + bond->from_atom_id;
9299                 to_atom = atom_cnt + bond->to_atom_id;
9300                 (*from_atoms)[cnt] = from_atom;
9301                 (*to_atoms)[cnt++] = to_atom;
9302             }
9303             atom_cnt += mol->n_atoms;
9304         }
9305     }
9306
9307     return(TNG_SUCCESS);
9308 }
9309
9310 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9311                 (const tng_trajectory_t tng_data,
9312                  const int64_t nr,
9313                  char *name,
9314                  int max_len)
9315 {
9316     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9317     tng_molecule_t mol;
9318     tng_atom_t atom;
9319     tng_bool found = TNG_FALSE;
9320
9321     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9322     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9323
9324     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9325
9326     if(!molecule_cnt_list)
9327     {
9328         return(TNG_FAILURE);
9329     }
9330
9331     for(i = 0; i < tng_data->n_molecules; i++)
9332     {
9333         mol = &tng_data->molecules[i];
9334         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9335         {
9336             cnt += mol->n_atoms * molecule_cnt_list[i];
9337             continue;
9338         }
9339         atom = &mol->atoms[nr % mol->n_atoms];
9340         found = TNG_TRUE;
9341         break;
9342     }
9343     if(!found)
9344     {
9345         return(TNG_FAILURE);
9346     }
9347     if(!atom->residue || !atom->residue->chain)
9348     {
9349         return(TNG_FAILURE);
9350     }
9351
9352     strncpy(name, atom->residue->chain->name, max_len - 1);
9353     name[max_len - 1] = 0;
9354
9355     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9356     {
9357         return(TNG_FAILURE);
9358     }
9359     return(TNG_SUCCESS);
9360 }
9361
9362 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9363                 (const tng_trajectory_t tng_data,
9364                  const int64_t nr,
9365                  char *name,
9366                  int max_len)
9367 {
9368     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9369     tng_molecule_t mol;
9370     tng_atom_t atom;
9371     tng_bool found = TNG_FALSE;
9372
9373     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9374     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9375
9376     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9377
9378     if(!molecule_cnt_list)
9379     {
9380         return(TNG_FAILURE);
9381     }
9382
9383     for(i = 0; i < tng_data->n_molecules; i++)
9384     {
9385         mol = &tng_data->molecules[i];
9386         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9387         {
9388             cnt += mol->n_atoms * molecule_cnt_list[i];
9389             continue;
9390         }
9391         atom = &mol->atoms[nr % mol->n_atoms];
9392         found = TNG_TRUE;
9393         break;
9394     }
9395     if(!found)
9396     {
9397         return(TNG_FAILURE);
9398     }
9399     if(!atom->residue)
9400     {
9401         return(TNG_FAILURE);
9402     }
9403
9404     strncpy(name, atom->residue->name, max_len - 1);
9405     name[max_len - 1] = 0;
9406
9407     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9408     {
9409         return(TNG_FAILURE);
9410     }
9411     return(TNG_SUCCESS);
9412 }
9413
9414 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9415                 (const tng_trajectory_t tng_data,
9416                  const int64_t nr,
9417                  int64_t *id)
9418 {
9419     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9420     tng_molecule_t mol;
9421     tng_atom_t atom;
9422     tng_bool found = TNG_FALSE;
9423
9424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9425     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9426
9427     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9428
9429     if(!molecule_cnt_list)
9430     {
9431         return(TNG_FAILURE);
9432     }
9433
9434     for(i = 0; i < tng_data->n_molecules; i++)
9435     {
9436         mol = &tng_data->molecules[i];
9437         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9438         {
9439             cnt += mol->n_atoms * molecule_cnt_list[i];
9440             continue;
9441         }
9442         atom = &mol->atoms[nr % mol->n_atoms];
9443         found = TNG_TRUE;
9444         break;
9445     }
9446     if(!found)
9447     {
9448         return(TNG_FAILURE);
9449     }
9450     if(!atom->residue)
9451     {
9452         return(TNG_FAILURE);
9453     }
9454
9455     *id = atom->residue->id;
9456
9457     return(TNG_SUCCESS);
9458 }
9459
9460 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9461                 (const tng_trajectory_t tng_data,
9462                  const int64_t nr,
9463                  int64_t *id)
9464 {
9465     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9466     tng_molecule_t mol;
9467     tng_atom_t atom;
9468     tng_bool found = TNG_FALSE;
9469
9470     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9471     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9472
9473     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9474
9475     if(!molecule_cnt_list)
9476     {
9477         return(TNG_FAILURE);
9478     }
9479
9480     for(i = 0; i < tng_data->n_molecules; i++)
9481     {
9482         mol = &tng_data->molecules[i];
9483         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9484         {
9485             cnt += mol->n_atoms * molecule_cnt_list[i];
9486             offset += mol->n_residues * molecule_cnt_list[i];
9487             continue;
9488         }
9489         atom = &mol->atoms[nr % mol->n_atoms];
9490         found = TNG_TRUE;
9491         break;
9492     }
9493     if(!found)
9494     {
9495         return(TNG_FAILURE);
9496     }
9497     if(!atom->residue)
9498     {
9499         return(TNG_FAILURE);
9500     }
9501
9502     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9503
9504     *id = atom->residue->id + offset;
9505
9506     return(TNG_SUCCESS);
9507 }
9508
9509 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9510                 (const tng_trajectory_t tng_data,
9511                  const int64_t nr,
9512                  char *name,
9513                  int max_len)
9514 {
9515     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9516     tng_molecule_t mol;
9517     tng_atom_t atom;
9518     tng_bool found = TNG_FALSE;
9519
9520     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9521     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9522
9523     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9524
9525     if(!molecule_cnt_list)
9526     {
9527         return(TNG_FAILURE);
9528     }
9529
9530     for(i = 0; i < tng_data->n_molecules; i++)
9531     {
9532         mol = &tng_data->molecules[i];
9533         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9534         {
9535             cnt += mol->n_atoms * molecule_cnt_list[i];
9536             continue;
9537         }
9538         atom = &mol->atoms[nr % mol->n_atoms];
9539         found = TNG_TRUE;
9540         break;
9541     }
9542     if(!found)
9543     {
9544         return(TNG_FAILURE);
9545     }
9546
9547     strncpy(name, atom->name, max_len - 1);
9548     name[max_len - 1] = 0;
9549
9550     if(strlen(atom->name) > (unsigned int)max_len - 1)
9551     {
9552         return(TNG_FAILURE);
9553     }
9554     return(TNG_SUCCESS);
9555 }
9556
9557 tng_function_status tng_atom_type_of_particle_nr_get
9558                 (const tng_trajectory_t tng_data,
9559                  const int64_t nr,
9560                  char *type,
9561                  int max_len)
9562 {
9563     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9564     tng_molecule_t mol;
9565     tng_atom_t atom;
9566     tng_bool found = TNG_FALSE;
9567
9568     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9569     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9570
9571     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9572
9573     if(!molecule_cnt_list)
9574     {
9575         return(TNG_FAILURE);
9576     }
9577
9578     for(i = 0; i < tng_data->n_molecules; i++)
9579     {
9580         mol = &tng_data->molecules[i];
9581         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9582         {
9583             cnt += mol->n_atoms * molecule_cnt_list[i];
9584             continue;
9585         }
9586         atom = &mol->atoms[nr % mol->n_atoms];
9587         found = TNG_TRUE;
9588         break;
9589     }
9590     if(!found)
9591     {
9592         return(TNG_FAILURE);
9593     }
9594
9595     strncpy(type, atom->atom_type, max_len - 1);
9596     type[max_len - 1] = 0;
9597
9598     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9599     {
9600         return(TNG_FAILURE);
9601     }
9602     return(TNG_SUCCESS);
9603 }
9604
9605 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9606                 (tng_trajectory_t tng_data,
9607                  const int64_t num_first_particle,
9608                  const int64_t n_particles,
9609                  const int64_t *mapping_table)
9610 {
9611     int64_t i;
9612     tng_particle_mapping_t mapping;
9613     tng_trajectory_frame_set_t frame_set;
9614
9615     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9616
9617     frame_set = &tng_data->current_trajectory_frame_set;
9618
9619     /* Sanity check of the particle ranges. Split into multiple if
9620      * statements for improved readability */
9621     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9622     {
9623         mapping = &frame_set->mappings[i];
9624         if(num_first_particle >= mapping->num_first_particle &&
9625            num_first_particle < mapping->num_first_particle +
9626                                    mapping->n_particles)
9627         {
9628             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9629             return(TNG_FAILURE);
9630         }
9631         if(num_first_particle + n_particles >=
9632            mapping->num_first_particle &&
9633            num_first_particle + n_particles <
9634            mapping->num_first_particle + mapping->n_particles)
9635         {
9636             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9637             return(TNG_FAILURE);
9638         }
9639         if(mapping->num_first_particle >= num_first_particle &&
9640            mapping->num_first_particle < num_first_particle +
9641                                             n_particles)
9642         {
9643             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9644             return(TNG_FAILURE);
9645         }
9646         if(mapping->num_first_particle + mapping->n_particles >
9647            num_first_particle &&
9648            mapping->num_first_particle + mapping->n_particles <
9649            num_first_particle + n_particles)
9650         {
9651             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9652             return(TNG_FAILURE);
9653         }
9654     }
9655
9656     frame_set->n_mapping_blocks++;
9657
9658     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9659                       frame_set->n_mapping_blocks);
9660
9661     if(!mapping)
9662     {
9663         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9664                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9665                __FILE__, __LINE__);
9666         free(frame_set->mappings);
9667         frame_set->mappings = 0;
9668         return(TNG_CRITICAL);
9669     }
9670     frame_set->mappings = mapping;
9671
9672     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9673     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9674
9675     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9676     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9677     {
9678         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9679                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9680         return(TNG_CRITICAL);
9681     }
9682
9683     for(i=0; i<n_particles; i++)
9684     {
9685         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9686     }
9687
9688     return(TNG_SUCCESS);
9689 }
9690
9691 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9692 {
9693     tng_trajectory_frame_set_t frame_set;
9694     tng_particle_mapping_t mapping;
9695     int64_t i;
9696
9697     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9698
9699     frame_set = &tng_data->current_trajectory_frame_set;
9700
9701     if(frame_set->n_mapping_blocks && frame_set->mappings)
9702     {
9703         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9704         {
9705             mapping = &frame_set->mappings[i];
9706             if(mapping->real_particle_numbers)
9707             {
9708                 free(mapping->real_particle_numbers);
9709                 mapping->real_particle_numbers = 0;
9710             }
9711         }
9712         free(frame_set->mappings);
9713         frame_set->mappings = 0;
9714         frame_set->n_mapping_blocks = 0;
9715     }
9716
9717     return(TNG_SUCCESS);
9718 }
9719
9720 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9721 {
9722     time_t seconds;
9723     tng_trajectory_frame_set_t frame_set;
9724     tng_trajectory_t tng_data;
9725
9726     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9727     if(!*tng_data_p)
9728     {
9729         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9730                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9731         return(TNG_CRITICAL);
9732     }
9733
9734     tng_data = *tng_data_p;
9735
9736     frame_set = &tng_data->current_trajectory_frame_set;
9737
9738     tng_data->input_file_path = 0;
9739     tng_data->input_file = 0;
9740     tng_data->input_file_len = 0;
9741     tng_data->output_file_path = 0;
9742     tng_data->output_file = 0;
9743
9744     tng_data->first_program_name = 0;
9745     tng_data->first_user_name = 0;
9746     tng_data->first_computer_name = 0;
9747     tng_data->first_pgp_signature = 0;
9748     tng_data->last_program_name = 0;
9749     tng_data->last_user_name = 0;
9750     tng_data->last_computer_name = 0;
9751     tng_data->last_pgp_signature = 0;
9752     tng_data->forcefield_name = 0;
9753
9754     seconds = time(0);
9755     if ( seconds == -1)
9756     {
9757         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9758     }
9759     else
9760     {
9761         tng_data->time = seconds;
9762     }
9763
9764     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9765     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9766     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9767     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9768     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9769     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9770     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9771     tng_data->frame_set_n_frames = 100;
9772     tng_data->n_trajectory_frame_sets = 0;
9773     tng_data->medium_stride_length = 100;
9774     tng_data->long_stride_length = 10000;
9775
9776     tng_data->time_per_frame = -1;
9777
9778     tng_data->n_particle_data_blocks = 0;
9779     tng_data->n_data_blocks = 0;
9780
9781     tng_data->non_tr_particle_data = 0;
9782     tng_data->non_tr_data = 0;
9783
9784     tng_data->compress_algo_pos = 0;
9785     tng_data->compress_algo_vel = 0;
9786     tng_data->compression_precision = 1000;
9787     tng_data->distance_unit_exponential = -9;
9788
9789     frame_set->first_frame = -1;
9790     frame_set->n_mapping_blocks = 0;
9791     frame_set->mappings = 0;
9792     frame_set->molecule_cnt_list = 0;
9793
9794     frame_set->n_particle_data_blocks = 0;
9795     frame_set->n_data_blocks = 0;
9796
9797     frame_set->tr_particle_data = 0;
9798     frame_set->tr_data = 0;
9799
9800     frame_set->n_written_frames = 0;
9801     frame_set->n_unwritten_frames = 0;
9802
9803     frame_set->next_frame_set_file_pos = -1;
9804     frame_set->prev_frame_set_file_pos = -1;
9805     frame_set->medium_stride_next_frame_set_file_pos = -1;
9806     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9807     frame_set->long_stride_next_frame_set_file_pos = -1;
9808     frame_set->long_stride_prev_frame_set_file_pos = -1;
9809
9810     frame_set->first_frame_time = -1;
9811
9812     tng_data->n_molecules = 0;
9813     tng_data->molecules = 0;
9814     tng_data->molecule_cnt_list = 0;
9815     tng_data->n_particles = 0;
9816
9817     {
9818       /* Check the endianness of the computer */
9819       static int32_t endianness_32 = 0x01234567;
9820       /* 0x01234567 */
9821       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9822         {
9823           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9824         }
9825
9826       /* 0x67452301 */
9827       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9828         {
9829           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9830
9831         }
9832
9833       /* 0x45670123 */
9834       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9835         {
9836           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9837         }
9838     }
9839     {
9840       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9841       /* 0x0123456789ABCDEF */
9842       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9843         {
9844           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9845         }
9846
9847       /* 0xEFCDAB8967452301 */
9848       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9849         {
9850           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9851         }
9852
9853       /* 0x89ABCDEF01234567 */
9854       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9855         {
9856           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9857         }
9858
9859       /* 0x45670123CDEF89AB */
9860       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9861         {
9862           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9863         }
9864
9865       /* 0x23016745AB89EFCD */
9866       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9867         {
9868           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9869         }
9870     }
9871
9872     /* By default do not swap the byte order, i.e. keep the byte order of the
9873      * architecture. The input file endianness will be set when reading the
9874      * header. The output endianness can be changed - before the file is
9875      * written. */
9876     tng_data->input_endianness_swap_func_32 = 0;
9877     tng_data->input_endianness_swap_func_64 = 0;
9878     tng_data->output_endianness_swap_func_32 = 0;
9879     tng_data->output_endianness_swap_func_64 = 0;
9880
9881     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9882     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9883     tng_data->current_trajectory_frame_set.n_frames = 0;
9884
9885     return(TNG_SUCCESS);
9886 }
9887
9888 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9889 {
9890     int64_t i, j, k, l;
9891     int64_t n_particles, n_values_per_frame;
9892     tng_trajectory_t tng_data = *tng_data_p;
9893     tng_trajectory_frame_set_t frame_set;
9894
9895     if(!*tng_data_p)
9896     {
9897         return(TNG_SUCCESS);
9898     }
9899
9900     frame_set = &tng_data->current_trajectory_frame_set;
9901
9902     if(tng_data->input_file_path)
9903     {
9904         free(tng_data->input_file_path);
9905         tng_data->input_file_path = 0;
9906     }
9907
9908     if(tng_data->input_file)
9909     {
9910         if(tng_data->output_file == tng_data->input_file)
9911         {
9912             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9913             tng_data->output_file = 0;
9914         }
9915         fclose(tng_data->input_file);
9916         tng_data->input_file = 0;
9917     }
9918
9919     if(tng_data->output_file_path)
9920     {
9921         free(tng_data->output_file_path);
9922         tng_data->output_file_path = 0;
9923     }
9924
9925     if(tng_data->output_file)
9926     {
9927         /* FIXME: Do not always write the hash */
9928         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9929         fclose(tng_data->output_file);
9930         tng_data->output_file = 0;
9931     }
9932
9933     if(tng_data->first_program_name)
9934     {
9935         free(tng_data->first_program_name);
9936         tng_data->first_program_name = 0;
9937     }
9938
9939     if(tng_data->last_program_name)
9940     {
9941         free(tng_data->last_program_name);
9942         tng_data->last_program_name = 0;
9943     }
9944
9945     if(tng_data->first_user_name)
9946     {
9947         free(tng_data->first_user_name);
9948         tng_data->first_user_name = 0;
9949     }
9950
9951     if(tng_data->last_user_name)
9952     {
9953         free(tng_data->last_user_name);
9954         tng_data->last_user_name = 0;
9955     }
9956
9957     if(tng_data->first_computer_name)
9958     {
9959         free(tng_data->first_computer_name);
9960         tng_data->first_computer_name = 0;
9961     }
9962
9963     if(tng_data->last_computer_name)
9964     {
9965         free(tng_data->last_computer_name);
9966         tng_data->last_computer_name = 0;
9967     }
9968
9969     if(tng_data->first_pgp_signature)
9970     {
9971         free(tng_data->first_pgp_signature);
9972         tng_data->first_pgp_signature = 0;
9973     }
9974
9975     if(tng_data->last_pgp_signature)
9976     {
9977         free(tng_data->last_pgp_signature);
9978         tng_data->last_pgp_signature = 0;
9979     }
9980
9981     if(tng_data->forcefield_name)
9982     {
9983         free(tng_data->forcefield_name);
9984         tng_data->forcefield_name = 0;
9985     }
9986
9987     tng_frame_set_particle_mapping_free(tng_data);
9988
9989     if(frame_set->molecule_cnt_list)
9990     {
9991         free(frame_set->molecule_cnt_list);
9992         frame_set->molecule_cnt_list = 0;
9993     }
9994
9995     if(tng_data->var_num_atoms_flag)
9996     {
9997         n_particles = frame_set->n_particles;
9998     }
9999     else
10000     {
10001         n_particles = tng_data->n_particles;
10002     }
10003
10004     if(tng_data->non_tr_particle_data)
10005     {
10006         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
10007         {
10008             if(tng_data->non_tr_particle_data[i].values)
10009             {
10010                 free(tng_data->non_tr_particle_data[i].values);
10011                 tng_data->non_tr_particle_data[i].values = 0;
10012             }
10013
10014             if(tng_data->non_tr_particle_data[i].strings)
10015             {
10016                 n_values_per_frame = tng_data->non_tr_particle_data[i].
10017                                      n_values_per_frame;
10018                 if(tng_data->non_tr_particle_data[i].strings[0])
10019                 {
10020                     for(j = 0; j < n_particles; j++)
10021                     {
10022                         if(tng_data->non_tr_particle_data[i].strings[0][j])
10023                         {
10024                             for(k = 0; k < n_values_per_frame; k++)
10025                             {
10026                                 if(tng_data->non_tr_particle_data[i].
10027                                    strings[0][j][k])
10028                                 {
10029                                     free(tng_data->non_tr_particle_data[i].
10030                                          strings[0][j][k]);
10031                                     tng_data->non_tr_particle_data[i].
10032                                     strings[0][j][k] = 0;
10033                                 }
10034                             }
10035                             free(tng_data->non_tr_particle_data[i].
10036                                  strings[0][j]);
10037                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
10038                         }
10039                     }
10040                     free(tng_data->non_tr_particle_data[i].strings[0]);
10041                     tng_data->non_tr_particle_data[i].strings[0] = 0;
10042                 }
10043                 free(tng_data->non_tr_particle_data[i].strings);
10044                 tng_data->non_tr_particle_data[i].strings = 0;
10045             }
10046
10047             if(tng_data->non_tr_particle_data[i].block_name)
10048             {
10049                 free(tng_data->non_tr_particle_data[i].block_name);
10050                 tng_data->non_tr_particle_data[i].block_name = 0;
10051             }
10052         }
10053         free(tng_data->non_tr_particle_data);
10054         tng_data->non_tr_particle_data = 0;
10055     }
10056
10057     if(tng_data->non_tr_data)
10058     {
10059         for(i = 0; i < tng_data->n_data_blocks; i++)
10060         {
10061             if(tng_data->non_tr_data[i].values)
10062             {
10063                 free(tng_data->non_tr_data[i].values);
10064                 tng_data->non_tr_data[i].values = 0;
10065             }
10066
10067             if(tng_data->non_tr_data[i].strings)
10068             {
10069                 n_values_per_frame = tng_data->non_tr_data[i].
10070                                      n_values_per_frame;
10071                 if(tng_data->non_tr_data[i].strings[0])
10072                 {
10073                     for(j = 0; j < n_values_per_frame; j++)
10074                     {
10075                         if(tng_data->non_tr_data[i].strings[0][j])
10076                         {
10077                             free(tng_data->non_tr_data[i].strings[0][j]);
10078                             tng_data->non_tr_data[i].strings[0][j] = 0;
10079                         }
10080                     }
10081                     free(tng_data->non_tr_data[i].strings[0]);
10082                     tng_data->non_tr_data[i].strings[0] = 0;
10083                 }
10084                 free(tng_data->non_tr_data[i].strings);
10085                 tng_data->non_tr_data[i].strings = 0;
10086             }
10087
10088             if(tng_data->non_tr_data[i].block_name)
10089             {
10090                 free(tng_data->non_tr_data[i].block_name);
10091                 tng_data->non_tr_data[i].block_name = 0;
10092             }
10093         }
10094         free(tng_data->non_tr_data);
10095         tng_data->non_tr_data = 0;
10096     }
10097
10098     tng_data->n_particle_data_blocks = 0;
10099     tng_data->n_data_blocks = 0;
10100
10101     if(tng_data->compress_algo_pos)
10102     {
10103         free(tng_data->compress_algo_pos);
10104         tng_data->compress_algo_pos = 0;
10105     }
10106     if(tng_data->compress_algo_vel)
10107     {
10108         free(tng_data->compress_algo_vel);
10109         tng_data->compress_algo_vel = 0;
10110     }
10111
10112     if(frame_set->tr_particle_data)
10113     {
10114         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10115         {
10116             if(frame_set->tr_particle_data[i].values)
10117             {
10118                 free(frame_set->tr_particle_data[i].values);
10119                 frame_set->tr_particle_data[i].values = 0;
10120             }
10121
10122             if(frame_set->tr_particle_data[i].strings)
10123             {
10124                 n_values_per_frame = frame_set->tr_particle_data[i].
10125                                      n_values_per_frame;
10126                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10127                 {
10128                     if(frame_set->tr_particle_data[i].strings[j])
10129                     {
10130                         for(k = 0; k < n_particles; k++)
10131                         {
10132                             if(frame_set->tr_particle_data[i].
10133                                 strings[j][k])
10134                             {
10135                                 for(l = 0; l < n_values_per_frame; l++)
10136                                 {
10137                                     if(frame_set->tr_particle_data[i].
10138                                         strings[j][k][l])
10139                                     {
10140                                         free(frame_set->tr_particle_data[i].
10141                                                 strings[j][k][l]);
10142                                         frame_set->tr_particle_data[i].
10143                                         strings[j][k][l] = 0;
10144                                     }
10145                                 }
10146                                 free(frame_set->tr_particle_data[i].
10147                                         strings[j][k]);
10148                                 frame_set->tr_particle_data[i].
10149                                 strings[j][k] = 0;
10150                             }
10151                         }
10152                         free(frame_set->tr_particle_data[i].strings[j]);
10153                         frame_set->tr_particle_data[i].strings[j] = 0;
10154                     }
10155                 }
10156                 free(frame_set->tr_particle_data[i].strings);
10157                 frame_set->tr_particle_data[i].strings = 0;
10158             }
10159
10160             if(frame_set->tr_particle_data[i].block_name)
10161             {
10162                 free(frame_set->tr_particle_data[i].block_name);
10163                 frame_set->tr_particle_data[i].block_name = 0;
10164             }
10165         }
10166         free(frame_set->tr_particle_data);
10167         frame_set->tr_particle_data = 0;
10168     }
10169
10170     if(frame_set->tr_data)
10171     {
10172         for(i = 0; i < frame_set->n_data_blocks; i++)
10173         {
10174             if(frame_set->tr_data[i].values)
10175             {
10176                 free(frame_set->tr_data[i].values);
10177                 frame_set->tr_data[i].values = 0;
10178             }
10179
10180             if(frame_set->tr_data[i].strings)
10181             {
10182                 n_values_per_frame = frame_set->tr_data[i].
10183                                      n_values_per_frame;
10184                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10185                 {
10186                     if(frame_set->tr_data[i].strings[j])
10187                     {
10188                         for(k = 0; k < n_values_per_frame; k++)
10189                         {
10190                             if(frame_set->tr_data[i].strings[j][k])
10191                             {
10192                                 free(frame_set->tr_data[i].strings[j][k]);
10193                                 frame_set->tr_data[i].strings[j][k] = 0;
10194                             }
10195                         }
10196                         free(frame_set->tr_data[i].strings[j]);
10197                         frame_set->tr_data[i].strings[j] = 0;
10198                     }
10199                 }
10200                 free(frame_set->tr_data[i].strings);
10201                 frame_set->tr_data[i].strings = 0;
10202             }
10203
10204             if(frame_set->tr_data[i].block_name)
10205             {
10206                 free(frame_set->tr_data[i].block_name);
10207                 frame_set->tr_data[i].block_name = 0;
10208             }
10209         }
10210         free(frame_set->tr_data);
10211         frame_set->tr_data = 0;
10212     }
10213
10214     frame_set->n_particle_data_blocks = 0;
10215     frame_set->n_data_blocks = 0;
10216
10217     if(tng_data->molecules)
10218     {
10219         for(i = 0; i < tng_data->n_molecules; i++)
10220         {
10221             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10222         }
10223         free(tng_data->molecules);
10224         tng_data->molecules = 0;
10225         tng_data->n_molecules = 0;
10226     }
10227     if(tng_data->molecule_cnt_list)
10228     {
10229         free(tng_data->molecule_cnt_list);
10230         tng_data->molecule_cnt_list = 0;
10231     }
10232
10233     free(*tng_data_p);
10234     *tng_data_p = 0;
10235
10236     return(TNG_SUCCESS);
10237 }
10238
10239 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10240                                                  tng_trajectory_t *dest_p)
10241 {
10242     tng_trajectory_frame_set_t frame_set;
10243     tng_trajectory_t dest;
10244
10245     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10246
10247     *dest_p = malloc(sizeof(struct tng_trajectory));
10248     if(!*dest_p)
10249     {
10250         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
10251                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10252         return(TNG_CRITICAL);
10253     }
10254
10255     dest = *dest_p;
10256
10257     frame_set = &dest->current_trajectory_frame_set;
10258
10259     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10260     if(!dest->input_file_path)
10261     {
10262         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10263                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10264         return(TNG_CRITICAL);
10265     }
10266     strcpy(dest->input_file_path, src->input_file_path);
10267     dest->input_file = 0;
10268     dest->input_file_len = src->input_file_len;
10269     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10270     if(!dest->output_file_path)
10271     {
10272         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10273                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10274         return(TNG_CRITICAL);
10275     }
10276     strcpy(dest->output_file_path, src->output_file_path);
10277     dest->output_file = 0;
10278
10279     dest->first_program_name = 0;
10280     dest->first_user_name = 0;
10281     dest->first_computer_name = 0;
10282     dest->first_pgp_signature = 0;
10283     dest->last_program_name = 0;
10284     dest->last_user_name = 0;
10285     dest->last_computer_name = 0;
10286     dest->last_pgp_signature = 0;
10287     dest->forcefield_name = 0;
10288
10289     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10290     dest->first_trajectory_frame_set_input_file_pos =
10291     src->first_trajectory_frame_set_input_file_pos;
10292     dest->last_trajectory_frame_set_input_file_pos =
10293     src->last_trajectory_frame_set_input_file_pos;
10294     dest->current_trajectory_frame_set_input_file_pos =
10295     src->current_trajectory_frame_set_input_file_pos;
10296     dest->first_trajectory_frame_set_output_file_pos =
10297     src->first_trajectory_frame_set_output_file_pos;
10298     dest->last_trajectory_frame_set_output_file_pos =
10299     src->last_trajectory_frame_set_output_file_pos;
10300     dest->current_trajectory_frame_set_output_file_pos =
10301     src->current_trajectory_frame_set_output_file_pos;
10302     dest->frame_set_n_frames = src->frame_set_n_frames;
10303     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10304     dest->medium_stride_length = src->medium_stride_length;
10305     dest->long_stride_length = src->long_stride_length;
10306
10307     dest->time_per_frame = src->time_per_frame;
10308
10309     /* Currently the non trajectory data blocks are not copied since it
10310      * can lead to problems when freeing memory in a parallel block. */
10311     dest->n_particle_data_blocks = 0;
10312     dest->n_data_blocks = 0;
10313     dest->non_tr_particle_data = 0;
10314     dest->non_tr_data = 0;
10315
10316     dest->compress_algo_pos = 0;
10317     dest->compress_algo_vel = 0;
10318     dest->distance_unit_exponential = -9;
10319     dest->compression_precision = 1000;
10320
10321     frame_set->n_mapping_blocks = 0;
10322     frame_set->mappings = 0;
10323     frame_set->molecule_cnt_list = 0;
10324
10325     frame_set->n_particle_data_blocks = 0;
10326     frame_set->n_data_blocks = 0;
10327
10328     frame_set->tr_particle_data = 0;
10329     frame_set->tr_data = 0;
10330
10331     frame_set->next_frame_set_file_pos = -1;
10332     frame_set->prev_frame_set_file_pos = -1;
10333     frame_set->medium_stride_next_frame_set_file_pos = -1;
10334     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10335     frame_set->long_stride_next_frame_set_file_pos = -1;
10336     frame_set->long_stride_prev_frame_set_file_pos = -1;
10337     frame_set->first_frame = -1;
10338
10339     dest->n_molecules = 0;
10340     dest->molecules = 0;
10341     dest->molecule_cnt_list = 0;
10342     dest->n_particles = src->n_particles;
10343
10344     dest->endianness_32 = src->endianness_32;
10345     dest->endianness_64 = src->endianness_64;
10346     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10347     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10348     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10349     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10350
10351     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10352     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10353     dest->current_trajectory_frame_set.n_frames = 0;
10354
10355     return(TNG_SUCCESS);
10356 }
10357
10358 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10359                                        char *file_name, const int max_len)
10360 {
10361     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10362     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10363
10364     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10365     file_name[max_len - 1] = 0;
10366
10367     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10368     {
10369         return(TNG_FAILURE);
10370     }
10371     return(TNG_SUCCESS);
10372 }
10373
10374 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10375                                                          const char *file_name)
10376 {
10377     unsigned int len;
10378     char *temp;
10379
10380     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10381     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10382
10383
10384     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10385                                            file_name) == 0)
10386     {
10387         return(TNG_SUCCESS);
10388     }
10389
10390     if(tng_data->input_file)
10391     {
10392         fclose(tng_data->input_file);
10393     }
10394
10395     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10396     temp = realloc(tng_data->input_file_path, len);
10397     if(!temp)
10398     {
10399         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10400                __FILE__, __LINE__);
10401         free(tng_data->input_file_path);
10402         tng_data->input_file_path = 0;
10403         return(TNG_CRITICAL);
10404     }
10405     tng_data->input_file_path = temp;
10406
10407     strncpy(tng_data->input_file_path, file_name, len);
10408
10409     return(tng_input_file_init(tng_data));
10410 }
10411
10412 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10413                                        char *file_name, const int max_len)
10414 {
10415     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10416     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10417
10418     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10419     file_name[max_len - 1] = 0;
10420
10421     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10422     {
10423         return(TNG_FAILURE);
10424     }
10425     return(TNG_SUCCESS);
10426 }
10427
10428 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10429                                                           const char *file_name)
10430 {
10431     int len;
10432     char *temp;
10433
10434     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10435     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10436
10437     if(tng_data->output_file_path &&
10438        strcmp(tng_data->output_file_path, file_name) == 0)
10439     {
10440         return(TNG_SUCCESS);
10441     }
10442
10443     if(tng_data->output_file)
10444     {
10445         fclose(tng_data->output_file);
10446     }
10447
10448     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10449     temp = realloc(tng_data->output_file_path, len);
10450     if(!temp)
10451     {
10452         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10453                __FILE__, __LINE__);
10454         free(tng_data->output_file_path);
10455         tng_data->output_file_path = 0;
10456         return(TNG_CRITICAL);
10457     }
10458     tng_data->output_file_path = temp;
10459
10460     strncpy(tng_data->output_file_path, file_name, len);
10461
10462     return(tng_output_file_init(tng_data));
10463 }
10464
10465 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10466                 (tng_trajectory_t tng_data,
10467                  const char *file_name)
10468 {
10469     int len;
10470     char *temp;
10471
10472     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10473     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10474
10475     if(tng_data->output_file_path &&
10476        strcmp(tng_data->output_file_path, file_name) == 0)
10477     {
10478         return(TNG_SUCCESS);
10479     }
10480
10481     if(tng_data->output_file)
10482     {
10483         fclose(tng_data->output_file);
10484     }
10485
10486     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10487     temp = realloc(tng_data->output_file_path, len);
10488     if(!temp)
10489     {
10490         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10491                __FILE__, __LINE__);
10492         free(tng_data->output_file_path);
10493         tng_data->output_file_path = 0;
10494         return(TNG_CRITICAL);
10495     }
10496     tng_data->output_file_path = temp;
10497
10498     strncpy(tng_data->output_file_path, file_name, len);
10499
10500     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10501     if(!tng_data->output_file)
10502     {
10503         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10504                 tng_data->output_file_path, __FILE__, __LINE__);
10505         return(TNG_CRITICAL);
10506     }
10507     tng_data->input_file = tng_data->output_file;
10508
10509     return(TNG_SUCCESS);
10510 }
10511
10512 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10513                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10514 {
10515     tng_endianness_32 end_32;
10516     tng_endianness_64 end_64;
10517
10518     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10519     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10520
10521     if(tng_data->output_endianness_swap_func_32)
10522     {
10523         /* If other endianness variants are added they must be added here as well */
10524         if(tng_data->output_endianness_swap_func_32 ==
10525            &tng_swap_byte_order_big_endian_32)
10526         {
10527             end_32 = TNG_BIG_ENDIAN_32;
10528         }
10529         else if(tng_data->output_endianness_swap_func_32 ==
10530                 &tng_swap_byte_order_little_endian_32)
10531         {
10532             end_32 = TNG_LITTLE_ENDIAN_32;
10533         }
10534         else
10535         {
10536             return(TNG_FAILURE);
10537         }
10538     }
10539     else
10540     {
10541         end_32 = (tng_endianness_32)tng_data->endianness_32;
10542     }
10543
10544     if(tng_data->output_endianness_swap_func_64)
10545     {
10546         /* If other endianness variants are added they must be added here as well */
10547         if(tng_data->output_endianness_swap_func_64 ==
10548            &tng_swap_byte_order_big_endian_64)
10549         {
10550             end_64 = TNG_BIG_ENDIAN_64;
10551         }
10552         else if(tng_data->output_endianness_swap_func_64 ==
10553                 &tng_swap_byte_order_little_endian_64)
10554         {
10555             end_64 = TNG_LITTLE_ENDIAN_64;
10556         }
10557         else
10558         {
10559             return(TNG_FAILURE);
10560         }
10561     }
10562     else
10563     {
10564         end_64 = (tng_endianness_64)tng_data->endianness_64;
10565     }
10566
10567     if((int)end_32 != (int)end_64)
10568     {
10569         return(TNG_FAILURE);
10570     }
10571
10572     if(end_32 == TNG_LITTLE_ENDIAN_32)
10573     {
10574         *endianness = TNG_LITTLE_ENDIAN;
10575     }
10576
10577     else if(end_32 == TNG_BIG_ENDIAN_32)
10578     {
10579         *endianness = TNG_BIG_ENDIAN;
10580     }
10581     else
10582     {
10583         return(TNG_FAILURE);
10584     }
10585
10586     return(TNG_SUCCESS);
10587 }
10588
10589 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10590                 (tng_trajectory_t tng_data,
10591                  const tng_file_endianness endianness)
10592 {
10593     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10594
10595     /* Tne endianness cannot be changed if the data has already been written
10596      * to the output file. */
10597     if(ftell(tng_data->output_file) > 0)
10598     {
10599         return(TNG_FAILURE);
10600     }
10601
10602     if(endianness == TNG_BIG_ENDIAN)
10603     {
10604         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10605         {
10606             tng_data->output_endianness_swap_func_32 = 0;
10607         }
10608         else
10609         {
10610             tng_data->output_endianness_swap_func_32 =
10611             &tng_swap_byte_order_big_endian_32;
10612         }
10613         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10614         {
10615             tng_data->output_endianness_swap_func_64 = 0;
10616         }
10617         else
10618         {
10619             tng_data->output_endianness_swap_func_64 =
10620             &tng_swap_byte_order_big_endian_64;
10621         }
10622         return(TNG_SUCCESS);
10623     }
10624     else if(endianness == TNG_LITTLE_ENDIAN)
10625     {
10626         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10627         {
10628             tng_data->output_endianness_swap_func_32 = 0;
10629         }
10630         else
10631         {
10632             tng_data->output_endianness_swap_func_32 =
10633             &tng_swap_byte_order_little_endian_32;
10634         }
10635         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10636         {
10637             tng_data->output_endianness_swap_func_64 = 0;
10638         }
10639         else
10640         {
10641             tng_data->output_endianness_swap_func_64 =
10642             &tng_swap_byte_order_little_endian_64;
10643         }
10644         return(TNG_SUCCESS);
10645     }
10646
10647     /* If the specified endianness is neither big nor little endian return a
10648      * failure. */
10649     return(TNG_FAILURE);
10650 }
10651
10652 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10653                     (const tng_trajectory_t tng_data,
10654                      char *name, const int max_len)
10655 {
10656     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10657     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10658
10659     strncpy(name, tng_data->first_program_name, max_len - 1);
10660     name[max_len - 1] = 0;
10661
10662     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10663     {
10664         return(TNG_FAILURE);
10665     }
10666     return(TNG_SUCCESS);
10667 }
10668
10669 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10670                                                                  const char *new_name)
10671 {
10672     unsigned int len;
10673
10674     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10675     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10676
10677     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10678
10679     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10680     {
10681         free(tng_data->first_program_name);
10682         tng_data->first_program_name = 0;
10683     }
10684     if(!tng_data->first_program_name)
10685     {
10686         tng_data->first_program_name = malloc(len);
10687         if(!tng_data->first_program_name)
10688         {
10689             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10690                    __FILE__, __LINE__);
10691             return(TNG_CRITICAL);
10692         }
10693     }
10694
10695     strncpy(tng_data->first_program_name, new_name, len);
10696
10697     return(TNG_SUCCESS);
10698 }
10699
10700 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10701                     (const tng_trajectory_t tng_data,
10702                      char *name, const int max_len)
10703 {
10704     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10705     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10706
10707     strncpy(name, tng_data->last_program_name, max_len - 1);
10708     name[max_len - 1] = 0;
10709
10710     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10711     {
10712         return(TNG_FAILURE);
10713     }
10714     return(TNG_SUCCESS);
10715 }
10716
10717 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10718                     (tng_trajectory_t tng_data,
10719                      const char *new_name)
10720 {
10721     unsigned int len;
10722
10723     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10724     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10725
10726     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10727
10728     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10729     {
10730         free(tng_data->last_program_name);
10731         tng_data->last_program_name = 0;
10732     }
10733     if(!tng_data->last_program_name)
10734     {
10735         tng_data->last_program_name = malloc(len);
10736         if(!tng_data->last_program_name)
10737         {
10738             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10739                    __FILE__, __LINE__);
10740             return(TNG_CRITICAL);
10741         }
10742     }
10743
10744     strncpy(tng_data->last_program_name, new_name, len);
10745
10746     return(TNG_SUCCESS);
10747 }
10748
10749 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10750                     (const tng_trajectory_t tng_data,
10751                      char *name, const int max_len)
10752 {
10753     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10754     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10755
10756     strncpy(name, tng_data->first_user_name, max_len - 1);
10757     name[max_len - 1] = 0;
10758
10759     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10760     {
10761         return(TNG_FAILURE);
10762     }
10763     return(TNG_SUCCESS);
10764 }
10765
10766 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10767                     (tng_trajectory_t tng_data,
10768                      const char *new_name)
10769 {
10770     unsigned int len;
10771
10772     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10773     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10774
10775     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10776
10777     /* If the currently stored string length is not enough to store the new
10778      * string it is freed and reallocated. */
10779     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10780     {
10781         free(tng_data->first_user_name);
10782         tng_data->first_user_name = 0;
10783     }
10784     if(!tng_data->first_user_name)
10785     {
10786         tng_data->first_user_name = malloc(len);
10787         if(!tng_data->first_user_name)
10788         {
10789             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10790                    __FILE__, __LINE__);
10791             return(TNG_CRITICAL);
10792         }
10793     }
10794
10795     strncpy(tng_data->first_user_name, new_name, len);
10796
10797     return(TNG_SUCCESS);
10798 }
10799
10800 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10801                     (const tng_trajectory_t tng_data,
10802                      char *name, const int max_len)
10803 {
10804     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10805     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10806
10807     strncpy(name, tng_data->last_user_name, max_len - 1);
10808     name[max_len - 1] = 0;
10809
10810     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10811     {
10812         return(TNG_FAILURE);
10813     }
10814     return(TNG_SUCCESS);
10815 }
10816
10817 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10818                     (tng_trajectory_t tng_data,
10819                      const char *new_name)
10820 {
10821     unsigned int len;
10822
10823     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10824     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10825
10826     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10827
10828     /* If the currently stored string length is not enough to store the new
10829      * string it is freed and reallocated. */
10830     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10831     {
10832         free(tng_data->last_user_name);
10833         tng_data->last_user_name = 0;
10834     }
10835     if(!tng_data->last_user_name)
10836     {
10837         tng_data->last_user_name = malloc(len);
10838         if(!tng_data->last_user_name)
10839         {
10840             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10841                    __FILE__, __LINE__);
10842             return(TNG_CRITICAL);
10843         }
10844     }
10845
10846     strncpy(tng_data->last_user_name, new_name, len);
10847
10848     return(TNG_SUCCESS);
10849 }
10850
10851 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10852                     (const tng_trajectory_t tng_data,
10853                      char *name, const int max_len)
10854 {
10855     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10856     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10857
10858     strncpy(name, tng_data->first_computer_name, max_len - 1);
10859     name[max_len - 1] = 0;
10860
10861     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10862     {
10863         return(TNG_FAILURE);
10864     }
10865     return(TNG_SUCCESS);
10866 }
10867
10868 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10869                     (tng_trajectory_t tng_data,
10870                      const char *new_name)
10871 {
10872     unsigned int len;
10873
10874     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10875     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10876
10877     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10878
10879     /* If the currently stored string length is not enough to store the new
10880      * string it is freed and reallocated. */
10881     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10882     {
10883         free(tng_data->first_computer_name);
10884         tng_data->first_computer_name = 0;
10885     }
10886     if(!tng_data->first_computer_name)
10887     {
10888         tng_data->first_computer_name = malloc(len);
10889         if(!tng_data->first_computer_name)
10890         {
10891             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10892                    __FILE__, __LINE__);
10893             return(TNG_CRITICAL);
10894         }
10895     }
10896
10897     strncpy(tng_data->first_computer_name, new_name, len);
10898
10899     return(TNG_SUCCESS);
10900 }
10901
10902 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10903                     (const tng_trajectory_t tng_data,
10904                      char *name, const int max_len)
10905 {
10906     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10907     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10908
10909     strncpy(name, tng_data->last_computer_name, max_len - 1);
10910     name[max_len - 1] = 0;
10911
10912     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10913     {
10914         return(TNG_FAILURE);
10915     }
10916     return(TNG_SUCCESS);
10917 }
10918
10919 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10920                     (tng_trajectory_t tng_data,
10921                      const char *new_name)
10922 {
10923     unsigned int len;
10924
10925     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10926     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10927
10928     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10929
10930     /* If the currently stored string length is not enough to store the new
10931      * string it is freed and reallocated. */
10932     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10933         len)
10934     {
10935         free(tng_data->last_computer_name);
10936         tng_data->last_computer_name = 0;
10937     }
10938     if(!tng_data->last_computer_name)
10939     {
10940         tng_data->last_computer_name = malloc(len);
10941         if(!tng_data->last_computer_name)
10942         {
10943             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10944                    __FILE__, __LINE__);
10945             return(TNG_CRITICAL);
10946         }
10947     }
10948
10949     strncpy(tng_data->last_computer_name, new_name, len);
10950
10951     return(TNG_SUCCESS);
10952 }
10953
10954 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10955                     (const tng_trajectory_t tng_data,
10956                      char *signature, const int max_len)
10957 {
10958     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10959     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10960
10961     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10962     signature[max_len - 1] = 0;
10963
10964     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10965     {
10966         return(TNG_FAILURE);
10967     }
10968     return(TNG_SUCCESS);
10969 }
10970
10971 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10972                     (tng_trajectory_t tng_data,
10973                      const char *signature)
10974 {
10975     unsigned int len;
10976
10977     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10978     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10979
10980     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10981
10982     /* If the currently stored string length is not enough to store the new
10983      * string it is freed and reallocated. */
10984     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10985         len)
10986     {
10987         free(tng_data->first_pgp_signature);
10988         tng_data->first_pgp_signature = 0;
10989     }
10990     if(!tng_data->first_pgp_signature)
10991     {
10992         tng_data->first_pgp_signature = malloc(len);
10993         if(!tng_data->first_pgp_signature)
10994         {
10995             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10996                    __FILE__, __LINE__);
10997             return(TNG_CRITICAL);
10998         }
10999     }
11000
11001     strncpy(tng_data->first_pgp_signature, signature, len);
11002
11003     return(TNG_SUCCESS);
11004 }
11005
11006 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
11007                     (const tng_trajectory_t tng_data,
11008                      char *signature, const int max_len)
11009 {
11010     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11011     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11012
11013     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
11014     signature[max_len - 1] = 0;
11015
11016     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
11017     {
11018         return(TNG_FAILURE);
11019     }
11020     return(TNG_SUCCESS);
11021 }
11022
11023 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
11024                     (tng_trajectory_t tng_data,
11025                      const char *signature)
11026 {
11027     unsigned int len;
11028
11029     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11030     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11031
11032     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11033
11034     /* If the currently stored string length is not enough to store the new
11035      * string it is freed and reallocated. */
11036     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
11037         len)
11038     {
11039         free(tng_data->last_pgp_signature);
11040         tng_data->last_pgp_signature = 0;
11041     }
11042     if(!tng_data->last_pgp_signature)
11043     {
11044         tng_data->last_pgp_signature = malloc(len);
11045         if(!tng_data->last_pgp_signature)
11046         {
11047             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11048                    __FILE__, __LINE__);
11049             return(TNG_CRITICAL);
11050         }
11051     }
11052
11053     strncpy(tng_data->last_pgp_signature, signature, len);
11054
11055     return(TNG_SUCCESS);
11056 }
11057
11058 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11059                     (const tng_trajectory_t tng_data,
11060                      char *name, const int max_len)
11061 {
11062     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11063     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11064
11065     strncpy(name, tng_data->forcefield_name, max_len - 1);
11066     name[max_len - 1] = 0;
11067
11068     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11069     {
11070         return(TNG_FAILURE);
11071     }
11072     return(TNG_SUCCESS);
11073 }
11074
11075 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11076                     (tng_trajectory_t tng_data,
11077                      const char *new_name)
11078 {
11079     unsigned int len;
11080
11081     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11082     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11083
11084     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11085
11086     /* If the currently stored string length is not enough to store the new
11087      * string it is freed and reallocated. */
11088     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11089     {
11090         free(tng_data->forcefield_name);
11091         tng_data->forcefield_name = 0;
11092     }
11093     if(!tng_data->forcefield_name)
11094     {
11095         tng_data->forcefield_name = malloc(len);
11096         if(!tng_data->forcefield_name)
11097         {
11098             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11099                    __FILE__, __LINE__);
11100             return(TNG_CRITICAL);
11101         }
11102     }
11103
11104     strncpy(tng_data->forcefield_name, new_name, len);
11105
11106     return(TNG_SUCCESS);
11107 }
11108
11109 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11110                     (const tng_trajectory_t tng_data,
11111                      int64_t *len)
11112 {
11113     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11114     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11115
11116     *len = tng_data->medium_stride_length;
11117
11118     return(TNG_SUCCESS);
11119 }
11120
11121 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11122                     (tng_trajectory_t tng_data,
11123                      const int64_t len)
11124 {
11125     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11126
11127     if(len >= tng_data->long_stride_length)
11128     {
11129         return(TNG_FAILURE);
11130     }
11131     tng_data->medium_stride_length = len;
11132
11133     return(TNG_SUCCESS);
11134 }
11135
11136 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11137                 (const tng_trajectory_t tng_data,
11138                  int64_t *len)
11139 {
11140     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11141     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11142
11143     *len = tng_data->long_stride_length;
11144
11145     return(TNG_SUCCESS);
11146 }
11147
11148 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11149                 (tng_trajectory_t tng_data,
11150                  const int64_t len)
11151 {
11152     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11153
11154     if(len <= tng_data->medium_stride_length)
11155     {
11156         return(TNG_FAILURE);
11157     }
11158     tng_data->long_stride_length = len;
11159
11160     return(TNG_SUCCESS);
11161 }
11162
11163 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11164                 (const tng_trajectory_t tng_data,
11165                  double *time)
11166 {
11167     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11168     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11169
11170     *time = tng_data->time_per_frame;
11171
11172     return(TNG_SUCCESS);
11173 }
11174
11175 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11176                 (tng_trajectory_t tng_data,
11177                  const double time)
11178 {
11179     tng_trajectory_frame_set_t frame_set;
11180
11181     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11182     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11183
11184     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11185     {
11186         return(TNG_SUCCESS);
11187     }
11188
11189     frame_set = &tng_data->current_trajectory_frame_set;
11190
11191     /* If the current frame set is not finished write it to disk before
11192        changing time per frame. */
11193     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11194     {
11195         frame_set->n_frames = frame_set->n_unwritten_frames;
11196         tng_frame_set_write(tng_data, TNG_USE_HASH);
11197     }
11198     tng_data->time_per_frame = time;
11199
11200     return(TNG_SUCCESS);
11201 }
11202
11203 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11204                     (const tng_trajectory_t tng_data,
11205                      int64_t *len)
11206 {
11207     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11208     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11209
11210     *len = tng_data->input_file_len;
11211
11212     return(TNG_SUCCESS);
11213 }
11214
11215 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11216                     (const tng_trajectory_t tng_data,
11217                      int64_t *n)
11218 {
11219     tng_gen_block_t block;
11220     tng_function_status stat;
11221     long file_pos;
11222     int64_t last_file_pos, first_frame, n_frames;
11223
11224     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11225     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11226     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11227
11228     file_pos = ftell(tng_data->input_file);
11229     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11230
11231     if(last_file_pos <= 0)
11232     {
11233         return(TNG_FAILURE);
11234     }
11235
11236     tng_block_init(&block);
11237     fseek(tng_data->input_file,
11238           (long)last_file_pos,
11239           SEEK_SET);
11240     /* Read block headers first to see that a frame set block is found. */
11241     stat = tng_block_header_read(tng_data, block);
11242     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11243     {
11244         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11245                 __FILE__, __LINE__);
11246         tng_block_destroy(&block);
11247         return(TNG_FAILURE);
11248     }
11249     tng_block_destroy(&block);
11250
11251     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11252     {
11253         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11254                __FILE__, __LINE__);
11255         return(TNG_CRITICAL);
11256     }
11257     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11258     {
11259         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11260                __FILE__, __LINE__);
11261         return(TNG_CRITICAL);
11262     }
11263     fseek(tng_data->input_file, file_pos, SEEK_SET);
11264
11265     *n = first_frame + n_frames;
11266
11267     return(TNG_SUCCESS);
11268 }
11269
11270 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11271                 (const tng_trajectory_t tng_data,
11272                  double *precision)
11273 {
11274     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11275
11276     *precision = tng_data->compression_precision;
11277
11278     return(TNG_SUCCESS);
11279 }
11280
11281 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11282                 (tng_trajectory_t tng_data,
11283                  const double precision)
11284 {
11285     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11286
11287     tng_data->compression_precision = precision;
11288
11289     return(TNG_SUCCESS);
11290 }
11291
11292 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11293                 (tng_trajectory_t tng_data,
11294                  const int64_t n)
11295 {
11296     tng_molecule_t mol;
11297     tng_chain_t chain;
11298     tng_residue_t res;
11299     tng_atom_t atom;
11300     tng_function_status stat;
11301     int64_t diff, n_mod, n_impl;
11302
11303     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11304
11305     diff = n - tng_data->n_particles;
11306
11307     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11308     if(stat == TNG_SUCCESS)
11309     {
11310         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11311         {
11312             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11313                     __FILE__, __LINE__);
11314             return(TNG_FAILURE);
11315         }
11316         diff -= n_impl * mol->n_atoms;
11317     }
11318
11319     if(diff == 0)
11320     {
11321         if(stat == TNG_SUCCESS)
11322         {
11323             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11324             return(stat);
11325         }
11326         return(TNG_SUCCESS);
11327     }
11328     else if(diff < 0)
11329     {
11330         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11331         fprintf(stderr, "particle count.\n");
11332         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11333                 __FILE__, __LINE__);
11334         /* FIXME: Should we set the count of all other molecules to 0 and add
11335          * implicit molecules? */
11336         return(TNG_FAILURE);
11337     }
11338     if(stat != TNG_SUCCESS)
11339     {
11340         stat = tng_molecule_add(tng_data,
11341                                 "TNG_IMPLICIT_MOL",
11342                                 &mol);
11343         if(stat != TNG_SUCCESS)
11344         {
11345             return(stat);
11346         }
11347         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11348         if(stat != TNG_SUCCESS)
11349         {
11350             return(stat);
11351         }
11352         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11353         if(stat != TNG_SUCCESS)
11354         {
11355             return(stat);
11356         }
11357         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11358         if(stat != TNG_SUCCESS)
11359         {
11360             return(stat);
11361         }
11362     }
11363     else
11364     {
11365         if(mol->n_atoms > 1)
11366         {
11367             n_mod = diff % mol->n_atoms;
11368             if(n_mod != 0)
11369             {
11370                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11371                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11372                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11373                         __FILE__, __LINE__);
11374                 return(TNG_FAILURE);
11375             }
11376             diff /= mol->n_atoms;
11377         }
11378     }
11379     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11380
11381     return(stat);
11382 }
11383
11384 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11385                 (const tng_trajectory_t tng_data,
11386                  int64_t *n)
11387 {
11388     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11389     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11390
11391     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11392     {
11393         *n = tng_data->n_particles;
11394     }
11395     else
11396     {
11397         *n = tng_data->current_trajectory_frame_set.n_particles;
11398     }
11399
11400     return(TNG_SUCCESS);
11401 }
11402
11403 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11404                 (const tng_trajectory_t tng_data,
11405                  char *variable)
11406 {
11407     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11408     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11409
11410     *variable = tng_data->var_num_atoms_flag;
11411
11412     return(TNG_SUCCESS);
11413 }
11414
11415 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11416                     (const tng_trajectory_t tng_data,
11417                      int64_t *n)
11418 {
11419     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11420     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11421
11422     *n = tng_data->n_molecules;
11423
11424     return(TNG_SUCCESS);
11425 }
11426
11427 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11428                     (const tng_trajectory_t tng_data,
11429                      int64_t *n)
11430 {
11431     int64_t *cnt_list = 0, cnt = 0, i;
11432
11433     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11434     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11435
11436     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11437
11438     if(!cnt_list)
11439     {
11440         return(TNG_FAILURE);
11441     }
11442
11443     for(i = 0; i < tng_data->n_molecules; i++)
11444     {
11445         cnt += cnt_list[i];
11446     }
11447
11448     *n = cnt;
11449
11450     return(TNG_SUCCESS);
11451 }
11452
11453 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11454                 (const tng_trajectory_t tng_data,
11455                  int64_t **mol_cnt_list)
11456 {
11457     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11458
11459     if(tng_data->var_num_atoms_flag)
11460     {
11461         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11462                        molecule_cnt_list;
11463     }
11464     else
11465     {
11466         *mol_cnt_list = tng_data->molecule_cnt_list;
11467     }
11468     if(*mol_cnt_list == 0)
11469     {
11470         return(TNG_FAILURE);
11471     }
11472     return(TNG_SUCCESS);
11473 }
11474
11475 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11476                 (const tng_trajectory_t tng_data,
11477                  int64_t *exp)
11478 {
11479     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11480     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11481
11482     *exp = tng_data->distance_unit_exponential;
11483
11484     return(TNG_SUCCESS);
11485 }
11486
11487 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11488                 (const tng_trajectory_t tng_data,
11489                  const int64_t exp)
11490 {
11491     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11492
11493     tng_data->distance_unit_exponential = exp;
11494
11495     return(TNG_SUCCESS);
11496 }
11497
11498 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11499                 (const tng_trajectory_t tng_data,
11500                  int64_t *n)
11501 {
11502     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11503     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11504
11505     *n = tng_data->frame_set_n_frames;
11506
11507     return(TNG_SUCCESS);
11508 }
11509
11510 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11511                 (const tng_trajectory_t tng_data,
11512                  const int64_t n)
11513 {
11514     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11515
11516     tng_data->frame_set_n_frames = n;
11517
11518     return(TNG_SUCCESS);
11519 }
11520
11521 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11522                 (const tng_trajectory_t tng_data,
11523                  int64_t *n)
11524 {
11525     int64_t long_stride_length, medium_stride_length;
11526     long file_pos, orig_frame_set_file_pos;
11527     tng_trajectory_frame_set_t frame_set;
11528     struct tng_trajectory_frame_set   orig_frame_set;
11529     tng_gen_block_t block;
11530     tng_function_status stat;
11531     int64_t cnt = 0;
11532
11533     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11534     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11535
11536     orig_frame_set = tng_data->current_trajectory_frame_set;
11537
11538     frame_set = &tng_data->current_trajectory_frame_set;
11539
11540     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11541     file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
11542
11543     tng_block_init(&block);
11544     fseek(tng_data->input_file,
11545           file_pos,
11546           SEEK_SET);
11547     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11548     /* Read block headers first to see what block is found. */
11549     stat = tng_block_header_read(tng_data, block);
11550     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11551     {
11552         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos,
11553                 __FILE__, __LINE__);
11554         tng_block_destroy(&block);
11555         return(TNG_CRITICAL);
11556     }
11557
11558     if(tng_block_read_next(tng_data, block,
11559                         TNG_SKIP_HASH) != TNG_SUCCESS)
11560     {
11561         tng_block_destroy(&block);
11562         return(TNG_CRITICAL);
11563     }
11564
11565     ++cnt;
11566
11567     long_stride_length = tng_data->long_stride_length;
11568     medium_stride_length = tng_data->medium_stride_length;
11569
11570     /* Take long steps forward until a long step forward would be too long or
11571      * the last frame set is found */
11572     file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11573     while(file_pos > 0)
11574     {
11575         if(file_pos > 0)
11576         {
11577             cnt += long_stride_length;
11578             fseek(tng_data->input_file, file_pos, SEEK_SET);
11579             /* Read block headers first to see what block is found. */
11580             stat = tng_block_header_read(tng_data, block);
11581             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11582             {
11583                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11584                        file_pos, __FILE__, __LINE__);
11585                 tng_block_destroy(&block);
11586                 return(TNG_CRITICAL);
11587             }
11588
11589             if(tng_block_read_next(tng_data, block,
11590                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11591             {
11592                 tng_block_destroy(&block);
11593                 return(TNG_CRITICAL);
11594             }
11595         }
11596         file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11597     }
11598
11599     /* Take medium steps forward until a medium step forward would be too long
11600      * or the last frame set is found */
11601     file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11602     while(file_pos > 0)
11603     {
11604         if(file_pos > 0)
11605         {
11606             cnt += medium_stride_length;
11607             fseek(tng_data->input_file,
11608                   file_pos,
11609                   SEEK_SET);
11610             /* Read block headers first to see what block is found. */
11611             stat = tng_block_header_read(tng_data, block);
11612             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11613             {
11614                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11615                        file_pos, __FILE__, __LINE__);
11616                 tng_block_destroy(&block);
11617                 return(TNG_CRITICAL);
11618             }
11619
11620             if(tng_block_read_next(tng_data, block,
11621                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11622             {
11623                 tng_block_destroy(&block);
11624                 return(TNG_CRITICAL);
11625             }
11626         }
11627         file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11628     }
11629
11630     /* Take one step forward until the last frame set is found */
11631     file_pos = (long)frame_set->next_frame_set_file_pos;
11632     while(file_pos > 0)
11633     {
11634         if(file_pos > 0)
11635         {
11636             ++cnt;
11637             fseek(tng_data->input_file,
11638                   file_pos,
11639                   SEEK_SET);
11640             /* Read block headers first to see what block is found. */
11641             stat = tng_block_header_read(tng_data, block);
11642             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11643             {
11644                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11645                        file_pos, __FILE__, __LINE__);
11646                 tng_block_destroy(&block);
11647                 return(TNG_CRITICAL);
11648             }
11649
11650             if(tng_block_read_next(tng_data, block,
11651                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11652             {
11653                 tng_block_destroy(&block);
11654                 return(TNG_CRITICAL);
11655             }
11656         }
11657         file_pos = (long)frame_set->next_frame_set_file_pos;
11658     }
11659
11660     tng_block_destroy(&block);
11661
11662     *n = tng_data->n_trajectory_frame_sets = cnt;
11663
11664     *frame_set = orig_frame_set;
11665
11666     fseek(tng_data->input_file,
11667           (long)tng_data->first_trajectory_frame_set_input_file_pos,
11668           SEEK_SET);
11669
11670     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11671
11672     return(TNG_SUCCESS);
11673 }
11674
11675 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11676                 (const tng_trajectory_t tng_data,
11677                  tng_trajectory_frame_set_t *frame_set_p)
11678 {
11679     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11680
11681     *frame_set_p = &tng_data->current_trajectory_frame_set;
11682
11683     return(TNG_SUCCESS);
11684 }
11685
11686 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11687                 (tng_trajectory_t tng_data,
11688                  const int64_t nr)
11689 {
11690     int64_t long_stride_length, medium_stride_length;
11691     int64_t file_pos, curr_nr = 0, n_frame_sets;
11692     tng_trajectory_frame_set_t frame_set;
11693     tng_gen_block_t block;
11694     tng_function_status stat;
11695
11696     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11697     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11698
11699     frame_set = &tng_data->current_trajectory_frame_set;
11700
11701     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11702
11703     if(stat != TNG_SUCCESS)
11704     {
11705         return(stat);
11706     }
11707
11708     if(nr >= n_frame_sets)
11709     {
11710         return(TNG_FAILURE);
11711     }
11712
11713     long_stride_length = tng_data->long_stride_length;
11714     medium_stride_length = tng_data->medium_stride_length;
11715
11716     /* FIXME: The frame set number of the current frame set is not stored */
11717
11718     if(nr < n_frame_sets - 1 - nr)
11719     {
11720         /* Start from the beginning */
11721         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11722     }
11723     else
11724     {
11725         /* Start from the end */
11726         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11727         curr_nr = n_frame_sets - 1;
11728     }
11729     if(file_pos <= 0)
11730     {
11731         return(TNG_FAILURE);
11732     }
11733
11734     tng_block_init(&block);
11735     fseek(tng_data->input_file,
11736           (long)file_pos,
11737           SEEK_SET);
11738     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11739     /* Read block headers first to see what block is found. */
11740     stat = tng_block_header_read(tng_data, block);
11741     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11742     {
11743         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11744                 __FILE__, __LINE__);
11745         tng_block_destroy(&block);
11746         return(TNG_CRITICAL);
11747     }
11748
11749     if(tng_block_read_next(tng_data, block,
11750                         TNG_SKIP_HASH) != TNG_SUCCESS)
11751     {
11752         tng_block_destroy(&block);
11753         return(TNG_CRITICAL);
11754     }
11755
11756     if(curr_nr == nr)
11757     {
11758         tng_block_destroy(&block);
11759         return(TNG_SUCCESS);
11760     }
11761
11762     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11763
11764     /* Take long steps forward until a long step forward would be too long or
11765      * the right frame set is found */
11766     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11767     {
11768         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11769         if(file_pos > 0)
11770         {
11771             curr_nr += long_stride_length;
11772             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11773             /* Read block headers first to see what block is found. */
11774             stat = tng_block_header_read(tng_data, block);
11775             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11776             {
11777                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11778                        file_pos,  __FILE__, __LINE__);
11779                 tng_block_destroy(&block);
11780                 return(TNG_CRITICAL);
11781             }
11782
11783             if(tng_block_read_next(tng_data, block,
11784                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11785             {
11786                 tng_block_destroy(&block);
11787                 return(TNG_CRITICAL);
11788             }
11789             if(curr_nr == nr)
11790             {
11791                 tng_block_destroy(&block);
11792                 return(TNG_SUCCESS);
11793             }
11794         }
11795     }
11796
11797     /* Take medium steps forward until a medium step forward would be too long
11798      * or the right frame set is found */
11799     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11800     {
11801         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11802         if(file_pos > 0)
11803         {
11804             curr_nr += medium_stride_length;
11805             fseek(tng_data->input_file,
11806                   (long)file_pos,
11807                   SEEK_SET);
11808             /* Read block headers first to see what block is found. */
11809             stat = tng_block_header_read(tng_data, block);
11810             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11811             {
11812                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11813                        file_pos, __FILE__, __LINE__);
11814                 tng_block_destroy(&block);
11815                 return(TNG_CRITICAL);
11816             }
11817
11818             if(tng_block_read_next(tng_data, block,
11819                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11820             {
11821                 tng_block_destroy(&block);
11822                 return(TNG_CRITICAL);
11823             }
11824             if(curr_nr == nr)
11825             {
11826                 tng_block_destroy(&block);
11827                 return(TNG_SUCCESS);
11828             }
11829         }
11830     }
11831
11832     /* Take one step forward until the right frame set is found */
11833     while(file_pos > 0 && curr_nr < nr)
11834     {
11835         file_pos = frame_set->next_frame_set_file_pos;
11836
11837         if(file_pos > 0)
11838         {
11839             ++curr_nr;
11840             fseek(tng_data->input_file,
11841                   (long)file_pos,
11842                   SEEK_SET);
11843             /* Read block headers first to see what block is found. */
11844             stat = tng_block_header_read(tng_data, block);
11845             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11846             {
11847                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11848                        file_pos, __FILE__, __LINE__);
11849                 tng_block_destroy(&block);
11850                 return(TNG_CRITICAL);
11851             }
11852
11853             if(tng_block_read_next(tng_data, block,
11854                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11855             {
11856                 tng_block_destroy(&block);
11857                 return(TNG_CRITICAL);
11858             }
11859             if(curr_nr == nr)
11860             {
11861                 tng_block_destroy(&block);
11862                 return(TNG_SUCCESS);
11863             }
11864         }
11865     }
11866
11867     /* Take long steps backward until a long step backward would be too long
11868      * or the right frame set is found */
11869     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11870     {
11871         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11872         if(file_pos > 0)
11873         {
11874             curr_nr -= long_stride_length;
11875             fseek(tng_data->input_file,
11876                   (long)file_pos,
11877                   SEEK_SET);
11878             /* Read block headers first to see what block is found. */
11879             stat = tng_block_header_read(tng_data, block);
11880             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11881             {
11882                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11883                        file_pos, __FILE__, __LINE__);
11884                 tng_block_destroy(&block);
11885                 return(TNG_CRITICAL);
11886             }
11887
11888             if(tng_block_read_next(tng_data, block,
11889                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11890             {
11891                 tng_block_destroy(&block);
11892                 return(TNG_CRITICAL);
11893             }
11894             if(curr_nr == nr)
11895             {
11896                 tng_block_destroy(&block);
11897                 return(TNG_SUCCESS);
11898             }
11899         }
11900     }
11901
11902     /* Take medium steps backward until a medium step backward would be too long
11903      * or the right frame set is found */
11904     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11905     {
11906         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11907         if(file_pos > 0)
11908         {
11909             curr_nr -= medium_stride_length;
11910             fseek(tng_data->input_file,
11911                   (long)file_pos,
11912                   SEEK_SET);
11913             /* Read block headers first to see what block is found. */
11914             stat = tng_block_header_read(tng_data, block);
11915             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11916             {
11917                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11918                        file_pos, __FILE__, __LINE__);
11919                 tng_block_destroy(&block);
11920                 return(TNG_CRITICAL);
11921             }
11922
11923             if(tng_block_read_next(tng_data, block,
11924                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11925             {
11926                 tng_block_destroy(&block);
11927                 return(TNG_CRITICAL);
11928             }
11929             if(curr_nr == nr)
11930             {
11931                 tng_block_destroy(&block);
11932                 return(TNG_SUCCESS);
11933             }
11934         }
11935     }
11936
11937     /* Take one step backward until the right frame set is found */
11938     while(file_pos > 0 && curr_nr > nr)
11939     {
11940         file_pos = frame_set->prev_frame_set_file_pos;
11941         if(file_pos > 0)
11942         {
11943             --curr_nr;
11944             fseek(tng_data->input_file,
11945                   (long)file_pos,
11946                   SEEK_SET);
11947             /* Read block headers first to see what block is found. */
11948             stat = tng_block_header_read(tng_data, block);
11949             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11950             {
11951                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11952                        file_pos, __FILE__, __LINE__);
11953                 tng_block_destroy(&block);
11954                 return(TNG_CRITICAL);
11955             }
11956
11957             if(tng_block_read_next(tng_data, block,
11958                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11959             {
11960                 tng_block_destroy(&block);
11961                 return(TNG_CRITICAL);
11962             }
11963             if(curr_nr == nr)
11964             {
11965                 tng_block_destroy(&block);
11966                 return(TNG_SUCCESS);
11967             }
11968         }
11969     }
11970
11971     /* If for some reason the current frame set is not yet found,
11972      * take one step forward until the right frame set is found */
11973     while(file_pos > 0 && curr_nr < nr)
11974     {
11975         file_pos = frame_set->next_frame_set_file_pos;
11976         if(file_pos > 0)
11977         {
11978             ++curr_nr;
11979             fseek(tng_data->input_file,
11980                   (long)file_pos,
11981                   SEEK_SET);
11982             /* Read block headers first to see what block is found. */
11983             stat = tng_block_header_read(tng_data, block);
11984             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11985             {
11986                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11987                        file_pos, __FILE__, __LINE__);
11988                 tng_block_destroy(&block);
11989                 return(TNG_CRITICAL);
11990             }
11991
11992             if(tng_block_read_next(tng_data, block,
11993                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11994             {
11995                 tng_block_destroy(&block);
11996                 return(TNG_CRITICAL);
11997             }
11998             if(curr_nr == nr)
11999             {
12000                 tng_block_destroy(&block);
12001                 return(TNG_SUCCESS);
12002             }
12003         }
12004     }
12005
12006     tng_block_destroy(&block);
12007     return(TNG_FAILURE);
12008 }
12009
12010 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
12011                 (tng_trajectory_t tng_data,
12012                  const int64_t frame)
12013 {
12014     int64_t first_frame, last_frame, n_frames_per_frame_set;
12015     int64_t long_stride_length, medium_stride_length;
12016     int64_t file_pos, temp_frame, n_frames;
12017     tng_trajectory_frame_set_t frame_set;
12018     tng_gen_block_t block;
12019     tng_function_status stat;
12020
12021     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12022     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
12023
12024     frame_set = &tng_data->current_trajectory_frame_set;
12025
12026     tng_block_init(&block);
12027
12028     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
12029     {
12030         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12031         fseek(tng_data->input_file,
12032                 (long)file_pos,
12033                 SEEK_SET);
12034         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
12035         /* Read block headers first to see what block is found. */
12036         stat = tng_block_header_read(tng_data, block);
12037         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12038         {
12039             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12040                     file_pos, __FILE__, __LINE__);
12041             tng_block_destroy(&block);
12042             return(TNG_CRITICAL);
12043         }
12044
12045         if(tng_block_read_next(tng_data, block,
12046                             TNG_SKIP_HASH) != TNG_SUCCESS)
12047         {
12048             tng_block_destroy(&block);
12049             return(TNG_CRITICAL);
12050         }
12051     }
12052
12053     first_frame = tng_max_i64(frame_set->first_frame, 0);
12054     last_frame = first_frame + frame_set->n_frames - 1;
12055     /* Is this the right frame set? */
12056     if(first_frame <= frame && frame <= last_frame)
12057     {
12058         tng_block_destroy(&block);
12059         return(TNG_SUCCESS);
12060     }
12061
12062     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12063     long_stride_length = tng_data->long_stride_length;
12064     medium_stride_length = tng_data->medium_stride_length;
12065
12066     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12067        TNG_SUCCESS)
12068     {
12069         if(temp_frame - first_frame > n_frames_per_frame_set)
12070         {
12071             n_frames_per_frame_set = temp_frame - first_frame;
12072         }
12073     }
12074
12075     tng_num_frames_get(tng_data, &n_frames);
12076
12077     if(frame >= n_frames)
12078     {
12079         tng_block_destroy(&block);
12080         return(TNG_FAILURE);
12081     }
12082
12083     if(first_frame - frame >= frame ||
12084        frame - last_frame >
12085        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12086     {
12087         /* Start from the beginning */
12088         if(first_frame - frame >= frame)
12089         {
12090             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12091
12092             if(file_pos <= 0)
12093             {
12094                 tng_block_destroy(&block);
12095                 return(TNG_FAILURE);
12096             }
12097         }
12098         /* Start from the end */
12099         else if(frame - first_frame > (n_frames - 1) - frame)
12100         {
12101             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12102
12103             /* If the last frame set position is not set start from the current
12104              * frame set, since it will be closer than the first frame set. */
12105         }
12106         /* Start from current */
12107         else
12108         {
12109             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12110         }
12111
12112         if(file_pos > 0)
12113         {
12114             fseek(tng_data->input_file,
12115                   (long)file_pos,
12116                   SEEK_SET);
12117             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
12118             /* Read block headers first to see what block is found. */
12119             stat = tng_block_header_read(tng_data, block);
12120             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12121             {
12122                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12123                        file_pos, __FILE__, __LINE__);
12124                 tng_block_destroy(&block);
12125                 return(TNG_CRITICAL);
12126             }
12127
12128             if(tng_block_read_next(tng_data, block,
12129                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12130             {
12131                 tng_block_destroy(&block);
12132                 return(TNG_CRITICAL);
12133             }
12134         }
12135     }
12136
12137     first_frame = tng_max_i64(frame_set->first_frame, 0);
12138     last_frame = first_frame + frame_set->n_frames - 1;
12139
12140     if(frame >= first_frame && frame <= last_frame)
12141     {
12142         tng_block_destroy(&block);
12143         return(TNG_SUCCESS);
12144     }
12145
12146     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12147
12148     /* Take long steps forward until a long step forward would be too long or
12149      * the right frame set is found */
12150     while(file_pos > 0 && first_frame + long_stride_length *
12151           n_frames_per_frame_set <= frame)
12152     {
12153         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12154         if(file_pos > 0)
12155         {
12156             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
12157             /* Read block headers first to see what block is found. */
12158             stat = tng_block_header_read(tng_data, block);
12159             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12160             {
12161                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12162                        file_pos, __FILE__, __LINE__);
12163                 tng_block_destroy(&block);
12164                 return(TNG_CRITICAL);
12165             }
12166
12167             if(tng_block_read_next(tng_data, block,
12168                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12169             {
12170                 tng_block_destroy(&block);
12171                 return(TNG_CRITICAL);
12172             }
12173         }
12174         first_frame = tng_max_i64(frame_set->first_frame, 0);
12175         last_frame = first_frame + frame_set->n_frames - 1;
12176         if(frame >= first_frame && frame <= last_frame)
12177         {
12178             tng_block_destroy(&block);
12179             return(TNG_SUCCESS);
12180         }
12181     }
12182
12183     /* Take medium steps forward until a medium step forward would be too long
12184      * or the right frame set is found */
12185     while(file_pos > 0 && first_frame + medium_stride_length *
12186           n_frames_per_frame_set <= frame)
12187     {
12188         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12189         if(file_pos > 0)
12190         {
12191             fseek(tng_data->input_file,
12192                   (long)file_pos,
12193                   SEEK_SET);
12194             /* Read block headers first to see what block is found. */
12195             stat = tng_block_header_read(tng_data, block);
12196             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12197             {
12198                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12199                        file_pos, __FILE__, __LINE__);
12200                 tng_block_destroy(&block);
12201                 return(TNG_CRITICAL);
12202             }
12203
12204             if(tng_block_read_next(tng_data, block,
12205                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12206             {
12207                 tng_block_destroy(&block);
12208                 return(TNG_CRITICAL);
12209             }
12210         }
12211         first_frame = tng_max_i64(frame_set->first_frame, 0);
12212         last_frame = first_frame + frame_set->n_frames - 1;
12213         if(frame >= first_frame && frame <= last_frame)
12214         {
12215             tng_block_destroy(&block);
12216             return(TNG_SUCCESS);
12217         }
12218     }
12219
12220     /* Take one step forward until the right frame set is found */
12221     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12222     {
12223         file_pos = frame_set->next_frame_set_file_pos;
12224         if(file_pos > 0)
12225         {
12226             fseek(tng_data->input_file,
12227                   (long)file_pos,
12228                   SEEK_SET);
12229             /* Read block headers first to see what block is found. */
12230             stat = tng_block_header_read(tng_data, block);
12231             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12232             {
12233                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12234                        file_pos, __FILE__, __LINE__);
12235                 tng_block_destroy(&block);
12236                 return(TNG_CRITICAL);
12237             }
12238
12239             if(tng_block_read_next(tng_data, block,
12240                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12241             {
12242                 tng_block_destroy(&block);
12243                 return(TNG_CRITICAL);
12244             }
12245         }
12246         first_frame = tng_max_i64(frame_set->first_frame, 0);
12247         last_frame = first_frame + frame_set->n_frames - 1;
12248         if(frame >= first_frame && frame <= last_frame)
12249         {
12250             tng_block_destroy(&block);
12251             return(TNG_SUCCESS);
12252         }
12253     }
12254
12255     /* Take long steps backward until a long step backward would be too long
12256      * or the right frame set is found */
12257     while(file_pos > 0 && first_frame - long_stride_length *
12258           n_frames_per_frame_set >= frame)
12259     {
12260         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12261         if(file_pos > 0)
12262         {
12263             fseek(tng_data->input_file,
12264                   (long)file_pos,
12265                   SEEK_SET);
12266             /* Read block headers first to see what block is found. */
12267             stat = tng_block_header_read(tng_data, block);
12268             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12269             {
12270                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12271                        file_pos, __FILE__, __LINE__);
12272                 tng_block_destroy(&block);
12273                 return(TNG_CRITICAL);
12274             }
12275
12276             if(tng_block_read_next(tng_data, block,
12277                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12278             {
12279                 tng_block_destroy(&block);
12280                 return(TNG_CRITICAL);
12281             }
12282         }
12283         first_frame = tng_max_i64(frame_set->first_frame, 0);
12284         last_frame = first_frame + frame_set->n_frames - 1;
12285         if(frame >= first_frame && frame <= last_frame)
12286         {
12287             tng_block_destroy(&block);
12288             return(TNG_SUCCESS);
12289         }
12290     }
12291
12292     /* Take medium steps backward until a medium step backward would be too long
12293      * or the right frame set is found */
12294     while(file_pos > 0 && first_frame - medium_stride_length *
12295           n_frames_per_frame_set >= frame)
12296     {
12297         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12298         if(file_pos > 0)
12299         {
12300             fseek(tng_data->input_file,
12301                   (long)file_pos,
12302                   SEEK_SET);
12303             /* Read block headers first to see what block is found. */
12304             stat = tng_block_header_read(tng_data, block);
12305             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12306             {
12307                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12308                        file_pos, __FILE__, __LINE__);
12309                 tng_block_destroy(&block);
12310                 return(TNG_CRITICAL);
12311             }
12312
12313             if(tng_block_read_next(tng_data, block,
12314                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12315             {
12316                 tng_block_destroy(&block);
12317                 return(TNG_CRITICAL);
12318             }
12319         }
12320         first_frame = tng_max_i64(frame_set->first_frame, 0);
12321         last_frame = first_frame + frame_set->n_frames - 1;
12322         if(frame >= first_frame && frame <= last_frame)
12323         {
12324             tng_block_destroy(&block);
12325             return(TNG_SUCCESS);
12326         }
12327     }
12328
12329     /* Take one step backward until the right frame set is found */
12330     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12331     {
12332         file_pos = frame_set->prev_frame_set_file_pos;
12333         if(file_pos > 0)
12334         {
12335             fseek(tng_data->input_file,
12336                   (long)file_pos,
12337                   SEEK_SET);
12338             /* Read block headers first to see what block is found. */
12339             stat = tng_block_header_read(tng_data, block);
12340             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12341             {
12342                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12343                        file_pos, __FILE__, __LINE__);
12344                 tng_block_destroy(&block);
12345                 return(TNG_CRITICAL);
12346             }
12347
12348             if(tng_block_read_next(tng_data, block,
12349                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12350             {
12351                 tng_block_destroy(&block);
12352                 return(TNG_CRITICAL);
12353             }
12354         }
12355         first_frame = tng_max_i64(frame_set->first_frame, 0);
12356         last_frame = first_frame + frame_set->n_frames - 1;
12357         if(frame >= first_frame && frame <= last_frame)
12358         {
12359             tng_block_destroy(&block);
12360             return(TNG_SUCCESS);
12361         }
12362     }
12363
12364     /* If for some reason the current frame set is not yet found,
12365      * take one step forward until the right frame set is found */
12366     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12367     {
12368         file_pos = frame_set->next_frame_set_file_pos;
12369         if(file_pos > 0)
12370         {
12371             fseek(tng_data->input_file,
12372                   (long)file_pos,
12373                   SEEK_SET);
12374             /* Read block headers first to see what block is found. */
12375             stat = tng_block_header_read(tng_data, block);
12376             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12377             {
12378                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12379                        file_pos, __FILE__, __LINE__);
12380                 tng_block_destroy(&block);
12381                 return(TNG_CRITICAL);
12382             }
12383
12384             if(tng_block_read_next(tng_data, block,
12385                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12386             {
12387                 tng_block_destroy(&block);
12388                 return(TNG_CRITICAL);
12389             }
12390         }
12391         first_frame = tng_max_i64(frame_set->first_frame, 0);
12392         last_frame = first_frame + frame_set->n_frames - 1;
12393         if(frame >= first_frame && frame <= last_frame)
12394         {
12395             tng_block_destroy(&block);
12396             return(TNG_SUCCESS);
12397         }
12398     }
12399
12400     tng_block_destroy(&block);
12401     return(TNG_FAILURE);
12402 }
12403
12404 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12405                 (const tng_trajectory_t tng_data,
12406                  const tng_trajectory_frame_set_t frame_set,
12407                  int64_t *pos)
12408 {
12409     (void)tng_data;
12410
12411     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12412     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12413
12414     *pos = frame_set->next_frame_set_file_pos;
12415
12416     return(TNG_SUCCESS);
12417 }
12418
12419 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12420                 (const tng_trajectory_t tng_data,
12421                  const tng_trajectory_frame_set_t frame_set,
12422                  int64_t *pos)
12423 {
12424     (void)tng_data;
12425
12426     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12427     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12428
12429     *pos = frame_set->prev_frame_set_file_pos;
12430
12431     return(TNG_SUCCESS);
12432 }
12433
12434 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12435                 (const tng_trajectory_t tng_data,
12436                  const tng_trajectory_frame_set_t frame_set,
12437                  int64_t *first_frame,
12438                  int64_t *last_frame)
12439 {
12440     (void)tng_data;
12441
12442     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12443     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12444     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12445
12446     *first_frame = frame_set->first_frame;
12447     *last_frame = *first_frame + frame_set->n_frames - 1;
12448
12449     return(TNG_SUCCESS);
12450 }
12451
12452 /** Translate from the particle numbering used in a frame set to the real
12453  *  particle numbering - used in the molecule description.
12454  * @param frame_set is the frame_set containing the mappings to use.
12455  * @param local is the index number of the atom in this frame set
12456  * @param real is set to the index of the atom in the molecular system.
12457  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12458  * cannot be found.
12459  */
12460 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12461                 (const tng_trajectory_frame_set_t frame_set,
12462                  const int64_t local,
12463                  int64_t *real)
12464 {
12465     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12466     tng_particle_mapping_t mapping;
12467     if(n_blocks <= 0)
12468     {
12469         *real = local;
12470         return(TNG_SUCCESS);
12471     }
12472     for(i = 0; i < n_blocks; i++)
12473     {
12474         mapping = &frame_set->mappings[i];
12475         first = mapping->num_first_particle;
12476         if(local < first ||
12477            local >= first + mapping->n_particles)
12478         {
12479             continue;
12480         }
12481         *real = mapping->real_particle_numbers[local-first];
12482         return(TNG_SUCCESS);
12483     }
12484     *real = local;
12485     return(TNG_FAILURE);
12486 }
12487
12488 /** Translate from the real particle numbering to the particle numbering
12489  *  used in a frame set.
12490  * @param frame_set is the frame_set containing the mappings to use.
12491  * @param real is the index number of the atom in the molecular system.
12492  * @param local is set to the index of the atom in this frame set.
12493  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12494  * cannot be found.
12495  */
12496 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12497                 (const tng_trajectory_frame_set_t frame_set,
12498                  const int64_t real,
12499                  int64_t *local)
12500 {
12501     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12502     tng_particle_mapping_t mapping;
12503     if(n_blocks <= 0)
12504     {
12505         *local = real;
12506         return(TNG_SUCCESS);
12507     }
12508     for(i = 0; i < n_blocks; i++)
12509     {
12510         mapping = &frame_set->mappings[i];
12511         for(j = mapping->n_particles; j--;)
12512         {
12513             if(mapping->real_particle_numbers[j] == real)
12514             {
12515                 *local = j;
12516                 return(TNG_SUCCESS);
12517             }
12518         }
12519     }
12520     return(TNG_FAILURE);
12521 }
12522 */
12523
12524 static tng_function_status tng_file_headers_len_get
12525                 (tng_trajectory_t tng_data,
12526                  int64_t *len)
12527 {
12528     int64_t orig_pos;
12529     tng_gen_block_t block;
12530
12531     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12532
12533     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12534     {
12535         return(TNG_CRITICAL);
12536     }
12537
12538     *len = 0;
12539
12540     orig_pos = ftell(tng_data->input_file);
12541
12542     if(!tng_data->input_file_len)
12543     {
12544         fseek(tng_data->input_file, 0, SEEK_END);
12545         tng_data->input_file_len = ftell(tng_data->input_file);
12546     }
12547     fseek(tng_data->input_file, 0, SEEK_SET);
12548
12549     tng_block_init(&block);
12550     /* Read through the headers of non-trajectory blocks (they come before the
12551      * trajectory blocks in the file) */
12552     while (*len < tng_data->input_file_len &&
12553            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12554            block->id != -1 &&
12555            block->id != TNG_TRAJECTORY_FRAME_SET)
12556     {
12557         *len += block->header_contents_size + block->block_contents_size;
12558         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12559     }
12560
12561     fseek(tng_data->input_file, orig_pos, SEEK_SET);
12562
12563     tng_block_destroy(&block);
12564
12565     return(TNG_SUCCESS);
12566 }
12567
12568 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12569                 (tng_trajectory_t tng_data,
12570                  const char hash_mode)
12571 {
12572     int64_t prev_pos = 0;
12573     tng_gen_block_t block;
12574
12575     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12576
12577     tng_data->n_trajectory_frame_sets = 0;
12578
12579     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12580     {
12581         return(TNG_CRITICAL);
12582     }
12583
12584     if(!tng_data->input_file_len)
12585     {
12586         fseek(tng_data->input_file, 0, SEEK_END);
12587         tng_data->input_file_len = ftell(tng_data->input_file);
12588     }
12589     fseek(tng_data->input_file, 0, SEEK_SET);
12590
12591     tng_block_init(&block);
12592     /* Non trajectory blocks (they come before the trajectory
12593      * blocks in the file) */
12594     while (prev_pos < tng_data->input_file_len &&
12595            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12596            block->id != -1 &&
12597            block->id != TNG_TRAJECTORY_FRAME_SET)
12598     {
12599         tng_block_read_next(tng_data, block, hash_mode);
12600         prev_pos = ftell(tng_data->input_file);
12601     }
12602
12603     /* Go back if a trajectory block was encountered */
12604     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12605     {
12606         fseek(tng_data->input_file, prev_pos, SEEK_SET);
12607     }
12608
12609     tng_block_destroy(&block);
12610
12611     return(TNG_SUCCESS);
12612 }
12613
12614 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12615                 (tng_trajectory_t tng_data,
12616                  const char hash_mode)
12617 {
12618     int i;
12619     int64_t len, orig_len, tot_len = 0, data_start_pos;
12620     tng_function_status stat;
12621     tng_gen_block_t block;
12622
12623     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12624
12625     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12626     {
12627         return(TNG_CRITICAL);
12628     }
12629
12630     if(tng_data->n_trajectory_frame_sets > 0)
12631     {
12632         stat = tng_file_headers_len_get(tng_data, &orig_len);
12633         if(stat != TNG_SUCCESS)
12634         {
12635             return(stat);
12636         }
12637
12638         tng_block_init(&block);
12639         block->name = malloc(TNG_MAX_STR_LEN);
12640         if(!block->name)
12641         {
12642             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12643                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12644             tng_block_destroy(&block);
12645             return(TNG_CRITICAL);
12646         }
12647         strcpy(block->name, "GENERAL INFO");
12648         tng_block_header_len_calculate(tng_data, block, &len);
12649         tot_len += len;
12650         tng_general_info_block_len_calculate(tng_data, &len);
12651         tot_len += len;
12652         strcpy(block->name, "MOLECULES");
12653         tng_block_header_len_calculate(tng_data, block, &len);
12654         tot_len += len;
12655         tng_molecules_block_len_calculate(tng_data, &len);
12656         tot_len += len;
12657
12658         for(i = 0; i < tng_data->n_data_blocks; i++)
12659         {
12660             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12661             tng_block_header_len_calculate(tng_data, block, &len);
12662             tot_len += len;
12663             tng_data_block_len_calculate(tng_data,
12664                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12665                                         TNG_FALSE, 1, 1, 1, 0,
12666                                         1, 0, &data_start_pos,
12667                                         &len);
12668             tot_len += len;
12669         }
12670         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12671         {
12672             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12673             tng_block_header_len_calculate(tng_data, block, &len);
12674             tot_len += len;
12675             tng_data_block_len_calculate(tng_data,
12676                                         &tng_data->non_tr_particle_data[i],
12677                                         TNG_TRUE, 1, 1, 1, 0,
12678                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12679                                         &data_start_pos,
12680                                         &len);
12681             tot_len += len;
12682         }
12683         tng_block_destroy(&block);
12684
12685         if(tot_len > orig_len)
12686         {
12687             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12688         }
12689
12690         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12691     }
12692
12693     /* TODO: If there is already frame set data written to this file (e.g. when
12694      * appending to an already existing file we might need to move frame sets to
12695      * the end of the file. */
12696
12697     if(tng_general_info_block_write(tng_data, hash_mode)
12698        != TNG_SUCCESS)
12699     {
12700         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12701                 tng_data->input_file_path, __FILE__, __LINE__);
12702         return(TNG_CRITICAL);
12703     }
12704
12705     if(tng_molecules_block_write(tng_data, hash_mode)
12706         != TNG_SUCCESS)
12707     {
12708         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12709                 tng_data->input_file_path, __FILE__, __LINE__);
12710         return(TNG_CRITICAL);
12711     }
12712
12713     /* FIXME: Currently writing non-trajectory data blocks here.
12714      * Should perhaps be moved. */
12715     tng_block_init(&block);
12716     for(i = 0; i < tng_data->n_data_blocks; i++)
12717     {
12718         block->id = tng_data->non_tr_data[i].block_id;
12719         tng_data_block_write(tng_data, block,
12720                              i, hash_mode);
12721     }
12722
12723     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12724     {
12725         block->id = tng_data->non_tr_particle_data[i].block_id;
12726         tng_particle_data_block_write(tng_data, block,
12727                                       i, 0, hash_mode);
12728     }
12729
12730     tng_block_destroy(&block);
12731
12732     return(TNG_SUCCESS);
12733 }
12734
12735 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12736                                         tng_gen_block_t block,
12737                                         const char hash_mode)
12738 {
12739     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12740     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12741
12742     switch(block->id)
12743     {
12744     case TNG_TRAJECTORY_FRAME_SET:
12745         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12746     case TNG_PARTICLE_MAPPING:
12747         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12748     case TNG_GENERAL_INFO:
12749         return(tng_general_info_block_read(tng_data, block, hash_mode));
12750     case TNG_MOLECULES:
12751         return(tng_molecules_block_read(tng_data, block, hash_mode));
12752     default:
12753         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12754         {
12755             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12756         }
12757         else
12758         {
12759             /* Skip to the next block */
12760             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12761             return(TNG_FAILURE);
12762         }
12763     }
12764 }
12765
12766 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12767                 (tng_trajectory_t tng_data,
12768                  const char hash_mode)
12769 {
12770     long file_pos;
12771     tng_gen_block_t block;
12772     tng_function_status stat;
12773
12774     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12775
12776     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12777     {
12778         return(TNG_CRITICAL);
12779     }
12780
12781     file_pos = ftell(tng_data->input_file);
12782
12783     tng_block_init(&block);
12784
12785     if(!tng_data->input_file_len)
12786     {
12787         fseek(tng_data->input_file, 0, SEEK_END);
12788         tng_data->input_file_len = ftell(tng_data->input_file);
12789         fseek(tng_data->input_file, file_pos, SEEK_SET);
12790     }
12791
12792     /* Read block headers first to see what block is found. */
12793     stat = tng_block_header_read(tng_data, block);
12794     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12795        block->id == -1)
12796     {
12797         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12798                file_pos, __FILE__, __LINE__);
12799         tng_block_destroy(&block);
12800         return(TNG_CRITICAL);
12801     }
12802
12803     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12804
12805     if(tng_block_read_next(tng_data, block,
12806                            hash_mode) == TNG_SUCCESS)
12807     {
12808         tng_data->n_trajectory_frame_sets++;
12809         file_pos = ftell(tng_data->input_file);
12810         /* Read all blocks until next frame set block */
12811         stat = tng_block_header_read(tng_data, block);
12812         while(file_pos < tng_data->input_file_len &&
12813               stat != TNG_CRITICAL &&
12814               block->id != TNG_TRAJECTORY_FRAME_SET &&
12815               block->id != -1)
12816         {
12817             stat = tng_block_read_next(tng_data, block,
12818                                        hash_mode);
12819             if(stat != TNG_CRITICAL)
12820             {
12821                 file_pos = ftell(tng_data->input_file);
12822                 if(file_pos < tng_data->input_file_len)
12823                 {
12824                     stat = tng_block_header_read(tng_data, block);
12825                 }
12826             }
12827         }
12828         if(stat == TNG_CRITICAL)
12829         {
12830             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12831                    file_pos, __FILE__, __LINE__);
12832             tng_block_destroy(&block);
12833             return(stat);
12834         }
12835
12836         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12837         {
12838             fseek(tng_data->input_file, file_pos, SEEK_SET);
12839         }
12840     }
12841
12842     tng_block_destroy(&block);
12843
12844     return(TNG_SUCCESS);
12845 }
12846
12847
12848 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12849                 (tng_trajectory_t tng_data,
12850                  const char hash_mode,
12851                  const int64_t block_id)
12852 {
12853     long file_pos;
12854     tng_gen_block_t block;
12855     tng_function_status stat;
12856     int found_flag = 1;
12857
12858     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12859
12860     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12861     {
12862         return(TNG_CRITICAL);
12863     }
12864
12865     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12866
12867     if(file_pos < 0)
12868     {
12869         /* No current frame set. This means that the first frame set must be
12870          * read */
12871         found_flag = 0;
12872         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12873     }
12874
12875     if(file_pos > 0)
12876     {
12877         fseek(tng_data->input_file,
12878               file_pos,
12879               SEEK_SET);
12880     }
12881     else
12882     {
12883         return(TNG_FAILURE);
12884     }
12885
12886     tng_block_init(&block);
12887
12888     if(!tng_data->input_file_len)
12889     {
12890         fseek(tng_data->input_file, 0, SEEK_END);
12891         tng_data->input_file_len = ftell(tng_data->input_file);
12892         fseek(tng_data->input_file, file_pos, SEEK_SET);
12893     }
12894
12895     /* Read block headers first to see what block is found. */
12896     stat = tng_block_header_read(tng_data, block);
12897     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12898     {
12899         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12900                file_pos, __FILE__, __LINE__);
12901         tng_block_destroy(&block);
12902         return(TNG_CRITICAL);
12903     }
12904     /* If the current frame set had already been read skip its block contents */
12905     if(found_flag)
12906     {
12907         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12908     }
12909     /* Otherwiese read the frame set block */
12910     else
12911     {
12912         stat = tng_block_read_next(tng_data, block,
12913                                    hash_mode);
12914         if(stat != TNG_SUCCESS)
12915         {
12916             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12917             tng_block_destroy(&block);
12918             return(stat);
12919         }
12920     }
12921     file_pos = ftell(tng_data->input_file);
12922
12923     found_flag = 0;
12924
12925     /* Read only blocks of the requested ID
12926         * until next frame set block */
12927     stat = tng_block_header_read(tng_data, block);
12928     while(file_pos < tng_data->input_file_len &&
12929             stat != TNG_CRITICAL &&
12930             block->id != TNG_TRAJECTORY_FRAME_SET &&
12931             block->id != -1)
12932     {
12933         if(block->id == block_id)
12934         {
12935             stat = tng_block_read_next(tng_data, block,
12936                                        hash_mode);
12937             if(stat != TNG_CRITICAL)
12938             {
12939                 file_pos = ftell(tng_data->input_file);
12940                 found_flag = 1;
12941                 if(file_pos < tng_data->input_file_len)
12942                 {
12943                     stat = tng_block_header_read(tng_data, block);
12944                 }
12945             }
12946         }
12947         else
12948         {
12949             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12950             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12951             if(file_pos < tng_data->input_file_len)
12952             {
12953                 stat = tng_block_header_read(tng_data, block);
12954             }
12955         }
12956     }
12957     if(stat == TNG_CRITICAL)
12958     {
12959         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12960                 file_pos, __FILE__, __LINE__);
12961         tng_block_destroy(&block);
12962         return(stat);
12963     }
12964
12965     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12966     {
12967         fseek(tng_data->input_file, file_pos, SEEK_SET);
12968     }
12969
12970     tng_block_destroy(&block);
12971
12972     if(found_flag)
12973     {
12974         return(TNG_SUCCESS);
12975     }
12976     else
12977     {
12978         return(TNG_FAILURE);
12979     }
12980 }
12981
12982 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12983                 (tng_trajectory_t tng_data,
12984                  const char hash_mode)
12985 {
12986     long file_pos;
12987
12988     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12989
12990     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12991     {
12992         return(TNG_CRITICAL);
12993     }
12994
12995     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12996
12997     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12998     {
12999         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13000     }
13001
13002     if(file_pos > 0)
13003     {
13004         fseek(tng_data->input_file,
13005               file_pos,
13006               SEEK_SET);
13007     }
13008     else
13009     {
13010         return(TNG_FAILURE);
13011     }
13012
13013     return(tng_frame_set_read(tng_data, hash_mode));
13014 }
13015
13016 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
13017                 (tng_trajectory_t tng_data,
13018                  const char hash_mode,
13019                  const int64_t block_id)
13020 {
13021     long file_pos;
13022     tng_gen_block_t block;
13023     tng_function_status stat;
13024
13025     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13026
13027     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13028     {
13029         return(TNG_CRITICAL);
13030     }
13031
13032     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13033
13034     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13035     {
13036         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13037     }
13038
13039     if(file_pos > 0)
13040     {
13041         fseek(tng_data->input_file,
13042               file_pos,
13043               SEEK_SET);
13044     }
13045     else
13046     {
13047         return(TNG_FAILURE);
13048     }
13049
13050     tng_block_init(&block);
13051
13052     if(!tng_data->input_file_len)
13053     {
13054         fseek(tng_data->input_file, 0, SEEK_END);
13055         tng_data->input_file_len = ftell(tng_data->input_file);
13056         fseek(tng_data->input_file, file_pos, SEEK_SET);
13057     }
13058
13059     /* Read block headers first to see what block is found. */
13060     stat = tng_block_header_read(tng_data, block);
13061     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13062     {
13063         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13064                file_pos, __FILE__, __LINE__);
13065         tng_block_destroy(&block);
13066         return(TNG_CRITICAL);
13067     }
13068
13069     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13070
13071     if(tng_block_read_next(tng_data, block,
13072                            hash_mode) == TNG_SUCCESS)
13073     {
13074         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13075     }
13076
13077     tng_block_destroy(&block);
13078
13079     return(stat);
13080 }
13081
13082 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13083                                         const char hash_mode)
13084 {
13085     int i, j;
13086     tng_gen_block_t block;
13087     tng_trajectory_frame_set_t frame_set;
13088     tng_function_status stat;
13089
13090     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13091
13092     frame_set = &tng_data->current_trajectory_frame_set;
13093
13094     if(frame_set->n_written_frames == frame_set->n_frames)
13095     {
13096         return(TNG_SUCCESS);
13097     }
13098
13099     tng_data->current_trajectory_frame_set_output_file_pos =
13100     ftell(tng_data->output_file);
13101     tng_data->last_trajectory_frame_set_output_file_pos =
13102     tng_data->current_trajectory_frame_set_output_file_pos;
13103
13104     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13105     {
13106         return(TNG_FAILURE);
13107     }
13108
13109     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13110     {
13111         tng_data->first_trajectory_frame_set_output_file_pos =
13112         tng_data->current_trajectory_frame_set_output_file_pos;
13113     }
13114
13115     tng_block_init(&block);
13116
13117     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13118     {
13119         tng_block_destroy(&block);
13120         return(TNG_FAILURE);
13121     }
13122
13123     /* Write non-particle data blocks */
13124     for(i = 0; i<frame_set->n_data_blocks; i++)
13125     {
13126         block->id = frame_set->tr_data[i].block_id;
13127         tng_data_block_write(tng_data, block, i, hash_mode);
13128     }
13129     /* Write the mapping blocks and particle data blocks*/
13130     if(frame_set->n_mapping_blocks)
13131     {
13132         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13133         {
13134             block->id = TNG_PARTICLE_MAPPING;
13135             if(frame_set->mappings[i].n_particles > 0)
13136             {
13137                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13138                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13139                 {
13140                     block->id = frame_set->tr_particle_data[j].block_id;
13141                     tng_particle_data_block_write(tng_data, block,
13142                                                   j, &frame_set->mappings[i],
13143                                                   hash_mode);
13144                 }
13145             }
13146         }
13147     }
13148     else
13149     {
13150         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13151         {
13152             block->id = frame_set->tr_particle_data[i].block_id;
13153             tng_particle_data_block_write(tng_data, block,
13154                                           i, 0, hash_mode);
13155         }
13156     }
13157
13158
13159     /* Update pointers in the general info block */
13160     stat = tng_header_pointers_update(tng_data, hash_mode);
13161
13162     if(stat == TNG_SUCCESS)
13163     {
13164         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13165     }
13166
13167     tng_block_destroy(&block);
13168
13169     frame_set->n_unwritten_frames = 0;
13170
13171     fflush(tng_data->output_file);
13172
13173     return(stat);
13174 }
13175
13176 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13177                 (tng_trajectory_t tng_data,
13178                  const char hash_mode)
13179 {
13180     tng_trajectory_frame_set_t frame_set;
13181
13182     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13183
13184     frame_set = &tng_data->current_trajectory_frame_set;
13185
13186     if(frame_set->n_unwritten_frames == 0)
13187     {
13188         return(TNG_SUCCESS);
13189     }
13190     frame_set->n_frames = frame_set->n_unwritten_frames;
13191
13192     return(tng_frame_set_write(tng_data, hash_mode));
13193 }
13194
13195 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13196                 (tng_trajectory_t tng_data,
13197                  const int64_t first_frame,
13198                  const int64_t n_frames)
13199 {
13200     tng_gen_block_t block;
13201     tng_trajectory_frame_set_t frame_set;
13202     FILE *temp = tng_data->input_file;
13203     int64_t curr_pos;
13204
13205     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13206     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13207     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13208
13209     frame_set = &tng_data->current_trajectory_frame_set;
13210
13211     curr_pos = ftell(tng_data->output_file);
13212
13213     if(curr_pos <= 10)
13214     {
13215         tng_file_headers_write(tng_data, TNG_USE_HASH);
13216     }
13217
13218     /* Set pointer to previous frame set to the one that was loaded
13219      * before.
13220      * FIXME: This is a bit risky. If they are not added in order
13221      * it will be wrong. */
13222     if(tng_data->n_trajectory_frame_sets)
13223     {
13224         frame_set->prev_frame_set_file_pos =
13225         tng_data->current_trajectory_frame_set_output_file_pos;
13226     }
13227
13228     tng_data->current_trajectory_frame_set_output_file_pos =
13229     ftell(tng_data->output_file);
13230
13231     tng_data->n_trajectory_frame_sets++;
13232
13233     /* Set the medium range pointers */
13234     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13235     {
13236         frame_set->medium_stride_prev_frame_set_file_pos =
13237         tng_data->first_trajectory_frame_set_output_file_pos;
13238     }
13239     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13240     {
13241         /* FIXME: Currently only working if the previous frame set has its
13242          * medium stride pointer already set. This might need some fixing. */
13243         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13244            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13245         {
13246             tng_block_init(&block);
13247             tng_data->input_file = tng_data->output_file;
13248
13249             curr_pos = ftell(tng_data->output_file);
13250             fseek(tng_data->output_file,
13251                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
13252                   SEEK_SET);
13253
13254             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13255             {
13256                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13257                     __FILE__, __LINE__);
13258                 tng_data->input_file = temp;
13259                 tng_block_destroy(&block);
13260                 return(TNG_CRITICAL);
13261             }
13262
13263             /* Read the next frame set from the previous frame set and one
13264              * medium stride step back */
13265             fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13266             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13267             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13268                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13269                1, tng_data->output_file) == 0)
13270             {
13271                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13272                 tng_data->input_file = temp;
13273                 tng_block_destroy(&block);
13274                 return(TNG_CRITICAL);
13275             }
13276
13277             if(tng_data->input_endianness_swap_func_64)
13278             {
13279                 if(tng_data->input_endianness_swap_func_64(tng_data,
13280                    &frame_set->medium_stride_prev_frame_set_file_pos)
13281                     != TNG_SUCCESS)
13282                 {
13283                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13284                             __FILE__, __LINE__);
13285                 }
13286             }
13287
13288             tng_block_destroy(&block);
13289
13290             /* Set the long range pointers */
13291             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13292             {
13293                 frame_set->long_stride_prev_frame_set_file_pos =
13294                 tng_data->first_trajectory_frame_set_output_file_pos;
13295             }
13296             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13297             {
13298                 /* FIXME: Currently only working if the previous frame set has its
13299                 * long stride pointer already set. This might need some fixing. */
13300                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13301                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13302                 {
13303                     tng_block_init(&block);
13304                     tng_data->input_file = tng_data->output_file;
13305
13306                     fseek(tng_data->output_file,
13307                           (long)frame_set->long_stride_prev_frame_set_file_pos,
13308                           SEEK_SET);
13309
13310                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13311                     {
13312                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13313                             __FILE__, __LINE__);
13314                         tng_data->input_file = temp;
13315                         tng_block_destroy(&block);
13316                         return(TNG_CRITICAL);
13317                     }
13318
13319                     /* Read the next frame set from the previous frame set and one
13320                     * long stride step back */
13321                     fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13322                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13323
13324                     tng_block_destroy(&block);
13325
13326                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13327                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13328                     1, tng_data->output_file) == 0)
13329                     {
13330                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13331                         tng_data->input_file = temp;
13332                         return(TNG_CRITICAL);
13333                     }
13334
13335                     if(tng_data->input_endianness_swap_func_64)
13336                     {
13337                         if(tng_data->input_endianness_swap_func_64(tng_data,
13338                            &frame_set->long_stride_prev_frame_set_file_pos)
13339                             != TNG_SUCCESS)
13340                         {
13341                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13342                                     __FILE__, __LINE__);
13343                         }
13344                     }
13345
13346                 }
13347             }
13348
13349             tng_data->input_file = temp;
13350             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
13351         }
13352     }
13353
13354     frame_set->first_frame = first_frame;
13355     frame_set->n_frames = n_frames;
13356     frame_set->n_written_frames = 0;
13357     frame_set->n_unwritten_frames = 0;
13358     frame_set->first_frame_time = -1;
13359
13360     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13361        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13362     {
13363         tng_data->first_trajectory_frame_set_output_file_pos =
13364         tng_data->current_trajectory_frame_set_output_file_pos;
13365     }
13366     /* FIXME: Should check the frame number instead of the file_pos,
13367      * in case frame sets are not in order */
13368     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13369        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13370        tng_data->last_trajectory_frame_set_output_file_pos <
13371        tng_data->current_trajectory_frame_set_output_file_pos)
13372     {
13373         tng_data->last_trajectory_frame_set_output_file_pos =
13374         tng_data->current_trajectory_frame_set_output_file_pos;
13375     }
13376
13377     return(TNG_SUCCESS);
13378 }
13379
13380 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13381                 (tng_trajectory_t tng_data,
13382                  const int64_t first_frame,
13383                  const int64_t n_frames,
13384                  const double first_frame_time)
13385 {
13386     tng_function_status stat;
13387
13388     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13389     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13390     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13391     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13392
13393
13394     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13395     if(stat != TNG_SUCCESS)
13396     {
13397         return(stat);
13398     }
13399     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13400
13401     return(stat);
13402 }
13403
13404 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13405                 (tng_trajectory_t tng_data,
13406                  const double first_frame_time)
13407 {
13408     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13409     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13410
13411     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13412
13413     return(TNG_SUCCESS);
13414 }
13415
13416 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13417                 (const tng_trajectory_t tng_data,
13418                  int64_t *frame)
13419 {
13420     long file_pos, next_frame_set_file_pos;
13421     tng_gen_block_t block;
13422     tng_function_status stat;
13423
13424     tng_trajectory_frame_set_t frame_set;
13425
13426     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13427     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13428     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13429
13430     file_pos = ftell(tng_data->input_file);
13431
13432     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13433     {
13434         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13435     }
13436     else
13437     {
13438         frame_set = &tng_data->current_trajectory_frame_set;
13439         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
13440     }
13441
13442     if(next_frame_set_file_pos <= 0)
13443     {
13444         return(TNG_FAILURE);
13445     }
13446
13447     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
13448     /* Read block headers first to see that a frame set block is found. */
13449     tng_block_init(&block);
13450     stat = tng_block_header_read(tng_data, block);
13451     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13452     {
13453         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13454                file_pos, __FILE__, __LINE__);
13455         return(TNG_CRITICAL);
13456     }
13457 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13458     {
13459         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13460     }*/
13461     tng_block_destroy(&block);
13462
13463     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13464     {
13465         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13466                __FILE__, __LINE__);
13467         return(TNG_CRITICAL);
13468     }
13469     fseek(tng_data->input_file, file_pos, SEEK_SET);
13470
13471     return(TNG_SUCCESS);
13472 }
13473
13474 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13475                 (tng_trajectory_t tng_data,
13476                  const int64_t id,
13477                  const char *block_name,
13478                  const char datatype,
13479                  const char block_type_flag,
13480                  int64_t n_frames,
13481                  const int64_t n_values_per_frame,
13482                  int64_t stride_length,
13483                  const int64_t codec_id,
13484                  void *new_data)
13485 {
13486     int i, j, size, len;
13487     tng_trajectory_frame_set_t frame_set;
13488     tng_non_particle_data_t data;
13489     char **first_dim_values;
13490     char *new_data_c=new_data;
13491     int64_t n_frames_div;
13492
13493     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13494     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13495     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13496
13497     frame_set = &tng_data->current_trajectory_frame_set;
13498
13499     if(stride_length <= 0)
13500     {
13501         stride_length = 1;
13502     }
13503
13504     /* If the block does not exist, create it */
13505     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13506     {
13507         if(tng_data_block_create(tng_data, block_type_flag) !=
13508             TNG_SUCCESS)
13509         {
13510             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13511                    __FILE__, __LINE__);
13512             return(TNG_CRITICAL);
13513         }
13514         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13515         {
13516             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13517         }
13518         else
13519         {
13520             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13521         }
13522         data->block_id = id;
13523
13524         data->block_name = malloc(strlen(block_name) + 1);
13525         if(!data->block_name)
13526         {
13527             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13528                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13529             return(TNG_CRITICAL);
13530         }
13531         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13532
13533         data->values = 0;
13534         /* FIXME: Memory leak from strings. */
13535         data->strings = 0;
13536         data->last_retrieved_frame = -1;
13537     }
13538
13539     data->datatype = datatype;
13540     data->stride_length = tng_max_i64(stride_length, 1);
13541     data->n_values_per_frame = n_values_per_frame;
13542     data->n_frames = n_frames;
13543     data->codec_id = codec_id;
13544     data->compression_multiplier = 1.0;
13545     /* FIXME: This can cause problems. */
13546     data->first_frame_with_data = frame_set->first_frame;
13547
13548     switch(datatype)
13549     {
13550     case TNG_FLOAT_DATA:
13551         size = sizeof(float);
13552         break;
13553     case TNG_INT_DATA:
13554         size = sizeof(int64_t);
13555         break;
13556     case TNG_DOUBLE_DATA:
13557     default:
13558         size = sizeof(double);
13559         break;
13560     }
13561
13562     if(new_data_c)
13563     {
13564         /* Allocate memory */
13565         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13566                                  n_values_per_frame) !=
13567         TNG_SUCCESS)
13568         {
13569             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13570                 __FILE__, __LINE__);
13571             return(TNG_CRITICAL);
13572         }
13573
13574         if(n_frames > frame_set->n_unwritten_frames)
13575         {
13576             frame_set->n_unwritten_frames = n_frames;
13577         }
13578
13579         n_frames_div = (n_frames % stride_length) ?
13580                      n_frames / stride_length + 1:
13581                      n_frames / stride_length;
13582
13583         if(datatype == TNG_CHAR_DATA)
13584         {
13585             for(i = 0; i < n_frames_div; i++)
13586             {
13587                 first_dim_values = data->strings[i];
13588                 for(j = 0; j < n_values_per_frame; j++)
13589                 {
13590                     len = tng_min_i((int)strlen(new_data_c) + 1,
13591                                 TNG_MAX_STR_LEN);
13592                     if(first_dim_values[j])
13593                     {
13594                         free(first_dim_values[j]);
13595                     }
13596                     first_dim_values[j] = malloc(len);
13597                     if(!first_dim_values[j])
13598                     {
13599                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13600                             len, __FILE__, __LINE__);
13601                         return(TNG_CRITICAL);
13602                     }
13603                     strncpy(first_dim_values[j],
13604                             new_data_c, len);
13605                     new_data_c += len;
13606                 }
13607             }
13608         }
13609         else
13610         {
13611             memcpy(data->values, new_data, size * n_frames_div *
13612                    n_values_per_frame);
13613         }
13614     }
13615
13616     return(TNG_SUCCESS);
13617 }
13618
13619 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13620                 (tng_trajectory_t tng_data,
13621                  const int64_t id,
13622                  const char *block_name,
13623                  const char datatype,
13624                  const char block_type_flag,
13625                  int64_t n_frames,
13626                  const int64_t n_values_per_frame,
13627                  int64_t stride_length,
13628                  const int64_t num_first_particle,
13629                  const int64_t n_particles,
13630                  const int64_t codec_id,
13631                  void *new_data)
13632 {
13633     int i, size, len;
13634     int64_t j, k;
13635     int64_t tot_n_particles, n_frames_div;
13636     char ***first_dim_values, **second_dim_values;
13637     tng_trajectory_frame_set_t frame_set;
13638     tng_particle_data_t data;
13639     char *new_data_c=new_data;
13640
13641     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13642     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13643     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13644     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13645     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13646
13647
13648     frame_set = &tng_data->current_trajectory_frame_set;
13649
13650     if(stride_length <= 0)
13651     {
13652         stride_length = 1;
13653     }
13654
13655     /* If the block does not exist, create it */
13656     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13657     {
13658         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13659             TNG_SUCCESS)
13660         {
13661             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13662                    __FILE__, __LINE__);
13663             return(TNG_CRITICAL);
13664         }
13665         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13666         {
13667             data = &frame_set->tr_particle_data[frame_set->
13668                                                 n_particle_data_blocks - 1];
13669         }
13670         else
13671         {
13672             data = &tng_data->non_tr_particle_data[tng_data->
13673                                                    n_particle_data_blocks - 1];
13674         }
13675         data->block_id = id;
13676
13677         data->block_name = malloc(strlen(block_name) + 1);
13678         if(!data->block_name)
13679         {
13680             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13681                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13682             return(TNG_CRITICAL);
13683         }
13684         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13685
13686         data->datatype = datatype;
13687
13688         data->values = 0;
13689         /* FIXME: Memory leak from strings. */
13690         data->strings = 0;
13691         data->last_retrieved_frame = -1;
13692     }
13693
13694     data->stride_length = tng_max_i64(stride_length, 1);
13695     data->n_values_per_frame = n_values_per_frame;
13696     data->n_frames = n_frames;
13697     data->codec_id = codec_id;
13698     data->compression_multiplier = 1.0;
13699     /* FIXME: This can cause problems. */
13700     data->first_frame_with_data = frame_set->first_frame;
13701
13702     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13703     {
13704         tot_n_particles = frame_set->n_particles;
13705     }
13706     else
13707     {
13708         tot_n_particles = tng_data->n_particles;
13709     }
13710
13711     /* If data values are supplied add that data to the data block. */
13712     if(new_data_c)
13713     {
13714         /* Allocate memory */
13715         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13716                                           stride_length, tot_n_particles,
13717                                           n_values_per_frame) !=
13718         TNG_SUCCESS)
13719         {
13720             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13721                 __FILE__, __LINE__);
13722             return(TNG_CRITICAL);
13723         }
13724
13725         if(n_frames > frame_set->n_unwritten_frames)
13726         {
13727             frame_set->n_unwritten_frames = n_frames;
13728         }
13729
13730         n_frames_div = (n_frames % stride_length) ?
13731                      n_frames / stride_length + 1:
13732                      n_frames / stride_length;
13733
13734         if(datatype == TNG_CHAR_DATA)
13735         {
13736             for(i = 0; i < n_frames_div; i++)
13737             {
13738                 first_dim_values = data->strings[i];
13739                 for(j = num_first_particle; j < num_first_particle + n_particles;
13740                     j++)
13741                 {
13742                     second_dim_values = first_dim_values[j];
13743                     for(k = 0; k < n_values_per_frame; k++)
13744                     {
13745                         len = tng_min_i((int)strlen(new_data_c) + 1,
13746                                 TNG_MAX_STR_LEN);
13747                         if(second_dim_values[k])
13748                         {
13749                             free(second_dim_values[k]);
13750                         }
13751                         second_dim_values[k] = malloc(len);
13752                         if(!second_dim_values[k])
13753                         {
13754                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13755                                 len, __FILE__, __LINE__);
13756                             return(TNG_CRITICAL);
13757                         }
13758                         strncpy(second_dim_values[k],
13759                                 new_data_c, len);
13760                         new_data_c += len;
13761                     }
13762                 }
13763             }
13764         }
13765         else
13766         {
13767             switch(datatype)
13768             {
13769             case TNG_INT_DATA:
13770                 size = sizeof(int64_t);
13771                 break;
13772             case TNG_FLOAT_DATA:
13773                 size = sizeof(float);
13774                 break;
13775             case TNG_DOUBLE_DATA:
13776             default:
13777                 size = sizeof(double);
13778             }
13779
13780             memcpy(data->values, new_data, size * n_frames_div *
13781                    n_particles * n_values_per_frame);
13782         }
13783     }
13784
13785     return(TNG_SUCCESS);
13786 }
13787
13788 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13789                 (tng_trajectory_t tng_data,
13790                  int64_t block_id,
13791                  char *name,
13792                  int max_len)
13793 {
13794     int64_t i;
13795     tng_trajectory_frame_set_t frame_set;
13796     tng_function_status stat;
13797     tng_particle_data_t p_data;
13798     tng_non_particle_data_t np_data;
13799     int block_type = -1;
13800
13801     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13802     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13803
13804     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13805     {
13806         p_data = &tng_data->non_tr_particle_data[i];
13807         if(p_data->block_id == block_id)
13808         {
13809             strncpy(name, p_data->block_name, max_len);
13810             name[max_len - 1] = '\0';
13811             return(TNG_SUCCESS);
13812         }
13813     }
13814     for(i = 0; i < tng_data->n_data_blocks; i++)
13815     {
13816         np_data = &tng_data->non_tr_data[i];
13817         if(np_data->block_id == block_id)
13818         {
13819             strncpy(name, np_data->block_name, max_len);
13820             name[max_len - 1] = '\0';
13821             return(TNG_SUCCESS);
13822         }
13823     }
13824
13825     frame_set = &tng_data->current_trajectory_frame_set;
13826
13827     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13828     if(stat == TNG_SUCCESS)
13829     {
13830         block_type = TNG_PARTICLE_BLOCK_DATA;
13831     }
13832     else
13833     {
13834         stat = tng_data_find(tng_data, block_id, &np_data);
13835         if(stat == TNG_SUCCESS)
13836         {
13837             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13838         }
13839         else
13840         {
13841             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13842             if(stat != TNG_SUCCESS)
13843             {
13844                 return(stat);
13845             }
13846             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13847             if(stat == TNG_SUCCESS)
13848             {
13849                 block_type = TNG_PARTICLE_BLOCK_DATA;
13850             }
13851             else
13852             {
13853                 stat = tng_data_find(tng_data, block_id, &np_data);
13854                 if(stat == TNG_SUCCESS)
13855                 {
13856                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13857                 }
13858             }
13859         }
13860     }
13861     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13862     {
13863         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13864         {
13865             p_data = &frame_set->tr_particle_data[i];
13866             if(p_data->block_id == block_id)
13867             {
13868                 strncpy(name, p_data->block_name, max_len);
13869                 name[max_len - 1] = '\0';
13870                 return(TNG_SUCCESS);
13871             }
13872         }
13873     }
13874     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13875     {
13876         for(i = 0; i < frame_set->n_data_blocks; i++)
13877         {
13878             np_data = &frame_set->tr_data[i];
13879             if(np_data->block_id == block_id)
13880             {
13881                 strncpy(name, np_data->block_name, max_len);
13882                 name[max_len - 1] = '\0';
13883                 return(TNG_SUCCESS);
13884             }
13885         }
13886     }
13887
13888     return(TNG_FAILURE);
13889 }
13890
13891 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13892                 (const tng_trajectory_t tng_data,
13893                  int64_t block_id,
13894                  int *block_dependency)
13895 {
13896     int64_t i;
13897     tng_function_status stat;
13898     tng_particle_data_t p_data;
13899     tng_non_particle_data_t np_data;
13900
13901     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13902     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13903
13904     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13905     {
13906         p_data = &tng_data->non_tr_particle_data[i];
13907         if(p_data->block_id == block_id)
13908         {
13909             *block_dependency = TNG_PARTICLE_DEPENDENT;
13910             return(TNG_SUCCESS);
13911         }
13912     }
13913     for(i = 0; i < tng_data->n_data_blocks; i++)
13914     {
13915         np_data = &tng_data->non_tr_data[i];
13916         if(np_data->block_id == block_id)
13917         {
13918             *block_dependency = 0;
13919             return(TNG_SUCCESS);
13920         }
13921     }
13922
13923     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13924     if(stat == TNG_SUCCESS)
13925     {
13926         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13927         return(TNG_SUCCESS);
13928     }
13929     else
13930     {
13931         stat = tng_data_find(tng_data, block_id, &np_data);
13932         if(stat == TNG_SUCCESS)
13933         {
13934             *block_dependency = TNG_FRAME_DEPENDENT;
13935             return(TNG_SUCCESS);
13936         }
13937         else
13938         {
13939             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13940             if(stat != TNG_SUCCESS)
13941             {
13942                 return(stat);
13943             }
13944             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13945             if(stat == TNG_SUCCESS)
13946             {
13947                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13948                 return(TNG_SUCCESS);
13949             }
13950             else
13951             {
13952                 stat = tng_data_find(tng_data, block_id, &np_data);
13953                 if(stat == TNG_SUCCESS)
13954                 {
13955                     *block_dependency = TNG_FRAME_DEPENDENT;
13956                     return(TNG_SUCCESS);
13957                 }
13958             }
13959         }
13960     }
13961
13962     return(TNG_FAILURE);
13963 }
13964
13965 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13966                 (const tng_trajectory_t tng_data,
13967                  int64_t block_id,
13968                  int64_t *n_values_per_frame)
13969 {
13970     int64_t i;
13971     tng_function_status stat;
13972     tng_particle_data_t p_data;
13973     tng_non_particle_data_t np_data;
13974
13975     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13976     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13977
13978     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13979     {
13980         p_data = &tng_data->non_tr_particle_data[i];
13981         if(p_data->block_id == block_id)
13982         {
13983             *n_values_per_frame = p_data->n_values_per_frame;
13984             return(TNG_SUCCESS);
13985         }
13986     }
13987     for(i = 0; i < tng_data->n_data_blocks; i++)
13988     {
13989         np_data = &tng_data->non_tr_data[i];
13990         if(np_data->block_id == block_id)
13991         {
13992             *n_values_per_frame = np_data->n_values_per_frame;
13993             return(TNG_SUCCESS);
13994         }
13995     }
13996
13997     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13998     if(stat == TNG_SUCCESS)
13999     {
14000         *n_values_per_frame = p_data->n_values_per_frame;
14001         return(TNG_SUCCESS);
14002     }
14003     else
14004     {
14005         stat = tng_data_find(tng_data, block_id, &np_data);
14006         if(stat == TNG_SUCCESS)
14007         {
14008             *n_values_per_frame = np_data->n_values_per_frame;
14009             return(TNG_SUCCESS);
14010         }
14011         else
14012         {
14013             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14014             if(stat != TNG_SUCCESS)
14015             {
14016                 return(stat);
14017             }
14018             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14019             if(stat == TNG_SUCCESS)
14020             {
14021                 *n_values_per_frame = p_data->n_values_per_frame;
14022                 return(TNG_SUCCESS);
14023             }
14024             else
14025             {
14026                 stat = tng_data_find(tng_data, block_id, &np_data);
14027                 if(stat == TNG_SUCCESS)
14028                 {
14029                     *n_values_per_frame = np_data->n_values_per_frame;
14030                     return(TNG_SUCCESS);
14031                 }
14032             }
14033         }
14034     }
14035
14036     return(TNG_FAILURE);
14037 }
14038
14039 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
14040                 (tng_trajectory_t tng_data,
14041                  const int64_t frame_nr,
14042                  const int64_t block_id,
14043                  const void *values,
14044                  const char hash_mode)
14045 {
14046     int64_t header_pos, file_pos;
14047     int64_t output_file_len, n_values_per_frame, size, contents_size;
14048     int64_t header_size, temp_first, temp_last;
14049     int64_t i, last_frame;
14050     long temp_current;
14051     tng_gen_block_t block;
14052     tng_trajectory_frame_set_t frame_set;
14053     FILE *temp = tng_data->input_file;
14054     struct tng_non_particle_data data;
14055     tng_function_status stat;
14056     char dependency, sparse_data, datatype;
14057     void *copy;
14058
14059     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14060     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14061     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14062
14063     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14064     {
14065         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14066                __FILE__, __LINE__);
14067         return(TNG_CRITICAL);
14068     }
14069
14070     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14071     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14072     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14073     tng_data->first_trajectory_frame_set_input_file_pos =
14074     tng_data->first_trajectory_frame_set_output_file_pos;
14075     tng_data->last_trajectory_frame_set_input_file_pos =
14076     tng_data->last_trajectory_frame_set_output_file_pos;
14077     tng_data->current_trajectory_frame_set_input_file_pos =
14078     tng_data->current_trajectory_frame_set_output_file_pos;
14079
14080     tng_data->input_file = tng_data->output_file;
14081
14082     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14083
14084     frame_set = &tng_data->current_trajectory_frame_set;
14085
14086     if(stat != TNG_SUCCESS)
14087     {
14088         last_frame = frame_set->first_frame +
14089                      frame_set->n_frames - 1;
14090         /* If the wanted frame would be in the frame set after the last
14091             * frame set create a new frame set. */
14092         if(stat == TNG_FAILURE &&
14093             last_frame < frame_nr)
14094 /*           (last_frame < frame_nr &&
14095             tng_data->current_trajectory_frame_set.first_frame +
14096             tng_data->frame_set_n_frames >= frame_nr))*/
14097         {
14098             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14099             {
14100                 last_frame = frame_nr - 1;
14101             }
14102             tng_frame_set_new(tng_data,
14103                               last_frame+1,
14104                               tng_data->frame_set_n_frames);
14105             file_pos = ftell(tng_data->output_file);
14106             fseek(tng_data->output_file, 0, SEEK_END);
14107             output_file_len = ftell(tng_data->output_file);
14108             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14109
14110             /* Read mapping blocks from the last frame set */
14111             tng_block_init(&block);
14112
14113             stat = tng_block_header_read(tng_data, block);
14114             while(file_pos < output_file_len &&
14115                   stat != TNG_CRITICAL &&
14116                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14117                   block->id != -1)
14118             {
14119                 if(block->id == TNG_PARTICLE_MAPPING)
14120                 {
14121                     tng_trajectory_mapping_block_read(tng_data, block,
14122                                                       hash_mode);
14123                 }
14124                 else
14125                 {
14126                     fseek(tng_data->output_file, (long)block->block_contents_size,
14127                         SEEK_CUR);
14128                 }
14129                 file_pos = ftell(tng_data->output_file);
14130                 if(file_pos < output_file_len)
14131                 {
14132                     stat = tng_block_header_read(tng_data, block);
14133                 }
14134             }
14135
14136             tng_block_destroy(&block);
14137             /* Write the frame set to disk */
14138             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14139             {
14140                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14141                 return(TNG_CRITICAL);
14142             }
14143         }
14144         else
14145         {
14146             tng_data->input_file = temp;
14147             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14148             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14149             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14150             return(stat);
14151         }
14152     }
14153
14154     tng_block_init(&block);
14155
14156     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14157
14158     fseek(tng_data->output_file, 0, SEEK_END);
14159     output_file_len = ftell(tng_data->output_file);
14160     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14161
14162     /* Read past the frame set block first */
14163     stat = tng_block_header_read(tng_data, block);
14164     if(stat == TNG_CRITICAL)
14165     {
14166         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14167                file_pos, __FILE__, __LINE__);
14168         tng_block_destroy(&block);
14169         tng_data->input_file = temp;
14170
14171         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14172         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14173         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14174         return(stat);
14175     }
14176     fseek(tng_data->output_file, (long)block->block_contents_size,
14177             SEEK_CUR);
14178
14179     /* Read all block headers until next frame set block or
14180      * until the wanted block id is found */
14181     stat = tng_block_header_read(tng_data, block);
14182     while(file_pos < output_file_len &&
14183             stat != TNG_CRITICAL &&
14184             block->id != block_id &&
14185             block->id != TNG_TRAJECTORY_FRAME_SET &&
14186             block->id != -1)
14187     {
14188         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14189         file_pos = ftell(tng_data->output_file);
14190         if(file_pos < output_file_len)
14191         {
14192             stat = tng_block_header_read(tng_data, block);
14193         }
14194     }
14195     if(stat == TNG_CRITICAL)
14196     {
14197         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14198                file_pos, __FILE__, __LINE__);
14199         tng_block_destroy(&block);
14200         tng_data->input_file = temp;
14201         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14202         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14203         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14204         return(stat);
14205     }
14206
14207     contents_size = block->block_contents_size;
14208     header_size = block->header_contents_size;
14209
14210     header_pos = ftell(tng_data->output_file) - header_size;
14211     frame_set = &tng_data->current_trajectory_frame_set;
14212
14213     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14214     {
14215         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14216         tng_block_destroy(&block);
14217         return(TNG_CRITICAL);
14218     }
14219     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14220     {
14221         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14222         tng_block_destroy(&block);
14223         return(TNG_CRITICAL);
14224     }
14225     data.datatype = datatype;
14226
14227     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14228        (dependency & TNG_PARTICLE_DEPENDENT))
14229     {
14230         tng_block_destroy(&block);
14231         tng_data->input_file = temp;
14232
14233         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14234         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14235         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14236         return(TNG_FAILURE);
14237     }
14238
14239     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14240     {
14241         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14242         tng_block_destroy(&block);
14243         return(TNG_CRITICAL);
14244     }
14245
14246     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14247              tng_data->input_file) == 0)
14248     {
14249         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14250         tng_block_destroy(&block);
14251         return(TNG_CRITICAL);
14252     }
14253     if(tng_data->output_endianness_swap_func_64)
14254     {
14255         if(tng_data->output_endianness_swap_func_64(tng_data,
14256             &data.n_values_per_frame)
14257             != TNG_SUCCESS)
14258         {
14259             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14260                     __FILE__, __LINE__);
14261         }
14262     }
14263
14264     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14265              tng_data->input_file) == 0)
14266     {
14267         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14268         tng_block_destroy(&block);
14269         return(TNG_CRITICAL);
14270     }
14271     if(tng_data->output_endianness_swap_func_64)
14272     {
14273         if(tng_data->output_endianness_swap_func_64(tng_data,
14274             &data.codec_id)
14275             != TNG_SUCCESS)
14276         {
14277             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14278                     __FILE__, __LINE__);
14279         }
14280     }
14281
14282     if(data.codec_id != TNG_UNCOMPRESSED)
14283     {
14284         if(fread(&data.compression_multiplier,
14285                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14286             == 0)
14287         {
14288             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14289             tng_block_destroy(&block);
14290             return(TNG_CRITICAL);
14291         }
14292         if(tng_data->output_endianness_swap_func_64)
14293         {
14294             if(tng_data->output_endianness_swap_func_64(tng_data,
14295                 (int64_t *)&data.compression_multiplier)
14296                 != TNG_SUCCESS)
14297             {
14298                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14299                         __FILE__, __LINE__);
14300             }
14301         }
14302     }
14303     else
14304     {
14305         data.compression_multiplier = 1;
14306     }
14307
14308     if(sparse_data)
14309     {
14310         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14311                  1, tng_data->input_file) == 0)
14312         {
14313             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14314             tng_block_destroy(&block);
14315             return(TNG_CRITICAL);
14316         }
14317         if(tng_data->output_endianness_swap_func_64)
14318         {
14319             if(tng_data->output_endianness_swap_func_64(tng_data,
14320                 &data.first_frame_with_data)
14321                 != TNG_SUCCESS)
14322             {
14323                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14324                         __FILE__, __LINE__);
14325             }
14326         }
14327
14328         if(fread(&data.stride_length, sizeof(data.stride_length),
14329                  1, tng_data->input_file) == 0)
14330         {
14331             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14332             tng_block_destroy(&block);
14333             return(TNG_CRITICAL);
14334         }
14335         if(tng_data->output_endianness_swap_func_64)
14336         {
14337             if(tng_data->output_endianness_swap_func_64(tng_data,
14338                 &data.stride_length)
14339                 != TNG_SUCCESS)
14340             {
14341                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14342                         __FILE__, __LINE__);
14343             }
14344         }
14345     }
14346     else
14347     {
14348         data.first_frame_with_data = 0;
14349         data.stride_length = 1;
14350     }
14351     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14352
14353     tng_data->input_file = temp;
14354
14355     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14356     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14357     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14358
14359     switch(data.datatype)
14360     {
14361         case(TNG_INT_DATA):
14362             size = sizeof(int64_t);
14363             break;
14364         case(TNG_FLOAT_DATA):
14365             size = sizeof(float);
14366             break;
14367         case(TNG_DOUBLE_DATA):
14368             size = sizeof(double);
14369             break;
14370         default:
14371             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14372                    __LINE__);
14373             tng_block_destroy(&block);
14374             return(TNG_FAILURE);
14375     }
14376
14377     n_values_per_frame = data.n_values_per_frame;
14378
14379     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14380                                data.first_frame_with_data)) /
14381                 data.stride_length;
14382     file_pos *= size * n_values_per_frame;
14383
14384     if(file_pos > contents_size)
14385     {
14386         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14387                __LINE__);
14388         tng_block_destroy(&block);
14389         return(TNG_FAILURE);
14390     }
14391
14392     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14393
14394     /* If the endianness is not big endian the data needs to be swapped */
14395     if((data.datatype == TNG_INT_DATA ||
14396         data.datatype == TNG_DOUBLE_DATA) &&
14397        tng_data->output_endianness_swap_func_64)
14398     {
14399         copy = malloc(n_values_per_frame * size);
14400         memcpy(copy, values, n_values_per_frame * size);
14401         for(i = 0; i < n_values_per_frame; i++)
14402         {
14403             if(tng_data->output_endianness_swap_func_64(tng_data,
14404                 (int64_t *)copy+i)
14405                 != TNG_SUCCESS)
14406             {
14407                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14408                         __FILE__, __LINE__);
14409             }
14410         }
14411         fwrite(copy, n_values_per_frame, size,
14412                tng_data->output_file);
14413         free(copy);
14414     }
14415     else if(data.datatype == TNG_FLOAT_DATA &&
14416             tng_data->output_endianness_swap_func_32)
14417     {
14418         copy = malloc(n_values_per_frame * size);
14419         memcpy(copy, values, n_values_per_frame * size);
14420         for(i = 0; i < n_values_per_frame; i++)
14421         {
14422             if(tng_data->output_endianness_swap_func_32(tng_data,
14423                 (int32_t *)copy+i)
14424                 != TNG_SUCCESS)
14425             {
14426                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14427                         __FILE__, __LINE__);
14428             }
14429         }
14430         fwrite(copy, n_values_per_frame, size,
14431                tng_data->output_file);
14432         free(copy);
14433     }
14434
14435     else
14436     {
14437         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14438     }
14439
14440     fflush(tng_data->output_file);
14441
14442     /* Update the number of written frames in the frame set. */
14443     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14444     {
14445         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14446     }
14447
14448     /* If the last frame has been written update the hash */
14449     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14450        data.first_frame_with_data) >=
14451        frame_set->n_frames)
14452     {
14453         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14454                             header_size);
14455     }
14456
14457     tng_block_destroy(&block);
14458
14459     return(TNG_SUCCESS);
14460 }
14461
14462 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14463                 (tng_trajectory_t tng_data,
14464                  const int64_t frame_nr,
14465                  const int64_t block_id,
14466                  const int64_t val_first_particle,
14467                  const int64_t val_n_particles,
14468                  const void *values,
14469                  const char hash_mode)
14470 {
14471     int64_t header_pos, file_pos, tot_n_particles;
14472     int64_t output_file_len, n_values_per_frame, size, contents_size;
14473     int64_t header_size, temp_first, temp_last;
14474     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14475     int64_t i, last_frame;
14476     long temp_current;
14477     tng_gen_block_t block;
14478     tng_trajectory_frame_set_t frame_set;
14479     FILE *temp = tng_data->input_file;
14480     struct tng_particle_data data;
14481     tng_function_status stat;
14482     tng_particle_mapping_t mapping;
14483     char dependency, sparse_data, datatype;
14484     void *copy;
14485
14486     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14487     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14488     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14489     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14490     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14491
14492     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14493     {
14494         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14495                __FILE__, __LINE__);
14496         return(TNG_CRITICAL);
14497     }
14498
14499     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14500     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14501     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14502     tng_data->first_trajectory_frame_set_input_file_pos =
14503     tng_data->first_trajectory_frame_set_output_file_pos;
14504     tng_data->last_trajectory_frame_set_input_file_pos =
14505     tng_data->last_trajectory_frame_set_output_file_pos;
14506     tng_data->current_trajectory_frame_set_input_file_pos =
14507     tng_data->current_trajectory_frame_set_output_file_pos;
14508
14509     tng_data->input_file = tng_data->output_file;
14510
14511     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14512
14513     frame_set = &tng_data->current_trajectory_frame_set;
14514
14515     if(stat != TNG_SUCCESS)
14516     {
14517         last_frame = frame_set->first_frame +
14518                      frame_set->n_frames - 1;
14519 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14520                   last_frame); */
14521         /* If the wanted frame would be in the frame set after the last
14522          * frame set create a new frame set. */
14523         if(stat == TNG_FAILURE &&
14524            (last_frame < frame_nr &&
14525             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14526         {
14527             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14528             {
14529                 last_frame = frame_nr - 1;
14530             }
14531             tng_frame_set_new(tng_data,
14532                               last_frame+1,
14533                               tng_data->frame_set_n_frames);
14534
14535             file_pos = ftell(tng_data->output_file);
14536             fseek(tng_data->output_file, 0, SEEK_END);
14537             output_file_len = ftell(tng_data->output_file);
14538             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14539
14540             /* Read mapping blocks from the last frame set */
14541             tng_block_init(&block);
14542
14543             stat = tng_block_header_read(tng_data, block);
14544             while(file_pos < output_file_len &&
14545                   stat != TNG_CRITICAL &&
14546                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14547                   block->id != -1)
14548             {
14549                 if(block->id == TNG_PARTICLE_MAPPING)
14550                 {
14551                     tng_trajectory_mapping_block_read(tng_data, block,
14552                                                       hash_mode);
14553                 }
14554                 else
14555                 {
14556                     fseek(tng_data->output_file, (long)block->block_contents_size,
14557                         SEEK_CUR);
14558                 }
14559                 file_pos = ftell(tng_data->output_file);
14560                 if(file_pos < output_file_len)
14561                 {
14562                     stat = tng_block_header_read(tng_data, block);
14563                 }
14564             }
14565
14566             tng_block_destroy(&block);
14567             /* Write the frame set to disk */
14568             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14569             {
14570                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14571                 exit(1);
14572             }
14573         }
14574         else
14575         {
14576             tng_data->input_file = temp;
14577             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14578             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14579             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14580             return(stat);
14581         }
14582     }
14583
14584
14585     tng_block_init(&block);
14586
14587     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14588
14589     fseek(tng_data->output_file, 0, SEEK_END);
14590     output_file_len = ftell(tng_data->output_file);
14591     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14592
14593     /* Read past the frame set block first */
14594     stat = tng_block_header_read(tng_data, block);
14595     if(stat == TNG_CRITICAL)
14596     {
14597         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14598                file_pos, __FILE__, __LINE__);
14599         tng_block_destroy(&block);
14600         tng_data->input_file = temp;
14601
14602         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14603         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14604         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14605         return(stat);
14606     }
14607     fseek(tng_data->output_file, (long)block->block_contents_size,
14608             SEEK_CUR);
14609
14610     if(tng_data->var_num_atoms_flag)
14611     {
14612         tot_n_particles = frame_set->n_particles;
14613     }
14614     else
14615     {
14616         tot_n_particles = tng_data->n_particles;
14617     }
14618
14619     if(val_n_particles < tot_n_particles)
14620     {
14621         mapping_block_end_pos = -1;
14622         /* Read all mapping blocks to find the right place to put the data */
14623         stat = tng_block_header_read(tng_data, block);
14624         while(file_pos < output_file_len &&
14625                 stat != TNG_CRITICAL &&
14626                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14627                 block->id != -1)
14628         {
14629             if(block->id == TNG_PARTICLE_MAPPING)
14630             {
14631                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14632             }
14633             else
14634             {
14635                 fseek(tng_data->output_file, (long)block->block_contents_size,
14636                       SEEK_CUR);
14637             }
14638             file_pos = ftell(tng_data->output_file);
14639             if(block->id == TNG_PARTICLE_MAPPING)
14640             {
14641                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14642                 if(val_first_particle >= mapping->num_first_particle &&
14643                    val_first_particle < mapping->num_first_particle +
14644                    mapping->n_particles &&
14645                    val_first_particle + val_n_particles <=
14646                    mapping->num_first_particle + mapping->n_particles)
14647                 {
14648                     mapping_block_end_pos = file_pos;
14649                 }
14650             }
14651             if(file_pos < output_file_len)
14652             {
14653                 stat = tng_block_header_read(tng_data, block);
14654             }
14655         }
14656         if(stat == TNG_CRITICAL)
14657         {
14658             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14659                    file_pos, __FILE__, __LINE__);
14660             tng_block_destroy(&block);
14661             tng_data->input_file = temp;
14662
14663             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14664             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14665             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14666             return(stat);
14667         }
14668         if(mapping_block_end_pos < 0)
14669         {
14670             tng_block_destroy(&block);
14671             tng_data->input_file = temp;
14672
14673             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14674             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14675             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14676             return(TNG_FAILURE);
14677         }
14678         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
14679     }
14680
14681     /* Read all block headers until next frame set block or
14682      * until the wanted block id is found */
14683     stat = tng_block_header_read(tng_data, block);
14684     while(file_pos < output_file_len &&
14685             stat != TNG_CRITICAL &&
14686             block->id != block_id &&
14687             block->id != TNG_PARTICLE_MAPPING &&
14688             block->id != TNG_TRAJECTORY_FRAME_SET &&
14689             block->id != -1)
14690     {
14691         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14692         file_pos = ftell(tng_data->output_file);
14693         if(file_pos < output_file_len)
14694         {
14695             stat = tng_block_header_read(tng_data, block);
14696         }
14697     }
14698     if(stat == TNG_CRITICAL)
14699     {
14700         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14701                 file_pos, __FILE__, __LINE__);
14702         tng_block_destroy(&block);
14703         tng_data->input_file = temp;
14704
14705         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14706         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14707         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14708         return(stat);
14709     }
14710
14711     contents_size = block->block_contents_size;
14712     header_size = block->header_contents_size;
14713
14714     header_pos = ftell(tng_data->output_file) - header_size;
14715     frame_set = &tng_data->current_trajectory_frame_set;
14716
14717     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14718     {
14719         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14720         tng_block_destroy(&block);
14721         return(TNG_CRITICAL);
14722     }
14723
14724     data.datatype = datatype;
14725
14726     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14727     {
14728         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14729         tng_block_destroy(&block);
14730         return(TNG_CRITICAL);
14731     }
14732
14733     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14734        !(dependency & TNG_PARTICLE_DEPENDENT))
14735     {
14736         tng_block_destroy(&block);
14737         tng_data->input_file = temp;
14738
14739         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14740         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14741         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14742         return(TNG_FAILURE);
14743     }
14744
14745     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14746     {
14747         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14748         tng_block_destroy(&block);
14749         return(TNG_CRITICAL);
14750     }
14751
14752     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14753              tng_data->input_file) == 0)
14754     {
14755         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14756         tng_block_destroy(&block);
14757         return(TNG_CRITICAL);
14758     }
14759     if(tng_data->output_endianness_swap_func_64)
14760     {
14761         if(tng_data->output_endianness_swap_func_64(tng_data,
14762             &data.n_values_per_frame)
14763             != TNG_SUCCESS)
14764         {
14765             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14766                     __FILE__, __LINE__);
14767         }
14768     }
14769
14770     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14771              tng_data->input_file) == 0)
14772     {
14773         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14774         tng_block_destroy(&block);
14775         return(TNG_CRITICAL);
14776     }
14777     if(tng_data->output_endianness_swap_func_64)
14778     {
14779         if(tng_data->output_endianness_swap_func_64(tng_data,
14780             &data.codec_id)
14781             != TNG_SUCCESS)
14782         {
14783             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14784                     __FILE__, __LINE__);
14785         }
14786     }
14787
14788     if(data.codec_id != TNG_UNCOMPRESSED)
14789     {
14790         if(fread(&data.compression_multiplier,
14791                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14792             == 0)
14793         {
14794             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14795             tng_block_destroy(&block);
14796             return(TNG_CRITICAL);
14797         }
14798
14799         if(tng_data->output_endianness_swap_func_64)
14800         {
14801             if(tng_data->output_endianness_swap_func_64(tng_data,
14802                (int64_t *)&data.compression_multiplier)
14803                 != TNG_SUCCESS)
14804             {
14805                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14806                         __FILE__, __LINE__);
14807             }
14808         }
14809     }
14810     else
14811     {
14812         data.compression_multiplier = 1;
14813     }
14814
14815     if(sparse_data)
14816     {
14817         if(fread(&data.first_frame_with_data,
14818                  sizeof(data.first_frame_with_data),
14819                  1, tng_data->input_file) == 0)
14820         {
14821             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14822             tng_block_destroy(&block);
14823             return(TNG_CRITICAL);
14824         }
14825         if(tng_data->output_endianness_swap_func_64)
14826         {
14827             if(tng_data->output_endianness_swap_func_64(tng_data,
14828                 &data.first_frame_with_data)
14829                 != TNG_SUCCESS)
14830             {
14831                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14832                         __FILE__, __LINE__);
14833             }
14834         }
14835
14836         if(fread(&data.stride_length, sizeof(data.stride_length),
14837                  1, tng_data->input_file) == 0)
14838         {
14839             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14840             tng_block_destroy(&block);
14841             return(TNG_CRITICAL);
14842         }
14843         if(tng_data->output_endianness_swap_func_64)
14844         {
14845             if(tng_data->output_endianness_swap_func_64(tng_data,
14846                 &data.stride_length)
14847                 != TNG_SUCCESS)
14848             {
14849                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14850                         __FILE__, __LINE__);
14851             }
14852         }
14853     }
14854     else
14855     {
14856         data.first_frame_with_data = 0;
14857         data.stride_length = 1;
14858     }
14859     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14860
14861     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14862              tng_data->input_file) == 0)
14863     {
14864         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14865         tng_block_destroy(&block);
14866         return(TNG_CRITICAL);
14867     }
14868     if(tng_data->output_endianness_swap_func_64)
14869     {
14870         if(tng_data->output_endianness_swap_func_64(tng_data,
14871             &num_first_particle)
14872             != TNG_SUCCESS)
14873         {
14874             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14875                     __FILE__, __LINE__);
14876         }
14877     }
14878
14879     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14880              tng_data->input_file) == 0)
14881     {
14882         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14883         tng_block_destroy(&block);
14884         return(TNG_CRITICAL);
14885     }
14886     if(tng_data->output_endianness_swap_func_64)
14887     {
14888         if(tng_data->output_endianness_swap_func_64(tng_data,
14889             &block_n_particles)
14890             != TNG_SUCCESS)
14891         {
14892             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14893                     __FILE__, __LINE__);
14894         }
14895     }
14896
14897
14898     tng_data->input_file = temp;
14899
14900     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14901     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14902     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14903
14904
14905     switch(data.datatype)
14906     {
14907         case(TNG_INT_DATA):
14908             size = sizeof(int64_t);
14909             break;
14910         case(TNG_FLOAT_DATA):
14911             size = sizeof(float);
14912             break;
14913         case(TNG_DOUBLE_DATA):
14914             size = sizeof(double);
14915             break;
14916         default:
14917             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14918                    __LINE__);
14919             tng_block_destroy(&block);
14920             return(TNG_FAILURE);
14921     }
14922
14923     n_values_per_frame = data.n_values_per_frame;
14924
14925     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14926                                data.first_frame_with_data)) /
14927                 data.stride_length;
14928     file_pos *= block_n_particles * size * n_values_per_frame;
14929
14930     if(file_pos > contents_size)
14931     {
14932         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14933                __LINE__);
14934         tng_block_destroy(&block);
14935         return(TNG_FAILURE);
14936     }
14937
14938     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14939
14940     /* If the endianness is not big endian the data needs to be swapped */
14941     if((data.datatype == TNG_INT_DATA ||
14942         data.datatype == TNG_DOUBLE_DATA) &&
14943        tng_data->output_endianness_swap_func_64)
14944     {
14945         copy = malloc(val_n_particles * n_values_per_frame * size);
14946         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14947         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14948         {
14949             if(tng_data->output_endianness_swap_func_64(tng_data,
14950                 (int64_t *) copy+i)
14951                 != TNG_SUCCESS)
14952             {
14953                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14954                         __FILE__, __LINE__);
14955             }
14956         }
14957         fwrite(copy, val_n_particles * n_values_per_frame, size,
14958                tng_data->output_file);
14959         free(copy);
14960     }
14961     else if(data.datatype == TNG_FLOAT_DATA &&
14962        tng_data->output_endianness_swap_func_32)
14963     {
14964         copy = malloc(val_n_particles * n_values_per_frame * size);
14965         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14966         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14967         {
14968             if(tng_data->output_endianness_swap_func_32(tng_data,
14969                 (int32_t *) copy+i)
14970                 != TNG_SUCCESS)
14971             {
14972                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14973                         __FILE__, __LINE__);
14974             }
14975         }
14976         fwrite(copy, val_n_particles * n_values_per_frame, size,
14977                tng_data->output_file);
14978         free(copy);
14979     }
14980
14981     else
14982     {
14983         fwrite(values, val_n_particles * n_values_per_frame, size,
14984                tng_data->output_file);
14985     }
14986     fflush(tng_data->output_file);
14987
14988     /* Update the number of written frames in the frame set. */
14989     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14990     {
14991         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14992     }
14993
14994     /* If the last frame has been written update the hash */
14995     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14996        data.first_frame_with_data) >=
14997        frame_set->n_frames)
14998     {
14999         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
15000                             header_size);
15001     }
15002
15003     tng_block_destroy(&block);
15004     return(TNG_SUCCESS);
15005 }
15006
15007 static tng_function_status tng_data_values_alloc
15008                 (const tng_trajectory_t tng_data,
15009                  union data_values ***values,
15010                  const int64_t n_frames,
15011                  const int64_t n_values_per_frame,
15012                  const char type)
15013 {
15014     int64_t i;
15015     tng_function_status stat;
15016
15017     if(n_frames <= 0 || n_values_per_frame <= 0)
15018     {
15019         return(TNG_FAILURE);
15020     }
15021
15022     if(*values)
15023     {
15024         stat = tng_data_values_free(tng_data, *values, n_frames,
15025                                     n_values_per_frame,
15026                                     type);
15027         if(stat != TNG_SUCCESS)
15028         {
15029             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15030                    __FILE__, __LINE__);
15031             return(stat);
15032         }
15033     }
15034     *values = malloc(sizeof(union data_values *) * n_frames);
15035     if(!*values)
15036     {
15037         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15038                sizeof(union data_values **) * n_frames,
15039                __FILE__, __LINE__);
15040         return(TNG_CRITICAL);
15041
15042     }
15043
15044     for(i = 0; i < n_frames; i++)
15045     {
15046         (*values)[i] = malloc(sizeof(union data_values) *
15047                            n_values_per_frame);
15048         if(!(*values)[i])
15049         {
15050             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15051                    sizeof(union data_values) * n_values_per_frame,
15052                    __FILE__, __LINE__);
15053             free(values);
15054             values = 0;
15055             return(TNG_CRITICAL);
15056         }
15057     }
15058     return(TNG_SUCCESS);
15059 }
15060
15061 /* FIXME: This needs ***values */
15062 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15063                 (const tng_trajectory_t tng_data,
15064                  union data_values **values,
15065                  const int64_t n_frames,
15066                  const int64_t n_values_per_frame,
15067                  const char type)
15068 {
15069     int64_t i, j;
15070     (void)tng_data;
15071
15072     if(values)
15073     {
15074         for(i = 0; i < n_frames; i++)
15075         {
15076             if(values[i])
15077             {
15078                 if(type == TNG_CHAR_DATA)
15079                 {
15080                     for(j = 0; j < n_values_per_frame; j++)
15081                     {
15082                         if(values[i][j].c)
15083                         {
15084                             free(values[i][j].c);
15085                             values[i][j].c = 0;
15086                         }
15087                     }
15088                 }
15089                 free(values[i]);
15090                 values[i] = 0;
15091             }
15092         }
15093         free(values);
15094         values = 0;
15095     }
15096
15097     return(TNG_SUCCESS);
15098 }
15099
15100 static tng_function_status tng_particle_data_values_alloc
15101                 (const tng_trajectory_t tng_data,
15102                  union data_values ****values,
15103                  const int64_t n_frames,
15104                  const int64_t n_particles,
15105                  const int64_t n_values_per_frame,
15106                  const char type)
15107 {
15108     int64_t i, j;
15109     tng_function_status stat;
15110
15111     if(n_particles == 0 || n_values_per_frame == 0)
15112     {
15113         return(TNG_FAILURE);
15114     }
15115
15116     if(*values)
15117     {
15118         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15119                                              n_particles, n_values_per_frame,
15120                                              type);
15121         if(stat != TNG_SUCCESS)
15122         {
15123             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15124                    __FILE__, __LINE__);
15125             return(stat);
15126         }
15127     }
15128     *values = malloc(sizeof(union data_values **) * n_frames);
15129     if(!*values)
15130     {
15131         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15132                sizeof(union data_values **) * n_frames,
15133                __FILE__, __LINE__);
15134         return(TNG_CRITICAL);
15135
15136     }
15137
15138     for(i = 0; i < n_frames; i++)
15139     {
15140         (*values)[i] = malloc(sizeof(union data_values *) *
15141                            n_particles);
15142         if(!(*values)[i])
15143         {
15144             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15145                    sizeof(union data_values *) * n_particles,
15146                    __FILE__, __LINE__);
15147             free(*values);
15148             *values = 0;
15149             return(TNG_CRITICAL);
15150         }
15151         for(j = 0; j < n_particles; j++)
15152         {
15153             (*values)[i][j] = malloc(sizeof(union data_values) *
15154                                   n_values_per_frame);
15155             if(!(*values)[i][j])
15156             {
15157                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15158                     sizeof(union data_values *) * n_particles,
15159                     __FILE__, __LINE__);
15160                 tng_particle_data_values_free(tng_data, *values, n_frames,
15161                                               n_particles, n_values_per_frame,
15162                                               type);
15163                 *values = 0;
15164                 return(TNG_CRITICAL);
15165             }
15166         }
15167     }
15168     return(TNG_SUCCESS);
15169 }
15170
15171 /* FIXME: This needs ****values */
15172 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15173                 (const tng_trajectory_t tng_data,
15174                  union data_values ***values,
15175                  const int64_t n_frames,
15176                  const int64_t n_particles,
15177                  const int64_t n_values_per_frame,
15178                  const char type)
15179 {
15180     int64_t i, j, k;
15181     (void)tng_data;
15182
15183     if(values)
15184     {
15185         for(i = 0; i < n_frames; i++)
15186         {
15187             if(values[i])
15188             {
15189                 for(j = 0; j < n_particles; j++)
15190                 {
15191                     if(type == TNG_CHAR_DATA)
15192                     {
15193                         for(k = 0; k < n_values_per_frame; k++)
15194                         {
15195                             if(values[i][j][k].c)
15196                             {
15197                                 free(values[i][j][k].c);
15198                                 values[i][j][k].c = 0;
15199                             }
15200                         }
15201                     }
15202                     free(values[i][j]);
15203                     values[i][j] = 0;
15204                 }
15205                 free(values[i]);
15206                 values[i] = 0;
15207             }
15208         }
15209         free(values);
15210         values = 0;
15211     }
15212
15213     return(TNG_SUCCESS);
15214 }
15215
15216
15217 tng_function_status DECLSPECDLLEXPORT tng_data_get
15218                 (tng_trajectory_t tng_data,
15219                  const int64_t block_id,
15220                  union data_values ***values,
15221                  int64_t *n_frames,
15222                  int64_t *n_values_per_frame,
15223                  char *type)
15224 {
15225     int64_t i, j, file_pos, block_index;
15226     int size;
15227     size_t len;
15228     tng_non_particle_data_t data;
15229     tng_trajectory_frame_set_t frame_set;
15230     tng_gen_block_t block;
15231     tng_function_status stat;
15232
15233     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15234     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15235     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15236     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15237
15238     frame_set = &tng_data->current_trajectory_frame_set;
15239
15240     block_index = -1;
15241     data = 0;
15242
15243     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15244     {
15245         tng_block_init(&block);
15246         file_pos = ftell(tng_data->input_file);
15247         /* Read all blocks until next frame set block */
15248         stat = tng_block_header_read(tng_data, block);
15249         while(file_pos < tng_data->input_file_len &&
15250                 stat != TNG_CRITICAL &&
15251                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15252                 block->id != -1)
15253         {
15254             /* Use hash by default */
15255             stat = tng_block_read_next(tng_data, block,
15256                                     TNG_USE_HASH);
15257             if(stat != TNG_CRITICAL)
15258             {
15259                 file_pos = ftell(tng_data->input_file);
15260                 if(file_pos < tng_data->input_file_len)
15261                 {
15262                     stat = tng_block_header_read(tng_data, block);
15263                 }
15264             }
15265         }
15266         tng_block_destroy(&block);
15267         if(stat == TNG_CRITICAL)
15268         {
15269             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15270                     file_pos, __FILE__, __LINE__);
15271             return(stat);
15272         }
15273
15274         for(i = 0; i < frame_set->n_data_blocks; i++)
15275         {
15276             data = &frame_set->tr_data[i];
15277             if(data->block_id == block_id)
15278             {
15279                 block_index = i;
15280                 break;
15281             }
15282         }
15283         if(block_index < 0)
15284         {
15285             return(TNG_FAILURE);
15286         }
15287     }
15288
15289     *n_frames = tng_max_i64(1, data->n_frames);
15290     *n_values_per_frame = data->n_values_per_frame;
15291     *type = data->datatype;
15292
15293     if(*values == 0)
15294     {
15295         if(tng_data_values_alloc(tng_data, values, *n_frames,
15296                                  *n_values_per_frame,
15297                                  *type)
15298         != TNG_SUCCESS)
15299         {
15300             return(TNG_CRITICAL);
15301         }
15302     }
15303
15304     switch(*type)
15305     {
15306     case TNG_CHAR_DATA:
15307         for(i = 0; i < *n_frames; i++)
15308         {
15309             for(j = 0; j < *n_values_per_frame; j++)
15310             {
15311                 len = strlen(data->strings[i][j]) + 1;
15312                 (*values)[i][j].c = malloc(len);
15313                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15314             }
15315         }
15316         break;
15317     case TNG_INT_DATA:
15318         size = sizeof(int);
15319         for(i = 0; i < *n_frames; i++)
15320         {
15321             for(j = 0; j < *n_values_per_frame; j++)
15322             {
15323                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15324                                              (i*(*n_values_per_frame) + j));
15325             }
15326         }
15327         break;
15328     case TNG_FLOAT_DATA:
15329         size = sizeof(float);
15330         for(i = 0; i < *n_frames; i++)
15331         {
15332             for(j = 0; j < *n_values_per_frame; j++)
15333             {
15334                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15335                                                (i*(*n_values_per_frame) + j));
15336             }
15337         }
15338         break;
15339     case TNG_DOUBLE_DATA:
15340     default:
15341         size = sizeof(double);
15342         for(i = 0; i < *n_frames; i++)
15343         {
15344             for(j = 0; j < *n_values_per_frame; j++)
15345             {
15346                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15347                                                 (i*(*n_values_per_frame) + j));
15348             }
15349         }
15350     }
15351
15352     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15353
15354     return(TNG_SUCCESS);
15355 }
15356
15357 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15358                                         const int64_t block_id,
15359                                         void **values,
15360                                         int64_t *n_frames,
15361                                         int64_t *stride_length,
15362                                         int64_t *n_values_per_frame,
15363                                         char *type)
15364 {
15365     int64_t file_pos, data_size, n_frames_div, block_index;
15366     int i, size;
15367     tng_non_particle_data_t data;
15368     tng_trajectory_frame_set_t frame_set;
15369     tng_gen_block_t block;
15370     void *temp;
15371     tng_function_status stat;
15372
15373     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15374     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15375     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15376     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15377     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15378
15379     frame_set = &tng_data->current_trajectory_frame_set;
15380
15381     block_index = -1;
15382     data = 0;
15383
15384     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15385     {
15386         tng_block_init(&block);
15387         file_pos = ftell(tng_data->input_file);
15388         /* Read all blocks until next frame set block */
15389         stat = tng_block_header_read(tng_data, block);
15390         while(file_pos < tng_data->input_file_len &&
15391                 stat != TNG_CRITICAL &&
15392                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15393                 block->id != -1)
15394         {
15395             /* Use hash by default */
15396             stat = tng_block_read_next(tng_data, block,
15397                                     TNG_USE_HASH);
15398             if(stat != TNG_CRITICAL)
15399             {
15400                 file_pos = ftell(tng_data->input_file);
15401                 if(file_pos < tng_data->input_file_len)
15402                 {
15403                     stat = tng_block_header_read(tng_data, block);
15404                 }
15405             }
15406         }
15407         tng_block_destroy(&block);
15408         if(stat == TNG_CRITICAL)
15409         {
15410             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15411                     file_pos, __FILE__, __LINE__);
15412             return(stat);
15413         }
15414
15415         for(i = 0; i < frame_set->n_data_blocks; i++)
15416         {
15417             data = &frame_set->tr_data[i];
15418             if(data->block_id == block_id)
15419             {
15420                 block_index = i;
15421                 break;
15422             }
15423         }
15424         if(block_index < 0)
15425         {
15426             return(TNG_FAILURE);
15427         }
15428     }
15429
15430     *type = data->datatype;
15431
15432     switch(*type)
15433     {
15434     case TNG_CHAR_DATA:
15435         return(TNG_FAILURE);
15436     case TNG_INT_DATA:
15437         size = sizeof(int64_t);
15438         break;
15439     case TNG_FLOAT_DATA:
15440         size = sizeof(float);
15441         break;
15442     case TNG_DOUBLE_DATA:
15443     default:
15444         size = sizeof(double);
15445     }
15446
15447     *n_frames = data->n_frames;
15448     *n_values_per_frame = data->n_values_per_frame;
15449     *stride_length = data->stride_length;
15450     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15451                    *n_frames / *stride_length;
15452
15453     data_size = n_frames_div * size *
15454                 *n_values_per_frame;
15455
15456     temp = realloc(*values, data_size);
15457     if(!temp)
15458     {
15459         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15460                data_size, __FILE__, __LINE__);
15461         free(*values);
15462         *values = 0;
15463         return(TNG_CRITICAL);
15464     }
15465
15466     *values = temp;
15467
15468     memcpy(*values, data->values, data_size);
15469
15470     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15471
15472     return(TNG_SUCCESS);
15473 }
15474
15475 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15476                 (tng_trajectory_t tng_data,
15477                  const int64_t block_id,
15478                  const int64_t start_frame_nr,
15479                  const int64_t end_frame_nr,
15480                  const char hash_mode,
15481                  union data_values ***values,
15482                  int64_t *n_values_per_frame,
15483                  char *type)
15484 {
15485     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15486     int64_t block_index;
15487     int size;
15488     size_t len;
15489     tng_non_particle_data_t data;
15490     tng_trajectory_frame_set_t frame_set;
15491     tng_gen_block_t block;
15492     tng_function_status stat;
15493
15494     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15495     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15496     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15497     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15498
15499     block_index = -1;
15500
15501     frame_set = &tng_data->current_trajectory_frame_set;
15502     first_frame = frame_set->first_frame;
15503
15504     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15505     if(stat != TNG_SUCCESS)
15506     {
15507         return(stat);
15508     }
15509
15510
15511     /* Do not re-read the frame set. */
15512     if(first_frame != frame_set->first_frame ||
15513        frame_set->n_data_blocks <= 0)
15514     {
15515         tng_block_init(&block);
15516         file_pos = ftell(tng_data->input_file);
15517         /* Read all blocks until next frame set block */
15518         stat = tng_block_header_read(tng_data, block);
15519         while(file_pos < tng_data->input_file_len &&
15520             stat != TNG_CRITICAL &&
15521             block->id != TNG_TRAJECTORY_FRAME_SET &&
15522             block->id != -1)
15523         {
15524             stat = tng_block_read_next(tng_data, block,
15525                                     hash_mode);
15526             if(stat != TNG_CRITICAL)
15527             {
15528                 file_pos = ftell(tng_data->input_file);
15529                 if(file_pos < tng_data->input_file_len)
15530                 {
15531                     stat = tng_block_header_read(tng_data, block);
15532                 }
15533             }
15534         }
15535         tng_block_destroy(&block);
15536         if(stat == TNG_CRITICAL)
15537         {
15538             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15539                     file_pos, __FILE__, __LINE__);
15540             return(stat);
15541         }
15542     }
15543
15544
15545     /* See if there is a data block of this ID.
15546      * Start checking the last read frame set */
15547     for(i = 0; i < frame_set->n_data_blocks; i++)
15548     {
15549         data = &frame_set->tr_data[i];
15550         if(data->block_id == block_id)
15551         {
15552             block_index = i;
15553             break;
15554         }
15555     }
15556
15557     if(block_index < 0)
15558     {
15559         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15560                 block_id, __FILE__, __LINE__);
15561         return(TNG_FAILURE);
15562     }
15563
15564     n_frames = end_frame_nr - start_frame_nr + 1;
15565     *n_values_per_frame = data->n_values_per_frame;
15566     *type = data->datatype;
15567
15568     if(*values == 0)
15569     {
15570         if(tng_data_values_alloc(tng_data, values, n_frames,
15571                                  *n_values_per_frame,
15572                                  *type) != TNG_SUCCESS)
15573         {
15574             return(TNG_CRITICAL);
15575         }
15576     }
15577
15578     current_frame_pos = start_frame_nr - frame_set->first_frame;
15579     /* It's not very elegant to reuse so much of the code in the different case
15580      * statements, but it's unnecessarily slow to have the switch-case block
15581      * inside the for loops. */
15582     switch(*type)
15583     {
15584     case TNG_CHAR_DATA:
15585         for(i=0; i<n_frames; i++)
15586         {
15587             if(current_frame_pos == frame_set->n_frames)
15588             {
15589                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15590                 if(stat != TNG_SUCCESS)
15591                 {
15592                     return(stat);
15593                 }
15594                 current_frame_pos = 0;
15595             }
15596             for(j = 0; j < *n_values_per_frame; j++)
15597             {
15598                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15599                 (*values)[i][j].c = malloc(len);
15600                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15601             }
15602             current_frame_pos++;
15603         }
15604         break;
15605     case TNG_INT_DATA:
15606         size = sizeof(int);
15607         for(i=0; i<n_frames; i++)
15608         {
15609             if(current_frame_pos == frame_set->n_frames)
15610             {
15611                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15612                 if(stat != TNG_SUCCESS)
15613                 {
15614                     return(stat);
15615                 }
15616                 current_frame_pos = 0;
15617             }
15618             for(j = 0; j < *n_values_per_frame; j++)
15619             {
15620                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15621                                             (current_frame_pos *
15622                                              (*n_values_per_frame) + j));
15623             }
15624             current_frame_pos++;
15625         }
15626         break;
15627     case TNG_FLOAT_DATA:
15628         size = sizeof(float);
15629         for(i=0; i<n_frames; i++)
15630         {
15631             if(current_frame_pos == frame_set->n_frames)
15632             {
15633                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15634                 if(stat != TNG_SUCCESS)
15635                 {
15636                     return(stat);
15637                 }
15638                 current_frame_pos = 0;
15639             }
15640             for(j = 0; j < *n_values_per_frame; j++)
15641             {
15642                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15643                                                (current_frame_pos *
15644                                                 (*n_values_per_frame) + j));
15645             }
15646             current_frame_pos++;
15647         }
15648         break;
15649     case TNG_DOUBLE_DATA:
15650     default:
15651         size = sizeof(double);
15652         for(i=0; i<n_frames; i++)
15653         {
15654             if(current_frame_pos == frame_set->n_frames)
15655             {
15656                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15657                 if(stat != TNG_SUCCESS)
15658                 {
15659                     return(stat);
15660                 }
15661                 current_frame_pos = 0;
15662             }
15663             for(j = 0; j < *n_values_per_frame; j++)
15664             {
15665                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15666                                                 (current_frame_pos *
15667                                                  (*n_values_per_frame) + j));
15668             }
15669             current_frame_pos++;
15670         }
15671     }
15672
15673     data->last_retrieved_frame = end_frame_nr;
15674
15675     return(TNG_SUCCESS);
15676 }
15677
15678 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15679                 (tng_trajectory_t tng_data,
15680                  const int64_t block_id,
15681                  const int64_t start_frame_nr,
15682                  const int64_t end_frame_nr,
15683                  const char hash_mode,
15684                  void **values,
15685                  int64_t *stride_length,
15686                  int64_t *n_values_per_frame,
15687                  char *type)
15688 {
15689     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15690     int64_t file_pos, current_frame_pos, data_size, frame_size;
15691     int64_t last_frame_pos;
15692     int size;
15693     tng_trajectory_frame_set_t frame_set;
15694     tng_non_particle_data_t np_data;
15695     tng_gen_block_t block;
15696     void *current_values = 0, *temp;
15697     tng_function_status stat;
15698
15699     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15700     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15701     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15702     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15703     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15704
15705     frame_set = &tng_data->current_trajectory_frame_set;
15706     first_frame = frame_set->first_frame;
15707
15708     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15709     if(stat != TNG_SUCCESS)
15710     {
15711         return(stat);
15712     }
15713
15714     /* Do not re-read the frame set and only need the requested block. */
15715     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15716     stat = tng_data_find(tng_data, block_id, &np_data);
15717     if(first_frame != frame_set->first_frame ||
15718        stat != TNG_SUCCESS)
15719     {
15720         tng_block_init(&block);
15721         if(stat != TNG_SUCCESS)
15722         {
15723             fseek(tng_data->input_file,
15724                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15725                   SEEK_SET);
15726             stat = tng_block_header_read(tng_data, block);
15727             if(stat != TNG_SUCCESS)
15728             {
15729                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15730                         __FILE__, __LINE__);
15731                 return(stat);
15732             }
15733
15734             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15735         }
15736         file_pos = ftell(tng_data->input_file);
15737         /* Read until next frame set block */
15738         stat = tng_block_header_read(tng_data, block);
15739         while(file_pos < tng_data->input_file_len &&
15740             stat != TNG_CRITICAL &&
15741             block->id != TNG_TRAJECTORY_FRAME_SET &&
15742             block->id != -1)
15743         {
15744             if(block->id == block_id)
15745             {
15746                 stat = tng_block_read_next(tng_data, block,
15747                                         hash_mode);
15748                 if(stat != TNG_CRITICAL)
15749                 {
15750                     file_pos = ftell(tng_data->input_file);
15751                     if(file_pos < tng_data->input_file_len)
15752                     {
15753                         stat = tng_block_header_read(tng_data, block);
15754                     }
15755                 }
15756             }
15757             else
15758             {
15759                 file_pos += block->block_contents_size + block->header_contents_size;
15760                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15761                 if(file_pos < tng_data->input_file_len)
15762                 {
15763                     stat = tng_block_header_read(tng_data, block);
15764                 }
15765             }
15766         }
15767         tng_block_destroy(&block);
15768         if(stat == TNG_CRITICAL)
15769         {
15770             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15771                     file_pos, __FILE__, __LINE__);
15772             return(stat);
15773         }
15774     }
15775
15776     stat = tng_data_find(tng_data, block_id, &np_data);
15777     if(stat != TNG_SUCCESS)
15778     {
15779         return(stat);
15780     }
15781
15782     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15783                                &n_frames, stride_length,
15784                                n_values_per_frame, type);
15785
15786     if(stat != TNG_SUCCESS)
15787     {
15788         if(current_values)
15789         {
15790             free(current_values);
15791         }
15792         return(stat);
15793     }
15794
15795     if(n_frames == 1 && n_frames < frame_set->n_frames)
15796     {
15797         tot_n_frames = 1;
15798     }
15799     else
15800     {
15801         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15802     }
15803
15804     switch(*type)
15805     {
15806     case TNG_CHAR_DATA:
15807         return(TNG_FAILURE);
15808     case TNG_INT_DATA:
15809         size = sizeof(int64_t);
15810         break;
15811     case TNG_FLOAT_DATA:
15812         size = sizeof(float);
15813         break;
15814     case TNG_DOUBLE_DATA:
15815     default:
15816         size = sizeof(double);
15817     }
15818
15819     n_frames_div = (tot_n_frames % *stride_length) ?
15820                  tot_n_frames / *stride_length + 1:
15821                  tot_n_frames / *stride_length;
15822     data_size = n_frames_div * size * (*n_values_per_frame);
15823
15824 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15825               size, n_frames_div, data_size);
15826 */
15827     temp = realloc(*values, data_size);
15828     if(!temp)
15829     {
15830         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15831                data_size, __FILE__, __LINE__);
15832         free(*values);
15833         *values = 0;
15834         return(TNG_CRITICAL);
15835     }
15836
15837     *values = temp;
15838
15839     if( n_frames == 1 && n_frames < frame_set->n_frames)
15840     {
15841         memcpy(*values, current_values, size * (*n_values_per_frame));
15842     }
15843     else
15844     {
15845         current_frame_pos = start_frame_nr - frame_set->first_frame;
15846
15847         frame_size = size * (*n_values_per_frame);
15848
15849         last_frame_pos = tng_min_i64(n_frames,
15850                                      end_frame_nr - start_frame_nr);
15851
15852         n_frames_div = current_frame_pos / *stride_length;
15853         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15854                        last_frame_pos / *stride_length + 1:
15855                        last_frame_pos / *stride_length;
15856         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15857
15858         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15859                n_frames_div_2 * frame_size);
15860
15861         current_frame_pos += n_frames - current_frame_pos;
15862
15863         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15864         {
15865             stat = tng_frame_set_read_next(tng_data, hash_mode);
15866             if(stat != TNG_SUCCESS)
15867             {
15868                 if(current_values)
15869                 {
15870                     free(current_values);
15871                 }
15872                 free(*values);
15873                 *values = 0;
15874                 return(stat);
15875             }
15876
15877             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15878                                     &n_frames, stride_length,
15879                                     n_values_per_frame, type);
15880
15881             if(stat != TNG_SUCCESS)
15882             {
15883                 if(current_values)
15884                 {
15885                     free(current_values);
15886                 }
15887                 free(*values);
15888                 *values = 0;
15889                 return(stat);
15890             }
15891
15892             last_frame_pos = tng_min_i64(n_frames,
15893                                          end_frame_nr - current_frame_pos);
15894
15895             n_frames_div = current_frame_pos / *stride_length;
15896             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15897                            last_frame_pos / *stride_length + 1:
15898                            last_frame_pos / *stride_length;
15899             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15900
15901             memcpy(((char *)*values) + n_frames_div * frame_size,
15902                    current_values,
15903                    n_frames_div_2 * frame_size);
15904
15905             current_frame_pos += n_frames;
15906         }
15907     }
15908
15909     if(current_values)
15910     {
15911         free(current_values);
15912     }
15913
15914     np_data->last_retrieved_frame = end_frame_nr;
15915
15916     return(TNG_SUCCESS);
15917 }
15918
15919 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15920                 (tng_trajectory_t tng_data,
15921                  const int64_t block_id,
15922                  union data_values ****values,
15923                  int64_t *n_frames,
15924                  int64_t *n_particles,
15925                  int64_t *n_values_per_frame,
15926                  char *type)
15927 {
15928     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15929     int size;
15930     size_t len;
15931     tng_particle_data_t data;
15932     tng_trajectory_frame_set_t frame_set;
15933     tng_gen_block_t block;
15934     char block_type_flag;
15935     tng_function_status stat;
15936
15937     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15938     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15939     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15940     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15941     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15942
15943     frame_set = &tng_data->current_trajectory_frame_set;
15944
15945     block_index = -1;
15946     data = 0;
15947
15948     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15949     {
15950         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15951         {
15952             block_type_flag = TNG_TRAJECTORY_BLOCK;
15953         }
15954         else
15955         {
15956             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15957         }
15958
15959         tng_block_init(&block);
15960         file_pos = ftell(tng_data->input_file);
15961         /* Read all blocks until next frame set block */
15962         stat = tng_block_header_read(tng_data, block);
15963         while(file_pos < tng_data->input_file_len &&
15964                 stat != TNG_CRITICAL &&
15965                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15966                 block->id != -1)
15967         {
15968             /* Use hash by default */
15969             stat = tng_block_read_next(tng_data, block,
15970                                     TNG_USE_HASH);
15971             if(stat != TNG_CRITICAL)
15972             {
15973                 file_pos = ftell(tng_data->input_file);
15974                 if(file_pos < tng_data->input_file_len)
15975                 {
15976                     stat = tng_block_header_read(tng_data, block);
15977                 }
15978             }
15979         }
15980         tng_block_destroy(&block);
15981         if(stat == TNG_CRITICAL)
15982         {
15983             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15984                     file_pos, __FILE__, __LINE__);
15985             return(stat);
15986         }
15987
15988         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
15989         {
15990             data = &frame_set->tr_particle_data[i];
15991             if(data->block_id == block_id)
15992             {
15993                 block_index = i;
15994                 block_type_flag = TNG_TRAJECTORY_BLOCK;
15995                 break;
15996             }
15997         }
15998         if(block_index < 0)
15999         {
16000             return(TNG_FAILURE);
16001         }
16002     }
16003     else
16004     {
16005         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16006         {
16007             block_type_flag = TNG_TRAJECTORY_BLOCK;
16008         }
16009         else
16010         {
16011             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16012         }
16013     }
16014
16015     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16016        tng_data->var_num_atoms_flag)
16017     {
16018         *n_particles = frame_set->n_particles;
16019     }
16020     else
16021     {
16022         *n_particles = tng_data->n_particles;
16023     }
16024
16025     *n_frames = tng_max_i64(1, data->n_frames);
16026     *n_values_per_frame = data->n_values_per_frame;
16027     *type = data->datatype;
16028
16029     if(*values == 0)
16030     {
16031         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
16032                                          *n_particles, *n_values_per_frame,
16033                                          *type)
16034             != TNG_SUCCESS)
16035         {
16036             return(TNG_CRITICAL);
16037         }
16038     }
16039
16040     /* It's not very elegant to reuse so much of the code in the different case
16041      * statements, but it's unnecessarily slow to have the switch-case block
16042      * inside the for loops. */
16043     switch(*type)
16044     {
16045     case TNG_CHAR_DATA:
16046         for(i = 0; i < *n_frames; i++)
16047         {
16048             for(j = 0; j < *n_particles; j++)
16049             {
16050                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16051                 for(k = 0; k < *n_values_per_frame; k++)
16052                 {
16053                     len = strlen(data->strings[i][j][k]) + 1;
16054                     (*values)[i][mapping][k].c = malloc(len);
16055                     strncpy((*values)[i][mapping][k].c,
16056                             data->strings[i][j][k], len);
16057                 }
16058             }
16059         }
16060         break;
16061     case TNG_INT_DATA:
16062         size = sizeof(int);
16063         i_step = (*n_particles) * (*n_values_per_frame);
16064         for(i = 0; i < *n_frames; i++)
16065         {
16066             for(j = 0; j < *n_particles; j++)
16067             {
16068                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16069                 for(k = 0; k < *n_values_per_frame; k++)
16070                 {
16071                     (*values)[i][mapping][k].i = *(int *)
16072                                                  ((char *)data->values + size *
16073                                                  (i * i_step + j *
16074                                                   (*n_values_per_frame) + k));
16075                 }
16076             }
16077         }
16078         break;
16079     case TNG_FLOAT_DATA:
16080         size = sizeof(float);
16081         i_step = (*n_particles) * (*n_values_per_frame);
16082         for(i = 0; i < *n_frames; i++)
16083         {
16084             for(j = 0; j < *n_particles; j++)
16085             {
16086                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16087                 for(k = 0; k < *n_values_per_frame; k++)
16088                 {
16089                     (*values)[i][mapping][k].f = *(float *)
16090                                                  ((char *)data->values + size *
16091                                                  (i * i_step + j *
16092                                                   (*n_values_per_frame) + k));
16093                 }
16094             }
16095         }
16096         break;
16097     case TNG_DOUBLE_DATA:
16098     default:
16099         size = sizeof(double);
16100         i_step = (*n_particles) * (*n_values_per_frame);
16101         for(i = 0; i < *n_frames; i++)
16102         {
16103             for(j = 0; j < *n_particles; j++)
16104             {
16105                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16106                 for(k = 0; k < *n_values_per_frame; k++)
16107                 {
16108                     (*values)[i][mapping][k].d = *(double *)
16109                                                  ((char *)data->values + size *
16110                                                  (i * i_step + j *
16111                                                   (*n_values_per_frame) + k));
16112                 }
16113             }
16114         }
16115     }
16116
16117     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16118
16119     return(TNG_SUCCESS);
16120 }
16121
16122 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16123                 (tng_trajectory_t tng_data,
16124                  const int64_t block_id,
16125                  void **values,
16126                  int64_t *n_frames,
16127                  int64_t *stride_length,
16128                  int64_t *n_particles,
16129                  int64_t *n_values_per_frame,
16130                  char *type)
16131 {
16132     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16133     int64_t block_index;
16134     int size;
16135     tng_particle_data_t data;
16136     tng_trajectory_frame_set_t frame_set;
16137     tng_gen_block_t block;
16138     void *temp;
16139     char block_type_flag;
16140     tng_function_status stat;
16141
16142     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16143     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16144     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16145     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16146     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16147
16148     frame_set = &tng_data->current_trajectory_frame_set;
16149
16150     block_index = -1;
16151     data = 0;
16152
16153     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16154     {
16155         tng_block_init(&block);
16156         file_pos = ftell(tng_data->input_file);
16157         /* Read all blocks until next frame set block */
16158         stat = tng_block_header_read(tng_data, block);
16159         while(file_pos < tng_data->input_file_len &&
16160                 stat != TNG_CRITICAL &&
16161                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16162                 block->id != -1)
16163         {
16164             /* Use hash by default */
16165             stat = tng_block_read_next(tng_data, block,
16166                                     TNG_USE_HASH);
16167             if(stat != TNG_CRITICAL)
16168             {
16169                 file_pos = ftell(tng_data->input_file);
16170                 if(file_pos < tng_data->input_file_len)
16171                 {
16172                     stat = tng_block_header_read(tng_data, block);
16173                 }
16174             }
16175         }
16176         tng_block_destroy(&block);
16177         if(stat == TNG_CRITICAL)
16178         {
16179             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16180                     file_pos, __FILE__, __LINE__);
16181             return(stat);
16182         }
16183
16184         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16185         {
16186             data = &frame_set->tr_particle_data[i];
16187             if(data->block_id == block_id)
16188             {
16189                 block_index = i;
16190                 break;
16191             }
16192         }
16193         if(block_index < 0)
16194         {
16195             return(TNG_FAILURE);
16196         }
16197     }
16198
16199     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16200     {
16201         block_type_flag = TNG_TRAJECTORY_BLOCK;
16202     }
16203     else
16204     {
16205         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16206     }
16207
16208    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16209       tng_data->var_num_atoms_flag)
16210     {
16211         *n_particles = frame_set->n_particles;
16212     }
16213     else
16214     {
16215         *n_particles = tng_data->n_particles;
16216     }
16217
16218     *type = data->datatype;
16219
16220     switch(*type)
16221     {
16222     case TNG_CHAR_DATA:
16223         return(TNG_FAILURE);
16224     case TNG_INT_DATA:
16225         size = sizeof(int64_t);
16226         break;
16227     case TNG_FLOAT_DATA:
16228         size = sizeof(float);
16229         break;
16230     case TNG_DOUBLE_DATA:
16231     default:
16232         size = sizeof(double);
16233     }
16234
16235     *n_frames = tng_max_i64(1, data->n_frames);
16236     *n_values_per_frame = data->n_values_per_frame;
16237     *stride_length = data->stride_length;
16238
16239     n_frames_div = (*n_frames % *stride_length) ?
16240                    *n_frames / *stride_length + 1:
16241                    *n_frames / *stride_length;
16242
16243     data_size = n_frames_div * size * (*n_particles) *
16244                 (*n_values_per_frame);
16245
16246     temp = realloc(*values, data_size);
16247     if(!temp)
16248     {
16249         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16250                data_size, __FILE__, __LINE__);
16251         free(*values);
16252         *values = 0;
16253         return(TNG_CRITICAL);
16254     }
16255
16256     *values = temp;
16257
16258     if(frame_set->n_mapping_blocks <= 0)
16259     {
16260         memcpy(*values, data->values, data_size);
16261     }
16262     else
16263     {
16264         i_step = (*n_particles) * (*n_values_per_frame);
16265         for(i = 0; i < *n_frames; i++)
16266         {
16267             for(j = 0; j < *n_particles; j++)
16268             {
16269                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16270                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16271                        (*n_values_per_frame)),
16272                        (char *)data->values + size *
16273                        (i * i_step + j * (*n_values_per_frame)),
16274                        size * (*n_values_per_frame));
16275             }
16276         }
16277     }
16278
16279     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16280
16281     return(TNG_SUCCESS);
16282 }
16283
16284 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16285                 (tng_trajectory_t tng_data,
16286                  const int64_t block_id,
16287                  const int64_t start_frame_nr,
16288                  const int64_t end_frame_nr,
16289                  const char hash_mode,
16290                  union data_values ****values,
16291                  int64_t *n_particles,
16292                  int64_t *n_values_per_frame,
16293                  char *type)
16294 {
16295     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16296     int64_t first_frame, block_index;
16297     int size;
16298     size_t len;
16299     tng_particle_data_t data;
16300     tng_trajectory_frame_set_t frame_set;
16301     tng_gen_block_t block;
16302     char block_type_flag;
16303     tng_function_status stat;
16304
16305     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16306     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16307     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16308     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16309     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16310
16311     block_index = -1;
16312
16313     frame_set = &tng_data->current_trajectory_frame_set;
16314     first_frame = frame_set->first_frame;
16315
16316     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16317     if(stat != TNG_SUCCESS)
16318     {
16319         return(stat);
16320     }
16321
16322     /* Do not re-read the frame set. */
16323     if(first_frame != frame_set->first_frame ||
16324        frame_set->n_particle_data_blocks <= 0)
16325     {
16326         tng_block_init(&block);
16327         file_pos = ftell(tng_data->input_file);
16328         /* Read all blocks until next frame set block */
16329         stat = tng_block_header_read(tng_data, block);
16330         while(file_pos < tng_data->input_file_len &&
16331                 stat != TNG_CRITICAL &&
16332                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16333                 block->id != -1)
16334         {
16335             stat = tng_block_read_next(tng_data, block,
16336                                     hash_mode);
16337             if(stat != TNG_CRITICAL)
16338             {
16339                 file_pos = ftell(tng_data->input_file);
16340                 if(file_pos < tng_data->input_file_len)
16341                 {
16342                     stat = tng_block_header_read(tng_data, block);
16343                 }
16344             }
16345         }
16346         tng_block_destroy(&block);
16347         if(stat == TNG_CRITICAL)
16348         {
16349             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16350                     file_pos, __FILE__, __LINE__);
16351             return(stat);
16352         }
16353     }
16354
16355     /* See if there is already a data block of this ID.
16356      * Start checking the last read frame set */
16357     for(i = frame_set->n_particle_data_blocks; i-- ;)
16358     {
16359         data = &frame_set->tr_particle_data[i];
16360         if(data->block_id == block_id)
16361         {
16362             block_index = i;
16363             block_type_flag = TNG_TRAJECTORY_BLOCK;
16364             break;
16365         }
16366     }
16367
16368     if(block_index < 0)
16369     {
16370         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16371                 block_id, __FILE__, __LINE__);
16372         return(TNG_FAILURE);
16373     }
16374
16375     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16376        tng_data->var_num_atoms_flag)
16377     {
16378         *n_particles = frame_set->n_particles;
16379     }
16380     else
16381     {
16382         *n_particles = tng_data->n_particles;
16383     }
16384
16385     n_frames = end_frame_nr - start_frame_nr + 1;
16386     *n_values_per_frame = data->n_values_per_frame;
16387     *type = data->datatype;
16388
16389     if(*values == 0)
16390     {
16391         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16392                                          *n_particles, *n_values_per_frame,
16393                                          *type)
16394             != TNG_SUCCESS)
16395         {
16396             return(TNG_CRITICAL);
16397         }
16398     }
16399
16400     current_frame_pos = start_frame_nr - frame_set->first_frame;
16401     /* It's not very elegant to reuse so much of the code in the different case
16402      * statements, but it's unnecessarily slow to have the switch-case block
16403      * inside the for loops. */
16404     switch(*type)
16405     {
16406     case TNG_CHAR_DATA:
16407         for(i=0; i<n_frames; i++)
16408         {
16409             if(current_frame_pos == frame_set->n_frames)
16410             {
16411                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16412                 if(stat != TNG_SUCCESS)
16413                 {
16414                     return(stat);
16415                 }
16416                 current_frame_pos = 0;
16417             }
16418             for(j = 0; j < *n_particles; j++)
16419             {
16420                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16421                 for(k = 0; k < *n_values_per_frame; k++)
16422                 {
16423                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16424                     (*values)[i][mapping][k].c = malloc(len);
16425                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16426                 }
16427             }
16428             current_frame_pos++;
16429         }
16430         break;
16431     case TNG_INT_DATA:
16432         size = sizeof(int);
16433         i_step = (*n_particles) * (*n_values_per_frame);
16434         for(i=0; i<n_frames; i++)
16435         {
16436             if(current_frame_pos == frame_set->n_frames)
16437             {
16438                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16439                 if(stat != TNG_SUCCESS)
16440                 {
16441                     return(stat);
16442                 }
16443                 current_frame_pos = 0;
16444             }
16445             for(j = 0; j < *n_particles; j++)
16446             {
16447                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16448                 for(k = 0; k < *n_values_per_frame; k++)
16449                 {
16450                     (*values)[i][mapping][k].i = *(int *)
16451                                                  ((char *)data->values + size *
16452                                                   (current_frame_pos *
16453                                                    i_step + j *
16454                                                    (*n_values_per_frame) + k));
16455                 }
16456             }
16457             current_frame_pos++;
16458         }
16459         break;
16460     case TNG_FLOAT_DATA:
16461         size = sizeof(float);
16462         i_step = (*n_particles) * (*n_values_per_frame);
16463         for(i=0; i<n_frames; i++)
16464         {
16465             if(current_frame_pos == frame_set->n_frames)
16466             {
16467                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16468                 if(stat != TNG_SUCCESS)
16469                 {
16470                     return(stat);
16471                 }
16472                 current_frame_pos = 0;
16473             }
16474             for(j=0; j<*n_particles; j++)
16475             {
16476                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16477                 for(k=0; k<*n_values_per_frame; k++)
16478                 {
16479                     (*values)[i][mapping][k].f = *(float *)
16480                                                  ((char *)data->values + size *
16481                                                   (current_frame_pos *
16482                                                    i_step + j *
16483                                                    (*n_values_per_frame) + k));
16484                 }
16485             }
16486             current_frame_pos++;
16487         }
16488         break;
16489     case TNG_DOUBLE_DATA:
16490     default:
16491         size = sizeof(double);
16492         i_step = (*n_particles) * (*n_values_per_frame);
16493         for(i=0; i<n_frames; i++)
16494         {
16495             if(current_frame_pos == frame_set->n_frames)
16496             {
16497                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16498                 if(stat != TNG_SUCCESS)
16499                 {
16500                     return(stat);
16501                 }
16502                 current_frame_pos = 0;
16503             }
16504             for(j=0; j<*n_particles; j++)
16505             {
16506                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16507                 for(k=0; k<*n_values_per_frame; k++)
16508                 {
16509                     (*values)[i][mapping][k].d = *(double *)
16510                                                  ((char *)data->values + size *
16511                                                   (current_frame_pos *
16512                                                    i_step + j *
16513                                                    (*n_values_per_frame) + k));
16514                 }
16515             }
16516             current_frame_pos++;
16517         }
16518     }
16519
16520     data->last_retrieved_frame = end_frame_nr;
16521
16522     return(TNG_SUCCESS);
16523 }
16524
16525 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16526                 (tng_trajectory_t tng_data,
16527                  const int64_t block_id,
16528                  const int64_t start_frame_nr,
16529                  const int64_t end_frame_nr,
16530                  const char hash_mode,
16531                  void **values,
16532                  int64_t *n_particles,
16533                  int64_t *stride_length,
16534                  int64_t *n_values_per_frame,
16535                  char *type)
16536 {
16537     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16538     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16539     int size;
16540     tng_trajectory_frame_set_t frame_set;
16541     tng_particle_data_t p_data;
16542     tng_gen_block_t block;
16543     void *current_values = 0, *temp;
16544     tng_function_status stat;
16545
16546     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16547     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16548     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16549     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16550     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16551     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16552
16553     frame_set = &tng_data->current_trajectory_frame_set;
16554     first_frame = frame_set->first_frame;
16555
16556     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16557     if(stat != TNG_SUCCESS)
16558     {
16559         return(stat);
16560     }
16561
16562     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16563     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16564     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16565     if(first_frame != frame_set->first_frame ||
16566        stat != TNG_SUCCESS)
16567     {
16568         tng_block_init(&block);
16569         if(stat != TNG_SUCCESS)
16570         {
16571             fseek(tng_data->input_file,
16572                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
16573                   SEEK_SET);
16574             stat = tng_block_header_read(tng_data, block);
16575             if(stat != TNG_SUCCESS)
16576             {
16577                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16578                         __FILE__, __LINE__);
16579                 return(stat);
16580             }
16581
16582             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16583         }
16584         file_pos = ftell(tng_data->input_file);
16585         /* Read until next frame set block */
16586         stat = tng_block_header_read(tng_data, block);
16587         while(file_pos < tng_data->input_file_len &&
16588             stat != TNG_CRITICAL &&
16589             block->id != TNG_TRAJECTORY_FRAME_SET &&
16590             block->id != -1)
16591         {
16592             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16593             {
16594                 stat = tng_block_read_next(tng_data, block,
16595                                         hash_mode);
16596                 if(stat != TNG_CRITICAL)
16597                 {
16598                     file_pos = ftell(tng_data->input_file);
16599                     if(file_pos < tng_data->input_file_len)
16600                     {
16601                         stat = tng_block_header_read(tng_data, block);
16602                     }
16603                 }
16604             }
16605             else
16606             {
16607                 file_pos += block->block_contents_size + block->header_contents_size;
16608                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16609                 if(file_pos < tng_data->input_file_len)
16610                 {
16611                     stat = tng_block_header_read(tng_data, block);
16612                 }
16613             }
16614         }
16615         tng_block_destroy(&block);
16616         if(stat == TNG_CRITICAL)
16617         {
16618             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16619                     file_pos, __FILE__, __LINE__);
16620             return(stat);
16621         }
16622     }
16623     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16624     if(stat != TNG_SUCCESS)
16625     {
16626         return(stat);
16627     }
16628
16629     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16630                                         &n_frames, stride_length, n_particles,
16631                                         n_values_per_frame, type);
16632
16633     if(stat != TNG_SUCCESS || *n_particles == 0)
16634     {
16635         if(current_values)
16636         {
16637             free(current_values);
16638         }
16639         return(stat);
16640     }
16641
16642     if(n_frames == 1 && n_frames < frame_set->n_frames)
16643     {
16644         tot_n_frames = 1;
16645     }
16646     else
16647     {
16648         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16649     }
16650
16651     switch(*type)
16652     {
16653     case TNG_CHAR_DATA:
16654         return(TNG_FAILURE);
16655     case TNG_INT_DATA:
16656         size = sizeof(int64_t);
16657         break;
16658     case TNG_FLOAT_DATA:
16659         size = sizeof(float);
16660         break;
16661     case TNG_DOUBLE_DATA:
16662     default:
16663         size = sizeof(double);
16664     }
16665
16666     n_frames_div = (tot_n_frames % *stride_length) ?
16667                  tot_n_frames / *stride_length + 1:
16668                  tot_n_frames / *stride_length;
16669
16670     data_size = n_frames_div * size * (*n_particles) *
16671                 (*n_values_per_frame);
16672
16673     temp = realloc(*values, data_size);
16674     if(!temp)
16675     {
16676         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16677                data_size, __FILE__, __LINE__);
16678         free(*values);
16679         *values = 0;
16680         return(TNG_CRITICAL);
16681     }
16682
16683     *values = temp;
16684
16685     if( n_frames == 1 && n_frames < frame_set->n_frames)
16686     {
16687         memcpy(*values, current_values, size * (*n_particles) *
16688                (*n_values_per_frame));
16689     }
16690     else
16691     {
16692         current_frame_pos = start_frame_nr - frame_set->first_frame;
16693
16694         frame_size = size * (*n_particles) * (*n_values_per_frame);
16695
16696         last_frame_pos = tng_min_i64(n_frames,
16697                                      end_frame_nr - start_frame_nr);
16698
16699         n_frames_div = current_frame_pos / *stride_length;
16700         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16701                        last_frame_pos / *stride_length + 1:
16702                        last_frame_pos / *stride_length;
16703         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16704
16705         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16706                n_frames_div_2 * frame_size);
16707
16708         current_frame_pos += n_frames - current_frame_pos;
16709
16710         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16711         {
16712             stat = tng_frame_set_read_next(tng_data, hash_mode);
16713             if(stat != TNG_SUCCESS)
16714             {
16715                 if(current_values)
16716                 {
16717                     free(current_values);
16718                 }
16719                 free(*values);
16720                 *values = 0;
16721                 return(stat);
16722             }
16723
16724             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16725                                                 &n_frames, stride_length, n_particles,
16726                                                 n_values_per_frame, type);
16727
16728             if(stat != TNG_SUCCESS)
16729             {
16730                 if(current_values)
16731                 {
16732                     free(current_values);
16733                 }
16734                 free(*values);
16735                 *values = 0;
16736                 return(stat);
16737             }
16738
16739             last_frame_pos = tng_min_i64(n_frames,
16740                                          end_frame_nr - current_frame_pos);
16741
16742             n_frames_div = current_frame_pos / *stride_length;
16743             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16744                            last_frame_pos / *stride_length + 1:
16745                            last_frame_pos / *stride_length;
16746             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16747
16748             memcpy(((char *)*values) + n_frames_div * frame_size,
16749                    current_values,
16750                    n_frames_div_2 * frame_size);
16751
16752             current_frame_pos += n_frames;
16753         }
16754     }
16755
16756     if(current_values)
16757     {
16758         free(current_values);
16759     }
16760
16761     p_data->last_retrieved_frame = end_frame_nr;
16762
16763     return(TNG_SUCCESS);
16764 }
16765
16766 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16767                 (const tng_trajectory_t tng_data,
16768                  const int64_t block_id,
16769                  int64_t frame,
16770                  int64_t *stride_length)
16771 {
16772     tng_function_status stat;
16773     tng_non_particle_data_t np_data;
16774     tng_particle_data_t p_data;
16775     long orig_file_pos, file_pos;
16776     int is_particle_data;
16777
16778     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16779     {
16780         frame = 0;
16781     }
16782
16783     if(frame >= 0)
16784     {
16785         stat = tng_frame_set_of_frame_find(tng_data, frame);
16786         if(stat != TNG_SUCCESS)
16787         {
16788             return(stat);
16789         }
16790     }
16791     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16792     stat = tng_data_find(tng_data, block_id, &np_data);
16793     if(stat != TNG_SUCCESS)
16794     {
16795         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16796         if(stat != TNG_SUCCESS)
16797         {
16798             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16799             /* If no specific frame was required read until this data block is found */
16800             if(frame < 0)
16801             {
16802                 file_pos = ftell(tng_data->input_file);
16803                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16804                 {
16805                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16806                     file_pos = ftell(tng_data->input_file);
16807                 }
16808             }
16809             if(stat != TNG_SUCCESS)
16810             {
16811                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16812
16813                 return(stat);
16814             }
16815             stat = tng_data_find(tng_data, block_id, &np_data);
16816             if(stat != TNG_SUCCESS)
16817             {
16818                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16819                 if(stat != TNG_SUCCESS)
16820                 {
16821                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16822
16823                     return(stat);
16824                 }
16825                 else
16826                 {
16827                     is_particle_data = 1;
16828                 }
16829             }
16830             else
16831             {
16832                 is_particle_data = 0;
16833             }
16834         }
16835         else
16836         {
16837             is_particle_data = 1;
16838         }
16839     }
16840     else
16841     {
16842         is_particle_data = 0;
16843     }
16844     if(is_particle_data)
16845     {
16846         *stride_length = p_data->stride_length;
16847     }
16848     else
16849     {
16850         *stride_length = np_data->stride_length;
16851     }
16852     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16853
16854     return(TNG_SUCCESS);
16855 }
16856
16857 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16858                 (const tng_trajectory_t tng_data,
16859                  char *time)
16860 {
16861     struct tm *time_data;
16862     time_t secs;
16863
16864     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16865     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16866
16867     secs = tng_data->time;
16868
16869     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16870     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16871              "%4d-%02d-%02d %02d:%02d:%02d",
16872              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16873              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16874
16875     return(TNG_SUCCESS);
16876 }
16877
16878
16879 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16880                 (const char *filename,
16881                  const char mode,
16882                  tng_trajectory_t *tng_data_p)
16883 {
16884     tng_function_status stat;
16885
16886     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16887
16888     if(mode != 'r' && mode != 'w' && mode != 'a')
16889     {
16890         return(TNG_FAILURE);
16891     }
16892
16893     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16894     {
16895         tng_trajectory_destroy(tng_data_p);
16896         return(TNG_CRITICAL);
16897     }
16898
16899     if(mode == 'r' || mode == 'a')
16900     {
16901         tng_input_file_set(*tng_data_p, filename);
16902
16903         /* Read the file headers */
16904         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16905
16906         tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16907     }
16908
16909     if(mode == 'w')
16910     {
16911         tng_output_file_set(*tng_data_p, filename);
16912     }
16913     else if(mode == 'a')
16914     {
16915         if((*tng_data_p)->output_file)
16916         {
16917             fclose((*tng_data_p)->output_file);
16918         }
16919         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
16920         fseek((*tng_data_p)->input_file,
16921                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16922                 SEEK_SET);
16923
16924         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16925         if(stat != TNG_SUCCESS)
16926         {
16927             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16928                    __FILE__, __LINE__);
16929         }
16930         (*tng_data_p)->output_file = 0;
16931
16932         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16933         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16934         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16935         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16936         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16937         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16938         if((*tng_data_p)->input_file)
16939         {
16940             fclose((*tng_data_p)->input_file);
16941             (*tng_data_p)->input_file = 0;
16942         }
16943         if((*tng_data_p)->input_file_path)
16944         {
16945             free((*tng_data_p)->input_file_path);
16946             (*tng_data_p)->input_file_path = 0;
16947         }
16948         tng_output_append_file_set(*tng_data_p, filename);
16949
16950         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16951     }
16952
16953     return(TNG_SUCCESS);
16954 }
16955
16956 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
16957                 (tng_trajectory_t *tng_data_p)
16958 {
16959     tng_trajectory_frame_set_t frame_set;
16960
16961     if(tng_data_p == 0)
16962     {
16963         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
16964                __FILE__, __LINE__);
16965         return(TNG_FAILURE);
16966     }
16967
16968     if(*tng_data_p == 0)
16969     {
16970         return(TNG_SUCCESS);
16971     }
16972
16973     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
16974
16975     if(frame_set->n_unwritten_frames > 0)
16976     {
16977         frame_set->n_frames = frame_set->n_unwritten_frames;
16978         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
16979     }
16980
16981     return(tng_trajectory_destroy(tng_data_p));
16982 }
16983
16984 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
16985                 (tng_trajectory_t tng_data,
16986                  const int64_t frame_nr,
16987                  double *time)
16988 {
16989     int64_t first_frame;
16990     tng_trajectory_frame_set_t frame_set;
16991     tng_function_status stat;
16992
16993     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16994     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16995
16996     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
16997     if(stat != TNG_SUCCESS)
16998     {
16999         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
17000                frame_nr, __FILE__, __LINE__);
17001         return(stat);
17002     }
17003
17004     frame_set = &tng_data->current_trajectory_frame_set;
17005     first_frame = frame_set->first_frame;
17006
17007     if(tng_data->time_per_frame <= 0)
17008     {
17009         return(TNG_FAILURE);
17010     }
17011
17012     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
17013
17014     return(TNG_SUCCESS);
17015 }
17016
17017 /*
17018 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
17019                 (tng_trajectory_t tng_data,
17020                  int64_t *n_mols,
17021                  int64_t **molecule_cnt_list,
17022                  tng_molecule_t *mols)
17023 {
17024     tng_trajectory_frame_set_t frame_set;
17025
17026     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17027     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
17028
17029     *n_mols = tng_data->n_molecules;
17030
17031     frame_set = &tng_data->current_trajectory_frame_set;
17032     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
17033     {
17034         *molecule_cnt_list = frame_set->molecule_cnt_list;
17035     }
17036     else
17037     {
17038         *molecule_cnt_list = tng_data->molecule_cnt_list;
17039     }
17040
17041     *mols = tng_data->molecules;
17042
17043     return(TNG_SUCCESS);
17044 }
17045 */
17046 /*
17047 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17048                 (tng_trajectory_t tng_data,
17049                  const char *name,
17050                  const int64_t cnt,
17051                  tng_molecule_t *mol)
17052 {
17053     tng_function_status stat;
17054
17055     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17056     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17057
17058     stat = tng_molecule_add(tng_data, name, mol);
17059     if(stat != TNG_SUCCESS)
17060     {
17061         return(stat);
17062     }
17063     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17064
17065     return(stat);
17066 }
17067 */
17068 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17069                 (tng_trajectory_t tng_data,
17070                  const tng_molecule_t mol,
17071                  int64_t *n_particles,
17072                  char ***names,
17073                  char ***types,
17074                  char ***res_names,
17075                  int64_t **res_ids,
17076                  char ***chain_names,
17077                  int64_t **chain_ids)
17078 {
17079     tng_atom_t atom;
17080     tng_residue_t res;
17081     tng_chain_t chain;
17082     int64_t i;
17083     (void)tng_data;
17084
17085     *n_particles = mol->n_atoms;
17086
17087     *names = malloc(sizeof(char *) * *n_particles);
17088     *types = malloc(sizeof(char *) * *n_particles);
17089     *res_names = malloc(sizeof(char *) * *n_particles);
17090     *chain_names = malloc(sizeof(char *) * *n_particles);
17091     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17092     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17093
17094     for(i = 0; i < *n_particles; i++)
17095     {
17096         atom = &mol->atoms[i];
17097         res = atom->residue;
17098         chain = res->chain;
17099         (*names)[i] = malloc(strlen(atom->name));
17100         strcpy(*names[i], atom->name);
17101         (*types)[i] = malloc(strlen(atom->atom_type));
17102         strcpy(*types[i], atom->atom_type);
17103         (*res_names)[i] = malloc(strlen(res->name));
17104         strcpy(*res_names[i], res->name);
17105         (*chain_names)[i] = malloc(strlen(chain->name));
17106         strcpy(*chain_names[i], chain->name);
17107         (*res_ids)[i] = res->id;
17108         (*chain_ids)[i] = chain->id;
17109     }
17110
17111     return(TNG_SUCCESS);
17112 }
17113
17114 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17115                 (tng_trajectory_t tng_data,
17116                  tng_molecule_t mol,
17117                  const int64_t n_particles,
17118                  const char **names,
17119                  const char **types,
17120                  const char **res_names,
17121                  const int64_t *res_ids,
17122                  const char **chain_names,
17123                  const int64_t *chain_ids)
17124 {
17125     int64_t i;
17126     tng_chain_t chain;
17127     tng_residue_t residue;
17128     tng_atom_t atom;
17129     tng_function_status stat;
17130
17131     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17132     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17133     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17134     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17135     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17136     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17137     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17138
17139     for(i = 0; i < n_particles; i++)
17140     {
17141         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17142            &chain) == TNG_FAILURE)
17143         {
17144             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17145                                           &chain);
17146             if(stat != TNG_SUCCESS)
17147             {
17148                 return(stat);
17149             }
17150         }
17151         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17152            &residue) == TNG_FAILURE)
17153         {
17154             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17155                                          &residue);
17156             if(stat != TNG_SUCCESS)
17157             {
17158                 return(stat);
17159             }
17160         }
17161         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17162         if(stat != TNG_SUCCESS)
17163         {
17164             return(stat);
17165         }
17166     }
17167     return(TNG_SUCCESS);
17168 }
17169
17170 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17171                 (tng_trajectory_t tng_data,
17172                  float **positions, int64_t *stride_length)
17173 {
17174     int64_t n_frames, n_particles, n_values_per_frame;
17175     char type;
17176     tng_function_status stat;
17177
17178     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17179     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17180     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17181
17182     stat = tng_num_frames_get(tng_data, &n_frames);
17183     if(stat != TNG_SUCCESS)
17184     {
17185         return(stat);
17186     }
17187
17188     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17189                                                  0, n_frames - 1, TNG_USE_HASH,
17190                                                  (void **)positions,
17191                                                  &n_particles,
17192                                                  stride_length,
17193                                                  &n_values_per_frame,
17194                                                  &type);
17195
17196     return(stat);
17197 }
17198
17199 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17200                 (tng_trajectory_t tng_data,
17201                  float **velocities, int64_t *stride_length)
17202 {
17203     int64_t n_frames, n_particles, n_values_per_frame;
17204     char type;
17205     tng_function_status stat;
17206
17207     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17208     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17209     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17210
17211     stat = tng_num_frames_get(tng_data, &n_frames);
17212     if(stat != TNG_SUCCESS)
17213     {
17214         return(stat);
17215     }
17216
17217     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17218                                                  0, n_frames - 1, TNG_USE_HASH,
17219                                                  (void **)velocities,
17220                                                  &n_particles,
17221                                                  stride_length,
17222                                                  &n_values_per_frame,
17223                                                  &type);
17224
17225     return(stat);
17226 }
17227
17228 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17229                 (tng_trajectory_t tng_data,
17230                  float **forces, int64_t *stride_length)
17231 {
17232     int64_t n_frames, n_particles, n_values_per_frame;
17233     char type;
17234     tng_function_status stat;
17235
17236     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17237     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17238     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17239
17240     stat = tng_num_frames_get(tng_data, &n_frames);
17241     if(stat != TNG_SUCCESS)
17242     {
17243         return(stat);
17244     }
17245
17246     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17247                                                  0, n_frames - 1, TNG_USE_HASH,
17248                                                  (void **)forces,
17249                                                  &n_particles,
17250                                                  stride_length,
17251                                                  &n_values_per_frame,
17252                                                  &type);
17253
17254     return(stat);
17255 }
17256
17257 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17258                 (tng_trajectory_t tng_data,
17259                  float **box_shape,
17260                  int64_t *stride_length)
17261 {
17262     int64_t n_frames, n_values_per_frame;
17263     char type;
17264     tng_function_status stat;
17265
17266     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17267     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17268     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17269
17270     stat = tng_num_frames_get(tng_data, &n_frames);
17271     if(stat != TNG_SUCCESS)
17272     {
17273         return(stat);
17274     }
17275
17276     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17277                                         0, n_frames - 1, TNG_USE_HASH,
17278                                         (void **)box_shape,
17279                                         stride_length,
17280                                         &n_values_per_frame,
17281                                         &type);
17282
17283     return(stat);
17284 }
17285
17286 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17287                 (tng_trajectory_t tng_data,
17288                  const int64_t block_id,
17289                  void **values,
17290                  char *data_type,
17291                  int64_t *retrieved_frame_number,
17292                  double *retrieved_time)
17293 {
17294     tng_trajectory_frame_set_t frame_set;
17295     tng_particle_data_t data = 0;
17296     tng_function_status stat;
17297     int size;
17298     int64_t i, data_size, n_particles;
17299     void *temp;
17300     long file_pos;
17301
17302     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17303     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17304     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17305     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17306     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17307
17308     frame_set = &tng_data->current_trajectory_frame_set;
17309
17310     stat = tng_particle_data_find(tng_data, block_id, &data);
17311     if(stat != TNG_SUCCESS)
17312     {
17313         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17314         file_pos = ftell(tng_data->input_file);
17315         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17316         {
17317             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17318             file_pos = ftell(tng_data->input_file);
17319         }
17320         if(stat != TNG_SUCCESS)
17321         {
17322             return(stat);
17323         }
17324         stat = tng_particle_data_find(tng_data, block_id, &data);
17325         if(stat != TNG_SUCCESS)
17326         {
17327             return(stat);
17328         }
17329     }
17330     if(data->last_retrieved_frame < 0)
17331     {
17332         fseek(tng_data->input_file,
17333               (long)tng_data->first_trajectory_frame_set_input_file_pos,
17334               SEEK_SET);
17335         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17336         if(stat != TNG_SUCCESS)
17337         {
17338             return(stat);
17339         }
17340         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17341         if(stat != TNG_SUCCESS)
17342         {
17343             return(stat);
17344         }
17345
17346         i = data->first_frame_with_data;
17347     }
17348     else
17349     {
17350         if(data->n_frames == 1)
17351         {
17352             i = data->last_retrieved_frame + 1;
17353         }
17354         else
17355         {
17356             i = data->last_retrieved_frame + data->stride_length;
17357         }
17358         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17359         {
17360             stat = tng_frame_set_of_frame_find(tng_data, i);
17361             if(stat != TNG_SUCCESS)
17362             {
17363                 /* If the frame set search found the frame set after the starting
17364                  * frame set there is a gap in the frame sets. So, even if the frame
17365                  * was not found the next frame with data is still in the found
17366                  * frame set. */
17367                 if(stat == TNG_CRITICAL)
17368                 {
17369                     return(stat);
17370                 }
17371                 i = frame_set->first_frame;
17372             }
17373         }
17374         if(data->last_retrieved_frame < frame_set->first_frame)
17375         {
17376             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17377             if(stat != TNG_SUCCESS)
17378             {
17379                 return(stat);
17380             }
17381         }
17382     }
17383     data->last_retrieved_frame = i;
17384     *retrieved_frame_number = i;
17385     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17386     {
17387         *retrieved_time = frame_set->first_frame_time +
17388                         (i - frame_set->first_frame) *
17389                         tng_data->time_per_frame;
17390     }
17391     else
17392     {
17393         *retrieved_time = 0;
17394     }
17395
17396     if(data->stride_length > 1)
17397     {
17398         i = (i - data->first_frame_with_data) / data->stride_length;
17399     }
17400     else
17401     {
17402         i = (i - frame_set->first_frame);
17403     }
17404
17405     tng_num_particles_get(tng_data, &n_particles);
17406
17407     *data_type = data->datatype;
17408
17409     switch(*data_type)
17410     {
17411     case TNG_CHAR_DATA:
17412         return(TNG_FAILURE);
17413     case TNG_INT_DATA:
17414         size = sizeof(int64_t);
17415         break;
17416     case TNG_FLOAT_DATA:
17417         size = sizeof(float);
17418         break;
17419     case TNG_DOUBLE_DATA:
17420     default:
17421         size = sizeof(double);
17422     }
17423
17424     data_size = size * n_particles * data->n_values_per_frame;
17425
17426 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17427 //            i, data_size, size, n_particles, data->n_values_per_frame);
17428
17429     temp = realloc(*values, data_size);
17430     if(!temp)
17431     {
17432         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17433                data_size, __FILE__, __LINE__);
17434         free(*values);
17435         *values = 0;
17436         return(TNG_CRITICAL);
17437     }
17438
17439     *values = temp;
17440
17441     memcpy(*values, (char *)data->values + i * data_size, data_size);
17442
17443     return(TNG_SUCCESS);
17444 }
17445
17446 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17447                 (tng_trajectory_t tng_data,
17448                  const int64_t block_id,
17449                  void **values,
17450                  char *data_type,
17451                  int64_t *retrieved_frame_number,
17452                  double *retrieved_time)
17453 {
17454     tng_trajectory_frame_set_t frame_set;
17455     tng_non_particle_data_t data = 0;
17456     tng_function_status stat;
17457     int size;
17458     int64_t i, data_size;
17459     void *temp;
17460     long file_pos;
17461
17462     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17463     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17464     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17465     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17466     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17467
17468     frame_set = &tng_data->current_trajectory_frame_set;
17469
17470     stat = tng_data_find(tng_data, block_id, &data);
17471     if(stat != TNG_SUCCESS)
17472     {
17473         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17474         file_pos = ftell(tng_data->input_file);
17475         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17476         {
17477             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17478             file_pos = ftell(tng_data->input_file);
17479         }
17480         if(stat != TNG_SUCCESS)
17481         {
17482             return(stat);
17483         }
17484         stat = tng_data_find(tng_data, block_id, &data);
17485         if(stat != TNG_SUCCESS)
17486         {
17487             return(stat);
17488         }
17489     }
17490     if(data->last_retrieved_frame < 0)
17491     {
17492         fseek(tng_data->input_file,
17493                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
17494                 SEEK_SET);
17495         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17496         if(stat != TNG_SUCCESS)
17497         {
17498             return(stat);
17499         }
17500         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17501         if(stat != TNG_SUCCESS)
17502         {
17503             return(stat);
17504         }
17505
17506         i = data->first_frame_with_data;
17507     }
17508     else
17509     {
17510         if(data->n_frames == 1)
17511         {
17512             i = data->last_retrieved_frame + 1;
17513         }
17514         else
17515         {
17516             i = data->last_retrieved_frame + data->stride_length;
17517         }
17518         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17519         {
17520             stat = tng_frame_set_of_frame_find(tng_data, i);
17521             if(stat != TNG_SUCCESS)
17522             {
17523                 /* If the frame set search found the frame set after the starting
17524                  * frame set there is a gap in the frame sets. So, even if the frame
17525                  * was not found the next frame with data is still in the found
17526                  * frame set. */
17527                 if(stat == TNG_CRITICAL)
17528                 {
17529                     return(stat);
17530                 }
17531                 i = frame_set->first_frame;
17532             }
17533         }
17534         if(data->last_retrieved_frame < frame_set->first_frame)
17535         {
17536             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17537             if(stat != TNG_SUCCESS)
17538             {
17539                 return(stat);
17540             }
17541         }
17542     }
17543     data->last_retrieved_frame = i;
17544     *retrieved_frame_number = i;
17545     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17546     {
17547         *retrieved_time = frame_set->first_frame_time +
17548                         (i - frame_set->first_frame) *
17549                         tng_data->time_per_frame;
17550     }
17551     else
17552     {
17553         *retrieved_time = 0;
17554     }
17555
17556     if(data->stride_length > 1)
17557     {
17558         i = (i - data->first_frame_with_data) / data->stride_length;
17559     }
17560     else
17561     {
17562         i = (i - frame_set->first_frame);
17563     }
17564
17565     *data_type = data->datatype;
17566
17567     switch(*data_type)
17568     {
17569     case TNG_CHAR_DATA:
17570         return(TNG_FAILURE);
17571     case TNG_INT_DATA:
17572         size = sizeof(int64_t);
17573         break;
17574     case TNG_FLOAT_DATA:
17575         size = sizeof(float);
17576         break;
17577     case TNG_DOUBLE_DATA:
17578     default:
17579         size = sizeof(double);
17580     }
17581
17582     data_size = size * data->n_values_per_frame;
17583
17584     temp = realloc(*values, data_size);
17585     if(!temp)
17586     {
17587         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17588                data_size, __FILE__, __LINE__);
17589         free(*values);
17590         *values = 0;
17591         return(TNG_CRITICAL);
17592     }
17593
17594     *values = temp;
17595
17596     memcpy(*values, (char *)data->values + i * data_size, data_size);
17597
17598     return(TNG_SUCCESS);
17599 }
17600
17601 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17602                 (tng_trajectory_t tng_data,
17603                  const int64_t first_frame,
17604                  const int64_t last_frame,
17605                  float **positions,
17606                  int64_t *stride_length)
17607 {
17608     int64_t n_particles, n_values_per_frame;
17609     char type;
17610     tng_function_status stat;
17611
17612     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17613     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17614     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17615     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17616
17617     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17618                                                  first_frame, last_frame,
17619                                                  TNG_USE_HASH,
17620                                                  (void **)positions,
17621                                                  &n_particles,
17622                                                  stride_length,
17623                                                  &n_values_per_frame,
17624                                                  &type);
17625
17626     return(stat);
17627 }
17628
17629 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17630                 (tng_trajectory_t tng_data,
17631                  const int64_t first_frame,
17632                  const int64_t last_frame,
17633                  float **velocities,
17634                  int64_t *stride_length)
17635 {
17636     int64_t n_particles, n_values_per_frame;
17637     char type;
17638     tng_function_status stat;
17639
17640     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17641     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17642     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17643     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17644
17645     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17646                                                  first_frame, last_frame,
17647                                                  TNG_USE_HASH,
17648                                                  (void **)velocities,
17649                                                  &n_particles,
17650                                                  stride_length,
17651                                                  &n_values_per_frame,
17652                                                  &type);
17653
17654     return(stat);
17655 }
17656
17657 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17658                 (tng_trajectory_t tng_data,
17659                  const int64_t first_frame,
17660                  const int64_t last_frame,
17661                  float **forces,
17662                  int64_t *stride_length)
17663 {
17664     int64_t n_particles, n_values_per_frame;
17665     char type;
17666     tng_function_status stat;
17667
17668     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17669     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17670     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17671     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17672
17673     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17674                                                  first_frame, last_frame,
17675                                                  TNG_USE_HASH,
17676                                                  (void **)forces,
17677                                                  &n_particles,
17678                                                  stride_length,
17679                                                  &n_values_per_frame,
17680                                                  &type);
17681
17682     return(stat);
17683 }
17684
17685 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17686                 (tng_trajectory_t tng_data,
17687                  const int64_t first_frame,
17688                  const int64_t last_frame,
17689                  float **box_shape,
17690                  int64_t *stride_length)
17691 {
17692     int64_t n_values_per_frame;
17693     char type;
17694     tng_function_status stat;
17695
17696     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17697     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17698     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17699     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17700
17701     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17702                                         first_frame, last_frame,
17703                                         TNG_USE_HASH,
17704                                         (void **)box_shape,
17705                                         stride_length,
17706                                         &n_values_per_frame,
17707                                         &type);
17708
17709     return(stat);
17710 }
17711
17712 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17713                 (tng_trajectory_t tng_data,
17714                  const int64_t i,
17715                  const int64_t n_values_per_frame,
17716                  const int64_t block_id,
17717                  const char *block_name,
17718                  const char particle_dependency,
17719                  const char compression)
17720 {
17721     tng_trajectory_frame_set_t frame_set;
17722     tng_particle_data_t p_data;
17723     tng_non_particle_data_t np_data;
17724     int64_t n_particles, n_frames;
17725     tng_function_status stat;
17726
17727     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17728     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17729
17730     if(i <= 0)
17731     {
17732         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17733                i, __FILE__, __LINE__);
17734         return(TNG_FAILURE);
17735     }
17736
17737     frame_set = &tng_data->current_trajectory_frame_set;
17738
17739     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17740     {
17741         n_frames = tng_data->frame_set_n_frames;
17742
17743         stat = tng_frame_set_new(tng_data, 0, n_frames);
17744         if(stat != TNG_SUCCESS)
17745         {
17746             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17747                 __LINE__);
17748             return(stat);
17749         }
17750     }
17751     else
17752     {
17753         n_frames = frame_set->n_frames;
17754     }
17755
17756     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17757     {
17758         tng_num_particles_get(tng_data, &n_particles);
17759         if(n_particles <= 0)
17760         {
17761             return(TNG_FAILURE);
17762         }
17763
17764         if(tng_particle_data_find(tng_data, block_id, &p_data)
17765         != TNG_SUCCESS)
17766         {
17767             stat = tng_particle_data_block_add(tng_data, block_id,
17768                                                block_name,
17769                                                TNG_FLOAT_DATA,
17770                                                TNG_TRAJECTORY_BLOCK,
17771                                                n_frames, n_values_per_frame, i,
17772                                                0, n_particles,
17773                                                compression, 0);
17774             if(stat != TNG_SUCCESS)
17775             {
17776                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17777                        __FILE__, __LINE__);
17778                 return(stat);
17779             }
17780             p_data = &frame_set->tr_particle_data[frame_set->
17781                                                   n_particle_data_blocks - 1];
17782             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17783                                                   i, n_particles,
17784                                                   n_values_per_frame);
17785             if(stat != TNG_SUCCESS)
17786             {
17787                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17788                        __FILE__, __LINE__);
17789                 return(stat);
17790             }
17791         }
17792         else
17793         {
17794             if(p_data->stride_length != i)
17795             {
17796                 p_data->stride_length = i;
17797                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17798                                                       i, n_particles,
17799                                                       n_values_per_frame);
17800                 if(stat != TNG_SUCCESS)
17801                 {
17802                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17803                            __FILE__, __LINE__);
17804                     return(stat);
17805                 }
17806             }
17807         }
17808     }
17809     else
17810     {
17811         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17812         {
17813             stat = tng_data_block_add(tng_data, block_id, block_name,
17814                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17815                                       n_frames, n_values_per_frame,
17816                                       i, compression, 0);
17817             if(stat != TNG_SUCCESS)
17818             {
17819                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17820                        __FILE__, __LINE__);
17821                 return(stat);
17822             }
17823             np_data = &frame_set->tr_data[frame_set->
17824                                           n_data_blocks - 1];
17825             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17826                                          i, n_values_per_frame);
17827             if(stat != TNG_SUCCESS)
17828             {
17829                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17830                        __FILE__, __LINE__);
17831                 return(stat);
17832             }
17833         }
17834         else
17835         {
17836             if(np_data->stride_length != i)
17837             {
17838                 np_data->stride_length = i;
17839                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17840                                              i, n_values_per_frame);
17841                 if(stat != TNG_SUCCESS)
17842                 {
17843                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17844                            __FILE__, __LINE__);
17845                     return(stat);
17846                 }
17847             }
17848         }
17849     }
17850
17851     return(TNG_SUCCESS);
17852 }
17853
17854 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17855                 (tng_trajectory_t tng_data,
17856                  const int64_t i,
17857                  const int64_t n_values_per_frame,
17858                  const int64_t block_id,
17859                  const char *block_name,
17860                  const char particle_dependency,
17861                  const char compression)
17862 {
17863     tng_trajectory_frame_set_t frame_set;
17864     tng_particle_data_t p_data;
17865     tng_non_particle_data_t np_data;
17866     int64_t n_particles, n_frames;
17867     tng_function_status stat;
17868
17869     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17870     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17871
17872     if(i <= 0)
17873     {
17874         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17875                i, __FILE__, __LINE__);
17876         return(TNG_FAILURE);
17877     }
17878
17879     frame_set = &tng_data->current_trajectory_frame_set;
17880
17881     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17882     {
17883         n_frames = tng_data->frame_set_n_frames;
17884
17885         stat = tng_frame_set_new(tng_data, 0, n_frames);
17886         if(stat != TNG_SUCCESS)
17887         {
17888             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17889                 __LINE__);
17890             return(stat);
17891         }
17892     }
17893     else
17894     {
17895         n_frames = frame_set->n_frames;
17896     }
17897
17898     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17899     {
17900         tng_num_particles_get(tng_data, &n_particles);
17901
17902         if(n_particles <= 0)
17903         {
17904             return(TNG_FAILURE);
17905         }
17906
17907         if(tng_particle_data_find(tng_data, block_id, &p_data)
17908         != TNG_SUCCESS)
17909         {
17910             stat = tng_particle_data_block_add(tng_data, block_id,
17911                                             block_name,
17912                                             TNG_DOUBLE_DATA,
17913                                             TNG_TRAJECTORY_BLOCK,
17914                                             n_frames, n_values_per_frame, i,
17915                                             0, n_particles,
17916                                             compression, 0);
17917             if(stat != TNG_SUCCESS)
17918             {
17919                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17920                        __FILE__, __LINE__);
17921                 return(stat);
17922             }
17923             p_data = &frame_set->tr_particle_data[frame_set->
17924                                                   n_particle_data_blocks - 1];
17925             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17926                                                   i, n_particles,
17927                                                   n_values_per_frame);
17928             if(stat != TNG_SUCCESS)
17929             {
17930                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17931                        __FILE__, __LINE__);
17932                 return(stat);
17933             }
17934         }
17935         else
17936         {
17937             p_data->stride_length = i;
17938         }
17939     }
17940     else
17941     {
17942         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17943         {
17944             stat = tng_data_block_add(tng_data, block_id, block_name,
17945                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17946                                       n_frames, n_values_per_frame,
17947                                       i, compression, 0);
17948             if(stat != TNG_SUCCESS)
17949             {
17950                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17951                        __FILE__, __LINE__);
17952                 return(stat);
17953             }
17954             np_data = &frame_set->tr_data[frame_set->
17955                                           n_data_blocks - 1];
17956             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17957                                          i, n_values_per_frame);
17958             if(stat != TNG_SUCCESS)
17959             {
17960                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17961                        __FILE__, __LINE__);
17962                 return(stat);
17963             }
17964         }
17965         else
17966         {
17967             np_data->stride_length = i;
17968         }
17969     }
17970
17971     return(TNG_SUCCESS);
17972 }
17973
17974 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
17975                 (tng_trajectory_t tng_data,
17976                  const int64_t i,
17977                  const int64_t n_values_per_frame,
17978                  const int64_t block_id,
17979                  const char *block_name,
17980                  const char particle_dependency,
17981                  const char compression)
17982 {
17983     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
17984            "See documentation. %s: %d", __FILE__, __LINE__);
17985     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
17986                                                block_id, block_name,
17987                                                particle_dependency,
17988                                                compression));
17989 }
17990 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
17991                 (tng_trajectory_t tng_data,
17992                  const int64_t i)
17993 {
17994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17995     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17996
17997     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17998                                                TNG_TRAJ_POSITIONS,
17999                                                "POSITIONS",
18000                                                TNG_PARTICLE_BLOCK_DATA,
18001                                                TNG_TNG_COMPRESSION));
18002 }
18003
18004 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
18005                 (tng_trajectory_t tng_data,
18006                  const int64_t i)
18007 {
18008     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18009     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18010
18011     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18012                                                       TNG_TRAJ_POSITIONS,
18013                                                       "POSITIONS",
18014                                                       TNG_PARTICLE_BLOCK_DATA,
18015                                                       TNG_TNG_COMPRESSION));
18016 }
18017
18018 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
18019                 (tng_trajectory_t tng_data,
18020                  const int64_t i)
18021 {
18022     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
18023            "See documentation. %s: %d", __FILE__, __LINE__);
18024     return(tng_util_pos_write_interval_set(tng_data, i));
18025 }
18026
18027 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
18028                 (tng_trajectory_t tng_data,
18029                  const int64_t i)
18030 {
18031     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18032     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18033
18034     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18035                                                TNG_TRAJ_VELOCITIES,
18036                                                "VELOCITIES",
18037                                                TNG_PARTICLE_BLOCK_DATA,
18038                                                TNG_TNG_COMPRESSION));
18039 }
18040
18041 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
18042                 (tng_trajectory_t tng_data,
18043                  const int64_t i)
18044 {
18045     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18046     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18047
18048     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18049                                                       TNG_TRAJ_VELOCITIES,
18050                                                       "VELOCITIES",
18051                                                       TNG_PARTICLE_BLOCK_DATA,
18052                                                       TNG_TNG_COMPRESSION));
18053 }
18054
18055 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18056                 (tng_trajectory_t tng_data,
18057                  const int64_t i)
18058 {
18059     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18060            "See documentation. %s: %d", __FILE__, __LINE__);
18061     return(tng_util_vel_write_interval_set(tng_data, i));
18062 }
18063
18064 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18065                 (tng_trajectory_t tng_data,
18066                  const int64_t i)
18067 {
18068     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18069     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18070
18071     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18072                                                TNG_TRAJ_FORCES,
18073                                                "FORCES",
18074                                                TNG_PARTICLE_BLOCK_DATA,
18075                                                TNG_GZIP_COMPRESSION));
18076 }
18077
18078 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18079                 (tng_trajectory_t tng_data,
18080                  const int64_t i)
18081 {
18082     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18083     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18084
18085     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18086                                                       TNG_TRAJ_FORCES,
18087                                                       "FORCES",
18088                                                       TNG_PARTICLE_BLOCK_DATA,
18089                                                       TNG_GZIP_COMPRESSION));
18090 }
18091
18092 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18093                 (tng_trajectory_t tng_data,
18094                  const int64_t i)
18095 {
18096     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18097            "See documentation. %s: %d", __FILE__, __LINE__);
18098     return(tng_util_force_write_interval_set(tng_data, i));
18099 }
18100
18101 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18102                 (tng_trajectory_t tng_data,
18103                  const int64_t i)
18104 {
18105     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18106     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18107
18108     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18109                                                TNG_TRAJ_BOX_SHAPE,
18110                                                "BOX SHAPE",
18111                                                TNG_NON_PARTICLE_BLOCK_DATA,
18112                                                TNG_GZIP_COMPRESSION));
18113 }
18114
18115 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18116                 (tng_trajectory_t tng_data,
18117                  const int64_t i)
18118 {
18119     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18120     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18121
18122     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18123                                                       TNG_TRAJ_BOX_SHAPE,
18124                                                       "BOX SHAPE",
18125                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18126                                                       TNG_GZIP_COMPRESSION));
18127 }
18128
18129 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18130                 (tng_trajectory_t tng_data,
18131                  const int64_t i)
18132 {
18133     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18134            "See documentation. %s: %d", __FILE__, __LINE__);
18135     return(tng_util_box_shape_write_interval_set(tng_data, i));
18136 }
18137
18138 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18139                 (tng_trajectory_t tng_data,
18140                  const int64_t frame_nr,
18141                  const float *values,
18142                  const int64_t n_values_per_frame,
18143                  const int64_t block_id,
18144                  const char *block_name,
18145                  const char particle_dependency,
18146                  const char compression)
18147 {
18148     tng_trajectory_frame_set_t frame_set;
18149     tng_particle_data_t p_data;
18150     tng_non_particle_data_t np_data;
18151     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18152     int64_t last_frame;
18153     int is_first_frame_flag = 0;
18154     char block_type_flag;
18155     tng_function_status stat;
18156
18157     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18158     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18159     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18160
18161     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18162     {
18163         tng_num_particles_get(tng_data, &n_particles);
18164         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18165     }
18166
18167     if(values == 0)
18168     {
18169         return(TNG_FAILURE);
18170     }
18171
18172     frame_set = &tng_data->current_trajectory_frame_set;
18173
18174     if(frame_nr < 0)
18175     {
18176         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18177         n_frames = stride_length = 1;
18178     }
18179     else
18180     {
18181         block_type_flag = TNG_TRAJECTORY_BLOCK;
18182
18183         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18184         {
18185             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18186             if(stat != TNG_SUCCESS)
18187             {
18188                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18189                     __LINE__);
18190                 return(stat);
18191             }
18192         }
18193         last_frame = frame_set->first_frame +
18194                      frame_set->n_frames - 1;
18195         if(frame_nr > last_frame)
18196         {
18197             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18198             if(stat != TNG_SUCCESS)
18199             {
18200                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18201                     __LINE__);
18202                 return(stat);
18203             }
18204             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18205             {
18206                 last_frame = frame_nr - 1;
18207             }
18208             stat = tng_frame_set_new(tng_data, last_frame + 1,
18209                                      tng_data->frame_set_n_frames);
18210             if(stat != TNG_SUCCESS)
18211             {
18212                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18213                     __LINE__);
18214                 return(stat);
18215             }
18216         }
18217         if(frame_set->n_unwritten_frames == 0)
18218         {
18219             is_first_frame_flag = 1;
18220         }
18221         frame_set->n_unwritten_frames = frame_nr -
18222                                         frame_set->first_frame + 1;
18223
18224         n_frames = frame_set->n_frames;
18225     }
18226
18227     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18228     {
18229         if(tng_particle_data_find(tng_data, block_id, &p_data)
18230         != TNG_SUCCESS)
18231         {
18232             stat = tng_particle_data_block_add(tng_data, block_id,
18233                                                block_name,
18234                                                TNG_FLOAT_DATA,
18235                                                block_type_flag,
18236                                                n_frames, n_values_per_frame,
18237                                                stride_length,
18238                                                0, n_particles,
18239                                                compression, 0);
18240             if(stat != TNG_SUCCESS)
18241             {
18242                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18243                        __FILE__, __LINE__);
18244                 return(stat);
18245             }
18246             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18247             {
18248                 p_data = &frame_set->tr_particle_data[frame_set->
18249                                                     n_particle_data_blocks - 1];
18250             }
18251             else
18252             {
18253                 p_data = &tng_data->non_tr_particle_data[tng_data->
18254                                                     n_particle_data_blocks - 1];
18255             }
18256             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18257                                                   stride_length, n_particles,
18258                                                   n_values_per_frame);
18259             if(stat != TNG_SUCCESS)
18260             {
18261                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18262                        __FILE__, __LINE__);
18263                 return(stat);
18264             }
18265         }
18266
18267         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18268         {
18269             stride_length = p_data->stride_length;
18270
18271             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18272             {
18273                 p_data->first_frame_with_data = frame_nr;
18274                 frame_pos = 0;
18275             }
18276             else
18277             {
18278                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18279             }
18280
18281             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18282                    n_values_per_frame, values, sizeof(float) *
18283                    n_particles * n_values_per_frame);
18284         }
18285         else
18286         {
18287             memcpy(p_data->values, values, sizeof(float) * n_particles *
18288                    n_values_per_frame);
18289         }
18290     }
18291     else
18292     {
18293         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18294         {
18295             stat = tng_data_block_add(tng_data, block_id, block_name,
18296                                       TNG_FLOAT_DATA, block_type_flag,
18297                                       n_frames, n_values_per_frame,
18298                                       stride_length, compression, 0);
18299             if(stat != TNG_SUCCESS)
18300             {
18301                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18302                        __FILE__, __LINE__);
18303                 return(stat);
18304             }
18305             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18306             {
18307                 np_data = &frame_set->tr_data[frame_set->
18308                                               n_data_blocks - 1];
18309             }
18310             else
18311             {
18312                 np_data = &tng_data->non_tr_data[tng_data->
18313                                                  n_data_blocks - 1];
18314             }
18315             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18316                                          stride_length, n_values_per_frame);
18317             if(stat != TNG_SUCCESS)
18318             {
18319                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18320                        __FILE__, __LINE__);
18321                 return(stat);
18322             }
18323         }
18324
18325         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18326         {
18327             stride_length = np_data->stride_length;
18328
18329             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18330             {
18331                 np_data->first_frame_with_data = frame_nr;
18332                 frame_pos = 0;
18333             }
18334             else
18335             {
18336                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18337             }
18338
18339             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18340                    n_values_per_frame, values, sizeof(float) *
18341                    n_values_per_frame);
18342         }
18343         else
18344         {
18345             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18346         }
18347     }
18348
18349     return(TNG_SUCCESS);
18350 }
18351
18352 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18353                 (tng_trajectory_t tng_data,
18354                  const int64_t frame_nr,
18355                  const double *values,
18356                  const int64_t n_values_per_frame,
18357                  const int64_t block_id,
18358                  const char *block_name,
18359                  const char particle_dependency,
18360                  const char compression)
18361 {
18362     tng_trajectory_frame_set_t frame_set;
18363     tng_particle_data_t p_data;
18364     tng_non_particle_data_t np_data;
18365     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18366     int64_t last_frame;
18367     int is_first_frame_flag = 0;
18368     char block_type_flag;
18369     tng_function_status stat;
18370
18371     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18372     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18373     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18374
18375     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18376     {
18377         tng_num_particles_get(tng_data, &n_particles);
18378         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18379     }
18380
18381     if(values == 0)
18382     {
18383         return(TNG_FAILURE);
18384     }
18385
18386     frame_set = &tng_data->current_trajectory_frame_set;
18387
18388     if(frame_nr < 0)
18389     {
18390         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18391         n_frames = stride_length = 1;
18392     }
18393     else
18394     {
18395         block_type_flag = TNG_TRAJECTORY_BLOCK;
18396
18397         n_frames = tng_data->frame_set_n_frames;
18398
18399         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18400         {
18401             stat = tng_frame_set_new(tng_data, 0, n_frames);
18402             if(stat != TNG_SUCCESS)
18403             {
18404                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18405                     __LINE__);
18406                 return(stat);
18407             }
18408         }
18409         else
18410         {
18411             n_frames = frame_set->n_frames;
18412         }
18413         last_frame = frame_set->first_frame +
18414                      frame_set->n_frames - 1;
18415         if(frame_nr > last_frame)
18416         {
18417             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18418             if(stat != TNG_SUCCESS)
18419             {
18420                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18421                     __LINE__);
18422                 return(stat);
18423             }
18424             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18425             {
18426                 last_frame = frame_nr - 1;
18427             }
18428             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18429             if(stat != TNG_SUCCESS)
18430             {
18431                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18432                     __LINE__);
18433                 return(stat);
18434             }
18435         }
18436         if(frame_set->n_unwritten_frames == 0)
18437         {
18438             is_first_frame_flag = 1;
18439         }
18440         frame_set->n_unwritten_frames = frame_nr -
18441                                         frame_set->first_frame + 1;
18442     }
18443
18444     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18445     {
18446         if(tng_particle_data_find(tng_data, block_id, &p_data)
18447         != TNG_SUCCESS)
18448         {
18449             stat = tng_particle_data_block_add(tng_data, block_id,
18450                                             block_name,
18451                                             TNG_DOUBLE_DATA,
18452                                             block_type_flag,
18453                                             n_frames, n_values_per_frame,
18454                                             stride_length,
18455                                             0, n_particles,
18456                                             compression, 0);
18457             if(stat != TNG_SUCCESS)
18458             {
18459                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18460                        __FILE__, __LINE__);
18461                 return(stat);
18462             }
18463             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18464             {
18465                 p_data = &frame_set->tr_particle_data[frame_set->
18466                                                     n_particle_data_blocks - 1];
18467             }
18468             else
18469             {
18470                 p_data = &tng_data->non_tr_particle_data[tng_data->
18471                                                     n_particle_data_blocks - 1];
18472             }
18473             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18474                                                   stride_length, n_particles,
18475                                                   n_values_per_frame);
18476             if(stat != TNG_SUCCESS)
18477             {
18478                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18479                        __FILE__, __LINE__);
18480                 return(stat);
18481             }
18482         }
18483
18484         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18485         {
18486             stride_length = p_data->stride_length;
18487
18488             if(is_first_frame_flag)
18489             {
18490                 p_data->first_frame_with_data = frame_nr;
18491                 frame_pos = 0;
18492             }
18493             else
18494             {
18495                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18496             }
18497
18498             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18499                    n_values_per_frame, values, sizeof(double) *
18500                    n_particles * n_values_per_frame);
18501         }
18502         else
18503         {
18504             memcpy(p_data->values, values, sizeof(double) * n_particles *
18505                    n_values_per_frame);
18506         }
18507     }
18508     else
18509     {
18510         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18511         {
18512             stat = tng_data_block_add(tng_data, block_id, block_name,
18513                                       TNG_DOUBLE_DATA, block_type_flag,
18514                                       n_frames, n_values_per_frame,
18515                                       stride_length, compression, 0);
18516             if(stat != TNG_SUCCESS)
18517             {
18518                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18519                        __FILE__, __LINE__);
18520                 return(stat);
18521             }
18522             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18523             {
18524                 np_data = &frame_set->tr_data[frame_set->
18525                                               n_data_blocks - 1];
18526             }
18527             else
18528             {
18529                 np_data = &tng_data->non_tr_data[tng_data->
18530                                                  n_data_blocks - 1];
18531             }
18532             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18533                                          stride_length, n_values_per_frame);
18534             if(stat != TNG_SUCCESS)
18535             {
18536                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18537                        __FILE__, __LINE__);
18538                 return(stat);
18539             }
18540         }
18541
18542         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18543         {
18544             stride_length = np_data->stride_length;
18545
18546             if(is_first_frame_flag)
18547             {
18548                 np_data->first_frame_with_data = frame_nr;
18549                 frame_pos = 0;
18550             }
18551             else
18552             {
18553                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18554             }
18555
18556             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18557                    n_values_per_frame, values, sizeof(double) *
18558                    n_values_per_frame);
18559         }
18560         else
18561         {
18562             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18563         }
18564     }
18565
18566     return(TNG_SUCCESS);
18567 }
18568
18569 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18570                 (tng_trajectory_t tng_data,
18571                  const int64_t frame_nr,
18572                  const float *positions)
18573 {
18574     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18575     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18576     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18577
18578     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18579                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18580                                   TNG_PARTICLE_BLOCK_DATA,
18581                                   TNG_TNG_COMPRESSION));
18582 }
18583
18584 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18585                 (tng_trajectory_t tng_data,
18586                  const int64_t frame_nr,
18587                  const double *positions)
18588 {
18589     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18590     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18591     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18592
18593     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18594                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18595                                          TNG_PARTICLE_BLOCK_DATA,
18596                                          TNG_TNG_COMPRESSION));
18597 }
18598
18599 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18600                 (tng_trajectory_t tng_data,
18601                  const int64_t frame_nr,
18602                  const float *velocities)
18603 {
18604     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18605     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18606     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18607
18608     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18609                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18610                                   TNG_PARTICLE_BLOCK_DATA,
18611                                   TNG_TNG_COMPRESSION));
18612 }
18613
18614 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18615                 (tng_trajectory_t tng_data,
18616                  const int64_t frame_nr,
18617                  const double *velocities)
18618 {
18619     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18620     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18621     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18622
18623     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18624                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18625                                          TNG_PARTICLE_BLOCK_DATA,
18626                                          TNG_TNG_COMPRESSION));
18627 }
18628
18629 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18630                 (tng_trajectory_t tng_data,
18631                  const int64_t frame_nr,
18632                  const float *forces)
18633 {
18634     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18635     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18636     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18637
18638     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18639                                   TNG_TRAJ_FORCES, "FORCES",
18640                                   TNG_PARTICLE_BLOCK_DATA,
18641                                   TNG_GZIP_COMPRESSION));
18642 }
18643
18644 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18645                 (tng_trajectory_t tng_data,
18646                  const int64_t frame_nr,
18647                  const double *forces)
18648 {
18649     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18650     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18651     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18652
18653     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18654                                          TNG_TRAJ_FORCES, "FORCES",
18655                                          TNG_PARTICLE_BLOCK_DATA,
18656                                          TNG_GZIP_COMPRESSION));
18657 }
18658
18659 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18660                 (tng_trajectory_t tng_data,
18661                  const int64_t frame_nr,
18662                  const float *box_shape)
18663 {
18664     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18665     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18666     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18667
18668     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18669                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18670                                   TNG_NON_PARTICLE_BLOCK_DATA,
18671                                   TNG_GZIP_COMPRESSION));
18672 }
18673
18674 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18675                 (tng_trajectory_t tng_data,
18676                  const int64_t frame_nr,
18677                  const double *box_shape)
18678 {
18679     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18680     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18681     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18682
18683     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18684                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18685                                          TNG_NON_PARTICLE_BLOCK_DATA,
18686                                          TNG_GZIP_COMPRESSION));
18687 }
18688
18689 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18690                 (tng_trajectory_t tng_data,
18691                  const int64_t frame_nr,
18692                  const double time,
18693                  const float *values,
18694                  const int64_t n_values_per_frame,
18695                  const int64_t block_id,
18696                  const char *block_name,
18697                  const char particle_dependency,
18698                  const char compression)
18699 {
18700     tng_trajectory_frame_set_t frame_set;
18701     tng_function_status stat;
18702
18703     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18704     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18705     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18706     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18707
18708     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18709                                   block_id, block_name,
18710                                   particle_dependency,
18711                                   compression);
18712
18713     if(stat != TNG_SUCCESS)
18714     {
18715         return(stat);
18716     }
18717
18718     frame_set = &tng_data->current_trajectory_frame_set;
18719
18720     /* first_frame_time is -1 when it is not yet set. */
18721     if(frame_set->first_frame_time < -0.1)
18722     {
18723         if(frame_nr > frame_set->first_frame)
18724         {
18725             stat = tng_frame_set_first_frame_time_set(tng_data,
18726                                                       time -
18727                                                       (frame_nr -
18728                                                        frame_set->first_frame) *
18729                                                       tng_data->time_per_frame);
18730         }
18731         else
18732         {
18733             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18734         }
18735     }
18736     return(stat);
18737 }
18738
18739 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18740                 (tng_trajectory_t tng_data,
18741                  const int64_t frame_nr,
18742                  const double time,
18743                  const double *values,
18744                  const int64_t n_values_per_frame,
18745                  const int64_t block_id,
18746                  const char *block_name,
18747                  const char particle_dependency,
18748                  const char compression)
18749 {
18750     tng_trajectory_frame_set_t frame_set;
18751     tng_function_status stat;
18752
18753     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18754     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18755     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18756     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18757
18758     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18759                                          block_id, block_name,
18760                                          particle_dependency,
18761                                          compression);
18762
18763     if(stat != TNG_SUCCESS)
18764     {
18765         return(stat);
18766     }
18767
18768     frame_set = &tng_data->current_trajectory_frame_set;
18769
18770     /* first_frame_time is -1 when it is not yet set. */
18771     if(frame_set->first_frame_time < -0.1)
18772     {
18773         if(frame_nr > frame_set->first_frame)
18774         {
18775             stat = tng_frame_set_first_frame_time_set(tng_data,
18776                                                       time -
18777                                                       (frame_nr -
18778                                                        frame_set->first_frame) *
18779                                                       tng_data->time_per_frame);
18780         }
18781         else
18782         {
18783             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18784         }
18785     }
18786     return(stat);
18787 }
18788
18789 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18790                 (tng_trajectory_t tng_data,
18791                  const int64_t frame_nr,
18792                  const double time,
18793                  const float *positions)
18794 {
18795     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18796     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18797     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18798     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18799
18800     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18801                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18802                                             TNG_PARTICLE_BLOCK_DATA,
18803                                             TNG_TNG_COMPRESSION));
18804 }
18805
18806 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18807                 (tng_trajectory_t tng_data,
18808                  const int64_t frame_nr,
18809                  const double time,
18810                  const double *positions)
18811 {
18812     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18813     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18814     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18815     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18816
18817     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18818                                                    positions, 3,
18819                                                    TNG_TRAJ_POSITIONS,
18820                                                    "POSITIONS",
18821                                                    TNG_PARTICLE_BLOCK_DATA,
18822                                                    TNG_TNG_COMPRESSION));
18823 }
18824
18825 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18826                 (tng_trajectory_t tng_data,
18827                  const int64_t frame_nr,
18828                  const double time,
18829                  const float *velocities)
18830 {
18831     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18832     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18833     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18834     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18835
18836     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18837                                             velocities, 3,
18838                                             TNG_TRAJ_VELOCITIES,
18839                                             "VELOCITIES",
18840                                             TNG_PARTICLE_BLOCK_DATA,
18841                                             TNG_TNG_COMPRESSION));
18842 }
18843
18844 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18845                 (tng_trajectory_t tng_data,
18846                  const int64_t frame_nr,
18847                  const double time,
18848                  const double *velocities)
18849 {
18850     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18851     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18852     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18853     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18854
18855     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18856                                                    velocities, 3,
18857                                                    TNG_TRAJ_VELOCITIES,
18858                                                    "VELOCITIES",
18859                                                    TNG_PARTICLE_BLOCK_DATA,
18860                                                    TNG_TNG_COMPRESSION));
18861 }
18862
18863 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18864                 (tng_trajectory_t tng_data,
18865                  const int64_t frame_nr,
18866                  const double time,
18867                  const float *forces)
18868 {
18869     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18870     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18871     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18872     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18873
18874     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18875                                             3, TNG_TRAJ_FORCES, "FORCES",
18876                                             TNG_PARTICLE_BLOCK_DATA,
18877                                             TNG_GZIP_COMPRESSION));
18878 }
18879
18880 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18881                 (tng_trajectory_t tng_data,
18882                  const int64_t frame_nr,
18883                  const double time,
18884                  const double *forces)
18885 {
18886     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18887     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18888     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18889     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18890
18891     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18892                                                    forces, 3,
18893                                                    TNG_TRAJ_FORCES, "FORCES",
18894                                                    TNG_PARTICLE_BLOCK_DATA,
18895                                                    TNG_GZIP_COMPRESSION));
18896 }
18897
18898 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18899                 (tng_trajectory_t tng_data,
18900                  const int64_t frame_nr,
18901                  const double time,
18902                  const float *box_shape)
18903 {
18904     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18905     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18906     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18907     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18908
18909     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18910                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18911                                             TNG_NON_PARTICLE_BLOCK_DATA,
18912                                             TNG_GZIP_COMPRESSION));
18913 }
18914
18915 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18916                 (tng_trajectory_t tng_data,
18917                  const int64_t frame_nr,
18918                  const double time,
18919                  const double *box_shape)
18920 {
18921     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18922     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18923     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18924     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18925
18926     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18927                                                    time, box_shape, 9,
18928                                                    TNG_TRAJ_BOX_SHAPE,
18929                                                    "BOX SHAPE",
18930                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18931                                                    TNG_GZIP_COMPRESSION));
18932 }
18933
18934 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18935                 (tng_trajectory_t tng_data,
18936                  const int64_t block_id,
18937                  int64_t *codec_id,
18938                  double *factor)
18939 {
18940     tng_trajectory_frame_set_t frame_set;
18941     tng_particle_data_t p_data = 0;
18942     tng_non_particle_data_t np_data = 0;
18943     tng_function_status stat;
18944     int64_t i;
18945     int block_type = -1;
18946
18947     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18948     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
18949     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
18950
18951     frame_set = &tng_data->current_trajectory_frame_set;
18952
18953     stat = tng_particle_data_find(tng_data, block_id, &p_data);
18954     if(stat == TNG_SUCCESS)
18955     {
18956         block_type = TNG_PARTICLE_BLOCK_DATA;
18957     }
18958     else
18959     {
18960         stat = tng_data_find(tng_data, block_id, &np_data);
18961         if(stat == TNG_SUCCESS)
18962         {
18963             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18964         }
18965         else
18966         {
18967             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18968             if(stat != TNG_SUCCESS)
18969             {
18970                 return(stat);
18971             }
18972             stat = tng_particle_data_find(tng_data, block_id, &p_data);
18973             if(stat == TNG_SUCCESS)
18974             {
18975                 block_type = TNG_PARTICLE_BLOCK_DATA;
18976             }
18977             else
18978             {
18979                 stat = tng_data_find(tng_data, block_id, &np_data);
18980                 if(stat == TNG_SUCCESS)
18981                 {
18982                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18983                 }
18984                 else
18985                 {
18986                     return(stat);
18987                 }
18988             }
18989         }
18990     }
18991     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18992     {
18993         if(p_data->last_retrieved_frame < 0)
18994         {
18995             i = p_data->first_frame_with_data;
18996         }
18997         else
18998         {
18999             i = p_data->last_retrieved_frame;
19000         }
19001     }
19002     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19003     {
19004         if(np_data->last_retrieved_frame < 0)
19005         {
19006             i = np_data->first_frame_with_data;
19007         }
19008         else
19009         {
19010             i = np_data->last_retrieved_frame;
19011         }
19012     }
19013     else
19014     {
19015         return(TNG_FAILURE);
19016     }
19017     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
19018     {
19019         stat = tng_frame_set_of_frame_find(tng_data, i);
19020         if(stat != TNG_SUCCESS)
19021         {
19022             return(stat);
19023         }
19024         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19025         if(stat != TNG_SUCCESS)
19026         {
19027             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19028                 __FILE__, __LINE__);
19029             return(stat);
19030         }
19031     }
19032     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19033     {
19034         *codec_id = p_data->codec_id;
19035         *factor   = p_data->compression_multiplier;
19036     }
19037     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19038     {
19039         *codec_id = np_data->codec_id;
19040         *factor   = np_data->compression_multiplier;
19041     }
19042     return(TNG_SUCCESS);
19043 }
19044
19045 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19046                 (tng_trajectory_t tng_data,
19047                  int64_t current_frame,
19048                  const int64_t n_requested_data_block_ids,
19049                  const int64_t *requested_data_block_ids,
19050                  int64_t *next_frame,
19051                  int64_t *n_data_blocks_in_next_frame,
19052                  int64_t **data_block_ids_in_next_frame)
19053 {
19054     tng_trajectory_frame_set_t frame_set;
19055     tng_function_status stat;
19056     tng_particle_data_t p_data;
19057     tng_non_particle_data_t np_data;
19058     tng_gen_block_t block;
19059     int64_t i, j, block_id, *temp;
19060     int64_t data_frame, frame_diff, min_diff;
19061     int64_t size, frame_set_file_pos;
19062     int found, read_all = 0;
19063     long file_pos;
19064
19065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19066     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19067     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19068     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19069
19070     if(n_requested_data_block_ids)
19071     {
19072         TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
19073         size = sizeof(int64_t) * n_requested_data_block_ids;
19074         temp = realloc(*data_block_ids_in_next_frame, size);
19075         if(!temp)
19076         {
19077             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19078                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19079                     __FILE__, __LINE__);
19080             free(*data_block_ids_in_next_frame);
19081             *data_block_ids_in_next_frame = 0;
19082             return(TNG_CRITICAL);
19083         }
19084         *data_block_ids_in_next_frame = temp;
19085     }
19086
19087     frame_set = &tng_data->current_trajectory_frame_set;
19088
19089     current_frame += 1;
19090
19091     if(current_frame < frame_set->first_frame ||
19092        current_frame >= frame_set->first_frame + frame_set->n_frames)
19093     {
19094         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19095         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19096         if(stat != TNG_SUCCESS)
19097         {
19098             /* If the frame set search found the frame set after the starting
19099              * frame set there is a gap in the frame sets. So, even if the frame
19100              * was not found the next frame with data is still in the found
19101              * frame set. */
19102             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19103                frame_set_file_pos)
19104             {
19105                 return(stat);
19106             }
19107             current_frame = frame_set->first_frame;
19108         }
19109     }
19110
19111     /* Check for data blocks only if they have not already been found. */
19112     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19113     {
19114         file_pos = ftell(tng_data->input_file);
19115         if(file_pos < tng_data->input_file_len)
19116         {
19117             tng_block_init(&block);
19118             stat = tng_block_header_read(tng_data, block);
19119             while(file_pos < tng_data->input_file_len &&
19120                 stat != TNG_CRITICAL &&
19121                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19122                 block->id != -1)
19123             {
19124                 stat = tng_block_read_next(tng_data, block,
19125                                         TNG_USE_HASH);
19126                 if(stat != TNG_CRITICAL)
19127                 {
19128                     file_pos = ftell(tng_data->input_file);
19129                     if(file_pos < tng_data->input_file_len)
19130                     {
19131                         stat = tng_block_header_read(tng_data, block);
19132                     }
19133                 }
19134             }
19135             tng_block_destroy(&block);
19136             if(stat == TNG_CRITICAL)
19137             {
19138                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
19139                         file_pos, __FILE__, __LINE__);
19140                 return(stat);
19141             }
19142         }
19143         read_all = 1;
19144     }
19145
19146     min_diff = -1;
19147
19148     *n_data_blocks_in_next_frame = 0;
19149
19150     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19151     {
19152         p_data = &frame_set->tr_particle_data[i];
19153         block_id = p_data->block_id;
19154
19155         if(n_requested_data_block_ids > 0)
19156         {
19157             found = 0;
19158             for(j = 0; j < n_requested_data_block_ids; j++)
19159             {
19160                 if(block_id == requested_data_block_ids[j])
19161                 {
19162                     found = 1;
19163                     break;
19164                 }
19165             }
19166             if(!found)
19167             {
19168                 continue;
19169             }
19170         }
19171
19172         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19173            p_data->last_retrieved_frame >=
19174            frame_set->first_frame + frame_set->n_frames))
19175         {
19176             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19177                                                                       TNG_USE_HASH, block_id);
19178             if(stat == TNG_CRITICAL)
19179             {
19180                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19181                     __FILE__, __LINE__);
19182                 return(stat);
19183             }
19184             if(stat == TNG_FAILURE)
19185             {
19186                 continue;
19187             }
19188         }
19189         if(frame_set->first_frame != current_frame &&
19190            p_data->last_retrieved_frame >= 0)
19191         {
19192             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19193         }
19194         else
19195         {
19196             data_frame = p_data->first_frame_with_data;
19197         }
19198         frame_diff = data_frame - current_frame;
19199         if(frame_diff < 0)
19200         {
19201             continue;
19202         }
19203         if(min_diff == -1 || frame_diff <= min_diff)
19204         {
19205             if(frame_diff < min_diff)
19206             {
19207                 *n_data_blocks_in_next_frame = 1;
19208             }
19209             else
19210             {
19211                 *n_data_blocks_in_next_frame += 1;
19212             }
19213             if(n_requested_data_block_ids <= 0)
19214             {
19215                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19216                 temp = realloc(*data_block_ids_in_next_frame, size);
19217                 if(!temp)
19218                 {
19219                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19220                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19221                            __FILE__, __LINE__);
19222                     free(*data_block_ids_in_next_frame);
19223                     *data_block_ids_in_next_frame = 0;
19224                     return(TNG_CRITICAL);
19225                 }
19226                 *data_block_ids_in_next_frame = temp;
19227             }
19228             else
19229             {
19230                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19231             }
19232             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19233
19234             min_diff = frame_diff;
19235         }
19236     }
19237     for(i = 0; i < frame_set->n_data_blocks; i++)
19238     {
19239         np_data = &frame_set->tr_data[i];
19240         block_id = np_data->block_id;
19241
19242         if(n_requested_data_block_ids > 0)
19243         {
19244             found = 0;
19245             for(j = 0; j < n_requested_data_block_ids; j++)
19246             {
19247                 if(block_id == requested_data_block_ids[j])
19248                 {
19249                     found = 1;
19250                     break;
19251                 }
19252             }
19253             if(!found)
19254             {
19255                 continue;
19256             }
19257         }
19258
19259         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19260            np_data->last_retrieved_frame >=
19261            frame_set->first_frame + frame_set->n_frames))
19262         {
19263             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19264                                                                       TNG_USE_HASH, block_id);
19265             if(stat == TNG_CRITICAL)
19266             {
19267                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19268                     __FILE__, __LINE__);
19269                 return(stat);
19270             }
19271             if(stat == TNG_FAILURE)
19272             {
19273                 continue;
19274             }
19275         }
19276         if(frame_set->first_frame != current_frame &&
19277            np_data->last_retrieved_frame >= 0)
19278         {
19279             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19280         }
19281         else
19282         {
19283             data_frame = np_data->first_frame_with_data;
19284         }
19285         frame_diff = data_frame - current_frame;
19286         if(frame_diff < 0)
19287         {
19288             continue;
19289         }
19290         if(min_diff == -1 || frame_diff <= min_diff)
19291         {
19292             if(frame_diff < min_diff)
19293             {
19294                 *n_data_blocks_in_next_frame = 1;
19295             }
19296             else
19297             {
19298                 *n_data_blocks_in_next_frame += 1;
19299             }
19300             if(n_requested_data_block_ids <= 0)
19301             {
19302                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19303                 temp = realloc(*data_block_ids_in_next_frame, size);
19304                 if(!temp)
19305                 {
19306                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19307                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19308                            __FILE__, __LINE__);
19309                     free(*data_block_ids_in_next_frame);
19310                     *data_block_ids_in_next_frame = 0;
19311                     return(TNG_CRITICAL);
19312                 }
19313                 *data_block_ids_in_next_frame = temp;
19314             }
19315             else
19316             {
19317                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19318             }
19319             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19320
19321             min_diff = frame_diff;
19322         }
19323     }
19324     if(min_diff < 0)
19325     {
19326         return(TNG_FAILURE);
19327     }
19328     *next_frame = current_frame + min_diff;
19329
19330     return(TNG_SUCCESS);
19331 }
19332
19333 /*
19334 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19335                 (tng_trajectory_t tng_data,
19336                  int64_t *n_data_blocks,
19337                  int64_t **data_block_ids,
19338                  char ***data_block_names,
19339                  int64_t **stride_lengths,
19340                  int64_t **n_values_per_frame,
19341                  char **block_types,
19342                  char **dependencies,
19343                  char **compressions)
19344 {
19345     tng_gen_block_t block;
19346     long orig_file_pos, file_pos;
19347
19348     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19349     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19350     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19351     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19352     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19353
19354     orig_file_pos = ftell(tng_data->input_file);
19355
19356     if(!tng_data->input_file_len)
19357     {
19358         fseek(tng_data->input_file, 0, SEEK_END);
19359         tng_data->input_file_len = ftell(tng_data->input_file);
19360     }
19361
19362     fseek(tng_data->input_file, 0, SEEK_SET);
19363     file_pos = 0;
19364
19365     *n_data_blocks = 0;
19366
19367     tng_block_init(&block);
19368
19369     while(file_pos < tng_data->input_file_len &&
19370           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19371     {
19372         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19373         {
19374
19375         }
19376         file_pos += (long)(block->block_contents_size + block->header_contents_size);
19377         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
19378     }
19379
19380     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
19381
19382     return(TNG_SUCCESS);
19383 }
19384 */
19385 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19386                 (tng_trajectory_t tng_data,
19387                  const int64_t prev_frame)
19388 {
19389     tng_function_status stat;
19390     FILE *temp = tng_data->input_file;
19391
19392     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19393     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19394
19395     tng_data->input_file = tng_data->output_file;
19396
19397     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19398     if(stat != TNG_SUCCESS)
19399     {
19400         return(stat);
19401     }
19402
19403     tng_data->current_trajectory_frame_set_output_file_pos =
19404     tng_data->current_trajectory_frame_set_input_file_pos;
19405
19406     tng_data->input_file = temp;
19407
19408     return(TNG_SUCCESS);
19409 }