Fixed TNG memory alignment problem and reset pointers.
[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, *temp_data_contents;
4766     int64_t algo_find_n_frames, compressed_len;
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     compressed_len = block->block_contents_size - (int64_t)((char *)start_pos - (char *)block->block_contents);
4795     temp_data_contents = malloc(compressed_len);
4796     if(!temp_data_contents)
4797     {
4798         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4799                 compressed_len, __FILE__, __LINE__);
4800         return(TNG_CRITICAL);
4801     }
4802
4803     memcpy(temp_data_contents, (char *)start_pos, compressed_len);
4804
4805     if(block->id == TNG_TRAJ_POSITIONS)
4806     {
4807         /* If there is only one frame in this frame set and there might be more
4808          * do not store the algorithm as the compression algorithm, but find
4809          * the best one without storing it */
4810         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4811         {
4812             nalgo = tng_compress_nalgo();
4813             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4814             if(type == TNG_FLOAT_DATA)
4815             {
4816                 dest = tng_compress_pos_float_find_algo((float *)temp_data_contents, (int)n_particles,
4817                                                         (int)n_frames,
4818                                                         f_precision,
4819                                                         0, alt_algo,
4820                                                         &new_len);
4821
4822             }
4823             else
4824             {
4825                 dest = tng_compress_pos_find_algo((double *)temp_data_contents, (int)n_particles,
4826                                            (int)n_frames,
4827                                            d_precision,
4828                                            0, alt_algo,
4829                                            &new_len);
4830             }
4831         }
4832         else if(!tng_data->compress_algo_pos)
4833         {
4834             if(n_frames > 10)
4835             {
4836                 algo_find_n_frames = 5;
4837             }
4838             else
4839             {
4840                 algo_find_n_frames = n_frames;
4841             }
4842
4843             nalgo = tng_compress_nalgo();
4844             tng_data->compress_algo_pos=malloc(nalgo *
4845                                            sizeof *tng_data->compress_algo_pos);
4846             if(type == TNG_FLOAT_DATA)
4847             {
4848                 dest = tng_compress_pos_float_find_algo((float *)temp_data_contents, (int)n_particles,
4849                                                         (int)algo_find_n_frames,
4850                                                         f_precision,
4851                                                         0, tng_data->
4852                                                         compress_algo_pos,
4853                                                         &new_len);
4854
4855                 if(algo_find_n_frames < n_frames)
4856                 {
4857                     dest = tng_compress_pos_float((float *)temp_data_contents, (int)n_particles,
4858                                                   (int)n_frames,
4859                                                   f_precision,
4860                                                   0, tng_data->compress_algo_pos,
4861                                                   &new_len);
4862                 }
4863             }
4864             else
4865             {
4866                 dest = tng_compress_pos_find_algo((double *)temp_data_contents, (int)n_particles,
4867                                            (int)algo_find_n_frames,
4868                                            d_precision,
4869                                            0, tng_data->
4870                                            compress_algo_pos,
4871                                            &new_len);
4872
4873                 if(algo_find_n_frames < n_frames)
4874                 {
4875                     dest = tng_compress_pos((double *)temp_data_contents, (int)n_particles,
4876                                             (int)n_frames,
4877                                             d_precision, 0,
4878                                             tng_data->compress_algo_pos,
4879                                             &new_len);
4880                 }
4881             }
4882         }
4883         else
4884         {
4885             if(type == TNG_FLOAT_DATA)
4886             {
4887                 dest = tng_compress_pos_float((float *)temp_data_contents, (int)n_particles,
4888                                               (int)n_frames,
4889                                               f_precision, 0,
4890                                               tng_data->compress_algo_pos, &new_len);
4891             }
4892             else
4893             {
4894                 dest = tng_compress_pos((double *)temp_data_contents, (int)n_particles,
4895                                         (int)n_frames,
4896                                         d_precision, 0,
4897                                         tng_data->compress_algo_pos,
4898                                         &new_len);
4899             }
4900         }
4901     }
4902     else if(block->id == TNG_TRAJ_VELOCITIES)
4903     {
4904         /* If there is only one frame in this frame set and there might be more
4905          * do not store the algorithm as the compression algorithm, but find
4906          * the best one without storing it */
4907         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4908         {
4909             nalgo = tng_compress_nalgo();
4910             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4911             if(type == TNG_FLOAT_DATA)
4912             {
4913                 dest = tng_compress_vel_float_find_algo((float *)temp_data_contents, (int)n_particles,
4914                                                         (int)n_frames,
4915                                                         f_precision,
4916                                                         0, alt_algo,
4917                                                         &new_len);
4918
4919             }
4920             else
4921             {
4922                 dest = tng_compress_vel_find_algo((double *)temp_data_contents, (int)n_particles,
4923                                                   (int)n_frames,
4924                                                   d_precision,
4925                                                   0, alt_algo,
4926                                                   &new_len);
4927             }
4928         }
4929         else if(!tng_data->compress_algo_vel)
4930         {
4931             if(n_frames > 10)
4932             {
4933                 algo_find_n_frames = 5;
4934             }
4935             else
4936             {
4937                 algo_find_n_frames = n_frames;
4938             }
4939
4940             nalgo = tng_compress_nalgo();
4941             tng_data->compress_algo_vel=malloc(nalgo *
4942                                            sizeof *tng_data->compress_algo_vel);
4943
4944             if(type == TNG_FLOAT_DATA)
4945             {
4946                 dest = tng_compress_vel_float_find_algo((float *)temp_data_contents, (int)n_particles,
4947                                                         (int)algo_find_n_frames,
4948                                                         f_precision,
4949                                                         0, tng_data->
4950                                                         compress_algo_vel,
4951                                                         &new_len);
4952                 if(algo_find_n_frames < n_frames)
4953                 {
4954                     dest = tng_compress_vel_float((float *)temp_data_contents, (int)n_particles,
4955                                                   (int)n_frames,
4956                                                   f_precision,
4957                                                   0, tng_data->compress_algo_vel,
4958                                                   &new_len);
4959                 }
4960             }
4961             else
4962             {
4963                 dest = tng_compress_vel_find_algo((double *)temp_data_contents, (int)n_particles,
4964                                                   (int)algo_find_n_frames,
4965                                                   d_precision,
4966                                                   0, tng_data->
4967                                                   compress_algo_vel,
4968                                                   &new_len);
4969                 if(algo_find_n_frames < n_frames)
4970                 {
4971                     dest = tng_compress_vel((double *)temp_data_contents, (int)n_particles,
4972                                             (int)n_frames,
4973                                             d_precision,
4974                                             0, tng_data->compress_algo_vel,
4975                                             &new_len);
4976                 }
4977             }
4978         }
4979         else
4980         {
4981             if(type == TNG_FLOAT_DATA)
4982             {
4983                 dest = tng_compress_vel_float((float *)temp_data_contents, (int)n_particles,
4984                                               (int)n_frames,
4985                                               f_precision,
4986                                               0, tng_data->
4987                                               compress_algo_vel,
4988                                               &new_len);
4989             }
4990             else
4991             {
4992                 dest = tng_compress_vel((double *)temp_data_contents, (int)n_particles,
4993                                         (int)n_frames,
4994                                         d_precision,
4995                                         0, tng_data->
4996                                         compress_algo_vel,
4997                                         &new_len);
4998             }
4999         }
5000     }
5001     else
5002     {
5003         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
5004         free(temp_data_contents);
5005         return(TNG_FAILURE);
5006     }
5007
5008     offset = (unsigned long)((char *)start_pos - block->block_contents);
5009
5010     if(alt_algo)
5011     {
5012         free(alt_algo);
5013     }
5014
5015     block->block_contents_size = new_len + offset;
5016
5017     free(temp_data_contents);
5018
5019     temp = realloc(block->block_contents, block->block_contents_size);
5020     if(!temp)
5021     {
5022         free(block->block_contents);
5023         block->block_contents = 0;
5024         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5025                block->block_contents_size, __FILE__, __LINE__);
5026         return(TNG_CRITICAL);
5027     }
5028     block->block_contents = temp;
5029     if(dest)
5030     {
5031         memcpy(temp + offset, dest, new_len);
5032         free(dest);
5033     }
5034     else
5035     {
5036         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
5037         return(TNG_FAILURE);
5038     }
5039
5040     return(TNG_SUCCESS);
5041 }
5042
5043 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
5044                                           tng_gen_block_t block,
5045                                           const char type,
5046                                           void *start_pos,
5047                                           const unsigned long uncompressed_len)
5048 {
5049     char *temp, *temp_data_contents;
5050     double *d_dest = 0;
5051     float *f_dest = 0;
5052     unsigned long offset;
5053     int result;
5054     (void)tng_data;
5055
5056     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5057
5058     if(block->id != TNG_TRAJ_POSITIONS &&
5059        block->id != TNG_TRAJ_VELOCITIES)
5060     {
5061         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5062                "TNG method.\n");
5063         return(TNG_FAILURE);
5064     }
5065     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5066     {
5067         fprintf(stderr, "TNG library: Data type not supported.\n");
5068         return(TNG_FAILURE);
5069     }
5070
5071     temp_data_contents = malloc(uncompressed_len);
5072     if(!temp_data_contents)
5073     {
5074         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5075                 uncompressed_len, __FILE__, __LINE__);
5076         return(TNG_CRITICAL);
5077     }
5078
5079     memcpy(temp_data_contents, (char *)start_pos, uncompressed_len);
5080
5081     if(type == TNG_FLOAT_DATA)
5082     {
5083         f_dest = malloc(uncompressed_len);
5084         if(!f_dest)
5085         {
5086             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5087                 uncompressed_len, __FILE__, __LINE__);
5088             free(temp_data_contents);
5089             return(TNG_CRITICAL);
5090         }
5091         result = tng_compress_uncompress_float(temp_data_contents, f_dest);
5092     }
5093     else
5094     {
5095         d_dest = malloc(uncompressed_len);
5096         if(!d_dest)
5097         {
5098             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5099                 uncompressed_len, __FILE__, __LINE__);
5100             free(temp_data_contents);
5101             return(TNG_CRITICAL);
5102         }
5103         result = tng_compress_uncompress(temp_data_contents, d_dest);
5104     }
5105
5106     if(result == 1)
5107     {
5108         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5109         free(temp_data_contents);
5110         return(TNG_FAILURE);
5111     }
5112
5113     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5114
5115     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5116
5117     temp = realloc(block->block_contents, uncompressed_len + offset);
5118     if(!temp)
5119     {
5120         free(block->block_contents);
5121         block->block_contents = 0;
5122         if(d_dest)
5123         {
5124             free(d_dest);
5125         }
5126         if(f_dest)
5127         {
5128             free(f_dest);
5129         }
5130         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5131                block->block_contents_size, __FILE__, __LINE__);
5132         free(temp_data_contents);
5133         return(TNG_CRITICAL);
5134     }
5135
5136     if(type == TNG_FLOAT_DATA)
5137     {
5138         memcpy(temp + offset, f_dest, uncompressed_len);
5139     }
5140     else
5141     {
5142         memcpy(temp + offset, d_dest, uncompressed_len);
5143     }
5144
5145     block->block_contents = temp;
5146
5147     free(temp_data_contents);
5148     if(d_dest)
5149     {
5150         free(d_dest);
5151     }
5152     if(f_dest)
5153     {
5154         free(f_dest);
5155     }
5156     return(TNG_SUCCESS);
5157 }
5158
5159 #ifdef USE_ZLIB
5160 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5161                                              tng_gen_block_t block,
5162                                              void *start_pos, const int len)
5163 {
5164     Bytef *dest;
5165     char *temp;
5166     unsigned long max_len, stat, offset;
5167     (void)tng_data;
5168
5169     max_len = compressBound(len);
5170     dest = malloc(max_len);
5171     if(!dest)
5172     {
5173         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
5174                max_len, __FILE__, __LINE__);
5175         return(TNG_CRITICAL);
5176     }
5177
5178     stat = compress(dest, &max_len, start_pos, len);
5179     if(stat != (unsigned long)Z_OK)
5180     {
5181         free(dest);
5182         if(stat == (unsigned long)Z_MEM_ERROR)
5183         {
5184             fprintf(stderr, "TNG library: Not enough memory. ");
5185         }
5186         else if(stat == (unsigned long)Z_BUF_ERROR)
5187         {
5188             fprintf(stderr, "TNG library: Destination buffer too small. ");
5189         }
5190         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5191         return(TNG_FAILURE);
5192     }
5193
5194     offset = (char *)start_pos - block->block_contents;
5195
5196     block->block_contents_size = max_len + offset;
5197
5198     temp = realloc(block->block_contents, block->block_contents_size);
5199     if(!temp)
5200     {
5201         free(block->block_contents);
5202         free(dest);
5203         block->block_contents = 0;
5204         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5205                block->block_contents_size, __FILE__, __LINE__);
5206         return(TNG_CRITICAL);
5207     }
5208
5209     block->block_contents = temp;
5210
5211     memcpy(temp + offset, dest, max_len);
5212
5213     free(dest);
5214
5215     return(TNG_SUCCESS);
5216 }
5217
5218 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5219                                                tng_gen_block_t block,
5220                                                void *start_pos,
5221                                                unsigned long uncompressed_len)
5222 {
5223     Bytef *dest;
5224     char *temp;
5225     unsigned long stat;
5226     int offset;
5227     (void)tng_data;
5228
5229     offset = (char *)start_pos - (char *)block->block_contents;
5230
5231     dest = malloc(uncompressed_len);
5232     if(!dest)
5233     {
5234         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5235                uncompressed_len, __FILE__, __LINE__);
5236         return(TNG_CRITICAL);
5237     }
5238
5239     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5240                       block->block_contents_size - offset);
5241
5242     if(stat != Z_OK)
5243     {
5244         free(dest);
5245         if(stat == (unsigned long)Z_MEM_ERROR)
5246         {
5247             fprintf(stderr, "TNG library: Not enough memory. ");
5248         }
5249         else if(stat == (unsigned long)Z_BUF_ERROR)
5250         {
5251             fprintf(stderr, "TNG library: Destination buffer too small. ");
5252         }
5253         else if(stat == (unsigned long)Z_DATA_ERROR)
5254         {
5255             fprintf(stderr, "TNG library: Data corrupt. ");
5256         }
5257         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5258                __LINE__);
5259         return(TNG_FAILURE);
5260     }
5261
5262
5263     block->block_contents_size = uncompressed_len + offset;
5264
5265     temp = realloc(block->block_contents, uncompressed_len + offset);
5266     if(!temp)
5267     {
5268         free(block->block_contents);
5269         block->block_contents = 0;
5270         free(dest);
5271         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5272                block->block_contents_size, __FILE__, __LINE__);
5273         return(TNG_CRITICAL);
5274     }
5275
5276     memcpy(temp + offset, dest, uncompressed_len);
5277
5278     block->block_contents = temp;
5279
5280     free(dest);
5281     return(TNG_SUCCESS);
5282 }
5283 #endif
5284
5285 /** Allocate memory for storing particle data.
5286  * The allocated block will be refered to by data->values.
5287  * @param tng_data is a trajectory data container.
5288  * @param data is the data struct, which will contain the allocated memory in
5289  * data->values.
5290  * @param n_frames is the number of frames of data to store.
5291  * @param n_particles is the number of particles with data.
5292  * @param n_values_per_frame is the number of data values per particle and
5293  * frame.
5294  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5295  * error has occured.
5296  */
5297 static tng_function_status tng_allocate_particle_data_mem
5298                 (tng_trajectory_t tng_data,
5299                  tng_particle_data_t data,
5300                  int64_t n_frames,
5301                  int64_t stride_length,
5302                  const int64_t n_particles,
5303                  const int64_t n_values_per_frame)
5304 {
5305     void ***values;
5306     int64_t i, j, k, size, frame_alloc;
5307     (void)tng_data;
5308
5309     if(n_particles == 0 || n_values_per_frame == 0)
5310     {
5311         return(TNG_FAILURE);
5312     }
5313
5314     if(data->strings && data->datatype == TNG_CHAR_DATA)
5315     {
5316         for(i = 0; i < data->n_frames; i++)
5317         {
5318             for(j = 0; j < n_particles; j++)
5319             {
5320                 for(k = 0; k < data->n_values_per_frame; k++)
5321                 {
5322                     if(data->strings[i][j][k])
5323                     {
5324                         free(data->strings[i][j][k]);
5325                     }
5326                 }
5327                 free(data->strings[i][j]);
5328             }
5329             free(data->strings[i]);
5330         }
5331         free(data->strings);
5332     }
5333     data->n_frames = n_frames;
5334     n_frames = tng_max_i64(1, n_frames);
5335     data->stride_length = tng_max_i64(1, stride_length);
5336     data->n_values_per_frame = n_values_per_frame;
5337     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5338
5339     if(data->datatype == TNG_CHAR_DATA)
5340     {
5341         data->strings = malloc(sizeof(char ***) * frame_alloc);
5342         for(i = 0; i < frame_alloc; i++)
5343         {
5344             data->strings[i] = malloc(sizeof(char **) *
5345                                     n_particles);
5346             if(!data->strings[i])
5347             {
5348                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5349                     sizeof(union data_values *) * n_particles,
5350                     __FILE__, __LINE__);
5351                 return(TNG_CRITICAL);
5352             }
5353             for(j = 0; j < n_particles; j++)
5354             {
5355                 data->strings[i][j] = malloc(sizeof(char *) *
5356                                             n_values_per_frame);
5357                 if(!data->strings[i][j])
5358                 {
5359                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5360                         sizeof(union data_values) * n_values_per_frame,
5361                         __FILE__, __LINE__);
5362                     return(TNG_CRITICAL);
5363                 }
5364                 for(k = 0; k < n_values_per_frame; k++)
5365                 {
5366                     data->strings[i][j][k] = 0;
5367                 }
5368             }
5369         }
5370     }
5371     else
5372     {
5373         switch(data->datatype)
5374         {
5375         case TNG_INT_DATA:
5376             size = sizeof(int64_t);
5377             break;
5378         case TNG_FLOAT_DATA:
5379             size = sizeof(float);
5380             break;
5381         case TNG_DOUBLE_DATA:
5382         default:
5383             size = sizeof(double);
5384         }
5385
5386         values = realloc(data->values,
5387                          size * frame_alloc *
5388                          n_particles * n_values_per_frame);
5389         if(!values)
5390         {
5391             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5392                    size * frame_alloc *
5393                    n_particles * n_values_per_frame,
5394                    __FILE__, __LINE__);
5395             free(data->values);
5396             data->values = 0;
5397             return(TNG_CRITICAL);
5398         }
5399         data->values = values;
5400     }
5401     return(TNG_SUCCESS);
5402 }
5403
5404 static tng_function_status tng_particle_data_find
5405                 (tng_trajectory_t tng_data,
5406                  const int64_t id,
5407                  tng_particle_data_t *data)
5408 {
5409     int64_t block_index, i;
5410     tng_trajectory_frame_set_t frame_set = &tng_data->
5411                                            current_trajectory_frame_set;
5412     char block_type_flag;
5413
5414     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5415        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5416     {
5417         block_type_flag = TNG_TRAJECTORY_BLOCK;
5418     }
5419     else
5420     {
5421         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5422     }
5423
5424     block_index = -1;
5425     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5426     {
5427         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5428         {
5429             *data = &frame_set->tr_particle_data[i];
5430             if((*data)->block_id == id)
5431             {
5432                 block_index = i;
5433                 break;
5434             }
5435         }
5436     }
5437     else
5438     {
5439         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5440         {
5441             *data = &tng_data->non_tr_particle_data[i];
5442             if((*data)->block_id == id)
5443             {
5444                 block_index = i;
5445                 break;
5446             }
5447         }
5448     }
5449     if(block_index == -1)
5450     {
5451         return(TNG_FAILURE);
5452     }
5453     return(TNG_SUCCESS);
5454 }
5455
5456 static tng_function_status tng_data_find
5457                 (tng_trajectory_t tng_data,
5458                  const int64_t id,
5459                  tng_non_particle_data_t *data)
5460 {
5461     int64_t block_index, i;
5462     tng_trajectory_frame_set_t frame_set = &tng_data->
5463                                            current_trajectory_frame_set;
5464     char block_type_flag;
5465
5466     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5467        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5468     {
5469         block_type_flag = TNG_TRAJECTORY_BLOCK;
5470     }
5471     else
5472     {
5473         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5474     }
5475
5476     block_index = -1;
5477     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5478     {
5479         for(i = 0; i < frame_set->n_data_blocks; i++)
5480         {
5481             *data = &frame_set->tr_data[i];
5482             if((*data)->block_id == id)
5483             {
5484                 block_index = i;
5485                 break;
5486             }
5487         }
5488         if(block_index == -1)
5489         {
5490             for(i = 0; i < tng_data->n_data_blocks; i++)
5491             {
5492                 *data = &tng_data->non_tr_data[i];
5493                 if((*data)->block_id == id)
5494                 {
5495                     block_index = i;
5496                     break;
5497                 }
5498             }
5499         }
5500     }
5501     else
5502     {
5503         for(i = 0; i < tng_data->n_data_blocks; i++)
5504         {
5505             *data = &tng_data->non_tr_data[i];
5506             if((*data)->block_id == id)
5507             {
5508                 block_index = i;
5509                 break;
5510             }
5511         }
5512     }
5513     if(block_index == -1)
5514     {
5515         return(TNG_FAILURE);
5516     }
5517     return(TNG_SUCCESS);
5518 }
5519
5520 static tng_function_status tng_data_block_len_calculate
5521                 (const tng_trajectory_t tng_data,
5522                  const tng_particle_data_t data,
5523                  const tng_bool is_particle_data,
5524                  const int64_t n_frames,
5525                  const int64_t frame_step,
5526                  const int64_t stride_length,
5527                  const int64_t num_first_particle,
5528                  const int64_t n_particles,
5529                  const char dependency,
5530                  int64_t *data_start_pos,
5531                  int64_t *len)
5532 {
5533     int size;
5534     int64_t i, j, k;
5535     char ***first_dim_values, **second_dim_values;
5536     (void)tng_data;
5537
5538     if(data == 0)
5539     {
5540         return(TNG_SUCCESS);
5541     }
5542
5543     switch(data->datatype)
5544     {
5545     case TNG_CHAR_DATA:
5546         size = 1;
5547         break;
5548     case TNG_INT_DATA:
5549         size = sizeof(int64_t);
5550         break;
5551     case TNG_FLOAT_DATA:
5552         size = sizeof(float);
5553         break;
5554     case TNG_DOUBLE_DATA:
5555     default:
5556         size = sizeof(double);
5557     }
5558
5559     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5560            sizeof(data->codec_id);
5561     if(is_particle_data)
5562     {
5563         *len += sizeof(num_first_particle) + sizeof(n_particles);
5564     }
5565
5566     if(stride_length > 1)
5567     {
5568         *len += sizeof(data->first_frame_with_data) +
5569                 sizeof(data->stride_length);
5570     }
5571
5572     if(data->codec_id != TNG_UNCOMPRESSED)
5573     {
5574         *len += sizeof(data->compression_multiplier);
5575     }
5576
5577     if(dependency & TNG_FRAME_DEPENDENT)
5578     {
5579         *len += sizeof(char);
5580     }
5581
5582     *data_start_pos = *len;
5583
5584     if(data->datatype == TNG_CHAR_DATA)
5585     {
5586         if(is_particle_data)
5587         {
5588             for(i = 0; i < n_frames; i++)
5589             {
5590                 first_dim_values = data->strings[i];
5591                 for(j = num_first_particle; j < num_first_particle + n_particles;
5592                     j++)
5593                 {
5594                     second_dim_values = first_dim_values[j];
5595                     for(k = 0; k < data->n_values_per_frame; k++)
5596                     {
5597                         *len += strlen(second_dim_values[k]) + 1;
5598                     }
5599                 }
5600             }
5601         }
5602         else
5603         {
5604             for(i = 0; i < n_frames; i++)
5605             {
5606                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5607                 for(j = 0; j < data->n_values_per_frame; j++)
5608                 {
5609                     *len += strlen(second_dim_values[j]) + 1;
5610                 }
5611             }
5612         }
5613     }
5614     else
5615     {
5616         *len += size * frame_step * n_particles * data->n_values_per_frame;
5617     }
5618
5619     return(TNG_SUCCESS);
5620 }
5621
5622 /** Read the values of a particle data block
5623  * @param tng_data is a trajectory data container.
5624  * @param block is the block to store the data (should already contain
5625  * the block headers and the block contents).
5626  * @param offset is the reading offset to point at the place where the actual
5627  * values are stored, starting from the beginning of the block_contents. The
5628  * offset is changed during the reading.
5629  * @param datatype is the type of data of the data block (char, int, float or
5630  * double).
5631  * @param num_first_particle is the number of the first particle in the data
5632  * block. This should be the same as in the corresponding particle mapping
5633  * block.
5634  * @param n_particles is the number of particles in the data block. This should
5635  * be the same as in the corresponding particle mapping block.
5636  * @param first_frame_with_data is the frame number of the first frame with data
5637  * in this data block.
5638  * @param stride_length is the number of frames between each data entry.
5639  * @param n_frames is the number of frames in this data block.
5640  * @param n_values is the number of values per particle and frame stored in this
5641  * data block.
5642  * @param codec_id is the ID of the codec to compress the data.
5643  * @param multiplier is the multiplication factor applied to each data value
5644  * before compression. This factor is applied since some compression algorithms
5645  * work only on integers.
5646  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5647  * error has occured.
5648  */
5649 static tng_function_status tng_particle_data_read
5650                 (tng_trajectory_t tng_data,
5651                  tng_gen_block_t block,
5652                  int *offset,
5653                  const char datatype,
5654                  const int64_t num_first_particle,
5655                  const int64_t n_particles,
5656                  const int64_t first_frame_with_data,
5657                  const int64_t stride_length,
5658                  int64_t n_frames,
5659                  const int64_t n_values,
5660                  const int64_t codec_id,
5661                  const double multiplier)
5662 {
5663     int64_t i, j, k, tot_n_particles, n_frames_div;
5664     int size, len;
5665     unsigned long data_size;
5666     char ***first_dim_values, **second_dim_values;
5667     tng_particle_data_t data;
5668     tng_trajectory_frame_set_t frame_set =
5669     &tng_data->current_trajectory_frame_set;
5670     char block_type_flag;
5671
5672     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5673
5674     switch(datatype)
5675     {
5676     case TNG_CHAR_DATA:
5677         size = 1;
5678         break;
5679     case TNG_INT_DATA:
5680         size = sizeof(int64_t);
5681         break;
5682     case TNG_FLOAT_DATA:
5683         size = sizeof(float);
5684         break;
5685     case TNG_DOUBLE_DATA:
5686     default:
5687         size = sizeof(double);
5688     }
5689
5690     /* If the block does not exist, create it */
5691     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5692     {
5693         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5694         {
5695             block_type_flag = TNG_TRAJECTORY_BLOCK;
5696         }
5697         else
5698         {
5699             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5700         }
5701
5702         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5703            TNG_SUCCESS)
5704         {
5705             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5706                    __FILE__, __LINE__);
5707             return(TNG_CRITICAL);
5708         }
5709         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5710         {
5711             data = &frame_set->tr_particle_data[frame_set->
5712                                                 n_particle_data_blocks - 1];
5713         }
5714         else
5715         {
5716             data = &tng_data->non_tr_particle_data[tng_data->
5717                                                    n_particle_data_blocks - 1];
5718         }
5719         data->block_id = block->id;
5720
5721         data->block_name = malloc(strlen(block->name) + 1);
5722         if(!data->block_name)
5723         {
5724             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5725                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5726             return(TNG_CRITICAL);
5727         }
5728         strcpy(data->block_name, block->name);
5729
5730         data->datatype = datatype;
5731
5732         data->values = 0;
5733         /* FIXME: Memory leak from strings. */
5734         data->strings = 0;
5735         data->n_frames = 0;
5736         data->codec_id = codec_id;
5737         data->compression_multiplier = multiplier;
5738         data->last_retrieved_frame = -1;
5739     }
5740
5741     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5742        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5743        tng_data->var_num_atoms_flag)
5744     {
5745         tot_n_particles = frame_set->n_particles;
5746     }
5747     else
5748     {
5749         tot_n_particles = tng_data->n_particles;
5750     }
5751
5752     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5753
5754     if(codec_id != TNG_UNCOMPRESSED)
5755     {
5756         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5757         switch(codec_id)
5758         {
5759         case TNG_XTC_COMPRESSION:
5760             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5761             break;
5762         case TNG_TNG_COMPRESSION:
5763 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5764             if(tng_uncompress(tng_data, block, datatype,
5765                               block->block_contents + *offset,
5766                               data_size) != TNG_SUCCESS)
5767             {
5768                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5769                        __FILE__, __LINE__);
5770                 return(TNG_CRITICAL);
5771             }
5772 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5773             break;
5774 #ifdef USE_ZLIB
5775         case TNG_GZIP_COMPRESSION:
5776 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5777             if(tng_gzip_uncompress(tng_data, block,
5778                                    block->block_contents + *offset,
5779                                    data_size) != TNG_SUCCESS)
5780             {
5781                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5782                     __LINE__);
5783                 return(TNG_CRITICAL);
5784             }
5785 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5786             break;
5787 #endif
5788         }
5789     }
5790     /* Allocate memory */
5791     if(!data->values || data->n_frames != n_frames ||
5792        data->n_values_per_frame != n_values)
5793     {
5794         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5795                                           stride_length,
5796                                           tot_n_particles, n_values) !=
5797            TNG_SUCCESS)
5798         {
5799             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5800                    __FILE__, __LINE__);
5801             return(TNG_CRITICAL);
5802         }
5803     }
5804
5805     data->first_frame_with_data = first_frame_with_data;
5806
5807     if(datatype == TNG_CHAR_DATA)
5808     {
5809         for(i = 0; i < n_frames_div; i++)
5810         {
5811             first_dim_values = data->strings[i];
5812             for(j = num_first_particle; j < num_first_particle + n_particles;
5813                 j++)
5814             {
5815                 second_dim_values = first_dim_values[j];
5816                 for(k = 0; k < n_values; k++)
5817                 {
5818                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5819                               TNG_MAX_STR_LEN);
5820                     if(second_dim_values[k])
5821                     {
5822                         free(second_dim_values[k]);
5823                     }
5824                     second_dim_values[k] = malloc(len);
5825                     if(!second_dim_values[k])
5826                     {
5827                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5828                             len, __FILE__, __LINE__);
5829                         return(TNG_CRITICAL);
5830                     }
5831                     strncpy(second_dim_values[k],
5832                             block->block_contents+*offset, len);
5833                     *offset += len;
5834                 }
5835             }
5836         }
5837     }
5838     else
5839     {
5840         memcpy((char *)data->values + n_frames_div * size * n_values *
5841                num_first_particle,
5842                block->block_contents + *offset,
5843                block->block_contents_size - *offset);
5844         switch(datatype)
5845         {
5846         case TNG_FLOAT_DATA:
5847             if(tng_data->input_endianness_swap_func_32)
5848             {
5849                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5850                 {
5851                     if(tng_data->input_endianness_swap_func_32(tng_data,
5852                         (int32_t *)((char *)data->values + i))
5853                         != TNG_SUCCESS)
5854                     {
5855                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5856                                 __FILE__, __LINE__);
5857                     }
5858                 }
5859             }
5860             break;
5861         case TNG_INT_DATA:
5862         case TNG_DOUBLE_DATA:
5863             if(tng_data->input_endianness_swap_func_64)
5864             {
5865                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5866                 {
5867                     if(tng_data->input_endianness_swap_func_64(tng_data,
5868                         (int64_t *)((char *)data->values + i))
5869                         != TNG_SUCCESS)
5870                     {
5871                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5872                                 __FILE__, __LINE__);
5873                     }
5874                 }
5875             }
5876             break;
5877         case TNG_CHAR_DATA:
5878             break;
5879         }
5880     }
5881     return(TNG_SUCCESS);
5882 }
5883
5884 /** Write a particle data block
5885  * @param tng_data is a trajectory data container.
5886  * @param block is the block to store the data (should already contain
5887  * the block headers and the block contents).
5888  * @param block_index is the index number of the data block in the frame set.
5889  * @param mapping is the particle mapping that is relevant for the data block.
5890  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5891  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5892  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5893  * error has occured.
5894  */
5895 static tng_function_status tng_particle_data_block_write
5896                 (tng_trajectory_t tng_data,
5897                  tng_gen_block_t block,
5898                  const int64_t block_index,
5899                  const tng_particle_mapping_t mapping,
5900                  const char hash_mode)
5901 {
5902     int64_t n_particles, num_first_particle, n_frames, stride_length;
5903     int64_t frame_step, data_start_pos;
5904     int64_t i, j, k;
5905     int size;
5906     size_t len, offset = 0;
5907     char dependency, temp, *temp_name;
5908     double multiplier;
5909     char ***first_dim_values, **second_dim_values;
5910     tng_trajectory_frame_set_t frame_set;
5911     tng_function_status stat;
5912
5913     tng_particle_data_t data;
5914     char block_type_flag;
5915
5916     frame_set = &tng_data->current_trajectory_frame_set;
5917
5918     /* If we have already started writing frame sets it is too late to write
5919      * non-trajectory data blocks */
5920     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5921     {
5922         block_type_flag = TNG_TRAJECTORY_BLOCK;
5923     }
5924     else
5925     {
5926         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5927     }
5928
5929     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5930     {
5931         return(TNG_CRITICAL);
5932     }
5933
5934     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5935     {
5936         data = &frame_set->tr_particle_data[block_index];
5937
5938         /* If this data block has not had any data added in this frame set
5939          * do not write it. */
5940         if(data->first_frame_with_data < frame_set->first_frame)
5941         {
5942             return(TNG_SUCCESS);
5943         }
5944
5945         stride_length = tng_max_i64(1, data->stride_length);
5946     }
5947     else
5948     {
5949         data = &tng_data->non_tr_particle_data[block_index];
5950         stride_length = 1;
5951     }
5952
5953     switch(data->datatype)
5954     {
5955     case TNG_CHAR_DATA:
5956         size = 1;
5957         break;
5958     case TNG_INT_DATA:
5959         size = sizeof(int64_t);
5960         break;
5961     case TNG_FLOAT_DATA:
5962         size = sizeof(float);
5963         break;
5964     case TNG_DOUBLE_DATA:
5965     default:
5966         size = sizeof(double);
5967     }
5968
5969     len = strlen(data->block_name) + 1;
5970
5971     if(!block->name || strlen(block->name) < len)
5972     {
5973         temp_name = realloc(block->name, len);
5974         if(!temp_name)
5975         {
5976             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
5977                    __FILE__, __LINE__);
5978             free(block->name);
5979             block->name = 0;
5980             return(TNG_CRITICAL);
5981         }
5982         block->name = temp_name;
5983     }
5984     strncpy(block->name, data->block_name, len);
5985     block->id = data->block_id;
5986
5987     /* If writing frame independent data data->n_frames is 0, but n_frames
5988        is used for the loop writing the data (and reserving memory) and needs
5989        to be at least 1 */
5990     n_frames = tng_max_i64(1, data->n_frames);
5991
5992     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5993     {
5994         /* If the frame set is finished before writing the full number of frames
5995            make sure the data block is not longer than the frame set. */
5996         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5997
5998         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5999     }
6000
6001     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6002                  n_frames / stride_length;
6003
6004     /* TNG compression will use compression precision to get integers from
6005      * floating point data. The compression multiplier stores that information
6006      * to be able to return the precision of the compressed data. */
6007     if(data->codec_id == TNG_TNG_COMPRESSION)
6008     {
6009         data->compression_multiplier = tng_data->compression_precision;
6010     }
6011     /* Uncompressed data blocks do not use compression multipliers at all.
6012      * GZip compression does not need it either. */
6013     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6014     {
6015         data->compression_multiplier = 1.0;
6016     }
6017
6018     if(mapping && mapping->n_particles != 0)
6019     {
6020         n_particles = mapping->n_particles;
6021         num_first_particle = mapping->num_first_particle;
6022     }
6023     else
6024     {
6025         num_first_particle = 0;
6026         if(tng_data->var_num_atoms_flag)
6027         {
6028             n_particles = frame_set->n_particles;
6029         }
6030         else
6031         {
6032             n_particles = tng_data->n_particles;
6033         }
6034     }
6035
6036     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6037     {
6038         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6039     }
6040     else
6041     {
6042         dependency = TNG_PARTICLE_DEPENDENT;
6043     }
6044
6045     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6046                                     frame_step, stride_length, num_first_particle,
6047                                     n_particles, dependency, &data_start_pos,
6048                                     &block->block_contents_size) != TNG_SUCCESS)
6049     {
6050         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6051                 __FILE__, __LINE__);
6052         return(TNG_CRITICAL);
6053     }
6054
6055     if(block->block_contents)
6056     {
6057         free(block->block_contents);
6058     }
6059     block->block_contents = malloc(block->block_contents_size);
6060     if(!block->block_contents)
6061     {
6062         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6063                block->block_contents_size, __FILE__, __LINE__);
6064         return(TNG_CRITICAL);
6065     }
6066
6067
6068     memcpy(block->block_contents, &data->datatype, sizeof(char));
6069     offset += sizeof(char);
6070
6071     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6072     offset += sizeof(char);
6073
6074     if(dependency & TNG_FRAME_DEPENDENT)
6075     {
6076         if(stride_length > 1)
6077         {
6078             temp = 1;
6079         }
6080         else
6081         {
6082             temp = 0;
6083         }
6084         memcpy(block->block_contents+offset, &temp, sizeof(char));
6085         offset += sizeof(char);
6086     }
6087
6088     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6089            sizeof(data->n_values_per_frame));
6090     if(tng_data->output_endianness_swap_func_64)
6091     {
6092         if(tng_data->output_endianness_swap_func_64(tng_data,
6093            (int64_t *)block->header_contents+offset)
6094             != TNG_SUCCESS)
6095         {
6096             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6097                     __FILE__, __LINE__);
6098         }
6099     }
6100     offset += sizeof(data->n_values_per_frame);
6101
6102     memcpy(block->block_contents+offset, &data->codec_id,
6103            sizeof(data->codec_id));
6104     if(tng_data->output_endianness_swap_func_64)
6105     {
6106         if(tng_data->output_endianness_swap_func_64(tng_data,
6107            (int64_t *)block->header_contents+offset)
6108             != TNG_SUCCESS)
6109         {
6110             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6111                     __FILE__, __LINE__);
6112         }
6113     }
6114     offset += sizeof(data->codec_id);
6115
6116     if(data->codec_id != TNG_UNCOMPRESSED)
6117     {
6118         memcpy(block->block_contents+offset, &data->compression_multiplier,
6119                sizeof(data->compression_multiplier));
6120         if(tng_data->output_endianness_swap_func_64)
6121         {
6122             if(tng_data->output_endianness_swap_func_64(tng_data,
6123                (int64_t *)block->header_contents+offset)
6124                 != TNG_SUCCESS)
6125             {
6126                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6127                         __FILE__, __LINE__);
6128             }
6129         }
6130         offset += sizeof(data->compression_multiplier);
6131     }
6132
6133     if(data->n_frames > 0 && stride_length > 1)
6134     {
6135         /* FIXME: first_frame_with_data is not reliably set */
6136         if(data->first_frame_with_data == 0)
6137         {
6138             data->first_frame_with_data = frame_set->first_frame;
6139         }
6140         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6141                sizeof(data->first_frame_with_data));
6142         if(tng_data->output_endianness_swap_func_64)
6143         {
6144             if(tng_data->output_endianness_swap_func_64(tng_data,
6145                (int64_t *)block->header_contents+offset)
6146                 != TNG_SUCCESS)
6147             {
6148                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6149                         __FILE__, __LINE__);
6150             }
6151         }
6152         offset += sizeof(data->first_frame_with_data);
6153
6154         memcpy(block->block_contents+offset, &stride_length,
6155                sizeof(stride_length));
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(stride_length);
6167     }
6168
6169
6170     memcpy(block->block_contents+offset, &num_first_particle,
6171            sizeof(num_first_particle));
6172     if(tng_data->output_endianness_swap_func_64)
6173     {
6174         if(tng_data->output_endianness_swap_func_64(tng_data,
6175            (int64_t *)block->header_contents+offset)
6176             != TNG_SUCCESS)
6177         {
6178             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6179                     __FILE__, __LINE__);
6180         }
6181     }
6182     offset += sizeof(num_first_particle);
6183
6184     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6185     if(tng_data->output_endianness_swap_func_64)
6186     {
6187         if(tng_data->output_endianness_swap_func_64(tng_data,
6188            (int64_t *)block->header_contents+offset)
6189             != TNG_SUCCESS)
6190         {
6191             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6192                     __FILE__, __LINE__);
6193         }
6194     }
6195     offset += sizeof(n_particles);
6196
6197     if(data->datatype == TNG_CHAR_DATA)
6198     {
6199         if(data->strings)
6200         {
6201             for(i = 0; i < frame_step; i++)
6202             {
6203                 first_dim_values = data->strings[i];
6204                 for(j = num_first_particle; j < num_first_particle + n_particles;
6205                     j++)
6206                 {
6207                     second_dim_values = first_dim_values[j];
6208                     for(k = 0; k < data->n_values_per_frame; k++)
6209                     {
6210                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6211                         strncpy(block->block_contents+offset,
6212                                 second_dim_values[k], len);
6213                         offset += len;
6214                     }
6215                 }
6216             }
6217         }
6218     }
6219     else if(data->values)
6220     {
6221         memcpy(block->block_contents + offset, data->values,
6222                block->block_contents_size - offset);
6223
6224         switch(data->datatype)
6225         {
6226         case TNG_FLOAT_DATA:
6227             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6228                data->codec_id == TNG_TNG_COMPRESSION)
6229             {
6230                 if(tng_data->input_endianness_swap_func_32)
6231                 {
6232                     for(i = offset; i < block->block_contents_size; i+=size)
6233                     {
6234                         if(tng_data->input_endianness_swap_func_32(tng_data,
6235                            (int32_t *)(block->block_contents + i))
6236                            != TNG_SUCCESS)
6237                         {
6238                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6239                                     __FILE__, __LINE__);
6240                         }
6241                     }
6242                 }
6243             }
6244             else
6245             {
6246                 multiplier = data->compression_multiplier;
6247                 if(fabs(multiplier - 1.0) > 0.00001 ||
6248                    tng_data->input_endianness_swap_func_32)
6249                 {
6250                     for(i = offset; i < block->block_contents_size; i+=size)
6251                     {
6252                         *(float *)(block->block_contents + i) *= (float)multiplier;
6253                         if(tng_data->input_endianness_swap_func_32 &&
6254                         tng_data->input_endianness_swap_func_32(tng_data,
6255                         (int32_t *)(block->block_contents + i))
6256                         != TNG_SUCCESS)
6257                         {
6258                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6259                                     __FILE__, __LINE__);
6260                         }
6261                     }
6262                 }
6263             }
6264             break;
6265         case TNG_INT_DATA:
6266             if(tng_data->input_endianness_swap_func_64)
6267             {
6268                 for(i = offset; i < block->block_contents_size; i+=size)
6269                 {
6270                     if(tng_data->input_endianness_swap_func_64(tng_data,
6271                        (int64_t *)(block->block_contents + i))
6272                        != TNG_SUCCESS)
6273                     {
6274                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6275                                 __FILE__, __LINE__);
6276                     }
6277                 }
6278             }
6279             break;
6280         case TNG_DOUBLE_DATA:
6281             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6282                data->codec_id == TNG_TNG_COMPRESSION)
6283             {
6284                 if(tng_data->input_endianness_swap_func_64)
6285                 {
6286                     for(i = offset; i < block->block_contents_size; i+=size)
6287                     {
6288                         if(tng_data->input_endianness_swap_func_64(tng_data,
6289                            (int64_t *)(block->block_contents + i))
6290                            != TNG_SUCCESS)
6291                         {
6292                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6293                                     __FILE__, __LINE__);
6294                         }
6295                     }
6296                 }
6297             }
6298             else
6299             {
6300                 multiplier = data->compression_multiplier;
6301                 if(fabs(multiplier - 1.0) > 0.00001 ||
6302                    tng_data->input_endianness_swap_func_64)
6303                 {
6304                     for(i = offset; i < block->block_contents_size; i+=size)
6305                     {
6306                         *(double *)(block->block_contents + i) *= multiplier;
6307                         if(tng_data->input_endianness_swap_func_64 &&
6308                         tng_data->input_endianness_swap_func_64(tng_data,
6309                         (int64_t *)(block->block_contents + i))
6310                         != TNG_SUCCESS)
6311                         {
6312                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6313                                     __FILE__, __LINE__);
6314                         }
6315                     }
6316                 }
6317             }
6318             break;
6319         case TNG_CHAR_DATA:
6320             break;
6321         }
6322     }
6323     else
6324     {
6325         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6326     }
6327
6328     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6329     frame_set->n_unwritten_frames = 0;
6330
6331     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6332     {
6333         switch(data->codec_id)
6334         {
6335         case TNG_XTC_COMPRESSION:
6336             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6337             data->codec_id = TNG_UNCOMPRESSED;
6338             break;
6339         case TNG_TNG_COMPRESSION:
6340             stat = tng_compress(tng_data, block, frame_step,
6341                                 n_particles, data->datatype,
6342                                 block->block_contents + data_start_pos);
6343             if(stat != TNG_SUCCESS)
6344             {
6345                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6346                     __FILE__, __LINE__);
6347                 if(stat == TNG_CRITICAL)
6348                 {
6349                     return(TNG_CRITICAL);
6350                 }
6351                 /* Set the data again, but with no compression (to write only
6352                  * the relevant data) */
6353                 data->codec_id = TNG_UNCOMPRESSED;
6354                 stat = tng_particle_data_block_write(tng_data, block,
6355                                                      block_index, mapping,
6356                                                      hash_mode);
6357                 return(stat);
6358             }
6359             break;
6360 #ifdef USE_ZLIB
6361         case TNG_GZIP_COMPRESSION:
6362     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6363             stat = tng_gzip_compress(tng_data, block,
6364                                      block->block_contents + data_start_pos,
6365                                      block->block_contents_size - data_start_pos);
6366             if(stat != TNG_SUCCESS)
6367             {
6368                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6369                     __LINE__);
6370                 if(stat == TNG_CRITICAL)
6371                 {
6372                     return(TNG_CRITICAL);
6373                 }
6374                 /* Set the data again, but with no compression (to write only
6375                  * the relevant data) */
6376                 data->codec_id = TNG_UNCOMPRESSED;
6377                 stat = tng_particle_data_block_write(tng_data, block,
6378                                                      block_index, mapping,
6379                                                      hash_mode);
6380                 return(stat);
6381             }
6382     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6383             break;
6384 #endif
6385         }
6386     }
6387
6388     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6389     {
6390         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6391                tng_data->output_file_path, __FILE__, __LINE__);
6392         return(TNG_CRITICAL);
6393     }
6394
6395     if(fwrite(block->block_contents, block->block_contents_size, 1,
6396         tng_data->output_file) != 1)
6397     {
6398         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6399                 __LINE__);
6400         return(TNG_CRITICAL);
6401     }
6402
6403     return(TNG_SUCCESS);
6404 }
6405
6406 /* TEST: */
6407 /** Create a non-particle data block
6408  * @param tng_data is a trajectory data container.
6409  * @param block_type_flag specifies if this is a trajectory block or a
6410  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6411  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6412  * error has occured.
6413  */
6414 static tng_function_status tng_data_block_create
6415                 (tng_trajectory_t tng_data,
6416                  const char block_type_flag)
6417 {
6418     tng_trajectory_frame_set_t frame_set =
6419     &tng_data->current_trajectory_frame_set;
6420
6421     tng_non_particle_data_t data;
6422
6423     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6424     {
6425         frame_set->n_data_blocks++;
6426         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6427                        frame_set->n_data_blocks);
6428         if(!data)
6429         {
6430             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6431                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6432                 __FILE__, __LINE__);
6433             free(frame_set->tr_data);
6434             frame_set->tr_data = 0;
6435             return(TNG_CRITICAL);
6436         }
6437         frame_set->tr_data = data;
6438     }
6439     else
6440     {
6441         tng_data->n_data_blocks++;
6442         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6443                         tng_data->n_data_blocks);
6444         if(!data)
6445         {
6446             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6447                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6448                 __FILE__, __LINE__);
6449             free(tng_data->non_tr_data);
6450             tng_data->non_tr_data = 0;
6451             return(TNG_CRITICAL);
6452         }
6453         tng_data->non_tr_data = data;
6454     }
6455
6456     return(TNG_SUCCESS);
6457 }
6458
6459 /* TEST: */
6460 /** Allocate memory for storing non-particle data.
6461  * The allocated block will be refered to by data->values.
6462  * @param tng_data is a trajectory data container.
6463  * @param data is the data struct, which will contain the allocated memory in
6464  * data->values.
6465  * @param n_frames is the number of frames of data to store.
6466  * @param n_values_per_frame is the number of data values per frame.
6467  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6468  * error has occured.
6469  */
6470 static tng_function_status tng_allocate_data_mem
6471                 (tng_trajectory_t tng_data,
6472                  tng_non_particle_data_t data,
6473                  int64_t n_frames,
6474                  int64_t stride_length,
6475                  const int64_t n_values_per_frame)
6476 {
6477     void **values;
6478     int64_t i, j, size, frame_alloc;
6479     (void)tng_data;
6480
6481     if(n_values_per_frame == 0)
6482     {
6483         return(TNG_FAILURE);
6484     }
6485
6486     if(data->strings && data->datatype == TNG_CHAR_DATA)
6487     {
6488         for(i = 0; i < data->n_frames; i++)
6489         {
6490             for(j = 0; j < data->n_values_per_frame; j++)
6491             {
6492                 if(data->strings[i][j])
6493                 {
6494                     free(data->strings[i][j]);
6495                     data->strings[i][j] = 0;
6496                 }
6497             }
6498             free(data->strings[i]);
6499             data->strings[i] = 0;
6500         }
6501         free(data->strings);
6502     }
6503     data->n_frames = n_frames;
6504     data->stride_length = tng_max_i64(1, stride_length);
6505     n_frames = tng_max_i64(1, n_frames);
6506     data->n_values_per_frame = n_values_per_frame;
6507     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6508
6509     if(data->datatype == TNG_CHAR_DATA)
6510     {
6511         data->strings = malloc(sizeof(char **) * frame_alloc);
6512         for(i = 0; i < frame_alloc; i++)
6513         {
6514             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6515             if(!data->strings[i])
6516             {
6517                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6518                        n_values_per_frame,
6519                        __FILE__, __LINE__);
6520                 return(TNG_CRITICAL);
6521             }
6522             for(j = 0; j < n_values_per_frame; j++)
6523             {
6524                 data->strings[i][j] = 0;
6525             }
6526         }
6527     }
6528     else
6529     {
6530         switch(data->datatype)
6531         {
6532         case TNG_INT_DATA:
6533             size = sizeof(int64_t);
6534             break;
6535         case TNG_FLOAT_DATA:
6536             size = sizeof(float);
6537             break;
6538         case TNG_DOUBLE_DATA:
6539         default:
6540             size = sizeof(double);
6541         }
6542
6543         values = realloc(data->values,
6544                          size * frame_alloc *
6545                          n_values_per_frame);
6546         if(!values)
6547         {
6548             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6549                    size * frame_alloc *
6550                    n_values_per_frame,
6551                    __FILE__, __LINE__);
6552             free(data->values);
6553             data->values = 0;
6554             return(TNG_CRITICAL);
6555         }
6556         data->values = values;
6557     }
6558
6559     return(TNG_SUCCESS);
6560 }
6561
6562 /** Read the values of a non-particle data block
6563  * @param tng_data is a trajectory data container.
6564  * @param block is the block to store the data (should already contain
6565  * the block headers and the block contents).
6566  * @param offset is the reading offset to point at the place where the actual
6567  * values are stored, starting from the beginning of the block_contents. The
6568  * offset is changed during the reading.
6569  * @param datatype is the type of data of the data block (char, int, float or
6570  * double).
6571  * @param first_frame_with_data is the frame number of the first frame with data
6572  * in this data block.
6573  * @param stride_length is the number of frames between each data entry.
6574  * @param n_frames is the number of frames in this data block.
6575  * @param n_values is the number of values per frame stored in this data block.
6576  * @param codec_id is the ID of the codec to compress the data.
6577  * @param multiplier is the multiplication factor applied to each data value
6578  * before compression. This factor is applied since some compression algorithms
6579  * work only on integers.
6580  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6581  * error has occured.
6582  */
6583 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6584                                          tng_gen_block_t block,
6585                                          int *offset,
6586                                          const char datatype,
6587                                          const int64_t first_frame_with_data,
6588                                          const int64_t stride_length,
6589                                          int64_t n_frames,
6590                                          const int64_t n_values,
6591                                          const int64_t codec_id,
6592                                          const double multiplier)
6593 {
6594     int64_t i, j, n_frames_div;
6595     int size, len;
6596 #ifdef USE_ZLIB
6597     unsigned long data_size;
6598 #endif
6599     tng_non_particle_data_t data;
6600     tng_trajectory_frame_set_t frame_set =
6601     &tng_data->current_trajectory_frame_set;
6602     char block_type_flag;
6603
6604     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6605
6606 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6607
6608     switch(datatype)
6609     {
6610     case TNG_CHAR_DATA:
6611         size = 1;
6612         break;
6613     case TNG_INT_DATA:
6614         size = sizeof(int64_t);
6615         break;
6616     case TNG_FLOAT_DATA:
6617         size = sizeof(float);
6618         break;
6619     case TNG_DOUBLE_DATA:
6620     default:
6621         size = sizeof(double);
6622     }
6623
6624     /* If the block does not exist, create it */
6625     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6626     {
6627         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6628         {
6629             block_type_flag = TNG_TRAJECTORY_BLOCK;
6630         }
6631         else
6632         {
6633             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6634         }
6635
6636         if(tng_data_block_create(tng_data, block_type_flag) !=
6637             TNG_SUCCESS)
6638         {
6639             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6640                    __FILE__, __LINE__);
6641             return(TNG_CRITICAL);
6642         }
6643         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6644         {
6645             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6646         }
6647         else
6648         {
6649             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6650         }
6651         data->block_id = block->id;
6652
6653         data->block_name = malloc(strlen(block->name) + 1);
6654         if(!data->block_name)
6655         {
6656             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6657                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6658             return(TNG_CRITICAL);
6659         }
6660         strcpy(data->block_name, block->name);
6661
6662         data->datatype = datatype;
6663
6664         data->values = 0;
6665         /* FIXME: Memory leak from strings. */
6666         data->strings = 0;
6667         data->n_frames = 0;
6668         data->codec_id = codec_id;
6669         data->compression_multiplier = multiplier;
6670         data->last_retrieved_frame = -1;
6671     }
6672
6673     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6674
6675     if(codec_id != TNG_UNCOMPRESSED)
6676     {
6677         switch(codec_id)
6678         {
6679 #ifdef USE_ZLIB
6680         case TNG_GZIP_COMPRESSION:
6681             data_size = n_frames_div * size * n_values;
6682     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6683             if(tng_gzip_uncompress(tng_data, block,
6684                                    block->block_contents + *offset,
6685                                    data_size) != TNG_SUCCESS)
6686             {
6687                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6688                     __LINE__);
6689                 return(TNG_CRITICAL);
6690             }
6691     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6692             break;
6693 #endif
6694         }
6695     }
6696
6697     /* Allocate memory */
6698     if(!data->values || data->n_frames != n_frames ||
6699        data->n_values_per_frame != n_values)
6700     {
6701         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6702                                  n_values) !=
6703            TNG_SUCCESS)
6704         {
6705             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6706                    __FILE__, __LINE__);
6707             return(TNG_CRITICAL);
6708         }
6709     }
6710
6711     data->first_frame_with_data = first_frame_with_data;
6712
6713     if(datatype == TNG_CHAR_DATA)
6714     {
6715         for(i = 0; i < n_frames_div; i++)
6716         {
6717             for(j = 0; j < n_values; j++)
6718             {
6719                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6720                               TNG_MAX_STR_LEN);
6721                 if(data->strings[i][j])
6722                 {
6723                     free(data->strings[i][j]);
6724                 }
6725                 data->strings[i][j] = malloc(len);
6726                 if(!data->strings[i][j])
6727                 {
6728                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6729                            len, __FILE__, __LINE__);
6730                     return(TNG_CRITICAL);
6731                 }
6732                 strncpy(data->strings[i][j], block->block_contents+*offset,
6733                         len);
6734                 *offset += len;
6735             }
6736         }
6737     }
6738     else
6739     {
6740         memcpy(data->values, block->block_contents + *offset,
6741                block->block_contents_size - *offset);
6742         switch(datatype)
6743         {
6744         case TNG_FLOAT_DATA:
6745             if(tng_data->input_endianness_swap_func_32)
6746             {
6747                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6748                 {
6749                     if(tng_data->input_endianness_swap_func_32(tng_data,
6750                         (int32_t *)((char *)data->values + i))
6751                         != TNG_SUCCESS)
6752                     {
6753                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6754                                 __FILE__, __LINE__);
6755                     }
6756                 }
6757             }
6758             break;
6759         case TNG_INT_DATA:
6760         case TNG_DOUBLE_DATA:
6761             if(tng_data->input_endianness_swap_func_64)
6762             {
6763                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6764                 {
6765                     if(tng_data->input_endianness_swap_func_64(tng_data,
6766                         (int64_t *)((char *)data->values + i))
6767                         != TNG_SUCCESS)
6768                     {
6769                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6770                                 __FILE__, __LINE__);
6771                     }
6772                 }
6773             }
6774             break;
6775         case TNG_CHAR_DATA:
6776             break;
6777         }
6778     }
6779     return(TNG_SUCCESS);
6780 }
6781
6782 /** Write a non-particle data block
6783  * @param tng_data is a trajectory data container.
6784  * @param block is the block to store the data (should already contain
6785  * the block headers and the block contents).
6786  * @param block_index is the index number of the data block in the frame set.
6787  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6788  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6789  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6790  * error has occured.
6791  */
6792 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6793                                                 tng_gen_block_t block,
6794                                                 const int64_t block_index,
6795                                                 const char hash_mode)
6796 {
6797     int64_t n_frames, stride_length, frame_step, data_start_pos;
6798     int64_t i, j;
6799     int offset = 0, size;
6800     unsigned int len;
6801 #ifdef USE_ZLIB
6802     tng_function_status stat;
6803 #endif
6804     char temp, dependency, *temp_name;
6805     double multiplier;
6806     tng_trajectory_frame_set_t frame_set =
6807     &tng_data->current_trajectory_frame_set;
6808
6809     tng_non_particle_data_t data;
6810     char block_type_flag;
6811
6812     /* If we have already started writing frame sets it is too late to write
6813      * non-trajectory data blocks */
6814     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6815     {
6816         block_type_flag = TNG_TRAJECTORY_BLOCK;
6817     }
6818     else
6819     {
6820         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6821     }
6822
6823     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6824     {
6825         return(TNG_CRITICAL);
6826     }
6827
6828     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6829     {
6830         data = &frame_set->tr_data[block_index];
6831
6832         /* If this data block has not had any data added in this frame set
6833          * do not write it. */
6834         if(data->first_frame_with_data < frame_set->first_frame)
6835         {
6836             return(TNG_SUCCESS);
6837         }
6838
6839         stride_length = tng_max_i64(1, data->stride_length);
6840     }
6841     else
6842     {
6843         data = &tng_data->non_tr_data[block_index];
6844         stride_length = 1;
6845     }
6846
6847     switch(data->datatype)
6848     {
6849     case TNG_CHAR_DATA:
6850         size = 1;
6851         break;
6852     case TNG_INT_DATA:
6853         size = sizeof(int64_t);
6854         break;
6855     case TNG_FLOAT_DATA:
6856         size = sizeof(float);
6857         break;
6858     case TNG_DOUBLE_DATA:
6859     default:
6860         size = sizeof(double);
6861     }
6862
6863     len = (unsigned int)strlen(data->block_name) + 1;
6864
6865     if(!block->name || strlen(block->name) < len)
6866     {
6867         temp_name = realloc(block->name, len);
6868         if(!temp_name)
6869         {
6870             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
6871                    __FILE__, __LINE__);
6872             free(block->name);
6873             block->name = 0;
6874             return(TNG_CRITICAL);
6875         }
6876         block->name = temp_name;
6877     }
6878     strncpy(block->name, data->block_name, len);
6879     block->id = data->block_id;
6880
6881     /* If writing frame independent data data->n_frames is 0, but n_frames
6882        is used for the loop writing the data (and reserving memory) and needs
6883        to be at least 1 */
6884     n_frames = tng_max_i64(1, data->n_frames);
6885
6886     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6887     {
6888         /* If the frame set is finished before writing the full number of frames
6889            make sure the data block is not longer than the frame set. */
6890         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6891
6892         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6893     }
6894
6895     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6896                  n_frames / stride_length;
6897
6898     /* TNG compression will use compression precision to get integers from
6899      * floating point data. The compression multiplier stores that information
6900      * to be able to return the precision of the compressed data. */
6901     if(data->codec_id == TNG_TNG_COMPRESSION)
6902     {
6903         data->compression_multiplier = tng_data->compression_precision;
6904     }
6905     /* Uncompressed data blocks do not use compression multipliers at all.
6906      * GZip compression does not need it either. */
6907     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6908     {
6909         data->compression_multiplier = 1.0;
6910     }
6911
6912     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6913     {
6914         dependency = TNG_FRAME_DEPENDENT;
6915     }
6916     else
6917     {
6918         dependency = 0;
6919     }
6920
6921     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6922                                     frame_step, stride_length, 0,
6923                                     1, dependency, &data_start_pos,
6924                                     &block->block_contents_size) != TNG_SUCCESS)
6925     {
6926         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6927                 __FILE__, __LINE__);
6928         return(TNG_CRITICAL);
6929     }
6930
6931     if(block->block_contents)
6932     {
6933         free(block->block_contents);
6934     }
6935     block->block_contents = malloc(block->block_contents_size);
6936     if(!block->block_contents)
6937     {
6938         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6939                block->block_contents_size, __FILE__, __LINE__);
6940         return(TNG_CRITICAL);
6941     }
6942
6943
6944     memcpy(block->block_contents, &data->datatype, sizeof(char));
6945     offset += sizeof(char);
6946
6947     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6948     offset += sizeof(char);
6949
6950     if(dependency & TNG_FRAME_DEPENDENT)
6951     {
6952         if(stride_length > 1)
6953         {
6954             temp = 1;
6955         }
6956         else
6957         {
6958             temp = 0;
6959         }
6960         memcpy(block->block_contents+offset, &temp, sizeof(char));
6961         offset += sizeof(char);
6962     }
6963
6964     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6965            sizeof(data->n_values_per_frame));
6966     if(tng_data->output_endianness_swap_func_64)
6967     {
6968         if(tng_data->output_endianness_swap_func_64(tng_data,
6969            (int64_t *)block->header_contents+offset)
6970             != TNG_SUCCESS)
6971         {
6972             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6973                     __FILE__, __LINE__);
6974         }
6975     }
6976     offset += sizeof(data->n_values_per_frame);
6977
6978     memcpy(block->block_contents+offset, &data->codec_id,
6979            sizeof(data->codec_id));
6980     if(tng_data->output_endianness_swap_func_64)
6981     {
6982         if(tng_data->output_endianness_swap_func_64(tng_data,
6983            (int64_t *)block->header_contents+offset)
6984             != TNG_SUCCESS)
6985         {
6986             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6987                     __FILE__, __LINE__);
6988         }
6989     }
6990     offset += sizeof(data->codec_id);
6991
6992     if(data->codec_id != TNG_UNCOMPRESSED)
6993     {
6994         memcpy(block->block_contents+offset, &data->compression_multiplier,
6995                sizeof(data->compression_multiplier));
6996         if(tng_data->output_endianness_swap_func_64)
6997         {
6998             if(tng_data->output_endianness_swap_func_64(tng_data,
6999             (int64_t *)block->header_contents+offset)
7000                 != TNG_SUCCESS)
7001             {
7002                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7003                         __FILE__, __LINE__);
7004             }
7005         }
7006         offset += sizeof(data->compression_multiplier);
7007     }
7008
7009     if(data->n_frames > 0 && stride_length > 1)
7010     {
7011         /* FIXME: first_frame_with_data is not reliably set */
7012         if(data->first_frame_with_data == 0)
7013         {
7014             data->first_frame_with_data = frame_set->first_frame;
7015         }
7016         memcpy(block->block_contents+offset, &data->first_frame_with_data,
7017                sizeof(data->first_frame_with_data));
7018         if(tng_data->output_endianness_swap_func_64)
7019         {
7020             if(tng_data->output_endianness_swap_func_64(tng_data,
7021             (int64_t *)block->header_contents+offset)
7022                 != TNG_SUCCESS)
7023             {
7024                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7025                         __FILE__, __LINE__);
7026             }
7027         }
7028         offset += sizeof(data->first_frame_with_data);
7029
7030         memcpy(block->block_contents+offset, &stride_length,
7031                sizeof(data->stride_length));
7032         if(tng_data->output_endianness_swap_func_64)
7033         {
7034             if(tng_data->output_endianness_swap_func_64(tng_data,
7035             (int64_t *)block->header_contents+offset)
7036                 != TNG_SUCCESS)
7037             {
7038                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7039                         __FILE__, __LINE__);
7040             }
7041         }
7042         offset += sizeof(data->stride_length);
7043     }
7044
7045     if(data->datatype == TNG_CHAR_DATA)
7046     {
7047         if(data->strings)
7048         {
7049             for(i = 0; i < frame_step; i++)
7050             {
7051                 for(j = 0; j < data->n_values_per_frame; j++)
7052                 {
7053                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7054                     strncpy(block->block_contents+offset, data->strings[i][j],
7055                             len);
7056                     offset += len;
7057                 }
7058             }
7059         }
7060     }
7061     else if(data->values)
7062     {
7063         memcpy(block->block_contents + offset, data->values,
7064                block->block_contents_size - offset);
7065         switch(data->datatype)
7066         {
7067         case TNG_FLOAT_DATA:
7068             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7069                data->codec_id == TNG_TNG_COMPRESSION)
7070             {
7071                 if(tng_data->input_endianness_swap_func_32)
7072                 {
7073                     for(i = offset; i < block->block_contents_size; i+=size)
7074                     {
7075                         if(tng_data->input_endianness_swap_func_32(tng_data,
7076                            (int32_t *)(block->block_contents + i))
7077                            != TNG_SUCCESS)
7078                         {
7079                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7080                                     __FILE__, __LINE__);
7081                         }
7082                     }
7083                 }
7084             }
7085             else
7086             {
7087                 multiplier = data->compression_multiplier;
7088                 if(fabs(multiplier - 1.0) > 0.00001 ||
7089                    tng_data->input_endianness_swap_func_32)
7090                 {
7091                     for(i = offset; block->block_contents_size; i+=size)
7092                     {
7093                         *(float *)(block->block_contents + i) *= (float)multiplier;
7094                         if(tng_data->input_endianness_swap_func_32 &&
7095                         tng_data->input_endianness_swap_func_32(tng_data,
7096                         (int32_t *)(block->block_contents + i))
7097                         != TNG_SUCCESS)
7098                         {
7099                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7100                                     __FILE__, __LINE__);
7101                         }
7102                     }
7103                 }
7104             }
7105             break;
7106         case TNG_INT_DATA:
7107             if(tng_data->input_endianness_swap_func_64)
7108             {
7109                 for(i = offset; i < block->block_contents_size; i+=size)
7110                 {
7111                     if(tng_data->input_endianness_swap_func_64(tng_data,
7112                        (int64_t *)(block->block_contents + i))
7113                        != TNG_SUCCESS)
7114                     {
7115                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7116                                 __FILE__, __LINE__);
7117                     }
7118                 }
7119             }
7120             break;
7121         case TNG_DOUBLE_DATA:
7122             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7123                data->codec_id == TNG_TNG_COMPRESSION)
7124             {
7125                 if(tng_data->input_endianness_swap_func_64)
7126                 {
7127                     for(i = offset; i < block->block_contents_size; i+=size)
7128                     {
7129                         if(tng_data->input_endianness_swap_func_64(tng_data,
7130                            (int64_t *)(block->block_contents + i))
7131                            != TNG_SUCCESS)
7132                         {
7133                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7134                                     __FILE__, __LINE__);
7135                         }
7136                     }
7137                 }
7138             }
7139             else
7140             {
7141                 multiplier = data->compression_multiplier;
7142                 if(fabs(multiplier - 1.0) > 0.00001 ||
7143                    tng_data->input_endianness_swap_func_64)
7144                 {
7145                     for(i = offset; i < block->block_contents_size; i+=size)
7146                     {
7147                         *(double *)(block->block_contents + i) *= multiplier;
7148                         if(tng_data->input_endianness_swap_func_64 &&
7149                         tng_data->input_endianness_swap_func_64(tng_data,
7150                         (int64_t *)(block->block_contents + i))
7151                         != TNG_SUCCESS)
7152                         {
7153                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7154                                     __FILE__, __LINE__);
7155                         }
7156                     }
7157                 }
7158             }
7159             break;
7160         case TNG_CHAR_DATA:
7161             break;
7162         }
7163     }
7164     else
7165     {
7166         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7167     }
7168
7169     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7170     frame_set->n_unwritten_frames = 0;
7171
7172     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7173     {
7174         switch(data->codec_id)
7175         {
7176 #ifdef USE_ZLIB
7177         case TNG_GZIP_COMPRESSION:
7178     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7179             stat = tng_gzip_compress(tng_data, block,
7180                                      block->block_contents + data_start_pos,
7181                                      block->block_contents_size - data_start_pos);
7182             if(stat != TNG_SUCCESS)
7183             {
7184                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7185                     __LINE__);
7186                 if(stat == TNG_CRITICAL)
7187                 {
7188                     return(TNG_CRITICAL);
7189                 }
7190                 data->codec_id = TNG_UNCOMPRESSED;
7191             }
7192     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7193             break;
7194 #endif
7195         }
7196     }
7197
7198     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7199     {
7200         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7201                tng_data->output_file_path, __FILE__, __LINE__);
7202         return(TNG_CRITICAL);
7203     }
7204
7205     if(fwrite(block->block_contents, block->block_contents_size, 1,
7206               tng_data->output_file) != 1)
7207     {
7208         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7209                __FILE__, __LINE__);
7210         return(TNG_CRITICAL);
7211     }
7212
7213     return(TNG_SUCCESS);
7214 }
7215
7216 /** Read the meta information of a data block (particle or non-particle data).
7217  * @param tng_data is a trajectory data container.
7218  * @param block is the block to store the data (should already contain
7219  * the block headers).
7220  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7221  * error has occured.
7222  */
7223 static tng_function_status tng_data_block_meta_information_read
7224                 (tng_trajectory_t tng_data,
7225                  tng_gen_block_t block,
7226                  int *offset,
7227                  char *datatype,
7228                  char *dependency,
7229                  char *sparse_data,
7230                  int64_t *n_values,
7231                  int64_t *codec_id,
7232                  int64_t *first_frame_with_data,
7233                  int64_t *stride_length,
7234                  int64_t *n_frames,
7235                  int64_t *num_first_particle,
7236                  int64_t *block_n_particles,
7237                  double *multiplier)
7238 {
7239     int meta_size;
7240     char *contents;
7241
7242     if(block->block_contents)
7243     {
7244         contents = block->block_contents;
7245     }
7246     else
7247     {
7248         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7249         contents = malloc(meta_size);
7250         if(!contents)
7251         {
7252             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7253                meta_size, __FILE__, __LINE__);
7254         }
7255
7256         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7257         {
7258             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7259             free(contents);
7260             return(TNG_CRITICAL);
7261         }
7262     }
7263
7264     memcpy(datatype, contents+*offset,
7265            sizeof(*datatype));
7266     *offset += sizeof(*datatype);
7267
7268     memcpy(dependency, contents+*offset,
7269            sizeof(*dependency));
7270     *offset += sizeof(*dependency);
7271
7272     if(*dependency & TNG_FRAME_DEPENDENT)
7273     {
7274         memcpy(sparse_data, contents+*offset,
7275                sizeof(*sparse_data));
7276         *offset += sizeof(*sparse_data);
7277     }
7278
7279     memcpy(n_values, contents+*offset,
7280         sizeof(*n_values));
7281     if(tng_data->input_endianness_swap_func_64)
7282     {
7283         if(tng_data->input_endianness_swap_func_64(tng_data,
7284                                                    n_values)
7285             != TNG_SUCCESS)
7286         {
7287             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7288                     __FILE__, __LINE__);
7289         }
7290     }
7291     *offset += sizeof(*n_values);
7292
7293     memcpy(codec_id, contents+*offset,
7294         sizeof(*codec_id));
7295     if(tng_data->input_endianness_swap_func_64)
7296     {
7297         if(tng_data->input_endianness_swap_func_64(tng_data,
7298                                                    codec_id)
7299             != TNG_SUCCESS)
7300         {
7301             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7302                     __FILE__, __LINE__);
7303         }
7304     }
7305     *offset += sizeof(*codec_id);
7306
7307     if(*codec_id != TNG_UNCOMPRESSED)
7308     {
7309         memcpy(multiplier, contents+*offset,
7310             sizeof(*multiplier));
7311         if(tng_data->input_endianness_swap_func_64)
7312         {
7313             if(tng_data->input_endianness_swap_func_64(tng_data,
7314                                                        (int64_t *) multiplier)
7315                 != TNG_SUCCESS)
7316             {
7317                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7318                         __FILE__, __LINE__);
7319             }
7320         }
7321         *offset += sizeof(*multiplier);
7322     }
7323     else
7324     {
7325         *multiplier = 1;
7326     }
7327
7328     if(*dependency & TNG_FRAME_DEPENDENT)
7329     {
7330         if(*sparse_data)
7331         {
7332             memcpy(first_frame_with_data, contents+*offset,
7333                 sizeof(*first_frame_with_data));
7334             if(tng_data->input_endianness_swap_func_64)
7335             {
7336                 if(tng_data->input_endianness_swap_func_64(tng_data,
7337                                                            first_frame_with_data)
7338                     != TNG_SUCCESS)
7339                 {
7340                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7341                             __FILE__, __LINE__);
7342                 }
7343             }
7344             *offset += sizeof(*first_frame_with_data);
7345
7346             memcpy(stride_length, contents+*offset,
7347                 sizeof(*stride_length));
7348             if(tng_data->input_endianness_swap_func_64)
7349             {
7350                 if(tng_data->input_endianness_swap_func_64(tng_data,
7351                                                            stride_length)
7352                     != TNG_SUCCESS)
7353                 {
7354                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7355                             __FILE__, __LINE__);
7356                 }
7357             }
7358             *offset += sizeof(*stride_length);
7359             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7360                         (*first_frame_with_data -
7361                         tng_data->current_trajectory_frame_set.first_frame);
7362         }
7363         else
7364         {
7365             *first_frame_with_data = 0;
7366             *stride_length = 1;
7367             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7368         }
7369     }
7370     else
7371     {
7372         *first_frame_with_data = 0;
7373         *stride_length = 1;
7374         *n_frames = 1;
7375     }
7376
7377     if (*dependency & TNG_PARTICLE_DEPENDENT)
7378     {
7379         memcpy(num_first_particle, contents+*offset,
7380                sizeof(*num_first_particle));
7381         if(tng_data->input_endianness_swap_func_64)
7382         {
7383             if(tng_data->input_endianness_swap_func_64(tng_data,
7384                                                        num_first_particle)
7385                 != TNG_SUCCESS)
7386             {
7387                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7388                         __FILE__, __LINE__);
7389             }
7390         }
7391         *offset += sizeof(*num_first_particle);
7392
7393         memcpy(block_n_particles, contents+*offset,
7394             sizeof(*block_n_particles));
7395         if(tng_data->input_endianness_swap_func_64)
7396         {
7397             if(tng_data->input_endianness_swap_func_64(tng_data,
7398                                                        block_n_particles)
7399                 != TNG_SUCCESS)
7400             {
7401                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7402                         __FILE__, __LINE__);
7403             }
7404         }
7405         *offset += sizeof(*block_n_particles);
7406     }
7407
7408     if(!block->block_contents)
7409     {
7410         free(contents);
7411     }
7412     return(TNG_SUCCESS);
7413 }
7414
7415 /** Read the contents of a data block (particle or non-particle data).
7416  * @param tng_data is a trajectory data container.
7417  * @param block is the block to store the data (should already contain
7418  * the block headers).
7419  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7420  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7421  * compared to the md5 hash of the read contents to ensure valid data.
7422  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7423  * error has occured.
7424  */
7425 static tng_function_status tng_data_block_contents_read
7426                 (tng_trajectory_t tng_data,
7427                  tng_gen_block_t block,
7428                  const char hash_mode)
7429 {
7430     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7431     int64_t stride_length, block_n_particles, num_first_particle;
7432     double multiplier;
7433     char datatype, dependency, sparse_data;
7434     int offset = 0;
7435     tng_bool same_hash;
7436
7437     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7438     {
7439         return(TNG_CRITICAL);
7440     }
7441
7442     if(block->block_contents)
7443     {
7444         free(block->block_contents);
7445     }
7446
7447     block->block_contents = malloc(block->block_contents_size);
7448     if(!block->block_contents)
7449     {
7450         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7451                block->block_contents_size, __FILE__, __LINE__);
7452         return(TNG_CRITICAL);
7453     }
7454
7455     /* Read the whole block into block_contents to be able to write it to
7456      * disk even if it cannot be interpreted. */
7457     if(fread(block->block_contents, block->block_contents_size, 1,
7458              tng_data->input_file) == 0)
7459     {
7460         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7461         return(TNG_CRITICAL);
7462     }
7463
7464     /* FIXME: Does not check if the size of the contents matches the expected
7465      * size or if the contents can be read. */
7466
7467     if(hash_mode == TNG_USE_HASH)
7468     {
7469         tng_md5_hash_match_verify(block, &same_hash);
7470         if(same_hash != TNG_TRUE)
7471         {
7472             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7473                 block->name, __FILE__, __LINE__);
7474     /*         return(TNG_FAILURE); */
7475         }
7476     }
7477
7478     if(tng_data_block_meta_information_read(tng_data, block,
7479                                             &offset, &datatype,
7480                                             &dependency, &sparse_data,
7481                                             &n_values, &codec_id,
7482                                             &first_frame_with_data,
7483                                             &stride_length, &n_frames,
7484                                             &num_first_particle,
7485                                             &block_n_particles,
7486                                             &multiplier) == TNG_CRITICAL)
7487     {
7488         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7489             block->name, __FILE__, __LINE__);
7490         return(TNG_CRITICAL);
7491     }
7492
7493     if (dependency & TNG_PARTICLE_DEPENDENT)
7494     {
7495         return(tng_particle_data_read(tng_data, block,
7496                                       &offset, datatype,
7497                                       num_first_particle,
7498                                       block_n_particles,
7499                                       first_frame_with_data,
7500                                       stride_length,
7501                                       n_frames, n_values,
7502                                       codec_id, multiplier));
7503     }
7504     else
7505     {
7506         return(tng_data_read(tng_data, block,
7507                              &offset, datatype,
7508                              first_frame_with_data,
7509                              stride_length,
7510                              n_frames, n_values,
7511                              codec_id, multiplier));
7512     }
7513 }
7514
7515 /*
7516 // ** Move the blocks in a frame set so that there is no unused space between
7517 //  * them. This can only be done on the last frame set in the file and should
7518 //  * be done e.g. if the last frame set in the file has fewer frames than
7519 //  * default or after compressing data blocks in a frame set.
7520 //  * @param tng_data is a trajectory data container.
7521 //  * @details the current_trajectory_frame_set is the one that will be modified.
7522 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7523 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7524 //  * FIXME: This function is not finished!!!
7525 //  *
7526 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7527 // {
7528 //     tng_gen_block_t block;
7529 //     tng_trajectory_frame_set_t frame_set;
7530 //     FILE *temp = tng_data->input_file;
7531 //     int64_t pos, contents_start_pos, output_file_len;
7532 //
7533 //     frame_set = &tng_data->current_trajectory_frame_set;
7534 //
7535 //     if(frame_set->n_written_frames == frame_set->n_frames)
7536 //     {
7537 //         return(TNG_SUCCESS);
7538 //     }
7539 //
7540 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7541 //        tng_data->last_trajectory_frame_set_output_file_pos)
7542 //     {
7543 //     }
7544 //
7545 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7546 //     {
7547 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7548 //                __FILE__, __LINE__);
7549 //         return(TNG_CRITICAL);
7550 //     }
7551 //
7552 //     tng_block_init(&block);
7553 // //     output_file_pos = ftell(tng_data->output_file);
7554 //
7555 //     tng_data->input_file = tng_data->output_file;
7556 //
7557 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7558 //
7559 //     fseek(tng_data->output_file, pos, SEEK_SET);
7560 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7561 //     {
7562 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7563 //             __FILE__, __LINE__);
7564 //         tng_data->input_file = temp;
7565 //         tng_block_destroy(&block);
7566 //         return(TNG_CRITICAL);
7567 //     }
7568 //
7569 //     contents_start_pos = ftell(tng_data->output_file);
7570 //
7571 //     fseek(tng_data->output_file, 0, SEEK_END);
7572 //     output_file_len = ftell(tng_data->output_file);
7573 //     pos = contents_start_pos + block->block_contents_size;
7574 //     fseek(tng_data->output_file, pos,
7575 //           SEEK_SET);
7576 //
7577 //     while(pos < output_file_len)
7578 //     {
7579 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7580 //         {
7581 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7582 //                    __FILE__, __LINE__);
7583 //             tng_data->input_file = temp;
7584 //             tng_block_destroy(&block);
7585 //             return(TNG_CRITICAL);
7586 //         }
7587 //         pos += block->header_contents_size + block->block_contents_size;
7588 //         fseek(tng_data->output_file, pos, SEEK_SET);
7589 //     }
7590 //
7591 //     return(TNG_SUCCESS);
7592 // }
7593 */
7594 /** Finish writing the current frame set. Update the number of frames
7595  * and the hashes of the frame set and all its data blocks (if hash_mode
7596  * == TNG_USE_HASH).
7597  * @param tng_data is a trajectory data container.
7598  * @param hash_mode specifies whether to update the block md5 hash when
7599  * updating the pointers.
7600  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7601  * error has occured.
7602  */
7603 static tng_function_status tng_frame_set_finalize
7604                 (tng_trajectory_t tng_data, const char hash_mode)
7605 {
7606     tng_gen_block_t block;
7607     tng_trajectory_frame_set_t frame_set;
7608     FILE *temp = tng_data->input_file;
7609     int64_t pos, contents_start_pos, output_file_len;
7610
7611     frame_set = &tng_data->current_trajectory_frame_set;
7612
7613     if(frame_set->n_written_frames == frame_set->n_frames)
7614     {
7615         return(TNG_SUCCESS);
7616     }
7617
7618     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7619     {
7620         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7621                __FILE__, __LINE__);
7622         return(TNG_CRITICAL);
7623     }
7624
7625     tng_block_init(&block);
7626 /*     output_file_pos = ftell(tng_data->output_file); */
7627
7628     tng_data->input_file = tng_data->output_file;
7629
7630     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7631
7632     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7633
7634     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7635     {
7636         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7637             __FILE__, __LINE__);
7638         tng_data->input_file = temp;
7639         tng_block_destroy(&block);
7640         return(TNG_CRITICAL);
7641     }
7642
7643     contents_start_pos = ftell(tng_data->output_file);
7644
7645     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7646     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7647               1, tng_data->output_file) != 1)
7648     {
7649         tng_data->input_file = temp;
7650         tng_block_destroy(&block);
7651         return(TNG_CRITICAL);
7652     }
7653
7654
7655     if(hash_mode == TNG_USE_HASH)
7656     {
7657         tng_md5_hash_update(tng_data, block, pos,
7658                             pos + block->header_contents_size);
7659     }
7660
7661     fseek(tng_data->output_file, 0, SEEK_END);
7662     output_file_len = ftell(tng_data->output_file);
7663     pos = contents_start_pos + block->block_contents_size;
7664     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7665
7666     while(pos < output_file_len)
7667     {
7668         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7669         {
7670             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7671                    __FILE__, __LINE__);
7672             tng_data->input_file = temp;
7673             tng_block_destroy(&block);
7674             return(TNG_CRITICAL);
7675         }
7676
7677         if(hash_mode == TNG_USE_HASH)
7678         {
7679             tng_md5_hash_update(tng_data, block, pos,
7680                                 pos + block->header_contents_size);
7681         }
7682         pos += block->header_contents_size + block->block_contents_size;
7683         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7684     }
7685
7686     tng_data->input_file = temp;
7687     tng_block_destroy(&block);
7688     return(TNG_SUCCESS);
7689 }
7690
7691 /*
7692 // ** Sets the name of a file contents block
7693 //  * @param tng_data is a trajectory data container.
7694 //  * @param block is the block, of which to change names.
7695 //  * @param new_name is the new name of the block.
7696 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7697 //  * error has occured.
7698 //
7699 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7700 //                                               tng_gen_block_t block,
7701 //                                               const char *new_name)
7702 // {
7703 //     int len;
7704 //
7705 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7706 //
7707 //      * If the currently stored string length is not enough to store the new
7708 //      * string it is freed and reallocated. *
7709 //     if(block->name && strlen(block->name) < len)
7710 //     {
7711 //         free(block->name);
7712 //         block->name = 0;
7713 //     }
7714 //     if(!block->name)
7715 //     {
7716 //         block->name = malloc(len);
7717 //         if(!block->name)
7718 //         {
7719 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7720 //                    __FILE__, __LINE__);
7721 //             return(TNG_CRITICAL);
7722 //         }
7723 //     }
7724 //
7725 //     strncpy(block->name, new_name, len);
7726 //
7727 //     return(TNG_SUCCESS);
7728 // }
7729 */
7730
7731 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7732                                          const tng_atom_t atom,
7733                                          tng_residue_t *residue)
7734 {
7735     (void) tng_data;
7736
7737     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7738
7739     *residue = atom->residue;
7740
7741     return(TNG_SUCCESS);
7742 }
7743
7744 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7745                                       const tng_atom_t atom,
7746                                       char *name,
7747                                       const int max_len)
7748 {
7749     (void) tng_data;
7750     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7751     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7752
7753     strncpy(name, atom->name, max_len - 1);
7754     name[max_len - 1] = 0;
7755
7756     if(strlen(atom->name) > (unsigned int)max_len - 1)
7757     {
7758         return(TNG_FAILURE);
7759     }
7760     return(TNG_SUCCESS);
7761 }
7762
7763 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7764                                       tng_atom_t atom,
7765                                       const char *new_name)
7766 {
7767     unsigned int len;
7768     (void)tng_data;
7769
7770     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7771     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7772
7773     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7774
7775     /* If the currently stored string length is not enough to store the new
7776      * string it is freed and reallocated. */
7777     if(atom->name && strlen(atom->name) < len)
7778     {
7779         free(atom->name);
7780         atom->name = 0;
7781     }
7782     if(!atom->name)
7783     {
7784         atom->name = malloc(len);
7785         if(!atom->name)
7786         {
7787             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7788                    __FILE__, __LINE__);
7789             return(TNG_CRITICAL);
7790         }
7791     }
7792
7793     strncpy(atom->name, new_name, len);
7794
7795     return(TNG_SUCCESS);
7796 }
7797
7798 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7799                                       const tng_atom_t atom,
7800                                       char *type,
7801                                       const int max_len)
7802 {
7803     (void) tng_data;
7804     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7805     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7806
7807     strncpy(type, atom->atom_type, max_len - 1);
7808     type[max_len - 1] = 0;
7809
7810     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7811     {
7812         return(TNG_FAILURE);
7813     }
7814     return(TNG_SUCCESS);
7815 }
7816
7817 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7818                                       tng_atom_t atom,
7819                                       const char *new_type)
7820 {
7821     unsigned int len;
7822     (void)tng_data;
7823
7824     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7825     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7826
7827     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7828
7829     /* If the currently stored string length is not enough to store the new
7830      * string it is freed and reallocated. */
7831     if(atom->atom_type && strlen(atom->atom_type) < len)
7832     {
7833         free(atom->atom_type);
7834         atom->atom_type = 0;
7835     }
7836     if(!atom->atom_type)
7837     {
7838         atom->atom_type = malloc(len);
7839         if(!atom->atom_type)
7840         {
7841             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7842                    __FILE__, __LINE__);
7843             return(TNG_CRITICAL);
7844         }
7845     }
7846
7847     strncpy(atom->atom_type, new_type, len);
7848
7849     return(TNG_SUCCESS);
7850 }
7851
7852 /** Initialise an atom struct
7853  * @param atom is the atom to initialise.
7854  * @return TNG_SUCCESS (0) if successful.
7855  */
7856 static tng_function_status tng_atom_init(tng_atom_t atom)
7857 {
7858     atom->name = 0;
7859     atom->atom_type = 0;
7860
7861     return(TNG_SUCCESS);
7862 }
7863
7864 /** Free the memory in an atom struct
7865  * @param atom is the atom to destroy.
7866  * @return TNG_SUCCESS (0) if successful.
7867  */
7868 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7869 {
7870     if(atom->name)
7871     {
7872         free(atom->name);
7873         atom->name = 0;
7874     }
7875     if(atom->atom_type)
7876     {
7877         free(atom->atom_type);
7878         atom->atom_type = 0;
7879     }
7880
7881     return(TNG_SUCCESS);
7882 }
7883
7884 tng_function_status DECLSPECDLLEXPORT tng_version_major
7885                 (const tng_trajectory_t tng_data,
7886                  int *version)
7887 {
7888     (void)tng_data;
7889
7890     *version = TNG_VERSION_MAJOR;
7891
7892     return(TNG_SUCCESS);
7893 }
7894
7895 tng_function_status DECLSPECDLLEXPORT tng_version_minor
7896                 (const tng_trajectory_t tng_data,
7897                  int *version)
7898 {
7899     (void)tng_data;
7900
7901     *version = TNG_VERSION_MINOR;
7902
7903     return(TNG_SUCCESS);
7904 }
7905
7906 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
7907                 (const tng_trajectory_t tng_data,
7908                  int *patch_level)
7909 {
7910     (void)tng_data;
7911
7912     *patch_level = TNG_VERSION_PATCHLEVEL;
7913
7914     return(TNG_SUCCESS);
7915 }
7916
7917 tng_function_status DECLSPECDLLEXPORT tng_version
7918                 (const tng_trajectory_t tng_data,
7919                  char *version,
7920                  const int max_len)
7921 {
7922     (void)tng_data;
7923     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
7924
7925     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
7926
7927     return(TNG_SUCCESS);
7928 }
7929
7930 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7931                 (tng_trajectory_t tng_data,
7932                  const char *name,
7933                  tng_molecule_t *molecule)
7934 {
7935     int64_t id;
7936
7937     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7938     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7939
7940     /* Set ID to the ID of the last molecule + 1 */
7941     if(tng_data->n_molecules)
7942     {
7943         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7944     }
7945     else
7946     {
7947         id = 1;
7948     }
7949
7950     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7951 }
7952
7953 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7954                 (tng_trajectory_t tng_data,
7955                  const char *name,
7956                  const int64_t id,
7957                  tng_molecule_t *molecule)
7958 {
7959     tng_molecule_t new_molecules;
7960     int64_t *new_molecule_cnt_list;
7961     tng_function_status stat = TNG_SUCCESS;
7962
7963     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7964     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7965
7966     new_molecules = realloc(tng_data->molecules,
7967                             sizeof(struct tng_molecule) *
7968                             (tng_data->n_molecules + 1));
7969
7970     if(!new_molecules)
7971     {
7972         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7973                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7974                __FILE__, __LINE__);
7975         free(tng_data->molecules);
7976         tng_data->molecules = 0;
7977         return(TNG_CRITICAL);
7978     }
7979
7980     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7981                                     sizeof(int64_t) *
7982                                     (tng_data->n_molecules + 1));
7983
7984     if(!new_molecule_cnt_list)
7985     {
7986         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7987                sizeof(int64_t) * (tng_data->n_molecules + 1),
7988                __FILE__, __LINE__);
7989         free(tng_data->molecule_cnt_list);
7990         tng_data->molecule_cnt_list = 0;
7991         free(new_molecules);
7992         return(TNG_CRITICAL);
7993     }
7994
7995     tng_data->molecules = new_molecules;
7996     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7997
7998     *molecule = &new_molecules[tng_data->n_molecules];
7999
8000     tng_molecule_init(tng_data, *molecule);
8001     tng_molecule_name_set(tng_data, *molecule, name);
8002
8003     /* FIXME: Should this be a function argument instead? */
8004     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8005
8006     (*molecule)->id = id;
8007
8008     tng_data->n_molecules++;
8009
8010     return(stat);
8011 }
8012
8013 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
8014                 (tng_trajectory_t tng_data,
8015                  tng_molecule_t *molecule_p)
8016 {
8017     int64_t *new_molecule_cnt_list, id;
8018     tng_molecule_t new_molecules, molecule;
8019
8020     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8021
8022     /* Set ID to the ID of the last molecule + 1 */
8023     if(tng_data->n_molecules)
8024     {
8025         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
8026     }
8027     else
8028     {
8029         id = 1;
8030     }
8031
8032     new_molecules = realloc(tng_data->molecules,
8033                             sizeof(struct tng_molecule) *
8034                             (tng_data->n_molecules + 1));
8035
8036     if(!new_molecules)
8037     {
8038         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8039                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8040                __FILE__, __LINE__);
8041         free(tng_data->molecules);
8042         tng_data->molecules = 0;
8043         return(TNG_CRITICAL);
8044     }
8045
8046     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8047                                     sizeof(int64_t) *
8048                                     (tng_data->n_molecules + 1));
8049
8050     if(!new_molecule_cnt_list)
8051     {
8052         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8053                sizeof(int64_t) * (tng_data->n_molecules + 1),
8054                __FILE__, __LINE__);
8055         free(tng_data->molecule_cnt_list);
8056         tng_data->molecule_cnt_list = 0;
8057         free(new_molecules);
8058         return(TNG_CRITICAL);
8059     }
8060
8061     molecule = *molecule_p;
8062
8063     tng_data->molecules = new_molecules;
8064     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8065
8066     new_molecules[tng_data->n_molecules] = *molecule;
8067
8068     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8069
8070     free(*molecule_p);
8071
8072     molecule = &new_molecules[tng_data->n_molecules];
8073
8074     *molecule_p = molecule;
8075
8076     molecule->id = id;
8077
8078     tng_data->n_molecules++;
8079
8080     return(TNG_SUCCESS);
8081 }
8082
8083 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8084                                           const tng_molecule_t molecule,
8085                                           char *name,
8086                                           const int max_len)
8087 {
8088     (void) tng_data;
8089     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8090     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8091
8092     strncpy(name, molecule->name, max_len - 1);
8093     name[max_len - 1] = 0;
8094
8095     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8096     {
8097         return(TNG_FAILURE);
8098     }
8099     return(TNG_SUCCESS);
8100 }
8101
8102 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8103                 (tng_trajectory_t tng_data,
8104                  tng_molecule_t molecule,
8105                  const char *new_name)
8106 {
8107     unsigned int len;
8108     (void)tng_data;
8109
8110     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8111     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8112
8113     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8114
8115     /* If the currently stored string length is not enough to store the new
8116      * string it is freed and reallocated. */
8117     if(molecule->name && strlen(molecule->name) < len)
8118     {
8119         free(molecule->name);
8120         molecule->name = 0;
8121     }
8122     if(!molecule->name)
8123     {
8124         molecule->name = malloc(len);
8125         if(!molecule->name)
8126         {
8127             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8128                    __FILE__, __LINE__);
8129             return(TNG_CRITICAL);
8130         }
8131     }
8132
8133     strncpy(molecule->name, new_name, len);
8134
8135     return(TNG_SUCCESS);
8136 }
8137
8138 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8139                 (const tng_trajectory_t tng_data,
8140                  const tng_molecule_t molecule,
8141                  int64_t *cnt)
8142 {
8143     int64_t i, index = -1;
8144
8145     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8146     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8147
8148     for(i = 0; i < tng_data->n_molecules; i++)
8149     {
8150         if(&tng_data->molecules[i] == molecule)
8151         {
8152             index = i;
8153             break;
8154         }
8155     }
8156     if(index == -1)
8157     {
8158         return(TNG_FAILURE);
8159     }
8160     *cnt = tng_data->molecule_cnt_list[index];
8161
8162     return(TNG_SUCCESS);
8163 }
8164
8165 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8166                 (tng_trajectory_t tng_data,
8167                  tng_molecule_t molecule,
8168                  const int64_t cnt)
8169 {
8170     int64_t i, old_cnt, index = -1;
8171
8172     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8173
8174     for(i = 0; i < tng_data->n_molecules; i++)
8175     {
8176         if(&tng_data->molecules[i] == molecule)
8177         {
8178             index = i;
8179             break;
8180         }
8181     }
8182     if(index == -1)
8183     {
8184         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8185                __FILE__, __LINE__);
8186         return(TNG_FAILURE);
8187     }
8188     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8189     {
8190         old_cnt = tng_data->molecule_cnt_list[index];
8191         tng_data->molecule_cnt_list[index] = cnt;
8192
8193         tng_data->n_particles += (cnt-old_cnt) *
8194                                  tng_data->molecules[index].n_atoms;
8195     }
8196     else
8197     {
8198         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8199         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8200
8201         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8202                 tng_data->molecules[index].n_atoms;
8203     }
8204
8205     return(TNG_SUCCESS);
8206 }
8207
8208 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8209                 (tng_trajectory_t tng_data,
8210                  const char *name,
8211                  int64_t nr,
8212                  tng_molecule_t *molecule)
8213 {
8214     int64_t i, n_molecules;
8215
8216     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8217     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8218     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8219
8220     n_molecules = tng_data->n_molecules;
8221
8222     for(i = n_molecules - 1; i >= 0; i--)
8223     {
8224         *molecule = &tng_data->molecules[i];
8225         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8226         {
8227             if(nr == -1 || nr == (*molecule)->id)
8228             {
8229                 return(TNG_SUCCESS);
8230             }
8231         }
8232     }
8233
8234     *molecule = 0;
8235
8236     return(TNG_FAILURE);
8237 }
8238
8239 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8240                 (tng_trajectory_t tng_data,
8241                  int64_t index,
8242                  tng_molecule_t *molecule)
8243 {
8244     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8245     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8246
8247     if(index >= tng_data->n_molecules)
8248     {
8249         *molecule = 0;
8250         return(TNG_FAILURE);
8251     }
8252     *molecule = &tng_data->molecules[index];
8253     return(TNG_SUCCESS);
8254 }
8255
8256 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8257                                                                tng_trajectory_t tng_data_dest)
8258 {
8259     tng_molecule_t molecule, molecule_temp;
8260     tng_chain_t chain, chain_temp;
8261     tng_residue_t residue, residue_temp;
8262     tng_atom_t atom, atom_temp;
8263     tng_bond_t bond_temp;
8264     tng_function_status stat;
8265     int64_t i, j, k, l, *list_temp;
8266
8267     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8268     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8269
8270     for(i = 0; i < tng_data_dest->n_molecules; i++)
8271     {
8272         molecule = &tng_data_dest->molecules[i];
8273         tng_molecule_destroy(tng_data_dest, molecule);
8274     }
8275
8276     tng_data_dest->n_molecules = 0;
8277     tng_data_dest->n_particles = 0;
8278
8279     molecule_temp = realloc(tng_data_dest->molecules,
8280                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8281     if(!molecule_temp)
8282     {
8283         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8284                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8285                __FILE__, __LINE__);
8286         free(tng_data_dest->molecules);
8287         tng_data_dest->molecules = 0;
8288         return(TNG_CRITICAL);
8289     }
8290     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8291                                      sizeof(int64_t) * tng_data_src->n_molecules);
8292     if(!list_temp)
8293     {
8294         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8295                sizeof(int64_t) * tng_data_src->n_molecules,
8296                __FILE__, __LINE__);
8297         free(tng_data_dest->molecule_cnt_list);
8298         tng_data_dest->molecule_cnt_list = 0;
8299         free(molecule_temp);
8300         return(TNG_CRITICAL);
8301     }
8302
8303     tng_data_dest->molecules = molecule_temp;
8304     tng_data_dest->molecule_cnt_list = list_temp;
8305
8306     for(i = 0; i < tng_data_src->n_molecules; i++)
8307     {
8308         molecule = &tng_data_src->molecules[i];
8309         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8310                                      &molecule_temp);
8311         if(stat != TNG_SUCCESS)
8312         {
8313             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8314                    __FILE__, __LINE__);
8315             return(stat);
8316         }
8317         molecule_temp->quaternary_str = molecule->quaternary_str;
8318         for(j = 0; j < molecule->n_chains; j++)
8319         {
8320             chain = &molecule->chains[j];
8321             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8322                                                chain->name, chain->id,
8323                                                &chain_temp);
8324             if(stat != TNG_SUCCESS)
8325             {
8326                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8327                        __FILE__, __LINE__);
8328                 return(stat);
8329             }
8330             for(k = 0; k < chain->n_residues; k++)
8331             {
8332                 residue = &chain->residues[k];
8333                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8334                                                   residue->name, residue->id,
8335                                                   &residue_temp);
8336                 if(stat != TNG_SUCCESS)
8337                 {
8338                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8339                            __FILE__, __LINE__);
8340                     return(stat);
8341                 }
8342                 for(l = 0; l < residue->n_atoms; l++)
8343                 {
8344                     atom = &molecule->atoms[residue->atoms_offset + l];
8345                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8346                                                      atom->name, atom->atom_type,
8347                                                      atom->id, &atom_temp);
8348                     if(stat != TNG_SUCCESS)
8349                     {
8350                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8351                            __FILE__, __LINE__);
8352                         return(stat);
8353                     }
8354                 }
8355             }
8356         }
8357         molecule_temp->n_bonds = molecule->n_bonds;
8358         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8359                             molecule->n_bonds);
8360         if(!bond_temp)
8361         {
8362             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8363                    sizeof(struct tng_bond) * molecule->n_bonds,
8364                    __FILE__, __LINE__);
8365             free(molecule_temp->bonds);
8366             molecule_temp->n_bonds = 0;
8367             return(TNG_CRITICAL);
8368         }
8369         molecule_temp->bonds = bond_temp;
8370         for(j = 0; j < molecule->n_bonds; j++)
8371         {
8372             molecule_temp->bonds[j] = molecule->bonds[j];
8373         }
8374         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8375                                     tng_data_src->molecule_cnt_list[i]);
8376         if(stat != TNG_SUCCESS)
8377         {
8378             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8379                    __FILE__, __LINE__);
8380             return(stat);
8381         }
8382     }
8383     return(TNG_SUCCESS);
8384 }
8385
8386 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8387                 (const tng_trajectory_t tng_data,
8388                  const tng_molecule_t molecule,
8389                  int64_t *n)
8390 {
8391     (void) tng_data;
8392     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8393     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8394
8395     *n = molecule->n_chains;
8396
8397     return(TNG_SUCCESS);
8398 }
8399
8400 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8401                 (tng_trajectory_t tng_data,
8402                  tng_molecule_t molecule,
8403                  int64_t index,
8404                  tng_chain_t *chain)
8405 {
8406     (void) tng_data;
8407     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8408     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8409
8410     if(index >= molecule->n_chains)
8411     {
8412         *chain = 0;
8413         return(TNG_FAILURE);
8414     }
8415     *chain = &molecule->chains[index];
8416     return(TNG_SUCCESS);
8417 }
8418
8419 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8420                 (const tng_trajectory_t tng_data,
8421                  const tng_molecule_t molecule,
8422                  int64_t *n)
8423 {
8424     (void) tng_data;
8425     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8426     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8427
8428     *n = molecule->n_residues;
8429
8430     return(TNG_SUCCESS);
8431 }
8432
8433 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8434                 (const tng_trajectory_t tng_data,
8435                  const tng_molecule_t molecule,
8436                  const int64_t index,
8437                  tng_residue_t *residue)
8438 {
8439     (void) tng_data;
8440     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8441     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8442
8443     if(index >= molecule->n_residues)
8444     {
8445         *residue = 0;
8446         return(TNG_FAILURE);
8447     }
8448     *residue = &molecule->residues[index];
8449     return(TNG_SUCCESS);
8450 }
8451
8452 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8453                 (const tng_trajectory_t tng_data,
8454                  const tng_molecule_t molecule,
8455                  int64_t *n)
8456 {
8457     (void) tng_data;
8458     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8459     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8460
8461     *n = molecule->n_atoms;
8462
8463     return(TNG_SUCCESS);
8464 }
8465
8466 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8467                 (const tng_trajectory_t tng_data,
8468                  const tng_molecule_t molecule,
8469                  const int64_t index,
8470                  tng_atom_t *atom)
8471 {
8472     (void) tng_data;
8473     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8474     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8475
8476     if(index >= molecule->n_atoms)
8477     {
8478         *atom = 0;
8479         return(TNG_FAILURE);
8480     }
8481     *atom = &molecule->atoms[index];
8482     return(TNG_SUCCESS);
8483 }
8484
8485 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8486                 (tng_trajectory_t tng_data,
8487                  tng_molecule_t molecule,
8488                  const char *name,
8489                  int64_t nr,
8490                  tng_chain_t *chain)
8491 {
8492     int64_t i, n_chains;
8493     (void)tng_data;
8494
8495     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8496     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8497
8498     n_chains = molecule->n_chains;
8499
8500     for(i = n_chains - 1; i >= 0; i--)
8501     {
8502         *chain = &molecule->chains[i];
8503         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8504         {
8505             if(nr == -1 || nr == (*chain)->id)
8506             {
8507                 return(TNG_SUCCESS);
8508             }
8509         }
8510     }
8511
8512     *chain = 0;
8513
8514     return(TNG_FAILURE);
8515 }
8516
8517 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8518                 (tng_trajectory_t tng_data,
8519                  tng_molecule_t molecule,
8520                  const char *name,
8521                  tng_chain_t *chain)
8522 {
8523     int64_t id;
8524
8525     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8526     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8527
8528     /* Set ID to the ID of the last chain + 1 */
8529     if(molecule->n_chains)
8530     {
8531         id = molecule->chains[molecule->n_chains-1].id + 1;
8532     }
8533     else
8534     {
8535         id = 1;
8536     }
8537
8538     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8539                                        id, chain));
8540 }
8541
8542 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8543                 (tng_trajectory_t tng_data,
8544                  tng_molecule_t molecule,
8545                  const char *name,
8546                  const int64_t id,
8547                  tng_chain_t *chain)
8548 {
8549     tng_chain_t new_chains;
8550     tng_function_status stat = TNG_SUCCESS;
8551
8552     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8553     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8554
8555     new_chains = realloc(molecule->chains,
8556                          sizeof(struct tng_chain) *
8557                          (molecule->n_chains + 1));
8558
8559     if(!new_chains)
8560     {
8561         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8562                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8563                __FILE__, __LINE__);
8564         free(molecule->chains);
8565         molecule->chains = 0;
8566         return(TNG_CRITICAL);
8567     }
8568
8569     molecule->chains = new_chains;
8570
8571     *chain = &new_chains[molecule->n_chains];
8572     (*chain)->name = 0;
8573
8574     tng_chain_name_set(tng_data, *chain, name);
8575
8576     (*chain)->molecule = molecule;
8577     (*chain)->n_residues = 0;
8578
8579     molecule->n_chains++;
8580
8581     (*chain)->id = id;
8582
8583     return(stat);
8584 }
8585
8586 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8587                 (const tng_trajectory_t tng_data,
8588                  tng_molecule_t molecule,
8589                  const int64_t from_atom_id,
8590                  const int64_t to_atom_id,
8591                  tng_bond_t *bond)
8592 {
8593     tng_bond_t new_bonds;
8594     (void)tng_data;
8595
8596     new_bonds = realloc(molecule->bonds,
8597                         sizeof(struct tng_bond) *
8598                         (molecule->n_bonds + 1));
8599
8600     if(!new_bonds)
8601     {
8602         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8603                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8604                __FILE__, __LINE__);
8605         *bond = 0;
8606         free(molecule->bonds);
8607         molecule->bonds = 0;
8608         return(TNG_CRITICAL);
8609     }
8610
8611     molecule->bonds = new_bonds;
8612
8613     *bond = &new_bonds[molecule->n_bonds];
8614
8615     (*bond)->from_atom_id = from_atom_id;
8616     (*bond)->to_atom_id = to_atom_id;
8617
8618     molecule->n_bonds++;
8619
8620     return(TNG_SUCCESS);
8621 }
8622
8623 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8624                 (tng_trajectory_t tng_data,
8625                  tng_molecule_t molecule,
8626                  const char *name,
8627                  int64_t id,
8628                  tng_atom_t *atom)
8629 {
8630     int64_t i, n_atoms;
8631     (void)tng_data;
8632
8633     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8634
8635     n_atoms = molecule->n_atoms;
8636
8637     for(i = n_atoms - 1; i >= 0; i--)
8638     {
8639         *atom = &molecule->atoms[i];
8640         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8641         {
8642             if(id == -1 || id == (*atom)->id)
8643             {
8644                 return(TNG_SUCCESS);
8645             }
8646         }
8647     }
8648
8649     *atom = 0;
8650
8651     return(TNG_FAILURE);
8652 }
8653
8654 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8655                                        const tng_chain_t chain,
8656                                        char *name,
8657                                        const int max_len)
8658 {
8659     (void) tng_data;
8660     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8661     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8662
8663     strncpy(name, chain->name, max_len - 1);
8664     name[max_len - 1] = 0;
8665
8666     if(strlen(chain->name) > (unsigned int)max_len - 1)
8667     {
8668         return(TNG_FAILURE);
8669     }
8670     return(TNG_SUCCESS);
8671 }
8672
8673 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8674                 (tng_trajectory_t tng_data,
8675                  tng_chain_t chain,
8676                  const char *new_name)
8677 {
8678     unsigned int len;
8679     (void)tng_data;
8680
8681     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8682
8683     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8684
8685     /* If the currently stored string length is not enough to store the new
8686      * string it is freed and reallocated. */
8687     if(chain->name && strlen(chain->name) < len)
8688     {
8689         free(chain->name);
8690         chain->name = 0;
8691     }
8692     if(!chain->name)
8693     {
8694         chain->name = malloc(len);
8695         if(!chain->name)
8696         {
8697             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8698                    __FILE__, __LINE__);
8699             return(TNG_CRITICAL);
8700         }
8701     }
8702
8703     strncpy(chain->name, new_name, len);
8704
8705     return(TNG_SUCCESS);
8706 }
8707
8708 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8709                 (const tng_trajectory_t tng_data,
8710                  const tng_chain_t chain,
8711                  int64_t *n)
8712 {
8713     (void) tng_data;
8714     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8715     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8716
8717     *n = chain->n_residues;
8718
8719     return(TNG_SUCCESS);
8720 }
8721
8722 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8723                 (const tng_trajectory_t tng_data,
8724                  const tng_chain_t chain,
8725                  const int64_t index,
8726                  tng_residue_t *residue)
8727 {
8728     (void) tng_data;
8729     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8730     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8731
8732     if(index >= chain->n_residues)
8733     {
8734         *residue = 0;
8735         return(TNG_FAILURE);
8736     }
8737     *residue = &chain->residues[index];
8738     return(TNG_SUCCESS);
8739 }
8740
8741 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8742                 (tng_trajectory_t tng_data,
8743                  tng_chain_t chain,
8744                  const char *name,
8745                  int64_t id,
8746                  tng_residue_t *residue)
8747 {
8748     int64_t i, n_residues;
8749     (void)tng_data;
8750
8751     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8752
8753     n_residues = chain->n_residues;
8754
8755     for(i = n_residues - 1; i >= 0; i--)
8756     {
8757         *residue = &chain->residues[i];
8758         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8759         {
8760             if(id == -1 || id == (*residue)->id)
8761             {
8762                 return(TNG_SUCCESS);
8763             }
8764         }
8765     }
8766
8767     *residue = 0;
8768
8769     return(TNG_FAILURE);
8770 }
8771
8772 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8773                 (tng_trajectory_t tng_data,
8774                  tng_chain_t chain,
8775                  const char *name,
8776                  tng_residue_t *residue)
8777 {
8778     int64_t id;
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     /* Set ID to the ID of the last residue + 1 */
8784     if(chain->n_residues)
8785     {
8786         id = chain->residues[chain->n_residues-1].id + 1;
8787     }
8788     else
8789     {
8790         id = 0;
8791     }
8792
8793     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8794                                       id, residue));
8795 }
8796
8797 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8798                 (tng_trajectory_t tng_data,
8799                  tng_chain_t chain,
8800                  const char *name,
8801                  const int64_t id,
8802                  tng_residue_t *residue)
8803 {
8804     int64_t curr_index;
8805     tng_residue_t new_residues, temp_residue, last_residue;
8806     tng_molecule_t molecule = chain->molecule;
8807     tng_function_status stat = TNG_SUCCESS;
8808
8809     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8810     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8811
8812     if(chain->n_residues)
8813     {
8814         curr_index = chain->residues - molecule->residues;
8815     }
8816     else
8817     {
8818         curr_index = -1;
8819     }
8820
8821     new_residues = realloc(molecule->residues,
8822                            sizeof(struct tng_residue) *
8823                            (molecule->n_residues + 1));
8824
8825     if(!new_residues)
8826     {
8827         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8828                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8829                __FILE__, __LINE__);
8830         free(molecule->residues);
8831         molecule->residues = 0;
8832         return(TNG_CRITICAL);
8833     }
8834
8835     molecule->residues = new_residues;
8836
8837     if(curr_index != -1)
8838     {
8839         chain->residues = new_residues + curr_index;
8840         if(molecule->n_residues)
8841         {
8842             last_residue = &new_residues[molecule->n_residues - 1];
8843
8844             temp_residue = chain->residues + (chain->n_residues - 1);
8845             /* Make space in list of residues to add the new residues together with the other
8846             * residues of this chain */
8847             if(temp_residue != last_residue)
8848             {
8849                 ++temp_residue;
8850                 memmove(temp_residue + 1, temp_residue,
8851                         last_residue - temp_residue);
8852             }
8853         }
8854     }
8855     else
8856     {
8857         curr_index = molecule->n_residues;
8858     }
8859
8860     *residue = &molecule->residues[curr_index + chain->n_residues];
8861
8862     if(!chain->n_residues)
8863     {
8864         chain->residues = *residue;
8865     }
8866     else
8867     {
8868         chain->residues = &molecule->residues[curr_index];
8869     }
8870
8871     (*residue)->name = 0;
8872     tng_residue_name_set(tng_data, *residue, name);
8873
8874     (*residue)->chain = chain;
8875     (*residue)->n_atoms = 0;
8876     (*residue)->atoms_offset = 0;
8877
8878     chain->n_residues++;
8879     molecule->n_residues++;
8880
8881     (*residue)->id = id;
8882
8883     return(stat);
8884 }
8885
8886 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8887                                          const tng_residue_t residue,
8888                                          char *name,
8889                                          const int max_len)
8890 {
8891     (void) tng_data;
8892     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8893     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8894
8895     strncpy(name, residue->name, max_len - 1);
8896     name[max_len - 1] = 0;
8897
8898     if(strlen(residue->name) > (unsigned int)max_len - 1)
8899     {
8900         return(TNG_FAILURE);
8901     }
8902     return(TNG_SUCCESS);
8903 }
8904
8905 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8906                                                            tng_residue_t residue,
8907                                                            const char *new_name)
8908 {
8909     unsigned int len;
8910     (void)tng_data;
8911
8912     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8913     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8914
8915     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8916
8917     /* If the currently stored string length is not enough to store the new
8918      * string it is freed and reallocated. */
8919     if(residue->name && strlen(residue->name) < len)
8920     {
8921         free(residue->name);
8922         residue->name = 0;
8923     }
8924     if(!residue->name)
8925     {
8926         residue->name = malloc(len);
8927         if(!residue->name)
8928         {
8929             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8930                    __FILE__, __LINE__);
8931             return(TNG_CRITICAL);
8932         }
8933     }
8934
8935     strncpy(residue->name, new_name, len);
8936
8937     return(TNG_SUCCESS);
8938 }
8939
8940 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8941                 (const tng_trajectory_t tng_data,
8942                  const tng_residue_t residue,
8943                  int64_t *n)
8944 {
8945     (void) tng_data;
8946     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8947     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8948
8949     *n = residue->n_atoms;
8950
8951     return(TNG_SUCCESS);
8952 }
8953
8954 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8955                 (const tng_trajectory_t tng_data,
8956                  const tng_residue_t residue,
8957                  const int64_t index,
8958                  tng_atom_t *atom)
8959 {
8960     tng_chain_t chain;
8961     tng_molecule_t molecule;
8962
8963     (void) tng_data;
8964     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8965     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8966
8967     if(index >= residue->n_atoms)
8968     {
8969         *atom = 0;
8970         return(TNG_FAILURE);
8971     }
8972     chain = residue->chain;
8973     molecule = chain->molecule;
8974
8975     if(index + residue->atoms_offset >= molecule->n_atoms)
8976     {
8977         *atom = 0;
8978         return(TNG_FAILURE);
8979     }
8980
8981     *atom = &molecule->atoms[residue->atoms_offset + index];
8982     return(TNG_SUCCESS);
8983 }
8984
8985 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8986                 (tng_trajectory_t tng_data,
8987                  tng_residue_t residue,
8988                  const char *atom_name,
8989                  const char *atom_type,
8990                  tng_atom_t *atom)
8991 {
8992     int64_t id;
8993
8994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8995     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8996     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8997
8998     /* Set ID to the ID of the last atom + 1 */
8999     if(residue->chain->molecule->n_atoms)
9000     {
9001         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
9002     }
9003     else
9004     {
9005         id = 0;
9006     }
9007
9008     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
9009                                      id, atom));
9010 }
9011
9012 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
9013                 (tng_trajectory_t tng_data,
9014                  tng_residue_t residue,
9015                  const char *atom_name,
9016                  const char *atom_type,
9017                  const int64_t id,
9018                  tng_atom_t *atom)
9019 {
9020     tng_atom_t new_atoms;
9021     tng_molecule_t molecule = residue->chain->molecule;
9022     tng_function_status stat = TNG_SUCCESS;
9023
9024     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9025     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9026     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9027
9028     if(!residue->n_atoms)
9029     {
9030         residue->atoms_offset = molecule->n_atoms;
9031     }
9032
9033     new_atoms = realloc(molecule->atoms,
9034                         sizeof(struct tng_atom) *
9035                         (molecule->n_atoms + 1));
9036
9037     if(!new_atoms)
9038     {
9039         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9040                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
9041                __FILE__, __LINE__);
9042         free(molecule->atoms);
9043         molecule->atoms = 0;
9044         return(TNG_CRITICAL);
9045     }
9046
9047     molecule->atoms = new_atoms;
9048
9049     *atom = &new_atoms[molecule->n_atoms];
9050
9051     tng_atom_init(*atom);
9052     tng_atom_name_set(tng_data, *atom, atom_name);
9053     tng_atom_type_set(tng_data, *atom, atom_type);
9054
9055     (*atom)->residue = residue;
9056
9057     residue->n_atoms++;
9058     molecule->n_atoms++;
9059
9060     (*atom)->id = id;
9061
9062     return(stat);
9063 }
9064
9065 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
9066                                                          tng_molecule_t *molecule_p)
9067 {
9068     *molecule_p = malloc(sizeof(struct tng_molecule));
9069     if(!*molecule_p)
9070     {
9071         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9072                sizeof(struct tng_molecule), __FILE__, __LINE__);
9073         return(TNG_CRITICAL);
9074     }
9075
9076     tng_molecule_init(tng_data, *molecule_p);
9077
9078     return(TNG_SUCCESS);
9079 }
9080
9081 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9082                                                         tng_molecule_t *molecule_p)
9083 {
9084     if(!*molecule_p)
9085     {
9086         return(TNG_SUCCESS);
9087     }
9088
9089     tng_molecule_destroy(tng_data, *molecule_p);
9090
9091     free(*molecule_p);
9092     *molecule_p = 0;
9093
9094     return(TNG_SUCCESS);
9095 }
9096
9097 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9098                                                         tng_molecule_t molecule)
9099 {
9100     (void)tng_data;
9101     molecule->quaternary_str = 1;
9102     molecule->name = 0;
9103     molecule->n_chains = 0;
9104     molecule->chains = 0;
9105     molecule->n_residues = 0;
9106     molecule->residues = 0;
9107     molecule->n_atoms = 0;
9108     molecule->atoms = 0;
9109     molecule->n_bonds = 0;
9110     molecule->bonds = 0;
9111
9112     return(TNG_SUCCESS);
9113 }
9114
9115 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9116                                                            tng_molecule_t molecule)
9117 {
9118     int64_t i;
9119     (void)tng_data;
9120
9121     if(molecule->name)
9122     {
9123         free(molecule->name);
9124         molecule->name = 0;
9125     }
9126
9127     if(molecule->chains)
9128     {
9129         for(i = 0; i < molecule->n_chains; i++)
9130         {
9131             if(molecule->chains[i].name)
9132             {
9133                 free(molecule->chains[i].name);
9134                 molecule->chains[i].name = 0;
9135             }
9136         }
9137         free(molecule->chains);
9138         molecule->chains = 0;
9139     }
9140     molecule->n_chains = 0;
9141
9142     if(molecule->residues)
9143     {
9144         for(i = 0; i < molecule->n_residues; i++)
9145         {
9146             if(molecule->residues[i].name)
9147             {
9148                 free(molecule->residues[i].name);
9149                 molecule->residues[i].name = 0;
9150             }
9151         }
9152         free(molecule->residues);
9153         molecule->residues = 0;
9154     }
9155     molecule->n_residues = 0;
9156
9157     if(molecule->atoms)
9158     {
9159         for(i = 0; i < molecule->n_atoms; i++)
9160         {
9161             tng_atom_destroy(&molecule->atoms[i]);
9162         }
9163         free(molecule->atoms);
9164         molecule->atoms = 0;
9165     }
9166     molecule->n_atoms = 0;
9167
9168     if(molecule->bonds)
9169     {
9170         free(molecule->bonds);
9171         molecule->bonds = 0;
9172     }
9173     molecule->n_bonds = 0;
9174
9175     return(TNG_SUCCESS);
9176 }
9177
9178 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9179                 (const tng_trajectory_t tng_data,
9180                  const int64_t nr,
9181                  char *name,
9182                  int max_len)
9183 {
9184     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9185     tng_molecule_t mol;
9186     tng_bool found = TNG_FALSE;
9187
9188     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9189     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9190
9191     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9192
9193     if(!molecule_cnt_list)
9194     {
9195         return(TNG_FAILURE);
9196     }
9197
9198     for(i = 0; i < tng_data->n_molecules; i++)
9199     {
9200         mol = &tng_data->molecules[i];
9201         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9202         {
9203             cnt += mol->n_atoms * molecule_cnt_list[i];
9204             continue;
9205         }
9206         found = TNG_TRUE;
9207         break;
9208     }
9209     if(!found)
9210     {
9211         return(TNG_FAILURE);
9212     }
9213
9214     strncpy(name, mol->name, max_len - 1);
9215     name[max_len - 1] = 0;
9216
9217     if(strlen(mol->name) > (unsigned int)max_len - 1)
9218     {
9219         return(TNG_FAILURE);
9220     }
9221     return(TNG_SUCCESS);
9222 }
9223
9224 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9225                 (const tng_trajectory_t tng_data,
9226                  const int64_t nr,
9227                  int64_t *id)
9228 {
9229     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9230     tng_molecule_t mol;
9231     tng_bool found = TNG_FALSE;
9232
9233     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9234     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9235
9236     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9237
9238     if(!molecule_cnt_list)
9239     {
9240         return(TNG_FAILURE);
9241     }
9242
9243     for(i = 0; i < tng_data->n_molecules; i++)
9244     {
9245         mol = &tng_data->molecules[i];
9246         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9247         {
9248             cnt += mol->n_atoms * molecule_cnt_list[i];
9249             continue;
9250         }
9251         found = TNG_TRUE;
9252         break;
9253     }
9254     if(!found)
9255     {
9256         return(TNG_FAILURE);
9257     }
9258
9259     *id = mol->id;
9260
9261     return(TNG_SUCCESS);
9262 }
9263
9264 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9265                 (const tng_trajectory_t tng_data,
9266                  int64_t *n_bonds,
9267                  int64_t **from_atoms,
9268                  int64_t **to_atoms)
9269 {
9270     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9271     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9272     tng_molecule_t mol;
9273     tng_bond_t bond;
9274
9275     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9276     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9277     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9278     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9279
9280     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9281
9282     if(!molecule_cnt_list)
9283     {
9284         return(TNG_FAILURE);
9285     }
9286
9287     *n_bonds = 0;
9288     /* First count the total number of bonds to allocate memory */
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         *n_bonds += mol_cnt * mol->n_bonds;
9294     }
9295     if(*n_bonds == 0)
9296     {
9297         return(TNG_SUCCESS);
9298     }
9299
9300     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9301     if(!*from_atoms)
9302     {
9303         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9304                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9305         return(TNG_CRITICAL);
9306     }
9307     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9308     if(!*to_atoms)
9309     {
9310         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9311                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9312         free(*from_atoms);
9313         *from_atoms = 0;
9314         return(TNG_CRITICAL);
9315     }
9316
9317     cnt = 0;
9318     for(i = 0; i < tng_data->n_molecules; i++)
9319     {
9320         mol = &tng_data->molecules[i];
9321         mol_cnt = molecule_cnt_list[i];
9322         for(j = 0; j < mol_cnt; j++)
9323         {
9324             for(k = 0; k < mol->n_bonds; k++)
9325             {
9326                 bond = &mol->bonds[k];
9327                 from_atom = atom_cnt + bond->from_atom_id;
9328                 to_atom = atom_cnt + bond->to_atom_id;
9329                 (*from_atoms)[cnt] = from_atom;
9330                 (*to_atoms)[cnt++] = to_atom;
9331             }
9332             atom_cnt += mol->n_atoms;
9333         }
9334     }
9335
9336     return(TNG_SUCCESS);
9337 }
9338
9339 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9340                 (const tng_trajectory_t tng_data,
9341                  const int64_t nr,
9342                  char *name,
9343                  int max_len)
9344 {
9345     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9346     tng_molecule_t mol;
9347     tng_atom_t atom;
9348     tng_bool found = TNG_FALSE;
9349
9350     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9351     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9352
9353     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9354
9355     if(!molecule_cnt_list)
9356     {
9357         return(TNG_FAILURE);
9358     }
9359
9360     for(i = 0; i < tng_data->n_molecules; i++)
9361     {
9362         mol = &tng_data->molecules[i];
9363         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9364         {
9365             cnt += mol->n_atoms * molecule_cnt_list[i];
9366             continue;
9367         }
9368         atom = &mol->atoms[nr % mol->n_atoms];
9369         found = TNG_TRUE;
9370         break;
9371     }
9372     if(!found)
9373     {
9374         return(TNG_FAILURE);
9375     }
9376     if(!atom->residue || !atom->residue->chain)
9377     {
9378         return(TNG_FAILURE);
9379     }
9380
9381     strncpy(name, atom->residue->chain->name, max_len - 1);
9382     name[max_len - 1] = 0;
9383
9384     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9385     {
9386         return(TNG_FAILURE);
9387     }
9388     return(TNG_SUCCESS);
9389 }
9390
9391 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9392                 (const tng_trajectory_t tng_data,
9393                  const int64_t nr,
9394                  char *name,
9395                  int max_len)
9396 {
9397     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9398     tng_molecule_t mol;
9399     tng_atom_t atom;
9400     tng_bool found = TNG_FALSE;
9401
9402     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9403     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9404
9405     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9406
9407     if(!molecule_cnt_list)
9408     {
9409         return(TNG_FAILURE);
9410     }
9411
9412     for(i = 0; i < tng_data->n_molecules; i++)
9413     {
9414         mol = &tng_data->molecules[i];
9415         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9416         {
9417             cnt += mol->n_atoms * molecule_cnt_list[i];
9418             continue;
9419         }
9420         atom = &mol->atoms[nr % mol->n_atoms];
9421         found = TNG_TRUE;
9422         break;
9423     }
9424     if(!found)
9425     {
9426         return(TNG_FAILURE);
9427     }
9428     if(!atom->residue)
9429     {
9430         return(TNG_FAILURE);
9431     }
9432
9433     strncpy(name, atom->residue->name, max_len - 1);
9434     name[max_len - 1] = 0;
9435
9436     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9437     {
9438         return(TNG_FAILURE);
9439     }
9440     return(TNG_SUCCESS);
9441 }
9442
9443 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9444                 (const tng_trajectory_t tng_data,
9445                  const int64_t nr,
9446                  int64_t *id)
9447 {
9448     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9449     tng_molecule_t mol;
9450     tng_atom_t atom;
9451     tng_bool found = TNG_FALSE;
9452
9453     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9454     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9455
9456     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9457
9458     if(!molecule_cnt_list)
9459     {
9460         return(TNG_FAILURE);
9461     }
9462
9463     for(i = 0; i < tng_data->n_molecules; i++)
9464     {
9465         mol = &tng_data->molecules[i];
9466         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9467         {
9468             cnt += mol->n_atoms * molecule_cnt_list[i];
9469             continue;
9470         }
9471         atom = &mol->atoms[nr % mol->n_atoms];
9472         found = TNG_TRUE;
9473         break;
9474     }
9475     if(!found)
9476     {
9477         return(TNG_FAILURE);
9478     }
9479     if(!atom->residue)
9480     {
9481         return(TNG_FAILURE);
9482     }
9483
9484     *id = atom->residue->id;
9485
9486     return(TNG_SUCCESS);
9487 }
9488
9489 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9490                 (const tng_trajectory_t tng_data,
9491                  const int64_t nr,
9492                  int64_t *id)
9493 {
9494     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9495     tng_molecule_t mol;
9496     tng_atom_t atom;
9497     tng_bool found = TNG_FALSE;
9498
9499     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9500     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9501
9502     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9503
9504     if(!molecule_cnt_list)
9505     {
9506         return(TNG_FAILURE);
9507     }
9508
9509     for(i = 0; i < tng_data->n_molecules; i++)
9510     {
9511         mol = &tng_data->molecules[i];
9512         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9513         {
9514             cnt += mol->n_atoms * molecule_cnt_list[i];
9515             offset += mol->n_residues * molecule_cnt_list[i];
9516             continue;
9517         }
9518         atom = &mol->atoms[nr % mol->n_atoms];
9519         found = TNG_TRUE;
9520         break;
9521     }
9522     if(!found)
9523     {
9524         return(TNG_FAILURE);
9525     }
9526     if(!atom->residue)
9527     {
9528         return(TNG_FAILURE);
9529     }
9530
9531     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9532
9533     *id = atom->residue->id + offset;
9534
9535     return(TNG_SUCCESS);
9536 }
9537
9538 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9539                 (const tng_trajectory_t tng_data,
9540                  const int64_t nr,
9541                  char *name,
9542                  int max_len)
9543 {
9544     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9545     tng_molecule_t mol;
9546     tng_atom_t atom;
9547     tng_bool found = TNG_FALSE;
9548
9549     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9550     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9551
9552     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9553
9554     if(!molecule_cnt_list)
9555     {
9556         return(TNG_FAILURE);
9557     }
9558
9559     for(i = 0; i < tng_data->n_molecules; i++)
9560     {
9561         mol = &tng_data->molecules[i];
9562         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9563         {
9564             cnt += mol->n_atoms * molecule_cnt_list[i];
9565             continue;
9566         }
9567         atom = &mol->atoms[nr % mol->n_atoms];
9568         found = TNG_TRUE;
9569         break;
9570     }
9571     if(!found)
9572     {
9573         return(TNG_FAILURE);
9574     }
9575
9576     strncpy(name, atom->name, max_len - 1);
9577     name[max_len - 1] = 0;
9578
9579     if(strlen(atom->name) > (unsigned int)max_len - 1)
9580     {
9581         return(TNG_FAILURE);
9582     }
9583     return(TNG_SUCCESS);
9584 }
9585
9586 tng_function_status tng_atom_type_of_particle_nr_get
9587                 (const tng_trajectory_t tng_data,
9588                  const int64_t nr,
9589                  char *type,
9590                  int max_len)
9591 {
9592     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9593     tng_molecule_t mol;
9594     tng_atom_t atom;
9595     tng_bool found = TNG_FALSE;
9596
9597     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9598     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9599
9600     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9601
9602     if(!molecule_cnt_list)
9603     {
9604         return(TNG_FAILURE);
9605     }
9606
9607     for(i = 0; i < tng_data->n_molecules; i++)
9608     {
9609         mol = &tng_data->molecules[i];
9610         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9611         {
9612             cnt += mol->n_atoms * molecule_cnt_list[i];
9613             continue;
9614         }
9615         atom = &mol->atoms[nr % mol->n_atoms];
9616         found = TNG_TRUE;
9617         break;
9618     }
9619     if(!found)
9620     {
9621         return(TNG_FAILURE);
9622     }
9623
9624     strncpy(type, atom->atom_type, max_len - 1);
9625     type[max_len - 1] = 0;
9626
9627     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9628     {
9629         return(TNG_FAILURE);
9630     }
9631     return(TNG_SUCCESS);
9632 }
9633
9634 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9635                 (tng_trajectory_t tng_data,
9636                  const int64_t num_first_particle,
9637                  const int64_t n_particles,
9638                  const int64_t *mapping_table)
9639 {
9640     int64_t i;
9641     tng_particle_mapping_t mapping;
9642     tng_trajectory_frame_set_t frame_set;
9643
9644     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9645
9646     frame_set = &tng_data->current_trajectory_frame_set;
9647
9648     /* Sanity check of the particle ranges. Split into multiple if
9649      * statements for improved readability */
9650     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9651     {
9652         mapping = &frame_set->mappings[i];
9653         if(num_first_particle >= mapping->num_first_particle &&
9654            num_first_particle < mapping->num_first_particle +
9655                                    mapping->n_particles)
9656         {
9657             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9658             return(TNG_FAILURE);
9659         }
9660         if(num_first_particle + n_particles >=
9661            mapping->num_first_particle &&
9662            num_first_particle + n_particles <
9663            mapping->num_first_particle + mapping->n_particles)
9664         {
9665             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9666             return(TNG_FAILURE);
9667         }
9668         if(mapping->num_first_particle >= num_first_particle &&
9669            mapping->num_first_particle < num_first_particle +
9670                                             n_particles)
9671         {
9672             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9673             return(TNG_FAILURE);
9674         }
9675         if(mapping->num_first_particle + mapping->n_particles >
9676            num_first_particle &&
9677            mapping->num_first_particle + mapping->n_particles <
9678            num_first_particle + n_particles)
9679         {
9680             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9681             return(TNG_FAILURE);
9682         }
9683     }
9684
9685     frame_set->n_mapping_blocks++;
9686
9687     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9688                       frame_set->n_mapping_blocks);
9689
9690     if(!mapping)
9691     {
9692         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9693                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9694                __FILE__, __LINE__);
9695         free(frame_set->mappings);
9696         frame_set->mappings = 0;
9697         return(TNG_CRITICAL);
9698     }
9699     frame_set->mappings = mapping;
9700
9701     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9702     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9703
9704     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9705     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9706     {
9707         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9708                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9709         return(TNG_CRITICAL);
9710     }
9711
9712     for(i=0; i<n_particles; i++)
9713     {
9714         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9715     }
9716
9717     return(TNG_SUCCESS);
9718 }
9719
9720 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9721 {
9722     tng_trajectory_frame_set_t frame_set;
9723     tng_particle_mapping_t mapping;
9724     int64_t i;
9725
9726     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9727
9728     frame_set = &tng_data->current_trajectory_frame_set;
9729
9730     if(frame_set->n_mapping_blocks && frame_set->mappings)
9731     {
9732         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9733         {
9734             mapping = &frame_set->mappings[i];
9735             if(mapping->real_particle_numbers)
9736             {
9737                 free(mapping->real_particle_numbers);
9738                 mapping->real_particle_numbers = 0;
9739             }
9740         }
9741         free(frame_set->mappings);
9742         frame_set->mappings = 0;
9743         frame_set->n_mapping_blocks = 0;
9744     }
9745
9746     return(TNG_SUCCESS);
9747 }
9748
9749 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9750 {
9751     time_t seconds;
9752     tng_trajectory_frame_set_t frame_set;
9753     tng_trajectory_t tng_data;
9754
9755     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9756     if(!*tng_data_p)
9757     {
9758         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9759                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9760         return(TNG_CRITICAL);
9761     }
9762
9763     tng_data = *tng_data_p;
9764
9765     frame_set = &tng_data->current_trajectory_frame_set;
9766
9767     tng_data->input_file_path = 0;
9768     tng_data->input_file = 0;
9769     tng_data->input_file_len = 0;
9770     tng_data->output_file_path = 0;
9771     tng_data->output_file = 0;
9772
9773     tng_data->first_program_name = 0;
9774     tng_data->first_user_name = 0;
9775     tng_data->first_computer_name = 0;
9776     tng_data->first_pgp_signature = 0;
9777     tng_data->last_program_name = 0;
9778     tng_data->last_user_name = 0;
9779     tng_data->last_computer_name = 0;
9780     tng_data->last_pgp_signature = 0;
9781     tng_data->forcefield_name = 0;
9782
9783     seconds = time(0);
9784     if ( seconds == -1)
9785     {
9786         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9787     }
9788     else
9789     {
9790         tng_data->time = seconds;
9791     }
9792
9793     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9794     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9795     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9796     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9797     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9798     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9799     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9800     tng_data->frame_set_n_frames = 100;
9801     tng_data->n_trajectory_frame_sets = 0;
9802     tng_data->medium_stride_length = 100;
9803     tng_data->long_stride_length = 10000;
9804
9805     tng_data->time_per_frame = -1;
9806
9807     tng_data->n_particle_data_blocks = 0;
9808     tng_data->n_data_blocks = 0;
9809
9810     tng_data->non_tr_particle_data = 0;
9811     tng_data->non_tr_data = 0;
9812
9813     tng_data->compress_algo_pos = 0;
9814     tng_data->compress_algo_vel = 0;
9815     tng_data->compression_precision = 1000;
9816     tng_data->distance_unit_exponential = -9;
9817
9818     frame_set->first_frame = -1;
9819     frame_set->n_mapping_blocks = 0;
9820     frame_set->mappings = 0;
9821     frame_set->molecule_cnt_list = 0;
9822
9823     frame_set->n_particle_data_blocks = 0;
9824     frame_set->n_data_blocks = 0;
9825
9826     frame_set->tr_particle_data = 0;
9827     frame_set->tr_data = 0;
9828
9829     frame_set->n_written_frames = 0;
9830     frame_set->n_unwritten_frames = 0;
9831
9832     frame_set->next_frame_set_file_pos = -1;
9833     frame_set->prev_frame_set_file_pos = -1;
9834     frame_set->medium_stride_next_frame_set_file_pos = -1;
9835     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9836     frame_set->long_stride_next_frame_set_file_pos = -1;
9837     frame_set->long_stride_prev_frame_set_file_pos = -1;
9838
9839     frame_set->first_frame_time = -1;
9840
9841     tng_data->n_molecules = 0;
9842     tng_data->molecules = 0;
9843     tng_data->molecule_cnt_list = 0;
9844     tng_data->n_particles = 0;
9845
9846     {
9847       /* Check the endianness of the computer */
9848       static int32_t endianness_32 = 0x01234567;
9849       /* 0x01234567 */
9850       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9851         {
9852           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9853         }
9854
9855       /* 0x67452301 */
9856       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9857         {
9858           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9859
9860         }
9861
9862       /* 0x45670123 */
9863       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9864         {
9865           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9866         }
9867     }
9868     {
9869       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9870       /* 0x0123456789ABCDEF */
9871       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9872         {
9873           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9874         }
9875
9876       /* 0xEFCDAB8967452301 */
9877       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9878         {
9879           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9880         }
9881
9882       /* 0x89ABCDEF01234567 */
9883       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9884         {
9885           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9886         }
9887
9888       /* 0x45670123CDEF89AB */
9889       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9890         {
9891           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9892         }
9893
9894       /* 0x23016745AB89EFCD */
9895       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9896         {
9897           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9898         }
9899     }
9900
9901     /* By default do not swap the byte order, i.e. keep the byte order of the
9902      * architecture. The input file endianness will be set when reading the
9903      * header. The output endianness can be changed - before the file is
9904      * written. */
9905     tng_data->input_endianness_swap_func_32 = 0;
9906     tng_data->input_endianness_swap_func_64 = 0;
9907     tng_data->output_endianness_swap_func_32 = 0;
9908     tng_data->output_endianness_swap_func_64 = 0;
9909
9910     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9911     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9912     tng_data->current_trajectory_frame_set.n_frames = 0;
9913
9914     return(TNG_SUCCESS);
9915 }
9916
9917 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9918 {
9919     int64_t i, j, k, l;
9920     int64_t n_particles, n_values_per_frame;
9921     tng_trajectory_t tng_data = *tng_data_p;
9922     tng_trajectory_frame_set_t frame_set;
9923
9924     if(!*tng_data_p)
9925     {
9926         return(TNG_SUCCESS);
9927     }
9928
9929     frame_set = &tng_data->current_trajectory_frame_set;
9930
9931     if(tng_data->input_file_path)
9932     {
9933         free(tng_data->input_file_path);
9934         tng_data->input_file_path = 0;
9935     }
9936
9937     if(tng_data->input_file)
9938     {
9939         if(tng_data->output_file == tng_data->input_file)
9940         {
9941             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9942             tng_data->output_file = 0;
9943         }
9944         fclose(tng_data->input_file);
9945         tng_data->input_file = 0;
9946     }
9947
9948     if(tng_data->output_file_path)
9949     {
9950         free(tng_data->output_file_path);
9951         tng_data->output_file_path = 0;
9952     }
9953
9954     if(tng_data->output_file)
9955     {
9956         /* FIXME: Do not always write the hash */
9957         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9958         fclose(tng_data->output_file);
9959         tng_data->output_file = 0;
9960     }
9961
9962     if(tng_data->first_program_name)
9963     {
9964         free(tng_data->first_program_name);
9965         tng_data->first_program_name = 0;
9966     }
9967
9968     if(tng_data->last_program_name)
9969     {
9970         free(tng_data->last_program_name);
9971         tng_data->last_program_name = 0;
9972     }
9973
9974     if(tng_data->first_user_name)
9975     {
9976         free(tng_data->first_user_name);
9977         tng_data->first_user_name = 0;
9978     }
9979
9980     if(tng_data->last_user_name)
9981     {
9982         free(tng_data->last_user_name);
9983         tng_data->last_user_name = 0;
9984     }
9985
9986     if(tng_data->first_computer_name)
9987     {
9988         free(tng_data->first_computer_name);
9989         tng_data->first_computer_name = 0;
9990     }
9991
9992     if(tng_data->last_computer_name)
9993     {
9994         free(tng_data->last_computer_name);
9995         tng_data->last_computer_name = 0;
9996     }
9997
9998     if(tng_data->first_pgp_signature)
9999     {
10000         free(tng_data->first_pgp_signature);
10001         tng_data->first_pgp_signature = 0;
10002     }
10003
10004     if(tng_data->last_pgp_signature)
10005     {
10006         free(tng_data->last_pgp_signature);
10007         tng_data->last_pgp_signature = 0;
10008     }
10009
10010     if(tng_data->forcefield_name)
10011     {
10012         free(tng_data->forcefield_name);
10013         tng_data->forcefield_name = 0;
10014     }
10015
10016     tng_frame_set_particle_mapping_free(tng_data);
10017
10018     if(frame_set->molecule_cnt_list)
10019     {
10020         free(frame_set->molecule_cnt_list);
10021         frame_set->molecule_cnt_list = 0;
10022     }
10023
10024     if(tng_data->var_num_atoms_flag)
10025     {
10026         n_particles = frame_set->n_particles;
10027     }
10028     else
10029     {
10030         n_particles = tng_data->n_particles;
10031     }
10032
10033     if(tng_data->non_tr_particle_data)
10034     {
10035         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
10036         {
10037             if(tng_data->non_tr_particle_data[i].values)
10038             {
10039                 free(tng_data->non_tr_particle_data[i].values);
10040                 tng_data->non_tr_particle_data[i].values = 0;
10041             }
10042
10043             if(tng_data->non_tr_particle_data[i].strings)
10044             {
10045                 n_values_per_frame = tng_data->non_tr_particle_data[i].
10046                                      n_values_per_frame;
10047                 if(tng_data->non_tr_particle_data[i].strings[0])
10048                 {
10049                     for(j = 0; j < n_particles; j++)
10050                     {
10051                         if(tng_data->non_tr_particle_data[i].strings[0][j])
10052                         {
10053                             for(k = 0; k < n_values_per_frame; k++)
10054                             {
10055                                 if(tng_data->non_tr_particle_data[i].
10056                                    strings[0][j][k])
10057                                 {
10058                                     free(tng_data->non_tr_particle_data[i].
10059                                          strings[0][j][k]);
10060                                     tng_data->non_tr_particle_data[i].
10061                                     strings[0][j][k] = 0;
10062                                 }
10063                             }
10064                             free(tng_data->non_tr_particle_data[i].
10065                                  strings[0][j]);
10066                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
10067                         }
10068                     }
10069                     free(tng_data->non_tr_particle_data[i].strings[0]);
10070                     tng_data->non_tr_particle_data[i].strings[0] = 0;
10071                 }
10072                 free(tng_data->non_tr_particle_data[i].strings);
10073                 tng_data->non_tr_particle_data[i].strings = 0;
10074             }
10075
10076             if(tng_data->non_tr_particle_data[i].block_name)
10077             {
10078                 free(tng_data->non_tr_particle_data[i].block_name);
10079                 tng_data->non_tr_particle_data[i].block_name = 0;
10080             }
10081         }
10082         free(tng_data->non_tr_particle_data);
10083         tng_data->non_tr_particle_data = 0;
10084     }
10085
10086     if(tng_data->non_tr_data)
10087     {
10088         for(i = 0; i < tng_data->n_data_blocks; i++)
10089         {
10090             if(tng_data->non_tr_data[i].values)
10091             {
10092                 free(tng_data->non_tr_data[i].values);
10093                 tng_data->non_tr_data[i].values = 0;
10094             }
10095
10096             if(tng_data->non_tr_data[i].strings)
10097             {
10098                 n_values_per_frame = tng_data->non_tr_data[i].
10099                                      n_values_per_frame;
10100                 if(tng_data->non_tr_data[i].strings[0])
10101                 {
10102                     for(j = 0; j < n_values_per_frame; j++)
10103                     {
10104                         if(tng_data->non_tr_data[i].strings[0][j])
10105                         {
10106                             free(tng_data->non_tr_data[i].strings[0][j]);
10107                             tng_data->non_tr_data[i].strings[0][j] = 0;
10108                         }
10109                     }
10110                     free(tng_data->non_tr_data[i].strings[0]);
10111                     tng_data->non_tr_data[i].strings[0] = 0;
10112                 }
10113                 free(tng_data->non_tr_data[i].strings);
10114                 tng_data->non_tr_data[i].strings = 0;
10115             }
10116
10117             if(tng_data->non_tr_data[i].block_name)
10118             {
10119                 free(tng_data->non_tr_data[i].block_name);
10120                 tng_data->non_tr_data[i].block_name = 0;
10121             }
10122         }
10123         free(tng_data->non_tr_data);
10124         tng_data->non_tr_data = 0;
10125     }
10126
10127     tng_data->n_particle_data_blocks = 0;
10128     tng_data->n_data_blocks = 0;
10129
10130     if(tng_data->compress_algo_pos)
10131     {
10132         free(tng_data->compress_algo_pos);
10133         tng_data->compress_algo_pos = 0;
10134     }
10135     if(tng_data->compress_algo_vel)
10136     {
10137         free(tng_data->compress_algo_vel);
10138         tng_data->compress_algo_vel = 0;
10139     }
10140
10141     if(frame_set->tr_particle_data)
10142     {
10143         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10144         {
10145             if(frame_set->tr_particle_data[i].values)
10146             {
10147                 free(frame_set->tr_particle_data[i].values);
10148                 frame_set->tr_particle_data[i].values = 0;
10149             }
10150
10151             if(frame_set->tr_particle_data[i].strings)
10152             {
10153                 n_values_per_frame = frame_set->tr_particle_data[i].
10154                                      n_values_per_frame;
10155                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10156                 {
10157                     if(frame_set->tr_particle_data[i].strings[j])
10158                     {
10159                         for(k = 0; k < n_particles; k++)
10160                         {
10161                             if(frame_set->tr_particle_data[i].
10162                                 strings[j][k])
10163                             {
10164                                 for(l = 0; l < n_values_per_frame; l++)
10165                                 {
10166                                     if(frame_set->tr_particle_data[i].
10167                                         strings[j][k][l])
10168                                     {
10169                                         free(frame_set->tr_particle_data[i].
10170                                                 strings[j][k][l]);
10171                                         frame_set->tr_particle_data[i].
10172                                         strings[j][k][l] = 0;
10173                                     }
10174                                 }
10175                                 free(frame_set->tr_particle_data[i].
10176                                         strings[j][k]);
10177                                 frame_set->tr_particle_data[i].
10178                                 strings[j][k] = 0;
10179                             }
10180                         }
10181                         free(frame_set->tr_particle_data[i].strings[j]);
10182                         frame_set->tr_particle_data[i].strings[j] = 0;
10183                     }
10184                 }
10185                 free(frame_set->tr_particle_data[i].strings);
10186                 frame_set->tr_particle_data[i].strings = 0;
10187             }
10188
10189             if(frame_set->tr_particle_data[i].block_name)
10190             {
10191                 free(frame_set->tr_particle_data[i].block_name);
10192                 frame_set->tr_particle_data[i].block_name = 0;
10193             }
10194         }
10195         free(frame_set->tr_particle_data);
10196         frame_set->tr_particle_data = 0;
10197     }
10198
10199     if(frame_set->tr_data)
10200     {
10201         for(i = 0; i < frame_set->n_data_blocks; i++)
10202         {
10203             if(frame_set->tr_data[i].values)
10204             {
10205                 free(frame_set->tr_data[i].values);
10206                 frame_set->tr_data[i].values = 0;
10207             }
10208
10209             if(frame_set->tr_data[i].strings)
10210             {
10211                 n_values_per_frame = frame_set->tr_data[i].
10212                                      n_values_per_frame;
10213                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10214                 {
10215                     if(frame_set->tr_data[i].strings[j])
10216                     {
10217                         for(k = 0; k < n_values_per_frame; k++)
10218                         {
10219                             if(frame_set->tr_data[i].strings[j][k])
10220                             {
10221                                 free(frame_set->tr_data[i].strings[j][k]);
10222                                 frame_set->tr_data[i].strings[j][k] = 0;
10223                             }
10224                         }
10225                         free(frame_set->tr_data[i].strings[j]);
10226                         frame_set->tr_data[i].strings[j] = 0;
10227                     }
10228                 }
10229                 free(frame_set->tr_data[i].strings);
10230                 frame_set->tr_data[i].strings = 0;
10231             }
10232
10233             if(frame_set->tr_data[i].block_name)
10234             {
10235                 free(frame_set->tr_data[i].block_name);
10236                 frame_set->tr_data[i].block_name = 0;
10237             }
10238         }
10239         free(frame_set->tr_data);
10240         frame_set->tr_data = 0;
10241     }
10242
10243     frame_set->n_particle_data_blocks = 0;
10244     frame_set->n_data_blocks = 0;
10245
10246     if(tng_data->molecules)
10247     {
10248         for(i = 0; i < tng_data->n_molecules; i++)
10249         {
10250             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10251         }
10252         free(tng_data->molecules);
10253         tng_data->molecules = 0;
10254         tng_data->n_molecules = 0;
10255     }
10256     if(tng_data->molecule_cnt_list)
10257     {
10258         free(tng_data->molecule_cnt_list);
10259         tng_data->molecule_cnt_list = 0;
10260     }
10261
10262     free(*tng_data_p);
10263     *tng_data_p = 0;
10264
10265     return(TNG_SUCCESS);
10266 }
10267
10268 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10269                                                  tng_trajectory_t *dest_p)
10270 {
10271     tng_trajectory_frame_set_t frame_set;
10272     tng_trajectory_t dest;
10273
10274     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10275
10276     *dest_p = malloc(sizeof(struct tng_trajectory));
10277     if(!*dest_p)
10278     {
10279         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
10280                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10281         return(TNG_CRITICAL);
10282     }
10283
10284     dest = *dest_p;
10285
10286     frame_set = &dest->current_trajectory_frame_set;
10287
10288     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10289     if(!dest->input_file_path)
10290     {
10291         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10292                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10293         return(TNG_CRITICAL);
10294     }
10295     strcpy(dest->input_file_path, src->input_file_path);
10296     dest->input_file = 0;
10297     dest->input_file_len = src->input_file_len;
10298     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10299     if(!dest->output_file_path)
10300     {
10301         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10302                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10303         return(TNG_CRITICAL);
10304     }
10305     strcpy(dest->output_file_path, src->output_file_path);
10306     dest->output_file = 0;
10307
10308     dest->first_program_name = 0;
10309     dest->first_user_name = 0;
10310     dest->first_computer_name = 0;
10311     dest->first_pgp_signature = 0;
10312     dest->last_program_name = 0;
10313     dest->last_user_name = 0;
10314     dest->last_computer_name = 0;
10315     dest->last_pgp_signature = 0;
10316     dest->forcefield_name = 0;
10317
10318     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10319     dest->first_trajectory_frame_set_input_file_pos =
10320     src->first_trajectory_frame_set_input_file_pos;
10321     dest->last_trajectory_frame_set_input_file_pos =
10322     src->last_trajectory_frame_set_input_file_pos;
10323     dest->current_trajectory_frame_set_input_file_pos =
10324     src->current_trajectory_frame_set_input_file_pos;
10325     dest->first_trajectory_frame_set_output_file_pos =
10326     src->first_trajectory_frame_set_output_file_pos;
10327     dest->last_trajectory_frame_set_output_file_pos =
10328     src->last_trajectory_frame_set_output_file_pos;
10329     dest->current_trajectory_frame_set_output_file_pos =
10330     src->current_trajectory_frame_set_output_file_pos;
10331     dest->frame_set_n_frames = src->frame_set_n_frames;
10332     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10333     dest->medium_stride_length = src->medium_stride_length;
10334     dest->long_stride_length = src->long_stride_length;
10335
10336     dest->time_per_frame = src->time_per_frame;
10337
10338     /* Currently the non trajectory data blocks are not copied since it
10339      * can lead to problems when freeing memory in a parallel block. */
10340     dest->n_particle_data_blocks = 0;
10341     dest->n_data_blocks = 0;
10342     dest->non_tr_particle_data = 0;
10343     dest->non_tr_data = 0;
10344
10345     dest->compress_algo_pos = 0;
10346     dest->compress_algo_vel = 0;
10347     dest->distance_unit_exponential = -9;
10348     dest->compression_precision = 1000;
10349
10350     frame_set->n_mapping_blocks = 0;
10351     frame_set->mappings = 0;
10352     frame_set->molecule_cnt_list = 0;
10353
10354     frame_set->n_particle_data_blocks = 0;
10355     frame_set->n_data_blocks = 0;
10356
10357     frame_set->tr_particle_data = 0;
10358     frame_set->tr_data = 0;
10359
10360     frame_set->next_frame_set_file_pos = -1;
10361     frame_set->prev_frame_set_file_pos = -1;
10362     frame_set->medium_stride_next_frame_set_file_pos = -1;
10363     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10364     frame_set->long_stride_next_frame_set_file_pos = -1;
10365     frame_set->long_stride_prev_frame_set_file_pos = -1;
10366     frame_set->first_frame = -1;
10367
10368     dest->n_molecules = 0;
10369     dest->molecules = 0;
10370     dest->molecule_cnt_list = 0;
10371     dest->n_particles = src->n_particles;
10372
10373     dest->endianness_32 = src->endianness_32;
10374     dest->endianness_64 = src->endianness_64;
10375     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10376     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10377     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10378     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10379
10380     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10381     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10382     dest->current_trajectory_frame_set.n_frames = 0;
10383
10384     return(TNG_SUCCESS);
10385 }
10386
10387 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10388                                        char *file_name, const int max_len)
10389 {
10390     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10391     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10392
10393     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10394     file_name[max_len - 1] = 0;
10395
10396     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10397     {
10398         return(TNG_FAILURE);
10399     }
10400     return(TNG_SUCCESS);
10401 }
10402
10403 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10404                                                          const char *file_name)
10405 {
10406     unsigned int len;
10407     char *temp;
10408
10409     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10410     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10411
10412
10413     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10414                                            file_name) == 0)
10415     {
10416         return(TNG_SUCCESS);
10417     }
10418
10419     if(tng_data->input_file)
10420     {
10421         fclose(tng_data->input_file);
10422     }
10423
10424     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10425     temp = realloc(tng_data->input_file_path, len);
10426     if(!temp)
10427     {
10428         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10429                __FILE__, __LINE__);
10430         free(tng_data->input_file_path);
10431         tng_data->input_file_path = 0;
10432         return(TNG_CRITICAL);
10433     }
10434     tng_data->input_file_path = temp;
10435
10436     strncpy(tng_data->input_file_path, file_name, len);
10437
10438     return(tng_input_file_init(tng_data));
10439 }
10440
10441 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10442                                        char *file_name, const int max_len)
10443 {
10444     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10445     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10446
10447     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10448     file_name[max_len - 1] = 0;
10449
10450     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10451     {
10452         return(TNG_FAILURE);
10453     }
10454     return(TNG_SUCCESS);
10455 }
10456
10457 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10458                                                           const char *file_name)
10459 {
10460     int len;
10461     char *temp;
10462
10463     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10464     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10465
10466     if(tng_data->output_file_path &&
10467        strcmp(tng_data->output_file_path, file_name) == 0)
10468     {
10469         return(TNG_SUCCESS);
10470     }
10471
10472     if(tng_data->output_file)
10473     {
10474         fclose(tng_data->output_file);
10475     }
10476
10477     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10478     temp = realloc(tng_data->output_file_path, len);
10479     if(!temp)
10480     {
10481         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10482                __FILE__, __LINE__);
10483         free(tng_data->output_file_path);
10484         tng_data->output_file_path = 0;
10485         return(TNG_CRITICAL);
10486     }
10487     tng_data->output_file_path = temp;
10488
10489     strncpy(tng_data->output_file_path, file_name, len);
10490
10491     return(tng_output_file_init(tng_data));
10492 }
10493
10494 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10495                 (tng_trajectory_t tng_data,
10496                  const char *file_name)
10497 {
10498     int len;
10499     char *temp;
10500
10501     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10502     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10503
10504     if(tng_data->output_file_path &&
10505        strcmp(tng_data->output_file_path, file_name) == 0)
10506     {
10507         return(TNG_SUCCESS);
10508     }
10509
10510     if(tng_data->output_file)
10511     {
10512         fclose(tng_data->output_file);
10513     }
10514
10515     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10516     temp = realloc(tng_data->output_file_path, len);
10517     if(!temp)
10518     {
10519         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10520                __FILE__, __LINE__);
10521         free(tng_data->output_file_path);
10522         tng_data->output_file_path = 0;
10523         return(TNG_CRITICAL);
10524     }
10525     tng_data->output_file_path = temp;
10526
10527     strncpy(tng_data->output_file_path, file_name, len);
10528
10529     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10530     if(!tng_data->output_file)
10531     {
10532         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10533                 tng_data->output_file_path, __FILE__, __LINE__);
10534         return(TNG_CRITICAL);
10535     }
10536     tng_data->input_file = tng_data->output_file;
10537
10538     return(TNG_SUCCESS);
10539 }
10540
10541 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10542                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10543 {
10544     tng_endianness_32 end_32;
10545     tng_endianness_64 end_64;
10546
10547     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10548     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10549
10550     if(tng_data->output_endianness_swap_func_32)
10551     {
10552         /* If other endianness variants are added they must be added here as well */
10553         if(tng_data->output_endianness_swap_func_32 ==
10554            &tng_swap_byte_order_big_endian_32)
10555         {
10556             end_32 = TNG_BIG_ENDIAN_32;
10557         }
10558         else if(tng_data->output_endianness_swap_func_32 ==
10559                 &tng_swap_byte_order_little_endian_32)
10560         {
10561             end_32 = TNG_LITTLE_ENDIAN_32;
10562         }
10563         else
10564         {
10565             return(TNG_FAILURE);
10566         }
10567     }
10568     else
10569     {
10570         end_32 = (tng_endianness_32)tng_data->endianness_32;
10571     }
10572
10573     if(tng_data->output_endianness_swap_func_64)
10574     {
10575         /* If other endianness variants are added they must be added here as well */
10576         if(tng_data->output_endianness_swap_func_64 ==
10577            &tng_swap_byte_order_big_endian_64)
10578         {
10579             end_64 = TNG_BIG_ENDIAN_64;
10580         }
10581         else if(tng_data->output_endianness_swap_func_64 ==
10582                 &tng_swap_byte_order_little_endian_64)
10583         {
10584             end_64 = TNG_LITTLE_ENDIAN_64;
10585         }
10586         else
10587         {
10588             return(TNG_FAILURE);
10589         }
10590     }
10591     else
10592     {
10593         end_64 = (tng_endianness_64)tng_data->endianness_64;
10594     }
10595
10596     if((int)end_32 != (int)end_64)
10597     {
10598         return(TNG_FAILURE);
10599     }
10600
10601     if(end_32 == TNG_LITTLE_ENDIAN_32)
10602     {
10603         *endianness = TNG_LITTLE_ENDIAN;
10604     }
10605
10606     else if(end_32 == TNG_BIG_ENDIAN_32)
10607     {
10608         *endianness = TNG_BIG_ENDIAN;
10609     }
10610     else
10611     {
10612         return(TNG_FAILURE);
10613     }
10614
10615     return(TNG_SUCCESS);
10616 }
10617
10618 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10619                 (tng_trajectory_t tng_data,
10620                  const tng_file_endianness endianness)
10621 {
10622     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10623
10624     /* Tne endianness cannot be changed if the data has already been written
10625      * to the output file. */
10626     if(ftell(tng_data->output_file) > 0)
10627     {
10628         return(TNG_FAILURE);
10629     }
10630
10631     if(endianness == TNG_BIG_ENDIAN)
10632     {
10633         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10634         {
10635             tng_data->output_endianness_swap_func_32 = 0;
10636         }
10637         else
10638         {
10639             tng_data->output_endianness_swap_func_32 =
10640             &tng_swap_byte_order_big_endian_32;
10641         }
10642         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10643         {
10644             tng_data->output_endianness_swap_func_64 = 0;
10645         }
10646         else
10647         {
10648             tng_data->output_endianness_swap_func_64 =
10649             &tng_swap_byte_order_big_endian_64;
10650         }
10651         return(TNG_SUCCESS);
10652     }
10653     else if(endianness == TNG_LITTLE_ENDIAN)
10654     {
10655         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10656         {
10657             tng_data->output_endianness_swap_func_32 = 0;
10658         }
10659         else
10660         {
10661             tng_data->output_endianness_swap_func_32 =
10662             &tng_swap_byte_order_little_endian_32;
10663         }
10664         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10665         {
10666             tng_data->output_endianness_swap_func_64 = 0;
10667         }
10668         else
10669         {
10670             tng_data->output_endianness_swap_func_64 =
10671             &tng_swap_byte_order_little_endian_64;
10672         }
10673         return(TNG_SUCCESS);
10674     }
10675
10676     /* If the specified endianness is neither big nor little endian return a
10677      * failure. */
10678     return(TNG_FAILURE);
10679 }
10680
10681 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10682                     (const tng_trajectory_t tng_data,
10683                      char *name, const int max_len)
10684 {
10685     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10686     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10687
10688     strncpy(name, tng_data->first_program_name, max_len - 1);
10689     name[max_len - 1] = 0;
10690
10691     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10692     {
10693         return(TNG_FAILURE);
10694     }
10695     return(TNG_SUCCESS);
10696 }
10697
10698 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10699                                                                  const char *new_name)
10700 {
10701     unsigned int len;
10702
10703     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10704     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10705
10706     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10707
10708     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10709     {
10710         free(tng_data->first_program_name);
10711         tng_data->first_program_name = 0;
10712     }
10713     if(!tng_data->first_program_name)
10714     {
10715         tng_data->first_program_name = malloc(len);
10716         if(!tng_data->first_program_name)
10717         {
10718             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10719                    __FILE__, __LINE__);
10720             return(TNG_CRITICAL);
10721         }
10722     }
10723
10724     strncpy(tng_data->first_program_name, new_name, len);
10725
10726     return(TNG_SUCCESS);
10727 }
10728
10729 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10730                     (const tng_trajectory_t tng_data,
10731                      char *name, const int max_len)
10732 {
10733     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10734     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10735
10736     strncpy(name, tng_data->last_program_name, max_len - 1);
10737     name[max_len - 1] = 0;
10738
10739     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10740     {
10741         return(TNG_FAILURE);
10742     }
10743     return(TNG_SUCCESS);
10744 }
10745
10746 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10747                     (tng_trajectory_t tng_data,
10748                      const char *new_name)
10749 {
10750     unsigned int len;
10751
10752     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10753     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10754
10755     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10756
10757     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10758     {
10759         free(tng_data->last_program_name);
10760         tng_data->last_program_name = 0;
10761     }
10762     if(!tng_data->last_program_name)
10763     {
10764         tng_data->last_program_name = malloc(len);
10765         if(!tng_data->last_program_name)
10766         {
10767             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10768                    __FILE__, __LINE__);
10769             return(TNG_CRITICAL);
10770         }
10771     }
10772
10773     strncpy(tng_data->last_program_name, new_name, len);
10774
10775     return(TNG_SUCCESS);
10776 }
10777
10778 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10779                     (const tng_trajectory_t tng_data,
10780                      char *name, const int max_len)
10781 {
10782     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10783     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10784
10785     strncpy(name, tng_data->first_user_name, max_len - 1);
10786     name[max_len - 1] = 0;
10787
10788     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10789     {
10790         return(TNG_FAILURE);
10791     }
10792     return(TNG_SUCCESS);
10793 }
10794
10795 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10796                     (tng_trajectory_t tng_data,
10797                      const char *new_name)
10798 {
10799     unsigned int len;
10800
10801     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10802     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10803
10804     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10805
10806     /* If the currently stored string length is not enough to store the new
10807      * string it is freed and reallocated. */
10808     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10809     {
10810         free(tng_data->first_user_name);
10811         tng_data->first_user_name = 0;
10812     }
10813     if(!tng_data->first_user_name)
10814     {
10815         tng_data->first_user_name = malloc(len);
10816         if(!tng_data->first_user_name)
10817         {
10818             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10819                    __FILE__, __LINE__);
10820             return(TNG_CRITICAL);
10821         }
10822     }
10823
10824     strncpy(tng_data->first_user_name, new_name, len);
10825
10826     return(TNG_SUCCESS);
10827 }
10828
10829 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10830                     (const tng_trajectory_t tng_data,
10831                      char *name, const int max_len)
10832 {
10833     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10834     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10835
10836     strncpy(name, tng_data->last_user_name, max_len - 1);
10837     name[max_len - 1] = 0;
10838
10839     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10840     {
10841         return(TNG_FAILURE);
10842     }
10843     return(TNG_SUCCESS);
10844 }
10845
10846 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10847                     (tng_trajectory_t tng_data,
10848                      const char *new_name)
10849 {
10850     unsigned int len;
10851
10852     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10853     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10854
10855     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10856
10857     /* If the currently stored string length is not enough to store the new
10858      * string it is freed and reallocated. */
10859     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10860     {
10861         free(tng_data->last_user_name);
10862         tng_data->last_user_name = 0;
10863     }
10864     if(!tng_data->last_user_name)
10865     {
10866         tng_data->last_user_name = malloc(len);
10867         if(!tng_data->last_user_name)
10868         {
10869             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10870                    __FILE__, __LINE__);
10871             return(TNG_CRITICAL);
10872         }
10873     }
10874
10875     strncpy(tng_data->last_user_name, new_name, len);
10876
10877     return(TNG_SUCCESS);
10878 }
10879
10880 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10881                     (const tng_trajectory_t tng_data,
10882                      char *name, const int max_len)
10883 {
10884     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10885     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10886
10887     strncpy(name, tng_data->first_computer_name, max_len - 1);
10888     name[max_len - 1] = 0;
10889
10890     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10891     {
10892         return(TNG_FAILURE);
10893     }
10894     return(TNG_SUCCESS);
10895 }
10896
10897 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10898                     (tng_trajectory_t tng_data,
10899                      const char *new_name)
10900 {
10901     unsigned int len;
10902
10903     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10904     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10905
10906     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10907
10908     /* If the currently stored string length is not enough to store the new
10909      * string it is freed and reallocated. */
10910     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10911     {
10912         free(tng_data->first_computer_name);
10913         tng_data->first_computer_name = 0;
10914     }
10915     if(!tng_data->first_computer_name)
10916     {
10917         tng_data->first_computer_name = malloc(len);
10918         if(!tng_data->first_computer_name)
10919         {
10920             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10921                    __FILE__, __LINE__);
10922             return(TNG_CRITICAL);
10923         }
10924     }
10925
10926     strncpy(tng_data->first_computer_name, new_name, len);
10927
10928     return(TNG_SUCCESS);
10929 }
10930
10931 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10932                     (const tng_trajectory_t tng_data,
10933                      char *name, const int max_len)
10934 {
10935     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10936     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10937
10938     strncpy(name, tng_data->last_computer_name, max_len - 1);
10939     name[max_len - 1] = 0;
10940
10941     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10942     {
10943         return(TNG_FAILURE);
10944     }
10945     return(TNG_SUCCESS);
10946 }
10947
10948 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10949                     (tng_trajectory_t tng_data,
10950                      const char *new_name)
10951 {
10952     unsigned int len;
10953
10954     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10955     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10956
10957     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10958
10959     /* If the currently stored string length is not enough to store the new
10960      * string it is freed and reallocated. */
10961     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10962         len)
10963     {
10964         free(tng_data->last_computer_name);
10965         tng_data->last_computer_name = 0;
10966     }
10967     if(!tng_data->last_computer_name)
10968     {
10969         tng_data->last_computer_name = malloc(len);
10970         if(!tng_data->last_computer_name)
10971         {
10972             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10973                    __FILE__, __LINE__);
10974             return(TNG_CRITICAL);
10975         }
10976     }
10977
10978     strncpy(tng_data->last_computer_name, new_name, len);
10979
10980     return(TNG_SUCCESS);
10981 }
10982
10983 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10984                     (const tng_trajectory_t tng_data,
10985                      char *signature, const int max_len)
10986 {
10987     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10988     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10989
10990     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10991     signature[max_len - 1] = 0;
10992
10993     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10994     {
10995         return(TNG_FAILURE);
10996     }
10997     return(TNG_SUCCESS);
10998 }
10999
11000 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
11001                     (tng_trajectory_t tng_data,
11002                      const char *signature)
11003 {
11004     unsigned int len;
11005
11006     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11007     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11008
11009     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11010
11011     /* If the currently stored string length is not enough to store the new
11012      * string it is freed and reallocated. */
11013     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
11014         len)
11015     {
11016         free(tng_data->first_pgp_signature);
11017         tng_data->first_pgp_signature = 0;
11018     }
11019     if(!tng_data->first_pgp_signature)
11020     {
11021         tng_data->first_pgp_signature = malloc(len);
11022         if(!tng_data->first_pgp_signature)
11023         {
11024             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11025                    __FILE__, __LINE__);
11026             return(TNG_CRITICAL);
11027         }
11028     }
11029
11030     strncpy(tng_data->first_pgp_signature, signature, len);
11031
11032     return(TNG_SUCCESS);
11033 }
11034
11035 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
11036                     (const tng_trajectory_t tng_data,
11037                      char *signature, const int max_len)
11038 {
11039     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11040     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11041
11042     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
11043     signature[max_len - 1] = 0;
11044
11045     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
11046     {
11047         return(TNG_FAILURE);
11048     }
11049     return(TNG_SUCCESS);
11050 }
11051
11052 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
11053                     (tng_trajectory_t tng_data,
11054                      const char *signature)
11055 {
11056     unsigned int len;
11057
11058     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11059     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11060
11061     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11062
11063     /* If the currently stored string length is not enough to store the new
11064      * string it is freed and reallocated. */
11065     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
11066         len)
11067     {
11068         free(tng_data->last_pgp_signature);
11069         tng_data->last_pgp_signature = 0;
11070     }
11071     if(!tng_data->last_pgp_signature)
11072     {
11073         tng_data->last_pgp_signature = malloc(len);
11074         if(!tng_data->last_pgp_signature)
11075         {
11076             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11077                    __FILE__, __LINE__);
11078             return(TNG_CRITICAL);
11079         }
11080     }
11081
11082     strncpy(tng_data->last_pgp_signature, signature, len);
11083
11084     return(TNG_SUCCESS);
11085 }
11086
11087 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11088                     (const tng_trajectory_t tng_data,
11089                      char *name, const int max_len)
11090 {
11091     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11092     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11093
11094     strncpy(name, tng_data->forcefield_name, max_len - 1);
11095     name[max_len - 1] = 0;
11096
11097     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11098     {
11099         return(TNG_FAILURE);
11100     }
11101     return(TNG_SUCCESS);
11102 }
11103
11104 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11105                     (tng_trajectory_t tng_data,
11106                      const char *new_name)
11107 {
11108     unsigned int len;
11109
11110     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11111     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11112
11113     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11114
11115     /* If the currently stored string length is not enough to store the new
11116      * string it is freed and reallocated. */
11117     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11118     {
11119         free(tng_data->forcefield_name);
11120         tng_data->forcefield_name = 0;
11121     }
11122     if(!tng_data->forcefield_name)
11123     {
11124         tng_data->forcefield_name = malloc(len);
11125         if(!tng_data->forcefield_name)
11126         {
11127             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11128                    __FILE__, __LINE__);
11129             return(TNG_CRITICAL);
11130         }
11131     }
11132
11133     strncpy(tng_data->forcefield_name, new_name, len);
11134
11135     return(TNG_SUCCESS);
11136 }
11137
11138 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11139                     (const tng_trajectory_t tng_data,
11140                      int64_t *len)
11141 {
11142     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11143     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11144
11145     *len = tng_data->medium_stride_length;
11146
11147     return(TNG_SUCCESS);
11148 }
11149
11150 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11151                     (tng_trajectory_t tng_data,
11152                      const int64_t len)
11153 {
11154     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11155
11156     if(len >= tng_data->long_stride_length)
11157     {
11158         return(TNG_FAILURE);
11159     }
11160     tng_data->medium_stride_length = len;
11161
11162     return(TNG_SUCCESS);
11163 }
11164
11165 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11166                 (const tng_trajectory_t tng_data,
11167                  int64_t *len)
11168 {
11169     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11170     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11171
11172     *len = tng_data->long_stride_length;
11173
11174     return(TNG_SUCCESS);
11175 }
11176
11177 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11178                 (tng_trajectory_t tng_data,
11179                  const int64_t len)
11180 {
11181     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11182
11183     if(len <= tng_data->medium_stride_length)
11184     {
11185         return(TNG_FAILURE);
11186     }
11187     tng_data->long_stride_length = len;
11188
11189     return(TNG_SUCCESS);
11190 }
11191
11192 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11193                 (const tng_trajectory_t tng_data,
11194                  double *time)
11195 {
11196     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11197     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11198
11199     *time = tng_data->time_per_frame;
11200
11201     return(TNG_SUCCESS);
11202 }
11203
11204 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11205                 (tng_trajectory_t tng_data,
11206                  const double time)
11207 {
11208     tng_trajectory_frame_set_t frame_set;
11209
11210     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11211     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11212
11213     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11214     {
11215         return(TNG_SUCCESS);
11216     }
11217
11218     frame_set = &tng_data->current_trajectory_frame_set;
11219
11220     /* If the current frame set is not finished write it to disk before
11221        changing time per frame. */
11222     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11223     {
11224         frame_set->n_frames = frame_set->n_unwritten_frames;
11225         tng_frame_set_write(tng_data, TNG_USE_HASH);
11226     }
11227     tng_data->time_per_frame = time;
11228
11229     return(TNG_SUCCESS);
11230 }
11231
11232 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11233                     (const tng_trajectory_t tng_data,
11234                      int64_t *len)
11235 {
11236     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11237     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11238
11239     *len = tng_data->input_file_len;
11240
11241     return(TNG_SUCCESS);
11242 }
11243
11244 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11245                     (const tng_trajectory_t tng_data,
11246                      int64_t *n)
11247 {
11248     tng_gen_block_t block;
11249     tng_function_status stat;
11250     long file_pos;
11251     int64_t last_file_pos, first_frame, n_frames;
11252
11253     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11254     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11255     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11256
11257     file_pos = ftell(tng_data->input_file);
11258     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11259
11260     if(last_file_pos <= 0)
11261     {
11262         return(TNG_FAILURE);
11263     }
11264
11265     tng_block_init(&block);
11266     fseek(tng_data->input_file,
11267           (long)last_file_pos,
11268           SEEK_SET);
11269     /* Read block headers first to see that a frame set block is found. */
11270     stat = tng_block_header_read(tng_data, block);
11271     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11272     {
11273         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11274                 __FILE__, __LINE__);
11275         tng_block_destroy(&block);
11276         return(TNG_FAILURE);
11277     }
11278     tng_block_destroy(&block);
11279
11280     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11281     {
11282         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11283                __FILE__, __LINE__);
11284         return(TNG_CRITICAL);
11285     }
11286     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11287     {
11288         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11289                __FILE__, __LINE__);
11290         return(TNG_CRITICAL);
11291     }
11292     fseek(tng_data->input_file, file_pos, SEEK_SET);
11293
11294     *n = first_frame + n_frames;
11295
11296     return(TNG_SUCCESS);
11297 }
11298
11299 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11300                 (const tng_trajectory_t tng_data,
11301                  double *precision)
11302 {
11303     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11304
11305     *precision = tng_data->compression_precision;
11306
11307     return(TNG_SUCCESS);
11308 }
11309
11310 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11311                 (tng_trajectory_t tng_data,
11312                  const double precision)
11313 {
11314     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11315
11316     tng_data->compression_precision = precision;
11317
11318     return(TNG_SUCCESS);
11319 }
11320
11321 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11322                 (tng_trajectory_t tng_data,
11323                  const int64_t n)
11324 {
11325     tng_molecule_t mol;
11326     tng_chain_t chain;
11327     tng_residue_t res;
11328     tng_atom_t atom;
11329     tng_function_status stat;
11330     int64_t diff, n_mod, n_impl;
11331
11332     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11333
11334     diff = n - tng_data->n_particles;
11335
11336     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11337     if(stat == TNG_SUCCESS)
11338     {
11339         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11340         {
11341             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11342                     __FILE__, __LINE__);
11343             return(TNG_FAILURE);
11344         }
11345         diff -= n_impl * mol->n_atoms;
11346     }
11347
11348     if(diff == 0)
11349     {
11350         if(stat == TNG_SUCCESS)
11351         {
11352             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11353             return(stat);
11354         }
11355         return(TNG_SUCCESS);
11356     }
11357     else if(diff < 0)
11358     {
11359         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11360         fprintf(stderr, "particle count.\n");
11361         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11362                 __FILE__, __LINE__);
11363         /* FIXME: Should we set the count of all other molecules to 0 and add
11364          * implicit molecules? */
11365         return(TNG_FAILURE);
11366     }
11367     if(stat != TNG_SUCCESS)
11368     {
11369         stat = tng_molecule_add(tng_data,
11370                                 "TNG_IMPLICIT_MOL",
11371                                 &mol);
11372         if(stat != TNG_SUCCESS)
11373         {
11374             return(stat);
11375         }
11376         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11377         if(stat != TNG_SUCCESS)
11378         {
11379             return(stat);
11380         }
11381         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11382         if(stat != TNG_SUCCESS)
11383         {
11384             return(stat);
11385         }
11386         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11387         if(stat != TNG_SUCCESS)
11388         {
11389             return(stat);
11390         }
11391     }
11392     else
11393     {
11394         if(mol->n_atoms > 1)
11395         {
11396             n_mod = diff % mol->n_atoms;
11397             if(n_mod != 0)
11398             {
11399                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11400                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11401                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11402                         __FILE__, __LINE__);
11403                 return(TNG_FAILURE);
11404             }
11405             diff /= mol->n_atoms;
11406         }
11407     }
11408     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11409
11410     return(stat);
11411 }
11412
11413 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11414                 (const tng_trajectory_t tng_data,
11415                  int64_t *n)
11416 {
11417     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11418     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11419
11420     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11421     {
11422         *n = tng_data->n_particles;
11423     }
11424     else
11425     {
11426         *n = tng_data->current_trajectory_frame_set.n_particles;
11427     }
11428
11429     return(TNG_SUCCESS);
11430 }
11431
11432 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11433                 (const tng_trajectory_t tng_data,
11434                  char *variable)
11435 {
11436     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11437     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11438
11439     *variable = tng_data->var_num_atoms_flag;
11440
11441     return(TNG_SUCCESS);
11442 }
11443
11444 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11445                     (const tng_trajectory_t tng_data,
11446                      int64_t *n)
11447 {
11448     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11449     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11450
11451     *n = tng_data->n_molecules;
11452
11453     return(TNG_SUCCESS);
11454 }
11455
11456 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11457                     (const tng_trajectory_t tng_data,
11458                      int64_t *n)
11459 {
11460     int64_t *cnt_list = 0, cnt = 0, i;
11461
11462     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11463     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11464
11465     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11466
11467     if(!cnt_list)
11468     {
11469         return(TNG_FAILURE);
11470     }
11471
11472     for(i = 0; i < tng_data->n_molecules; i++)
11473     {
11474         cnt += cnt_list[i];
11475     }
11476
11477     *n = cnt;
11478
11479     return(TNG_SUCCESS);
11480 }
11481
11482 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11483                 (const tng_trajectory_t tng_data,
11484                  int64_t **mol_cnt_list)
11485 {
11486     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11487
11488     if(tng_data->var_num_atoms_flag)
11489     {
11490         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11491                        molecule_cnt_list;
11492     }
11493     else
11494     {
11495         *mol_cnt_list = tng_data->molecule_cnt_list;
11496     }
11497     if(*mol_cnt_list == 0)
11498     {
11499         return(TNG_FAILURE);
11500     }
11501     return(TNG_SUCCESS);
11502 }
11503
11504 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11505                 (const tng_trajectory_t tng_data,
11506                  int64_t *exp)
11507 {
11508     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11509     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11510
11511     *exp = tng_data->distance_unit_exponential;
11512
11513     return(TNG_SUCCESS);
11514 }
11515
11516 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11517                 (const tng_trajectory_t tng_data,
11518                  const int64_t exp)
11519 {
11520     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11521
11522     tng_data->distance_unit_exponential = exp;
11523
11524     return(TNG_SUCCESS);
11525 }
11526
11527 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11528                 (const tng_trajectory_t tng_data,
11529                  int64_t *n)
11530 {
11531     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11532     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11533
11534     *n = tng_data->frame_set_n_frames;
11535
11536     return(TNG_SUCCESS);
11537 }
11538
11539 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11540                 (const tng_trajectory_t tng_data,
11541                  const int64_t n)
11542 {
11543     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11544
11545     tng_data->frame_set_n_frames = n;
11546
11547     return(TNG_SUCCESS);
11548 }
11549
11550 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11551                 (const tng_trajectory_t tng_data,
11552                  int64_t *n)
11553 {
11554     int64_t long_stride_length, medium_stride_length;
11555     long file_pos, orig_frame_set_file_pos;
11556     tng_trajectory_frame_set_t frame_set;
11557     struct tng_trajectory_frame_set orig_frame_set;
11558     tng_gen_block_t block;
11559     tng_function_status stat;
11560     int64_t cnt = 0;
11561
11562     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11563     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11564
11565     orig_frame_set = tng_data->current_trajectory_frame_set;
11566
11567     frame_set = &tng_data->current_trajectory_frame_set;
11568
11569     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11570     file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
11571
11572     if(file_pos < 0)
11573     {
11574         *n = tng_data->n_trajectory_frame_sets = cnt;
11575         return(TNG_SUCCESS);
11576     }
11577
11578     tng_block_init(&block);
11579     fseek(tng_data->input_file,
11580           file_pos,
11581           SEEK_SET);
11582     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11583     /* Read block headers first to see what block is found. */
11584     stat = tng_block_header_read(tng_data, block);
11585     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11586     {
11587         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos,
11588                 __FILE__, __LINE__);
11589         tng_block_destroy(&block);
11590         return(TNG_CRITICAL);
11591     }
11592
11593     if(tng_block_read_next(tng_data, block,
11594                         TNG_SKIP_HASH) != TNG_SUCCESS)
11595     {
11596         tng_block_destroy(&block);
11597         return(TNG_CRITICAL);
11598     }
11599
11600     ++cnt;
11601
11602     long_stride_length = tng_data->long_stride_length;
11603     medium_stride_length = tng_data->medium_stride_length;
11604
11605     /* Take long steps forward until a long step forward would be too long or
11606      * the last frame set is found */
11607     file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11608     while(file_pos > 0)
11609     {
11610         if(file_pos > 0)
11611         {
11612             cnt += long_stride_length;
11613             fseek(tng_data->input_file, file_pos, SEEK_SET);
11614             /* Read block headers first to see what block is found. */
11615             stat = tng_block_header_read(tng_data, block);
11616             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11617             {
11618                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11619                        file_pos, __FILE__, __LINE__);
11620                 tng_block_destroy(&block);
11621                 return(TNG_CRITICAL);
11622             }
11623
11624             if(tng_block_read_next(tng_data, block,
11625                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11626             {
11627                 tng_block_destroy(&block);
11628                 return(TNG_CRITICAL);
11629             }
11630         }
11631         file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11632     }
11633
11634     /* Take medium steps forward until a medium step forward would be too long
11635      * or the last frame set is found */
11636     file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11637     while(file_pos > 0)
11638     {
11639         if(file_pos > 0)
11640         {
11641             cnt += medium_stride_length;
11642             fseek(tng_data->input_file,
11643                   file_pos,
11644                   SEEK_SET);
11645             /* Read block headers first to see what block is found. */
11646             stat = tng_block_header_read(tng_data, block);
11647             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11648             {
11649                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11650                        file_pos, __FILE__, __LINE__);
11651                 tng_block_destroy(&block);
11652                 return(TNG_CRITICAL);
11653             }
11654
11655             if(tng_block_read_next(tng_data, block,
11656                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11657             {
11658                 tng_block_destroy(&block);
11659                 return(TNG_CRITICAL);
11660             }
11661         }
11662         file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11663     }
11664
11665     /* Take one step forward until the last frame set is found */
11666     file_pos = (long)frame_set->next_frame_set_file_pos;
11667     while(file_pos > 0)
11668     {
11669         if(file_pos > 0)
11670         {
11671             ++cnt;
11672             fseek(tng_data->input_file,
11673                   file_pos,
11674                   SEEK_SET);
11675             /* Read block headers first to see what block is found. */
11676             stat = tng_block_header_read(tng_data, block);
11677             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11678             {
11679                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11680                        file_pos, __FILE__, __LINE__);
11681                 tng_block_destroy(&block);
11682                 return(TNG_CRITICAL);
11683             }
11684
11685             if(tng_block_read_next(tng_data, block,
11686                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11687             {
11688                 tng_block_destroy(&block);
11689                 return(TNG_CRITICAL);
11690             }
11691         }
11692         file_pos = (long)frame_set->next_frame_set_file_pos;
11693     }
11694
11695     tng_block_destroy(&block);
11696
11697     *n = tng_data->n_trajectory_frame_sets = cnt;
11698
11699     *frame_set = orig_frame_set;
11700     /* The mapping block in the original frame set has been freed when reading
11701      * other frame sets. */
11702     frame_set->mappings = 0;
11703     frame_set->n_mapping_blocks = 0;
11704
11705     fseek(tng_data->input_file,
11706           (long)tng_data->first_trajectory_frame_set_input_file_pos,
11707           SEEK_SET);
11708
11709     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11710
11711     return(TNG_SUCCESS);
11712 }
11713
11714 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11715                 (const tng_trajectory_t tng_data,
11716                  tng_trajectory_frame_set_t *frame_set_p)
11717 {
11718     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11719
11720     *frame_set_p = &tng_data->current_trajectory_frame_set;
11721
11722     return(TNG_SUCCESS);
11723 }
11724
11725 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11726                 (tng_trajectory_t tng_data,
11727                  const int64_t nr)
11728 {
11729     int64_t long_stride_length, medium_stride_length;
11730     int64_t file_pos, curr_nr = 0, n_frame_sets;
11731     tng_trajectory_frame_set_t frame_set;
11732     tng_gen_block_t block;
11733     tng_function_status stat;
11734
11735     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11736     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11737
11738     frame_set = &tng_data->current_trajectory_frame_set;
11739
11740     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11741
11742     if(stat != TNG_SUCCESS)
11743     {
11744         return(stat);
11745     }
11746
11747     if(nr >= n_frame_sets)
11748     {
11749         return(TNG_FAILURE);
11750     }
11751
11752     long_stride_length = tng_data->long_stride_length;
11753     medium_stride_length = tng_data->medium_stride_length;
11754
11755     /* FIXME: The frame set number of the current frame set is not stored */
11756
11757     if(nr < n_frame_sets - 1 - nr)
11758     {
11759         /* Start from the beginning */
11760         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11761     }
11762     else
11763     {
11764         /* Start from the end */
11765         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11766         curr_nr = n_frame_sets - 1;
11767     }
11768     if(file_pos <= 0)
11769     {
11770         return(TNG_FAILURE);
11771     }
11772
11773     tng_block_init(&block);
11774     fseek(tng_data->input_file,
11775           (long)file_pos,
11776           SEEK_SET);
11777     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11778     /* Read block headers first to see what block is found. */
11779     stat = tng_block_header_read(tng_data, block);
11780     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11781     {
11782         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11783                 __FILE__, __LINE__);
11784         tng_block_destroy(&block);
11785         return(TNG_CRITICAL);
11786     }
11787
11788     if(tng_block_read_next(tng_data, block,
11789                         TNG_SKIP_HASH) != TNG_SUCCESS)
11790     {
11791         tng_block_destroy(&block);
11792         return(TNG_CRITICAL);
11793     }
11794
11795     if(curr_nr == nr)
11796     {
11797         tng_block_destroy(&block);
11798         return(TNG_SUCCESS);
11799     }
11800
11801     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11802
11803     /* Take long steps forward until a long step forward would be too long or
11804      * the right frame set is found */
11805     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11806     {
11807         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11808         if(file_pos > 0)
11809         {
11810             curr_nr += long_stride_length;
11811             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11812             /* Read block headers first to see what block is found. */
11813             stat = tng_block_header_read(tng_data, block);
11814             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11815             {
11816                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11817                        file_pos,  __FILE__, __LINE__);
11818                 tng_block_destroy(&block);
11819                 return(TNG_CRITICAL);
11820             }
11821
11822             if(tng_block_read_next(tng_data, block,
11823                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11824             {
11825                 tng_block_destroy(&block);
11826                 return(TNG_CRITICAL);
11827             }
11828             if(curr_nr == nr)
11829             {
11830                 tng_block_destroy(&block);
11831                 return(TNG_SUCCESS);
11832             }
11833         }
11834     }
11835
11836     /* Take medium steps forward until a medium step forward would be too long
11837      * or the right frame set is found */
11838     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11839     {
11840         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11841         if(file_pos > 0)
11842         {
11843             curr_nr += medium_stride_length;
11844             fseek(tng_data->input_file,
11845                   (long)file_pos,
11846                   SEEK_SET);
11847             /* Read block headers first to see what block is found. */
11848             stat = tng_block_header_read(tng_data, block);
11849             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11850             {
11851                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11852                        file_pos, __FILE__, __LINE__);
11853                 tng_block_destroy(&block);
11854                 return(TNG_CRITICAL);
11855             }
11856
11857             if(tng_block_read_next(tng_data, block,
11858                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11859             {
11860                 tng_block_destroy(&block);
11861                 return(TNG_CRITICAL);
11862             }
11863             if(curr_nr == nr)
11864             {
11865                 tng_block_destroy(&block);
11866                 return(TNG_SUCCESS);
11867             }
11868         }
11869     }
11870
11871     /* Take one step forward until the right frame set is found */
11872     while(file_pos > 0 && curr_nr < nr)
11873     {
11874         file_pos = frame_set->next_frame_set_file_pos;
11875
11876         if(file_pos > 0)
11877         {
11878             ++curr_nr;
11879             fseek(tng_data->input_file,
11880                   (long)file_pos,
11881                   SEEK_SET);
11882             /* Read block headers first to see what block is found. */
11883             stat = tng_block_header_read(tng_data, block);
11884             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11885             {
11886                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11887                        file_pos, __FILE__, __LINE__);
11888                 tng_block_destroy(&block);
11889                 return(TNG_CRITICAL);
11890             }
11891
11892             if(tng_block_read_next(tng_data, block,
11893                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11894             {
11895                 tng_block_destroy(&block);
11896                 return(TNG_CRITICAL);
11897             }
11898             if(curr_nr == nr)
11899             {
11900                 tng_block_destroy(&block);
11901                 return(TNG_SUCCESS);
11902             }
11903         }
11904     }
11905
11906     /* Take long steps backward until a long step backward would be too long
11907      * or the right frame set is found */
11908     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11909     {
11910         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11911         if(file_pos > 0)
11912         {
11913             curr_nr -= long_stride_length;
11914             fseek(tng_data->input_file,
11915                   (long)file_pos,
11916                   SEEK_SET);
11917             /* Read block headers first to see what block is found. */
11918             stat = tng_block_header_read(tng_data, block);
11919             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11920             {
11921                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11922                        file_pos, __FILE__, __LINE__);
11923                 tng_block_destroy(&block);
11924                 return(TNG_CRITICAL);
11925             }
11926
11927             if(tng_block_read_next(tng_data, block,
11928                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11929             {
11930                 tng_block_destroy(&block);
11931                 return(TNG_CRITICAL);
11932             }
11933             if(curr_nr == nr)
11934             {
11935                 tng_block_destroy(&block);
11936                 return(TNG_SUCCESS);
11937             }
11938         }
11939     }
11940
11941     /* Take medium steps backward until a medium step backward would be too long
11942      * or the right frame set is found */
11943     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11944     {
11945         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11946         if(file_pos > 0)
11947         {
11948             curr_nr -= medium_stride_length;
11949             fseek(tng_data->input_file,
11950                   (long)file_pos,
11951                   SEEK_SET);
11952             /* Read block headers first to see what block is found. */
11953             stat = tng_block_header_read(tng_data, block);
11954             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11955             {
11956                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11957                        file_pos, __FILE__, __LINE__);
11958                 tng_block_destroy(&block);
11959                 return(TNG_CRITICAL);
11960             }
11961
11962             if(tng_block_read_next(tng_data, block,
11963                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11964             {
11965                 tng_block_destroy(&block);
11966                 return(TNG_CRITICAL);
11967             }
11968             if(curr_nr == nr)
11969             {
11970                 tng_block_destroy(&block);
11971                 return(TNG_SUCCESS);
11972             }
11973         }
11974     }
11975
11976     /* Take one step backward until the right frame set is found */
11977     while(file_pos > 0 && curr_nr > nr)
11978     {
11979         file_pos = frame_set->prev_frame_set_file_pos;
11980         if(file_pos > 0)
11981         {
11982             --curr_nr;
11983             fseek(tng_data->input_file,
11984                   (long)file_pos,
11985                   SEEK_SET);
11986             /* Read block headers first to see what block is found. */
11987             stat = tng_block_header_read(tng_data, block);
11988             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11989             {
11990                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11991                        file_pos, __FILE__, __LINE__);
11992                 tng_block_destroy(&block);
11993                 return(TNG_CRITICAL);
11994             }
11995
11996             if(tng_block_read_next(tng_data, block,
11997                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11998             {
11999                 tng_block_destroy(&block);
12000                 return(TNG_CRITICAL);
12001             }
12002             if(curr_nr == nr)
12003             {
12004                 tng_block_destroy(&block);
12005                 return(TNG_SUCCESS);
12006             }
12007         }
12008     }
12009
12010     /* If for some reason the current frame set is not yet found,
12011      * take one step forward until the right frame set is found */
12012     while(file_pos > 0 && curr_nr < nr)
12013     {
12014         file_pos = frame_set->next_frame_set_file_pos;
12015         if(file_pos > 0)
12016         {
12017             ++curr_nr;
12018             fseek(tng_data->input_file,
12019                   (long)file_pos,
12020                   SEEK_SET);
12021             /* Read block headers first to see what block is found. */
12022             stat = tng_block_header_read(tng_data, block);
12023             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12024             {
12025                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12026                        file_pos, __FILE__, __LINE__);
12027                 tng_block_destroy(&block);
12028                 return(TNG_CRITICAL);
12029             }
12030
12031             if(tng_block_read_next(tng_data, block,
12032                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12033             {
12034                 tng_block_destroy(&block);
12035                 return(TNG_CRITICAL);
12036             }
12037             if(curr_nr == nr)
12038             {
12039                 tng_block_destroy(&block);
12040                 return(TNG_SUCCESS);
12041             }
12042         }
12043     }
12044
12045     tng_block_destroy(&block);
12046     return(TNG_FAILURE);
12047 }
12048
12049 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
12050                 (tng_trajectory_t tng_data,
12051                  const int64_t frame)
12052 {
12053     int64_t first_frame, last_frame, n_frames_per_frame_set;
12054     int64_t long_stride_length, medium_stride_length;
12055     int64_t file_pos, temp_frame, n_frames;
12056     tng_trajectory_frame_set_t frame_set;
12057     tng_gen_block_t block;
12058     tng_function_status stat;
12059
12060     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12061     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
12062
12063     frame_set = &tng_data->current_trajectory_frame_set;
12064
12065     tng_block_init(&block);
12066
12067     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
12068     {
12069         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12070         fseek(tng_data->input_file,
12071                 (long)file_pos,
12072                 SEEK_SET);
12073         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
12074         /* Read block headers first to see what block is found. */
12075         stat = tng_block_header_read(tng_data, block);
12076         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12077         {
12078             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12079                     file_pos, __FILE__, __LINE__);
12080             tng_block_destroy(&block);
12081             return(TNG_CRITICAL);
12082         }
12083
12084         if(tng_block_read_next(tng_data, block,
12085                             TNG_SKIP_HASH) != TNG_SUCCESS)
12086         {
12087             tng_block_destroy(&block);
12088             return(TNG_CRITICAL);
12089         }
12090     }
12091
12092     first_frame = tng_max_i64(frame_set->first_frame, 0);
12093     last_frame = first_frame + frame_set->n_frames - 1;
12094     /* Is this the right frame set? */
12095     if(first_frame <= frame && frame <= last_frame)
12096     {
12097         tng_block_destroy(&block);
12098         return(TNG_SUCCESS);
12099     }
12100
12101     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12102     long_stride_length = tng_data->long_stride_length;
12103     medium_stride_length = tng_data->medium_stride_length;
12104
12105     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12106        TNG_SUCCESS)
12107     {
12108         if(temp_frame - first_frame > n_frames_per_frame_set)
12109         {
12110             n_frames_per_frame_set = temp_frame - first_frame;
12111         }
12112     }
12113
12114     tng_num_frames_get(tng_data, &n_frames);
12115
12116     if(frame >= n_frames)
12117     {
12118         tng_block_destroy(&block);
12119         return(TNG_FAILURE);
12120     }
12121
12122     if(first_frame - frame >= frame ||
12123        frame - last_frame >
12124        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12125     {
12126         /* Start from the beginning */
12127         if(first_frame - frame >= frame)
12128         {
12129             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12130
12131             if(file_pos <= 0)
12132             {
12133                 tng_block_destroy(&block);
12134                 return(TNG_FAILURE);
12135             }
12136         }
12137         /* Start from the end */
12138         else if(frame - first_frame > (n_frames - 1) - frame)
12139         {
12140             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12141
12142             /* If the last frame set position is not set start from the current
12143              * frame set, since it will be closer than the first frame set. */
12144         }
12145         /* Start from current */
12146         else
12147         {
12148             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12149         }
12150
12151         if(file_pos > 0)
12152         {
12153             fseek(tng_data->input_file,
12154                   (long)file_pos,
12155                   SEEK_SET);
12156             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
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     }
12175
12176     first_frame = tng_max_i64(frame_set->first_frame, 0);
12177     last_frame = first_frame + frame_set->n_frames - 1;
12178
12179     if(frame >= first_frame && frame <= last_frame)
12180     {
12181         tng_block_destroy(&block);
12182         return(TNG_SUCCESS);
12183     }
12184
12185     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12186
12187     /* Take long steps forward until a long step forward would be too long or
12188      * the right frame set is found */
12189     while(file_pos > 0 && first_frame + long_stride_length *
12190           n_frames_per_frame_set <= frame)
12191     {
12192         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12193         if(file_pos > 0)
12194         {
12195             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
12196             /* Read block headers first to see what block is found. */
12197             stat = tng_block_header_read(tng_data, block);
12198             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12199             {
12200                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12201                        file_pos, __FILE__, __LINE__);
12202                 tng_block_destroy(&block);
12203                 return(TNG_CRITICAL);
12204             }
12205
12206             if(tng_block_read_next(tng_data, block,
12207                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12208             {
12209                 tng_block_destroy(&block);
12210                 return(TNG_CRITICAL);
12211             }
12212         }
12213         first_frame = tng_max_i64(frame_set->first_frame, 0);
12214         last_frame = first_frame + frame_set->n_frames - 1;
12215         if(frame >= first_frame && frame <= last_frame)
12216         {
12217             tng_block_destroy(&block);
12218             return(TNG_SUCCESS);
12219         }
12220     }
12221
12222     /* Take medium steps forward until a medium step forward would be too long
12223      * or the right frame set is found */
12224     while(file_pos > 0 && first_frame + medium_stride_length *
12225           n_frames_per_frame_set <= frame)
12226     {
12227         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12228         if(file_pos > 0)
12229         {
12230             fseek(tng_data->input_file,
12231                   (long)file_pos,
12232                   SEEK_SET);
12233             /* Read block headers first to see what block is found. */
12234             stat = tng_block_header_read(tng_data, block);
12235             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12236             {
12237                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12238                        file_pos, __FILE__, __LINE__);
12239                 tng_block_destroy(&block);
12240                 return(TNG_CRITICAL);
12241             }
12242
12243             if(tng_block_read_next(tng_data, block,
12244                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12245             {
12246                 tng_block_destroy(&block);
12247                 return(TNG_CRITICAL);
12248             }
12249         }
12250         first_frame = tng_max_i64(frame_set->first_frame, 0);
12251         last_frame = first_frame + frame_set->n_frames - 1;
12252         if(frame >= first_frame && frame <= last_frame)
12253         {
12254             tng_block_destroy(&block);
12255             return(TNG_SUCCESS);
12256         }
12257     }
12258
12259     /* Take one step forward until the right frame set is found */
12260     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12261     {
12262         file_pos = frame_set->next_frame_set_file_pos;
12263         if(file_pos > 0)
12264         {
12265             fseek(tng_data->input_file,
12266                   (long)file_pos,
12267                   SEEK_SET);
12268             /* Read block headers first to see what block is found. */
12269             stat = tng_block_header_read(tng_data, block);
12270             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12271             {
12272                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12273                        file_pos, __FILE__, __LINE__);
12274                 tng_block_destroy(&block);
12275                 return(TNG_CRITICAL);
12276             }
12277
12278             if(tng_block_read_next(tng_data, block,
12279                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12280             {
12281                 tng_block_destroy(&block);
12282                 return(TNG_CRITICAL);
12283             }
12284         }
12285         first_frame = tng_max_i64(frame_set->first_frame, 0);
12286         last_frame = first_frame + frame_set->n_frames - 1;
12287         if(frame >= first_frame && frame <= last_frame)
12288         {
12289             tng_block_destroy(&block);
12290             return(TNG_SUCCESS);
12291         }
12292     }
12293
12294     /* Take long steps backward until a long step backward would be too long
12295      * or the right frame set is found */
12296     while(file_pos > 0 && first_frame - long_stride_length *
12297           n_frames_per_frame_set >= frame)
12298     {
12299         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12300         if(file_pos > 0)
12301         {
12302             fseek(tng_data->input_file,
12303                   (long)file_pos,
12304                   SEEK_SET);
12305             /* Read block headers first to see what block is found. */
12306             stat = tng_block_header_read(tng_data, block);
12307             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12308             {
12309                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12310                        file_pos, __FILE__, __LINE__);
12311                 tng_block_destroy(&block);
12312                 return(TNG_CRITICAL);
12313             }
12314
12315             if(tng_block_read_next(tng_data, block,
12316                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12317             {
12318                 tng_block_destroy(&block);
12319                 return(TNG_CRITICAL);
12320             }
12321         }
12322         first_frame = tng_max_i64(frame_set->first_frame, 0);
12323         last_frame = first_frame + frame_set->n_frames - 1;
12324         if(frame >= first_frame && frame <= last_frame)
12325         {
12326             tng_block_destroy(&block);
12327             return(TNG_SUCCESS);
12328         }
12329     }
12330
12331     /* Take medium steps backward until a medium step backward would be too long
12332      * or the right frame set is found */
12333     while(file_pos > 0 && first_frame - medium_stride_length *
12334           n_frames_per_frame_set >= frame)
12335     {
12336         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12337         if(file_pos > 0)
12338         {
12339             fseek(tng_data->input_file,
12340                   (long)file_pos,
12341                   SEEK_SET);
12342             /* Read block headers first to see what block is found. */
12343             stat = tng_block_header_read(tng_data, block);
12344             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12345             {
12346                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12347                        file_pos, __FILE__, __LINE__);
12348                 tng_block_destroy(&block);
12349                 return(TNG_CRITICAL);
12350             }
12351
12352             if(tng_block_read_next(tng_data, block,
12353                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12354             {
12355                 tng_block_destroy(&block);
12356                 return(TNG_CRITICAL);
12357             }
12358         }
12359         first_frame = tng_max_i64(frame_set->first_frame, 0);
12360         last_frame = first_frame + frame_set->n_frames - 1;
12361         if(frame >= first_frame && frame <= last_frame)
12362         {
12363             tng_block_destroy(&block);
12364             return(TNG_SUCCESS);
12365         }
12366     }
12367
12368     /* Take one step backward until the right frame set is found */
12369     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12370     {
12371         file_pos = frame_set->prev_frame_set_file_pos;
12372         if(file_pos > 0)
12373         {
12374             fseek(tng_data->input_file,
12375                   (long)file_pos,
12376                   SEEK_SET);
12377             /* Read block headers first to see what block is found. */
12378             stat = tng_block_header_read(tng_data, block);
12379             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12380             {
12381                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12382                        file_pos, __FILE__, __LINE__);
12383                 tng_block_destroy(&block);
12384                 return(TNG_CRITICAL);
12385             }
12386
12387             if(tng_block_read_next(tng_data, block,
12388                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12389             {
12390                 tng_block_destroy(&block);
12391                 return(TNG_CRITICAL);
12392             }
12393         }
12394         first_frame = tng_max_i64(frame_set->first_frame, 0);
12395         last_frame = first_frame + frame_set->n_frames - 1;
12396         if(frame >= first_frame && frame <= last_frame)
12397         {
12398             tng_block_destroy(&block);
12399             return(TNG_SUCCESS);
12400         }
12401     }
12402
12403     /* If for some reason the current frame set is not yet found,
12404      * take one step forward until the right frame set is found */
12405     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12406     {
12407         file_pos = frame_set->next_frame_set_file_pos;
12408         if(file_pos > 0)
12409         {
12410             fseek(tng_data->input_file,
12411                   (long)file_pos,
12412                   SEEK_SET);
12413             /* Read block headers first to see what block is found. */
12414             stat = tng_block_header_read(tng_data, block);
12415             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12416             {
12417                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12418                        file_pos, __FILE__, __LINE__);
12419                 tng_block_destroy(&block);
12420                 return(TNG_CRITICAL);
12421             }
12422
12423             if(tng_block_read_next(tng_data, block,
12424                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12425             {
12426                 tng_block_destroy(&block);
12427                 return(TNG_CRITICAL);
12428             }
12429         }
12430         first_frame = tng_max_i64(frame_set->first_frame, 0);
12431         last_frame = first_frame + frame_set->n_frames - 1;
12432         if(frame >= first_frame && frame <= last_frame)
12433         {
12434             tng_block_destroy(&block);
12435             return(TNG_SUCCESS);
12436         }
12437     }
12438
12439     tng_block_destroy(&block);
12440     return(TNG_FAILURE);
12441 }
12442
12443 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12444                 (const tng_trajectory_t tng_data,
12445                  const tng_trajectory_frame_set_t frame_set,
12446                  int64_t *pos)
12447 {
12448     (void)tng_data;
12449
12450     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12451     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12452
12453     *pos = frame_set->next_frame_set_file_pos;
12454
12455     return(TNG_SUCCESS);
12456 }
12457
12458 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12459                 (const tng_trajectory_t tng_data,
12460                  const tng_trajectory_frame_set_t frame_set,
12461                  int64_t *pos)
12462 {
12463     (void)tng_data;
12464
12465     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12466     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12467
12468     *pos = frame_set->prev_frame_set_file_pos;
12469
12470     return(TNG_SUCCESS);
12471 }
12472
12473 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12474                 (const tng_trajectory_t tng_data,
12475                  const tng_trajectory_frame_set_t frame_set,
12476                  int64_t *first_frame,
12477                  int64_t *last_frame)
12478 {
12479     (void)tng_data;
12480
12481     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12482     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12483     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12484
12485     *first_frame = frame_set->first_frame;
12486     *last_frame = *first_frame + frame_set->n_frames - 1;
12487
12488     return(TNG_SUCCESS);
12489 }
12490
12491 /** Translate from the particle numbering used in a frame set to the real
12492  *  particle numbering - used in the molecule description.
12493  * @param frame_set is the frame_set containing the mappings to use.
12494  * @param local is the index number of the atom in this frame set
12495  * @param real is set to the index of the atom in the molecular system.
12496  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12497  * cannot be found.
12498  */
12499 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12500                 (const tng_trajectory_frame_set_t frame_set,
12501                  const int64_t local,
12502                  int64_t *real)
12503 {
12504     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12505     tng_particle_mapping_t mapping;
12506     if(n_blocks <= 0)
12507     {
12508         *real = local;
12509         return(TNG_SUCCESS);
12510     }
12511     for(i = 0; i < n_blocks; i++)
12512     {
12513         mapping = &frame_set->mappings[i];
12514         first = mapping->num_first_particle;
12515         if(local < first ||
12516            local >= first + mapping->n_particles)
12517         {
12518             continue;
12519         }
12520         *real = mapping->real_particle_numbers[local-first];
12521         return(TNG_SUCCESS);
12522     }
12523     *real = local;
12524     return(TNG_FAILURE);
12525 }
12526
12527 /** Translate from the real particle numbering to the particle numbering
12528  *  used in a frame set.
12529  * @param frame_set is the frame_set containing the mappings to use.
12530  * @param real is the index number of the atom in the molecular system.
12531  * @param local is set to the index of the atom in this frame set.
12532  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12533  * cannot be found.
12534  */
12535 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12536                 (const tng_trajectory_frame_set_t frame_set,
12537                  const int64_t real,
12538                  int64_t *local)
12539 {
12540     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12541     tng_particle_mapping_t mapping;
12542     if(n_blocks <= 0)
12543     {
12544         *local = real;
12545         return(TNG_SUCCESS);
12546     }
12547     for(i = 0; i < n_blocks; i++)
12548     {
12549         mapping = &frame_set->mappings[i];
12550         for(j = mapping->n_particles; j--;)
12551         {
12552             if(mapping->real_particle_numbers[j] == real)
12553             {
12554                 *local = j;
12555                 return(TNG_SUCCESS);
12556             }
12557         }
12558     }
12559     return(TNG_FAILURE);
12560 }
12561 */
12562
12563 static tng_function_status tng_file_headers_len_get
12564                 (tng_trajectory_t tng_data,
12565                  int64_t *len)
12566 {
12567     int64_t orig_pos;
12568     tng_gen_block_t block;
12569
12570     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12571
12572     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12573     {
12574         return(TNG_CRITICAL);
12575     }
12576
12577     *len = 0;
12578
12579     orig_pos = ftell(tng_data->input_file);
12580
12581     if(!tng_data->input_file_len)
12582     {
12583         fseek(tng_data->input_file, 0, SEEK_END);
12584         tng_data->input_file_len = ftell(tng_data->input_file);
12585     }
12586     fseek(tng_data->input_file, 0, SEEK_SET);
12587
12588     tng_block_init(&block);
12589     /* Read through the headers of non-trajectory blocks (they come before the
12590      * trajectory blocks in the file) */
12591     while (*len < tng_data->input_file_len &&
12592            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12593            block->id != -1 &&
12594            block->id != TNG_TRAJECTORY_FRAME_SET)
12595     {
12596         *len += block->header_contents_size + block->block_contents_size;
12597         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12598     }
12599
12600     fseek(tng_data->input_file, orig_pos, SEEK_SET);
12601
12602     tng_block_destroy(&block);
12603
12604     return(TNG_SUCCESS);
12605 }
12606
12607 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12608                 (tng_trajectory_t tng_data,
12609                  const char hash_mode)
12610 {
12611     int64_t prev_pos = 0;
12612     tng_gen_block_t block;
12613
12614     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12615
12616     tng_data->n_trajectory_frame_sets = 0;
12617
12618     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12619     {
12620         return(TNG_CRITICAL);
12621     }
12622
12623     if(!tng_data->input_file_len)
12624     {
12625         fseek(tng_data->input_file, 0, SEEK_END);
12626         tng_data->input_file_len = ftell(tng_data->input_file);
12627     }
12628     fseek(tng_data->input_file, 0, SEEK_SET);
12629
12630     tng_block_init(&block);
12631     /* Non trajectory blocks (they come before the trajectory
12632      * blocks in the file) */
12633     while (prev_pos < tng_data->input_file_len &&
12634            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12635            block->id != -1 &&
12636            block->id != TNG_TRAJECTORY_FRAME_SET)
12637     {
12638         tng_block_read_next(tng_data, block, hash_mode);
12639         prev_pos = ftell(tng_data->input_file);
12640     }
12641
12642     /* Go back if a trajectory block was encountered */
12643     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12644     {
12645         fseek(tng_data->input_file, prev_pos, SEEK_SET);
12646     }
12647
12648     tng_block_destroy(&block);
12649
12650     return(TNG_SUCCESS);
12651 }
12652
12653 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12654                 (tng_trajectory_t tng_data,
12655                  const char hash_mode)
12656 {
12657     int i;
12658     int64_t len, orig_len, tot_len = 0, data_start_pos;
12659     tng_function_status stat;
12660     tng_gen_block_t block;
12661
12662     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12663
12664     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12665     {
12666         return(TNG_CRITICAL);
12667     }
12668
12669     if(tng_data->n_trajectory_frame_sets > 0)
12670     {
12671         stat = tng_file_headers_len_get(tng_data, &orig_len);
12672         if(stat != TNG_SUCCESS)
12673         {
12674             return(stat);
12675         }
12676
12677         tng_block_init(&block);
12678         block->name = malloc(TNG_MAX_STR_LEN);
12679         if(!block->name)
12680         {
12681             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12682                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12683             tng_block_destroy(&block);
12684             return(TNG_CRITICAL);
12685         }
12686         strcpy(block->name, "GENERAL INFO");
12687         tng_block_header_len_calculate(tng_data, block, &len);
12688         tot_len += len;
12689         tng_general_info_block_len_calculate(tng_data, &len);
12690         tot_len += len;
12691         strcpy(block->name, "MOLECULES");
12692         tng_block_header_len_calculate(tng_data, block, &len);
12693         tot_len += len;
12694         tng_molecules_block_len_calculate(tng_data, &len);
12695         tot_len += len;
12696
12697         for(i = 0; i < tng_data->n_data_blocks; i++)
12698         {
12699             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12700             tng_block_header_len_calculate(tng_data, block, &len);
12701             tot_len += len;
12702             tng_data_block_len_calculate(tng_data,
12703                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12704                                         TNG_FALSE, 1, 1, 1, 0,
12705                                         1, 0, &data_start_pos,
12706                                         &len);
12707             tot_len += len;
12708         }
12709         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12710         {
12711             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12712             tng_block_header_len_calculate(tng_data, block, &len);
12713             tot_len += len;
12714             tng_data_block_len_calculate(tng_data,
12715                                         &tng_data->non_tr_particle_data[i],
12716                                         TNG_TRUE, 1, 1, 1, 0,
12717                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12718                                         &data_start_pos,
12719                                         &len);
12720             tot_len += len;
12721         }
12722         tng_block_destroy(&block);
12723
12724         if(tot_len > orig_len)
12725         {
12726             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12727         }
12728
12729         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12730     }
12731
12732     /* TODO: If there is already frame set data written to this file (e.g. when
12733      * appending to an already existing file we might need to move frame sets to
12734      * the end of the file. */
12735
12736     if(tng_general_info_block_write(tng_data, hash_mode)
12737        != TNG_SUCCESS)
12738     {
12739         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12740                 tng_data->input_file_path, __FILE__, __LINE__);
12741         return(TNG_CRITICAL);
12742     }
12743
12744     if(tng_molecules_block_write(tng_data, hash_mode)
12745         != TNG_SUCCESS)
12746     {
12747         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12748                 tng_data->input_file_path, __FILE__, __LINE__);
12749         return(TNG_CRITICAL);
12750     }
12751
12752     /* FIXME: Currently writing non-trajectory data blocks here.
12753      * Should perhaps be moved. */
12754     tng_block_init(&block);
12755     for(i = 0; i < tng_data->n_data_blocks; i++)
12756     {
12757         block->id = tng_data->non_tr_data[i].block_id;
12758         tng_data_block_write(tng_data, block,
12759                              i, hash_mode);
12760     }
12761
12762     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12763     {
12764         block->id = tng_data->non_tr_particle_data[i].block_id;
12765         tng_particle_data_block_write(tng_data, block,
12766                                       i, 0, hash_mode);
12767     }
12768
12769     tng_block_destroy(&block);
12770
12771     return(TNG_SUCCESS);
12772 }
12773
12774 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12775                                         tng_gen_block_t block,
12776                                         const char hash_mode)
12777 {
12778     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12779     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12780
12781     switch(block->id)
12782     {
12783     case TNG_TRAJECTORY_FRAME_SET:
12784         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12785     case TNG_PARTICLE_MAPPING:
12786         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12787     case TNG_GENERAL_INFO:
12788         return(tng_general_info_block_read(tng_data, block, hash_mode));
12789     case TNG_MOLECULES:
12790         return(tng_molecules_block_read(tng_data, block, hash_mode));
12791     default:
12792         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12793         {
12794             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12795         }
12796         else
12797         {
12798             /* Skip to the next block */
12799             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12800             return(TNG_FAILURE);
12801         }
12802     }
12803 }
12804
12805 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12806                 (tng_trajectory_t tng_data,
12807                  const char hash_mode)
12808 {
12809     long file_pos;
12810     tng_gen_block_t block;
12811     tng_function_status stat;
12812
12813     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12814
12815     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12816     {
12817         return(TNG_CRITICAL);
12818     }
12819
12820     file_pos = ftell(tng_data->input_file);
12821
12822     tng_block_init(&block);
12823
12824     if(!tng_data->input_file_len)
12825     {
12826         fseek(tng_data->input_file, 0, SEEK_END);
12827         tng_data->input_file_len = ftell(tng_data->input_file);
12828         fseek(tng_data->input_file, file_pos, SEEK_SET);
12829     }
12830
12831     /* Read block headers first to see what block is found. */
12832     stat = tng_block_header_read(tng_data, block);
12833     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12834        block->id == -1)
12835     {
12836         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12837                file_pos, __FILE__, __LINE__);
12838         tng_block_destroy(&block);
12839         return(TNG_CRITICAL);
12840     }
12841
12842     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12843
12844     if(tng_block_read_next(tng_data, block,
12845                            hash_mode) == TNG_SUCCESS)
12846     {
12847         tng_data->n_trajectory_frame_sets++;
12848         file_pos = ftell(tng_data->input_file);
12849         /* Read all blocks until next frame set block */
12850         stat = tng_block_header_read(tng_data, block);
12851         while(file_pos < tng_data->input_file_len &&
12852               stat != TNG_CRITICAL &&
12853               block->id != TNG_TRAJECTORY_FRAME_SET &&
12854               block->id != -1)
12855         {
12856             stat = tng_block_read_next(tng_data, block,
12857                                        hash_mode);
12858             if(stat != TNG_CRITICAL)
12859             {
12860                 file_pos = ftell(tng_data->input_file);
12861                 if(file_pos < tng_data->input_file_len)
12862                 {
12863                     stat = tng_block_header_read(tng_data, block);
12864                 }
12865             }
12866         }
12867         if(stat == TNG_CRITICAL)
12868         {
12869             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12870                    file_pos, __FILE__, __LINE__);
12871             tng_block_destroy(&block);
12872             return(stat);
12873         }
12874
12875         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12876         {
12877             fseek(tng_data->input_file, file_pos, SEEK_SET);
12878         }
12879     }
12880
12881     tng_block_destroy(&block);
12882
12883     return(TNG_SUCCESS);
12884 }
12885
12886
12887 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12888                 (tng_trajectory_t tng_data,
12889                  const char hash_mode,
12890                  const int64_t block_id)
12891 {
12892     long file_pos;
12893     tng_gen_block_t block;
12894     tng_function_status stat;
12895     int found_flag = 1;
12896
12897     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12898
12899     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12900     {
12901         return(TNG_CRITICAL);
12902     }
12903
12904     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12905
12906     if(file_pos < 0)
12907     {
12908         /* No current frame set. This means that the first frame set must be
12909          * read */
12910         found_flag = 0;
12911         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12912     }
12913
12914     if(file_pos > 0)
12915     {
12916         fseek(tng_data->input_file,
12917               file_pos,
12918               SEEK_SET);
12919     }
12920     else
12921     {
12922         return(TNG_FAILURE);
12923     }
12924
12925     tng_block_init(&block);
12926
12927     if(!tng_data->input_file_len)
12928     {
12929         fseek(tng_data->input_file, 0, SEEK_END);
12930         tng_data->input_file_len = ftell(tng_data->input_file);
12931         fseek(tng_data->input_file, file_pos, SEEK_SET);
12932     }
12933
12934     /* Read block headers first to see what block is found. */
12935     stat = tng_block_header_read(tng_data, block);
12936     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12937     {
12938         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12939                file_pos, __FILE__, __LINE__);
12940         tng_block_destroy(&block);
12941         return(TNG_CRITICAL);
12942     }
12943     /* If the current frame set had already been read skip its block contents */
12944     if(found_flag)
12945     {
12946         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12947     }
12948     /* Otherwiese read the frame set block */
12949     else
12950     {
12951         stat = tng_block_read_next(tng_data, block,
12952                                    hash_mode);
12953         if(stat != TNG_SUCCESS)
12954         {
12955             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12956             tng_block_destroy(&block);
12957             return(stat);
12958         }
12959     }
12960     file_pos = ftell(tng_data->input_file);
12961
12962     found_flag = 0;
12963
12964     /* Read only blocks of the requested ID
12965         * until next frame set block */
12966     stat = tng_block_header_read(tng_data, block);
12967     while(file_pos < tng_data->input_file_len &&
12968             stat != TNG_CRITICAL &&
12969             block->id != TNG_TRAJECTORY_FRAME_SET &&
12970             block->id != -1)
12971     {
12972         if(block->id == block_id)
12973         {
12974             stat = tng_block_read_next(tng_data, block,
12975                                        hash_mode);
12976             if(stat != TNG_CRITICAL)
12977             {
12978                 file_pos = ftell(tng_data->input_file);
12979                 found_flag = 1;
12980                 if(file_pos < tng_data->input_file_len)
12981                 {
12982                     stat = tng_block_header_read(tng_data, block);
12983                 }
12984             }
12985         }
12986         else
12987         {
12988             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12989             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12990             if(file_pos < tng_data->input_file_len)
12991             {
12992                 stat = tng_block_header_read(tng_data, block);
12993             }
12994         }
12995     }
12996     if(stat == TNG_CRITICAL)
12997     {
12998         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12999                 file_pos, __FILE__, __LINE__);
13000         tng_block_destroy(&block);
13001         return(stat);
13002     }
13003
13004     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13005     {
13006         fseek(tng_data->input_file, file_pos, SEEK_SET);
13007     }
13008
13009     tng_block_destroy(&block);
13010
13011     if(found_flag)
13012     {
13013         return(TNG_SUCCESS);
13014     }
13015     else
13016     {
13017         return(TNG_FAILURE);
13018     }
13019 }
13020
13021 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
13022                 (tng_trajectory_t tng_data,
13023                  const char hash_mode)
13024 {
13025     long file_pos;
13026
13027     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13028
13029     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13030     {
13031         return(TNG_CRITICAL);
13032     }
13033
13034     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13035
13036     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13037     {
13038         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13039     }
13040
13041     if(file_pos > 0)
13042     {
13043         fseek(tng_data->input_file,
13044               file_pos,
13045               SEEK_SET);
13046     }
13047     else
13048     {
13049         return(TNG_FAILURE);
13050     }
13051
13052     return(tng_frame_set_read(tng_data, hash_mode));
13053 }
13054
13055 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
13056                 (tng_trajectory_t tng_data,
13057                  const char hash_mode,
13058                  const int64_t block_id)
13059 {
13060     long file_pos;
13061     tng_gen_block_t block;
13062     tng_function_status stat;
13063
13064     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13065
13066     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13067     {
13068         return(TNG_CRITICAL);
13069     }
13070
13071     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13072
13073     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13074     {
13075         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13076     }
13077
13078     if(file_pos > 0)
13079     {
13080         fseek(tng_data->input_file,
13081               file_pos,
13082               SEEK_SET);
13083     }
13084     else
13085     {
13086         return(TNG_FAILURE);
13087     }
13088
13089     tng_block_init(&block);
13090
13091     if(!tng_data->input_file_len)
13092     {
13093         fseek(tng_data->input_file, 0, SEEK_END);
13094         tng_data->input_file_len = ftell(tng_data->input_file);
13095         fseek(tng_data->input_file, file_pos, SEEK_SET);
13096     }
13097
13098     /* Read block headers first to see what block is found. */
13099     stat = tng_block_header_read(tng_data, block);
13100     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13101     {
13102         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13103                file_pos, __FILE__, __LINE__);
13104         tng_block_destroy(&block);
13105         return(TNG_CRITICAL);
13106     }
13107
13108     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13109
13110     if(tng_block_read_next(tng_data, block,
13111                            hash_mode) == TNG_SUCCESS)
13112     {
13113         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13114     }
13115
13116     tng_block_destroy(&block);
13117
13118     return(stat);
13119 }
13120
13121 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13122                                         const char hash_mode)
13123 {
13124     int i, j;
13125     tng_gen_block_t block;
13126     tng_trajectory_frame_set_t frame_set;
13127     tng_function_status stat;
13128
13129     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13130
13131     frame_set = &tng_data->current_trajectory_frame_set;
13132
13133     if(frame_set->n_written_frames == frame_set->n_frames)
13134     {
13135         return(TNG_SUCCESS);
13136     }
13137
13138     tng_data->current_trajectory_frame_set_output_file_pos =
13139     ftell(tng_data->output_file);
13140     tng_data->last_trajectory_frame_set_output_file_pos =
13141     tng_data->current_trajectory_frame_set_output_file_pos;
13142
13143     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13144     {
13145         return(TNG_FAILURE);
13146     }
13147
13148     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13149     {
13150         tng_data->first_trajectory_frame_set_output_file_pos =
13151         tng_data->current_trajectory_frame_set_output_file_pos;
13152     }
13153
13154     tng_block_init(&block);
13155
13156     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13157     {
13158         tng_block_destroy(&block);
13159         return(TNG_FAILURE);
13160     }
13161
13162     /* Write non-particle data blocks */
13163     for(i = 0; i<frame_set->n_data_blocks; i++)
13164     {
13165         block->id = frame_set->tr_data[i].block_id;
13166         tng_data_block_write(tng_data, block, i, hash_mode);
13167     }
13168     /* Write the mapping blocks and particle data blocks*/
13169     if(frame_set->n_mapping_blocks)
13170     {
13171         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13172         {
13173             block->id = TNG_PARTICLE_MAPPING;
13174             if(frame_set->mappings[i].n_particles > 0)
13175             {
13176                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13177                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13178                 {
13179                     block->id = frame_set->tr_particle_data[j].block_id;
13180                     tng_particle_data_block_write(tng_data, block,
13181                                                   j, &frame_set->mappings[i],
13182                                                   hash_mode);
13183                 }
13184             }
13185         }
13186     }
13187     else
13188     {
13189         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13190         {
13191             block->id = frame_set->tr_particle_data[i].block_id;
13192             tng_particle_data_block_write(tng_data, block,
13193                                           i, 0, hash_mode);
13194         }
13195     }
13196
13197
13198     /* Update pointers in the general info block */
13199     stat = tng_header_pointers_update(tng_data, hash_mode);
13200
13201     if(stat == TNG_SUCCESS)
13202     {
13203         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13204     }
13205
13206     tng_block_destroy(&block);
13207
13208     frame_set->n_unwritten_frames = 0;
13209
13210     fflush(tng_data->output_file);
13211
13212     return(stat);
13213 }
13214
13215 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13216                 (tng_trajectory_t tng_data,
13217                  const char hash_mode)
13218 {
13219     tng_trajectory_frame_set_t frame_set;
13220
13221     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13222
13223     frame_set = &tng_data->current_trajectory_frame_set;
13224
13225     if(frame_set->n_unwritten_frames == 0)
13226     {
13227         return(TNG_SUCCESS);
13228     }
13229     frame_set->n_frames = frame_set->n_unwritten_frames;
13230
13231     return(tng_frame_set_write(tng_data, hash_mode));
13232 }
13233
13234 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13235                 (tng_trajectory_t tng_data,
13236                  const int64_t first_frame,
13237                  const int64_t n_frames)
13238 {
13239     tng_gen_block_t block;
13240     tng_trajectory_frame_set_t frame_set;
13241     FILE *temp = tng_data->input_file;
13242     int64_t curr_pos;
13243
13244     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13245     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13246     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13247
13248     frame_set = &tng_data->current_trajectory_frame_set;
13249
13250     curr_pos = ftell(tng_data->output_file);
13251
13252     if(curr_pos <= 10)
13253     {
13254         tng_file_headers_write(tng_data, TNG_USE_HASH);
13255     }
13256
13257     /* Set pointer to previous frame set to the one that was loaded
13258      * before.
13259      * FIXME: This is a bit risky. If they are not added in order
13260      * it will be wrong. */
13261     if(tng_data->n_trajectory_frame_sets)
13262     {
13263         frame_set->prev_frame_set_file_pos =
13264         tng_data->current_trajectory_frame_set_output_file_pos;
13265     }
13266
13267     tng_data->current_trajectory_frame_set_output_file_pos =
13268     ftell(tng_data->output_file);
13269
13270     tng_data->n_trajectory_frame_sets++;
13271
13272     /* Set the medium range pointers */
13273     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13274     {
13275         frame_set->medium_stride_prev_frame_set_file_pos =
13276         tng_data->first_trajectory_frame_set_output_file_pos;
13277     }
13278     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13279     {
13280         /* FIXME: Currently only working if the previous frame set has its
13281          * medium stride pointer already set. This might need some fixing. */
13282         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13283            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13284         {
13285             tng_block_init(&block);
13286             tng_data->input_file = tng_data->output_file;
13287
13288             curr_pos = ftell(tng_data->output_file);
13289             fseek(tng_data->output_file,
13290                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
13291                   SEEK_SET);
13292
13293             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13294             {
13295                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13296                     __FILE__, __LINE__);
13297                 tng_data->input_file = temp;
13298                 tng_block_destroy(&block);
13299                 return(TNG_CRITICAL);
13300             }
13301
13302             /* Read the next frame set from the previous frame set and one
13303              * medium stride step back */
13304             fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13305             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13306             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13307                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13308                1, tng_data->output_file) == 0)
13309             {
13310                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13311                 tng_data->input_file = temp;
13312                 tng_block_destroy(&block);
13313                 return(TNG_CRITICAL);
13314             }
13315
13316             if(tng_data->input_endianness_swap_func_64)
13317             {
13318                 if(tng_data->input_endianness_swap_func_64(tng_data,
13319                    &frame_set->medium_stride_prev_frame_set_file_pos)
13320                     != TNG_SUCCESS)
13321                 {
13322                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13323                             __FILE__, __LINE__);
13324                 }
13325             }
13326
13327             tng_block_destroy(&block);
13328
13329             /* Set the long range pointers */
13330             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13331             {
13332                 frame_set->long_stride_prev_frame_set_file_pos =
13333                 tng_data->first_trajectory_frame_set_output_file_pos;
13334             }
13335             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13336             {
13337                 /* FIXME: Currently only working if the previous frame set has its
13338                 * long stride pointer already set. This might need some fixing. */
13339                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13340                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13341                 {
13342                     tng_block_init(&block);
13343                     tng_data->input_file = tng_data->output_file;
13344
13345                     fseek(tng_data->output_file,
13346                           (long)frame_set->long_stride_prev_frame_set_file_pos,
13347                           SEEK_SET);
13348
13349                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13350                     {
13351                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13352                             __FILE__, __LINE__);
13353                         tng_data->input_file = temp;
13354                         tng_block_destroy(&block);
13355                         return(TNG_CRITICAL);
13356                     }
13357
13358                     /* Read the next frame set from the previous frame set and one
13359                     * long stride step back */
13360                     fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13361                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13362
13363                     tng_block_destroy(&block);
13364
13365                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13366                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13367                     1, tng_data->output_file) == 0)
13368                     {
13369                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13370                         tng_data->input_file = temp;
13371                         return(TNG_CRITICAL);
13372                     }
13373
13374                     if(tng_data->input_endianness_swap_func_64)
13375                     {
13376                         if(tng_data->input_endianness_swap_func_64(tng_data,
13377                            &frame_set->long_stride_prev_frame_set_file_pos)
13378                             != TNG_SUCCESS)
13379                         {
13380                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13381                                     __FILE__, __LINE__);
13382                         }
13383                     }
13384
13385                 }
13386             }
13387
13388             tng_data->input_file = temp;
13389             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
13390         }
13391     }
13392
13393     frame_set->first_frame = first_frame;
13394     frame_set->n_frames = n_frames;
13395     frame_set->n_written_frames = 0;
13396     frame_set->n_unwritten_frames = 0;
13397     frame_set->first_frame_time = -1;
13398
13399     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13400        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13401     {
13402         tng_data->first_trajectory_frame_set_output_file_pos =
13403         tng_data->current_trajectory_frame_set_output_file_pos;
13404     }
13405     /* FIXME: Should check the frame number instead of the file_pos,
13406      * in case frame sets are not in order */
13407     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13408        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13409        tng_data->last_trajectory_frame_set_output_file_pos <
13410        tng_data->current_trajectory_frame_set_output_file_pos)
13411     {
13412         tng_data->last_trajectory_frame_set_output_file_pos =
13413         tng_data->current_trajectory_frame_set_output_file_pos;
13414     }
13415
13416     return(TNG_SUCCESS);
13417 }
13418
13419 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13420                 (tng_trajectory_t tng_data,
13421                  const int64_t first_frame,
13422                  const int64_t n_frames,
13423                  const double first_frame_time)
13424 {
13425     tng_function_status stat;
13426
13427     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13428     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13429     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13430     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13431
13432
13433     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13434     if(stat != TNG_SUCCESS)
13435     {
13436         return(stat);
13437     }
13438     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13439
13440     return(stat);
13441 }
13442
13443 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13444                 (tng_trajectory_t tng_data,
13445                  const double first_frame_time)
13446 {
13447     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13448     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13449
13450     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13451
13452     return(TNG_SUCCESS);
13453 }
13454
13455 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13456                 (const tng_trajectory_t tng_data,
13457                  int64_t *frame)
13458 {
13459     long file_pos, next_frame_set_file_pos;
13460     tng_gen_block_t block;
13461     tng_function_status stat;
13462
13463     tng_trajectory_frame_set_t frame_set;
13464
13465     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13466     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13467     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13468
13469     file_pos = ftell(tng_data->input_file);
13470
13471     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13472     {
13473         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13474     }
13475     else
13476     {
13477         frame_set = &tng_data->current_trajectory_frame_set;
13478         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
13479     }
13480
13481     if(next_frame_set_file_pos <= 0)
13482     {
13483         return(TNG_FAILURE);
13484     }
13485
13486     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
13487     /* Read block headers first to see that a frame set block is found. */
13488     tng_block_init(&block);
13489     stat = tng_block_header_read(tng_data, block);
13490     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13491     {
13492         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13493                file_pos, __FILE__, __LINE__);
13494         return(TNG_CRITICAL);
13495     }
13496 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13497     {
13498         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13499     }*/
13500     tng_block_destroy(&block);
13501
13502     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13503     {
13504         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13505                __FILE__, __LINE__);
13506         return(TNG_CRITICAL);
13507     }
13508     fseek(tng_data->input_file, file_pos, SEEK_SET);
13509
13510     return(TNG_SUCCESS);
13511 }
13512
13513 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13514                 (tng_trajectory_t tng_data,
13515                  const int64_t id,
13516                  const char *block_name,
13517                  const char datatype,
13518                  const char block_type_flag,
13519                  int64_t n_frames,
13520                  const int64_t n_values_per_frame,
13521                  int64_t stride_length,
13522                  const int64_t codec_id,
13523                  void *new_data)
13524 {
13525     int i, j, size, len;
13526     tng_trajectory_frame_set_t frame_set;
13527     tng_non_particle_data_t data;
13528     char **first_dim_values;
13529     char *new_data_c=new_data;
13530     int64_t n_frames_div;
13531
13532     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13533     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13534     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13535
13536     frame_set = &tng_data->current_trajectory_frame_set;
13537
13538     if(stride_length <= 0)
13539     {
13540         stride_length = 1;
13541     }
13542
13543     /* If the block does not exist, create it */
13544     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13545     {
13546         if(tng_data_block_create(tng_data, block_type_flag) !=
13547             TNG_SUCCESS)
13548         {
13549             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13550                    __FILE__, __LINE__);
13551             return(TNG_CRITICAL);
13552         }
13553         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13554         {
13555             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13556         }
13557         else
13558         {
13559             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13560         }
13561         data->block_id = id;
13562
13563         data->block_name = malloc(strlen(block_name) + 1);
13564         if(!data->block_name)
13565         {
13566             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13567                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13568             return(TNG_CRITICAL);
13569         }
13570         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13571
13572         data->values = 0;
13573         /* FIXME: Memory leak from strings. */
13574         data->strings = 0;
13575         data->last_retrieved_frame = -1;
13576     }
13577
13578     data->datatype = datatype;
13579     data->stride_length = tng_max_i64(stride_length, 1);
13580     data->n_values_per_frame = n_values_per_frame;
13581     data->n_frames = n_frames;
13582     data->codec_id = codec_id;
13583     data->compression_multiplier = 1.0;
13584     /* FIXME: This can cause problems. */
13585     data->first_frame_with_data = frame_set->first_frame;
13586
13587     switch(datatype)
13588     {
13589     case TNG_FLOAT_DATA:
13590         size = sizeof(float);
13591         break;
13592     case TNG_INT_DATA:
13593         size = sizeof(int64_t);
13594         break;
13595     case TNG_DOUBLE_DATA:
13596     default:
13597         size = sizeof(double);
13598         break;
13599     }
13600
13601     if(new_data_c)
13602     {
13603         /* Allocate memory */
13604         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13605                                  n_values_per_frame) !=
13606         TNG_SUCCESS)
13607         {
13608             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13609                 __FILE__, __LINE__);
13610             return(TNG_CRITICAL);
13611         }
13612
13613         if(n_frames > frame_set->n_unwritten_frames)
13614         {
13615             frame_set->n_unwritten_frames = n_frames;
13616         }
13617
13618         n_frames_div = (n_frames % stride_length) ?
13619                      n_frames / stride_length + 1:
13620                      n_frames / stride_length;
13621
13622         if(datatype == TNG_CHAR_DATA)
13623         {
13624             for(i = 0; i < n_frames_div; i++)
13625             {
13626                 first_dim_values = data->strings[i];
13627                 for(j = 0; j < n_values_per_frame; j++)
13628                 {
13629                     len = tng_min_i((int)strlen(new_data_c) + 1,
13630                                 TNG_MAX_STR_LEN);
13631                     if(first_dim_values[j])
13632                     {
13633                         free(first_dim_values[j]);
13634                     }
13635                     first_dim_values[j] = malloc(len);
13636                     if(!first_dim_values[j])
13637                     {
13638                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13639                             len, __FILE__, __LINE__);
13640                         return(TNG_CRITICAL);
13641                     }
13642                     strncpy(first_dim_values[j],
13643                             new_data_c, len);
13644                     new_data_c += len;
13645                 }
13646             }
13647         }
13648         else
13649         {
13650             memcpy(data->values, new_data, size * n_frames_div *
13651                    n_values_per_frame);
13652         }
13653     }
13654
13655     return(TNG_SUCCESS);
13656 }
13657
13658 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13659                 (tng_trajectory_t tng_data,
13660                  const int64_t id,
13661                  const char *block_name,
13662                  const char datatype,
13663                  const char block_type_flag,
13664                  int64_t n_frames,
13665                  const int64_t n_values_per_frame,
13666                  int64_t stride_length,
13667                  const int64_t num_first_particle,
13668                  const int64_t n_particles,
13669                  const int64_t codec_id,
13670                  void *new_data)
13671 {
13672     int i, size, len;
13673     int64_t j, k;
13674     int64_t tot_n_particles, n_frames_div;
13675     char ***first_dim_values, **second_dim_values;
13676     tng_trajectory_frame_set_t frame_set;
13677     tng_particle_data_t data;
13678     char *new_data_c=new_data;
13679
13680     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13681     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13682     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13683     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13684     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13685
13686
13687     frame_set = &tng_data->current_trajectory_frame_set;
13688
13689     if(stride_length <= 0)
13690     {
13691         stride_length = 1;
13692     }
13693
13694     /* If the block does not exist, create it */
13695     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13696     {
13697         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13698             TNG_SUCCESS)
13699         {
13700             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13701                    __FILE__, __LINE__);
13702             return(TNG_CRITICAL);
13703         }
13704         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13705         {
13706             data = &frame_set->tr_particle_data[frame_set->
13707                                                 n_particle_data_blocks - 1];
13708         }
13709         else
13710         {
13711             data = &tng_data->non_tr_particle_data[tng_data->
13712                                                    n_particle_data_blocks - 1];
13713         }
13714         data->block_id = id;
13715
13716         data->block_name = malloc(strlen(block_name) + 1);
13717         if(!data->block_name)
13718         {
13719             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13720                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13721             return(TNG_CRITICAL);
13722         }
13723         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13724
13725         data->datatype = datatype;
13726
13727         data->values = 0;
13728         /* FIXME: Memory leak from strings. */
13729         data->strings = 0;
13730         data->last_retrieved_frame = -1;
13731     }
13732
13733     data->stride_length = tng_max_i64(stride_length, 1);
13734     data->n_values_per_frame = n_values_per_frame;
13735     data->n_frames = n_frames;
13736     data->codec_id = codec_id;
13737     data->compression_multiplier = 1.0;
13738     /* FIXME: This can cause problems. */
13739     data->first_frame_with_data = frame_set->first_frame;
13740
13741     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13742     {
13743         tot_n_particles = frame_set->n_particles;
13744     }
13745     else
13746     {
13747         tot_n_particles = tng_data->n_particles;
13748     }
13749
13750     /* If data values are supplied add that data to the data block. */
13751     if(new_data_c)
13752     {
13753         /* Allocate memory */
13754         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13755                                           stride_length, tot_n_particles,
13756                                           n_values_per_frame) !=
13757         TNG_SUCCESS)
13758         {
13759             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13760                 __FILE__, __LINE__);
13761             return(TNG_CRITICAL);
13762         }
13763
13764         if(n_frames > frame_set->n_unwritten_frames)
13765         {
13766             frame_set->n_unwritten_frames = n_frames;
13767         }
13768
13769         n_frames_div = (n_frames % stride_length) ?
13770                      n_frames / stride_length + 1:
13771                      n_frames / stride_length;
13772
13773         if(datatype == TNG_CHAR_DATA)
13774         {
13775             for(i = 0; i < n_frames_div; i++)
13776             {
13777                 first_dim_values = data->strings[i];
13778                 for(j = num_first_particle; j < num_first_particle + n_particles;
13779                     j++)
13780                 {
13781                     second_dim_values = first_dim_values[j];
13782                     for(k = 0; k < n_values_per_frame; k++)
13783                     {
13784                         len = tng_min_i((int)strlen(new_data_c) + 1,
13785                                 TNG_MAX_STR_LEN);
13786                         if(second_dim_values[k])
13787                         {
13788                             free(second_dim_values[k]);
13789                         }
13790                         second_dim_values[k] = malloc(len);
13791                         if(!second_dim_values[k])
13792                         {
13793                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13794                                 len, __FILE__, __LINE__);
13795                             return(TNG_CRITICAL);
13796                         }
13797                         strncpy(second_dim_values[k],
13798                                 new_data_c, len);
13799                         new_data_c += len;
13800                     }
13801                 }
13802             }
13803         }
13804         else
13805         {
13806             switch(datatype)
13807             {
13808             case TNG_INT_DATA:
13809                 size = sizeof(int64_t);
13810                 break;
13811             case TNG_FLOAT_DATA:
13812                 size = sizeof(float);
13813                 break;
13814             case TNG_DOUBLE_DATA:
13815             default:
13816                 size = sizeof(double);
13817             }
13818
13819             memcpy(data->values, new_data, size * n_frames_div *
13820                    n_particles * n_values_per_frame);
13821         }
13822     }
13823
13824     return(TNG_SUCCESS);
13825 }
13826
13827 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13828                 (tng_trajectory_t tng_data,
13829                  int64_t block_id,
13830                  char *name,
13831                  int max_len)
13832 {
13833     int64_t i;
13834     tng_trajectory_frame_set_t frame_set;
13835     tng_function_status stat;
13836     tng_particle_data_t p_data;
13837     tng_non_particle_data_t np_data;
13838     int block_type = -1;
13839
13840     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13841     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13842
13843     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13844     {
13845         p_data = &tng_data->non_tr_particle_data[i];
13846         if(p_data->block_id == block_id)
13847         {
13848             strncpy(name, p_data->block_name, max_len);
13849             name[max_len - 1] = '\0';
13850             return(TNG_SUCCESS);
13851         }
13852     }
13853     for(i = 0; i < tng_data->n_data_blocks; i++)
13854     {
13855         np_data = &tng_data->non_tr_data[i];
13856         if(np_data->block_id == block_id)
13857         {
13858             strncpy(name, np_data->block_name, max_len);
13859             name[max_len - 1] = '\0';
13860             return(TNG_SUCCESS);
13861         }
13862     }
13863
13864     frame_set = &tng_data->current_trajectory_frame_set;
13865
13866     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13867     if(stat == TNG_SUCCESS)
13868     {
13869         block_type = TNG_PARTICLE_BLOCK_DATA;
13870     }
13871     else
13872     {
13873         stat = tng_data_find(tng_data, block_id, &np_data);
13874         if(stat == TNG_SUCCESS)
13875         {
13876             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13877         }
13878         else
13879         {
13880             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13881             if(stat != TNG_SUCCESS)
13882             {
13883                 return(stat);
13884             }
13885             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13886             if(stat == TNG_SUCCESS)
13887             {
13888                 block_type = TNG_PARTICLE_BLOCK_DATA;
13889             }
13890             else
13891             {
13892                 stat = tng_data_find(tng_data, block_id, &np_data);
13893                 if(stat == TNG_SUCCESS)
13894                 {
13895                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13896                 }
13897             }
13898         }
13899     }
13900     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13901     {
13902         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13903         {
13904             p_data = &frame_set->tr_particle_data[i];
13905             if(p_data->block_id == block_id)
13906             {
13907                 strncpy(name, p_data->block_name, max_len);
13908                 name[max_len - 1] = '\0';
13909                 return(TNG_SUCCESS);
13910             }
13911         }
13912     }
13913     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13914     {
13915         for(i = 0; i < frame_set->n_data_blocks; i++)
13916         {
13917             np_data = &frame_set->tr_data[i];
13918             if(np_data->block_id == block_id)
13919             {
13920                 strncpy(name, np_data->block_name, max_len);
13921                 name[max_len - 1] = '\0';
13922                 return(TNG_SUCCESS);
13923             }
13924         }
13925     }
13926
13927     return(TNG_FAILURE);
13928 }
13929
13930 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13931                 (const tng_trajectory_t tng_data,
13932                  int64_t block_id,
13933                  int *block_dependency)
13934 {
13935     int64_t i;
13936     tng_function_status stat;
13937     tng_particle_data_t p_data;
13938     tng_non_particle_data_t np_data;
13939
13940     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13941     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13942
13943     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13944     {
13945         p_data = &tng_data->non_tr_particle_data[i];
13946         if(p_data->block_id == block_id)
13947         {
13948             *block_dependency = TNG_PARTICLE_DEPENDENT;
13949             return(TNG_SUCCESS);
13950         }
13951     }
13952     for(i = 0; i < tng_data->n_data_blocks; i++)
13953     {
13954         np_data = &tng_data->non_tr_data[i];
13955         if(np_data->block_id == block_id)
13956         {
13957             *block_dependency = 0;
13958             return(TNG_SUCCESS);
13959         }
13960     }
13961
13962     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13963     if(stat == TNG_SUCCESS)
13964     {
13965         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13966         return(TNG_SUCCESS);
13967     }
13968     else
13969     {
13970         stat = tng_data_find(tng_data, block_id, &np_data);
13971         if(stat == TNG_SUCCESS)
13972         {
13973             *block_dependency = TNG_FRAME_DEPENDENT;
13974             return(TNG_SUCCESS);
13975         }
13976         else
13977         {
13978             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13979             if(stat != TNG_SUCCESS)
13980             {
13981                 return(stat);
13982             }
13983             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13984             if(stat == TNG_SUCCESS)
13985             {
13986                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13987                 return(TNG_SUCCESS);
13988             }
13989             else
13990             {
13991                 stat = tng_data_find(tng_data, block_id, &np_data);
13992                 if(stat == TNG_SUCCESS)
13993                 {
13994                     *block_dependency = TNG_FRAME_DEPENDENT;
13995                     return(TNG_SUCCESS);
13996                 }
13997             }
13998         }
13999     }
14000
14001     return(TNG_FAILURE);
14002 }
14003
14004 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
14005                 (const tng_trajectory_t tng_data,
14006                  int64_t block_id,
14007                  int64_t *n_values_per_frame)
14008 {
14009     int64_t i;
14010     tng_function_status stat;
14011     tng_particle_data_t p_data;
14012     tng_non_particle_data_t np_data;
14013
14014     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14015     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14016
14017     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
14018     {
14019         p_data = &tng_data->non_tr_particle_data[i];
14020         if(p_data->block_id == block_id)
14021         {
14022             *n_values_per_frame = p_data->n_values_per_frame;
14023             return(TNG_SUCCESS);
14024         }
14025     }
14026     for(i = 0; i < tng_data->n_data_blocks; i++)
14027     {
14028         np_data = &tng_data->non_tr_data[i];
14029         if(np_data->block_id == block_id)
14030         {
14031             *n_values_per_frame = np_data->n_values_per_frame;
14032             return(TNG_SUCCESS);
14033         }
14034     }
14035
14036     stat = tng_particle_data_find(tng_data, block_id, &p_data);
14037     if(stat == TNG_SUCCESS)
14038     {
14039         *n_values_per_frame = p_data->n_values_per_frame;
14040         return(TNG_SUCCESS);
14041     }
14042     else
14043     {
14044         stat = tng_data_find(tng_data, block_id, &np_data);
14045         if(stat == TNG_SUCCESS)
14046         {
14047             *n_values_per_frame = np_data->n_values_per_frame;
14048             return(TNG_SUCCESS);
14049         }
14050         else
14051         {
14052             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14053             if(stat != TNG_SUCCESS)
14054             {
14055                 return(stat);
14056             }
14057             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14058             if(stat == TNG_SUCCESS)
14059             {
14060                 *n_values_per_frame = p_data->n_values_per_frame;
14061                 return(TNG_SUCCESS);
14062             }
14063             else
14064             {
14065                 stat = tng_data_find(tng_data, block_id, &np_data);
14066                 if(stat == TNG_SUCCESS)
14067                 {
14068                     *n_values_per_frame = np_data->n_values_per_frame;
14069                     return(TNG_SUCCESS);
14070                 }
14071             }
14072         }
14073     }
14074
14075     return(TNG_FAILURE);
14076 }
14077
14078 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
14079                 (tng_trajectory_t tng_data,
14080                  const int64_t frame_nr,
14081                  const int64_t block_id,
14082                  const void *values,
14083                  const char hash_mode)
14084 {
14085     int64_t header_pos, file_pos;
14086     int64_t output_file_len, n_values_per_frame, size, contents_size;
14087     int64_t header_size, temp_first, temp_last;
14088     int64_t i, last_frame;
14089     long temp_current;
14090     tng_gen_block_t block;
14091     tng_trajectory_frame_set_t frame_set;
14092     FILE *temp = tng_data->input_file;
14093     struct tng_non_particle_data data;
14094     tng_function_status stat;
14095     char dependency, sparse_data, datatype;
14096     void *copy;
14097
14098     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14099     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14100     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14101
14102     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14103     {
14104         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14105                __FILE__, __LINE__);
14106         return(TNG_CRITICAL);
14107     }
14108
14109     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14110     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14111     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14112     tng_data->first_trajectory_frame_set_input_file_pos =
14113     tng_data->first_trajectory_frame_set_output_file_pos;
14114     tng_data->last_trajectory_frame_set_input_file_pos =
14115     tng_data->last_trajectory_frame_set_output_file_pos;
14116     tng_data->current_trajectory_frame_set_input_file_pos =
14117     tng_data->current_trajectory_frame_set_output_file_pos;
14118
14119     tng_data->input_file = tng_data->output_file;
14120
14121     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14122
14123     frame_set = &tng_data->current_trajectory_frame_set;
14124
14125     if(stat != TNG_SUCCESS)
14126     {
14127         last_frame = frame_set->first_frame +
14128                      frame_set->n_frames - 1;
14129         /* If the wanted frame would be in the frame set after the last
14130             * frame set create a new frame set. */
14131         if(stat == TNG_FAILURE &&
14132             last_frame < frame_nr)
14133 /*           (last_frame < frame_nr &&
14134             tng_data->current_trajectory_frame_set.first_frame +
14135             tng_data->frame_set_n_frames >= frame_nr))*/
14136         {
14137             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14138             {
14139                 last_frame = frame_nr - 1;
14140             }
14141             tng_frame_set_new(tng_data,
14142                               last_frame+1,
14143                               tng_data->frame_set_n_frames);
14144             file_pos = ftell(tng_data->output_file);
14145             fseek(tng_data->output_file, 0, SEEK_END);
14146             output_file_len = ftell(tng_data->output_file);
14147             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14148
14149             /* Read mapping blocks from the last frame set */
14150             tng_block_init(&block);
14151
14152             stat = tng_block_header_read(tng_data, block);
14153             while(file_pos < output_file_len &&
14154                   stat != TNG_CRITICAL &&
14155                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14156                   block->id != -1)
14157             {
14158                 if(block->id == TNG_PARTICLE_MAPPING)
14159                 {
14160                     tng_trajectory_mapping_block_read(tng_data, block,
14161                                                       hash_mode);
14162                 }
14163                 else
14164                 {
14165                     fseek(tng_data->output_file, (long)block->block_contents_size,
14166                         SEEK_CUR);
14167                 }
14168                 file_pos = ftell(tng_data->output_file);
14169                 if(file_pos < output_file_len)
14170                 {
14171                     stat = tng_block_header_read(tng_data, block);
14172                 }
14173             }
14174
14175             tng_block_destroy(&block);
14176             /* Write the frame set to disk */
14177             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14178             {
14179                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14180                 return(TNG_CRITICAL);
14181             }
14182         }
14183         else
14184         {
14185             tng_data->input_file = temp;
14186             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14187             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14188             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14189             return(stat);
14190         }
14191     }
14192
14193     tng_block_init(&block);
14194
14195     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14196
14197     fseek(tng_data->output_file, 0, SEEK_END);
14198     output_file_len = ftell(tng_data->output_file);
14199     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14200
14201     /* Read past the frame set block first */
14202     stat = tng_block_header_read(tng_data, block);
14203     if(stat == TNG_CRITICAL)
14204     {
14205         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14206                file_pos, __FILE__, __LINE__);
14207         tng_block_destroy(&block);
14208         tng_data->input_file = temp;
14209
14210         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14211         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14212         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14213         return(stat);
14214     }
14215     fseek(tng_data->output_file, (long)block->block_contents_size,
14216             SEEK_CUR);
14217
14218     /* Read all block headers until next frame set block or
14219      * until the wanted block id is found */
14220     stat = tng_block_header_read(tng_data, block);
14221     while(file_pos < output_file_len &&
14222             stat != TNG_CRITICAL &&
14223             block->id != block_id &&
14224             block->id != TNG_TRAJECTORY_FRAME_SET &&
14225             block->id != -1)
14226     {
14227         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14228         file_pos = ftell(tng_data->output_file);
14229         if(file_pos < output_file_len)
14230         {
14231             stat = tng_block_header_read(tng_data, block);
14232         }
14233     }
14234     if(stat == TNG_CRITICAL)
14235     {
14236         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14237                file_pos, __FILE__, __LINE__);
14238         tng_block_destroy(&block);
14239         tng_data->input_file = temp;
14240         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14241         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14242         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14243         return(stat);
14244     }
14245
14246     contents_size = block->block_contents_size;
14247     header_size = block->header_contents_size;
14248
14249     header_pos = ftell(tng_data->output_file) - header_size;
14250     frame_set = &tng_data->current_trajectory_frame_set;
14251
14252     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14253     {
14254         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14255         tng_block_destroy(&block);
14256         return(TNG_CRITICAL);
14257     }
14258     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14259     {
14260         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14261         tng_block_destroy(&block);
14262         return(TNG_CRITICAL);
14263     }
14264     data.datatype = datatype;
14265
14266     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14267        (dependency & TNG_PARTICLE_DEPENDENT))
14268     {
14269         tng_block_destroy(&block);
14270         tng_data->input_file = temp;
14271
14272         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14273         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14274         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14275         return(TNG_FAILURE);
14276     }
14277
14278     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14279     {
14280         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14281         tng_block_destroy(&block);
14282         return(TNG_CRITICAL);
14283     }
14284
14285     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14286              tng_data->input_file) == 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             &data.n_values_per_frame)
14296             != TNG_SUCCESS)
14297         {
14298             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14299                     __FILE__, __LINE__);
14300         }
14301     }
14302
14303     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14304              tng_data->input_file) == 0)
14305     {
14306         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14307         tng_block_destroy(&block);
14308         return(TNG_CRITICAL);
14309     }
14310     if(tng_data->output_endianness_swap_func_64)
14311     {
14312         if(tng_data->output_endianness_swap_func_64(tng_data,
14313             &data.codec_id)
14314             != TNG_SUCCESS)
14315         {
14316             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14317                     __FILE__, __LINE__);
14318         }
14319     }
14320
14321     if(data.codec_id != TNG_UNCOMPRESSED)
14322     {
14323         if(fread(&data.compression_multiplier,
14324                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14325             == 0)
14326         {
14327             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14328             tng_block_destroy(&block);
14329             return(TNG_CRITICAL);
14330         }
14331         if(tng_data->output_endianness_swap_func_64)
14332         {
14333             if(tng_data->output_endianness_swap_func_64(tng_data,
14334                 (int64_t *)&data.compression_multiplier)
14335                 != TNG_SUCCESS)
14336             {
14337                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14338                         __FILE__, __LINE__);
14339             }
14340         }
14341     }
14342     else
14343     {
14344         data.compression_multiplier = 1;
14345     }
14346
14347     if(sparse_data)
14348     {
14349         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14350                  1, tng_data->input_file) == 0)
14351         {
14352             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14353             tng_block_destroy(&block);
14354             return(TNG_CRITICAL);
14355         }
14356         if(tng_data->output_endianness_swap_func_64)
14357         {
14358             if(tng_data->output_endianness_swap_func_64(tng_data,
14359                 &data.first_frame_with_data)
14360                 != TNG_SUCCESS)
14361             {
14362                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14363                         __FILE__, __LINE__);
14364             }
14365         }
14366
14367         if(fread(&data.stride_length, sizeof(data.stride_length),
14368                  1, tng_data->input_file) == 0)
14369         {
14370             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14371             tng_block_destroy(&block);
14372             return(TNG_CRITICAL);
14373         }
14374         if(tng_data->output_endianness_swap_func_64)
14375         {
14376             if(tng_data->output_endianness_swap_func_64(tng_data,
14377                 &data.stride_length)
14378                 != TNG_SUCCESS)
14379             {
14380                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14381                         __FILE__, __LINE__);
14382             }
14383         }
14384     }
14385     else
14386     {
14387         data.first_frame_with_data = 0;
14388         data.stride_length = 1;
14389     }
14390     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14391
14392     tng_data->input_file = temp;
14393
14394     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14395     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14396     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14397
14398     switch(data.datatype)
14399     {
14400         case(TNG_INT_DATA):
14401             size = sizeof(int64_t);
14402             break;
14403         case(TNG_FLOAT_DATA):
14404             size = sizeof(float);
14405             break;
14406         case(TNG_DOUBLE_DATA):
14407             size = sizeof(double);
14408             break;
14409         default:
14410             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14411                    __LINE__);
14412             tng_block_destroy(&block);
14413             return(TNG_FAILURE);
14414     }
14415
14416     n_values_per_frame = data.n_values_per_frame;
14417
14418     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14419                                data.first_frame_with_data)) /
14420                 data.stride_length;
14421     file_pos *= size * n_values_per_frame;
14422
14423     if(file_pos > contents_size)
14424     {
14425         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14426                __LINE__);
14427         tng_block_destroy(&block);
14428         return(TNG_FAILURE);
14429     }
14430
14431     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14432
14433     /* If the endianness is not big endian the data needs to be swapped */
14434     if((data.datatype == TNG_INT_DATA ||
14435         data.datatype == TNG_DOUBLE_DATA) &&
14436        tng_data->output_endianness_swap_func_64)
14437     {
14438         copy = malloc(n_values_per_frame * size);
14439         memcpy(copy, values, n_values_per_frame * size);
14440         for(i = 0; i < n_values_per_frame; i++)
14441         {
14442             if(tng_data->output_endianness_swap_func_64(tng_data,
14443                 (int64_t *)copy+i)
14444                 != TNG_SUCCESS)
14445             {
14446                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14447                         __FILE__, __LINE__);
14448             }
14449         }
14450         fwrite(copy, n_values_per_frame, size,
14451                tng_data->output_file);
14452         free(copy);
14453     }
14454     else if(data.datatype == TNG_FLOAT_DATA &&
14455             tng_data->output_endianness_swap_func_32)
14456     {
14457         copy = malloc(n_values_per_frame * size);
14458         memcpy(copy, values, n_values_per_frame * size);
14459         for(i = 0; i < n_values_per_frame; i++)
14460         {
14461             if(tng_data->output_endianness_swap_func_32(tng_data,
14462                 (int32_t *)copy+i)
14463                 != TNG_SUCCESS)
14464             {
14465                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14466                         __FILE__, __LINE__);
14467             }
14468         }
14469         fwrite(copy, n_values_per_frame, size,
14470                tng_data->output_file);
14471         free(copy);
14472     }
14473
14474     else
14475     {
14476         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14477     }
14478
14479     fflush(tng_data->output_file);
14480
14481     /* Update the number of written frames in the frame set. */
14482     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14483     {
14484         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14485     }
14486
14487     /* If the last frame has been written update the hash */
14488     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14489        data.first_frame_with_data) >=
14490        frame_set->n_frames)
14491     {
14492         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14493                             header_size);
14494     }
14495
14496     tng_block_destroy(&block);
14497
14498     return(TNG_SUCCESS);
14499 }
14500
14501 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14502                 (tng_trajectory_t tng_data,
14503                  const int64_t frame_nr,
14504                  const int64_t block_id,
14505                  const int64_t val_first_particle,
14506                  const int64_t val_n_particles,
14507                  const void *values,
14508                  const char hash_mode)
14509 {
14510     int64_t header_pos, file_pos, tot_n_particles;
14511     int64_t output_file_len, n_values_per_frame, size, contents_size;
14512     int64_t header_size, temp_first, temp_last;
14513     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14514     int64_t i, last_frame;
14515     long temp_current;
14516     tng_gen_block_t block;
14517     tng_trajectory_frame_set_t frame_set;
14518     FILE *temp = tng_data->input_file;
14519     struct tng_particle_data data;
14520     tng_function_status stat;
14521     tng_particle_mapping_t mapping;
14522     char dependency, sparse_data, datatype;
14523     void *copy;
14524
14525     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14526     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14527     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14528     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14529     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14530
14531     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14532     {
14533         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14534                __FILE__, __LINE__);
14535         return(TNG_CRITICAL);
14536     }
14537
14538     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14539     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14540     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14541     tng_data->first_trajectory_frame_set_input_file_pos =
14542     tng_data->first_trajectory_frame_set_output_file_pos;
14543     tng_data->last_trajectory_frame_set_input_file_pos =
14544     tng_data->last_trajectory_frame_set_output_file_pos;
14545     tng_data->current_trajectory_frame_set_input_file_pos =
14546     tng_data->current_trajectory_frame_set_output_file_pos;
14547
14548     tng_data->input_file = tng_data->output_file;
14549
14550     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14551
14552     frame_set = &tng_data->current_trajectory_frame_set;
14553
14554     if(stat != TNG_SUCCESS)
14555     {
14556         last_frame = frame_set->first_frame +
14557                      frame_set->n_frames - 1;
14558 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14559                   last_frame); */
14560         /* If the wanted frame would be in the frame set after the last
14561          * frame set create a new frame set. */
14562         if(stat == TNG_FAILURE &&
14563            (last_frame < frame_nr &&
14564             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14565         {
14566             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14567             {
14568                 last_frame = frame_nr - 1;
14569             }
14570             tng_frame_set_new(tng_data,
14571                               last_frame+1,
14572                               tng_data->frame_set_n_frames);
14573
14574             file_pos = ftell(tng_data->output_file);
14575             fseek(tng_data->output_file, 0, SEEK_END);
14576             output_file_len = ftell(tng_data->output_file);
14577             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14578
14579             /* Read mapping blocks from the last frame set */
14580             tng_block_init(&block);
14581
14582             stat = tng_block_header_read(tng_data, block);
14583             while(file_pos < output_file_len &&
14584                   stat != TNG_CRITICAL &&
14585                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14586                   block->id != -1)
14587             {
14588                 if(block->id == TNG_PARTICLE_MAPPING)
14589                 {
14590                     tng_trajectory_mapping_block_read(tng_data, block,
14591                                                       hash_mode);
14592                 }
14593                 else
14594                 {
14595                     fseek(tng_data->output_file, (long)block->block_contents_size,
14596                         SEEK_CUR);
14597                 }
14598                 file_pos = ftell(tng_data->output_file);
14599                 if(file_pos < output_file_len)
14600                 {
14601                     stat = tng_block_header_read(tng_data, block);
14602                 }
14603             }
14604
14605             tng_block_destroy(&block);
14606             /* Write the frame set to disk */
14607             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14608             {
14609                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14610                 exit(1);
14611             }
14612         }
14613         else
14614         {
14615             tng_data->input_file = temp;
14616             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14617             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14618             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14619             return(stat);
14620         }
14621     }
14622
14623
14624     tng_block_init(&block);
14625
14626     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14627
14628     fseek(tng_data->output_file, 0, SEEK_END);
14629     output_file_len = ftell(tng_data->output_file);
14630     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14631
14632     /* Read past the frame set block first */
14633     stat = tng_block_header_read(tng_data, block);
14634     if(stat == TNG_CRITICAL)
14635     {
14636         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14637                file_pos, __FILE__, __LINE__);
14638         tng_block_destroy(&block);
14639         tng_data->input_file = temp;
14640
14641         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14642         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14643         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14644         return(stat);
14645     }
14646     fseek(tng_data->output_file, (long)block->block_contents_size,
14647             SEEK_CUR);
14648
14649     if(tng_data->var_num_atoms_flag)
14650     {
14651         tot_n_particles = frame_set->n_particles;
14652     }
14653     else
14654     {
14655         tot_n_particles = tng_data->n_particles;
14656     }
14657
14658     if(val_n_particles < tot_n_particles)
14659     {
14660         mapping_block_end_pos = -1;
14661         /* Read all mapping blocks to find the right place to put the data */
14662         stat = tng_block_header_read(tng_data, block);
14663         while(file_pos < output_file_len &&
14664                 stat != TNG_CRITICAL &&
14665                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14666                 block->id != -1)
14667         {
14668             if(block->id == TNG_PARTICLE_MAPPING)
14669             {
14670                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14671             }
14672             else
14673             {
14674                 fseek(tng_data->output_file, (long)block->block_contents_size,
14675                       SEEK_CUR);
14676             }
14677             file_pos = ftell(tng_data->output_file);
14678             if(block->id == TNG_PARTICLE_MAPPING)
14679             {
14680                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14681                 if(val_first_particle >= mapping->num_first_particle &&
14682                    val_first_particle < mapping->num_first_particle +
14683                    mapping->n_particles &&
14684                    val_first_particle + val_n_particles <=
14685                    mapping->num_first_particle + mapping->n_particles)
14686                 {
14687                     mapping_block_end_pos = file_pos;
14688                 }
14689             }
14690             if(file_pos < output_file_len)
14691             {
14692                 stat = tng_block_header_read(tng_data, block);
14693             }
14694         }
14695         if(stat == TNG_CRITICAL)
14696         {
14697             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14698                    file_pos, __FILE__, __LINE__);
14699             tng_block_destroy(&block);
14700             tng_data->input_file = temp;
14701
14702             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14703             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14704             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14705             return(stat);
14706         }
14707         if(mapping_block_end_pos < 0)
14708         {
14709             tng_block_destroy(&block);
14710             tng_data->input_file = temp;
14711
14712             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14713             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14714             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14715             return(TNG_FAILURE);
14716         }
14717         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
14718     }
14719
14720     /* Read all block headers until next frame set block or
14721      * until the wanted block id is found */
14722     stat = tng_block_header_read(tng_data, block);
14723     while(file_pos < output_file_len &&
14724             stat != TNG_CRITICAL &&
14725             block->id != block_id &&
14726             block->id != TNG_PARTICLE_MAPPING &&
14727             block->id != TNG_TRAJECTORY_FRAME_SET &&
14728             block->id != -1)
14729     {
14730         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14731         file_pos = ftell(tng_data->output_file);
14732         if(file_pos < output_file_len)
14733         {
14734             stat = tng_block_header_read(tng_data, block);
14735         }
14736     }
14737     if(stat == TNG_CRITICAL)
14738     {
14739         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14740                 file_pos, __FILE__, __LINE__);
14741         tng_block_destroy(&block);
14742         tng_data->input_file = temp;
14743
14744         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14745         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14746         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14747         return(stat);
14748     }
14749
14750     contents_size = block->block_contents_size;
14751     header_size = block->header_contents_size;
14752
14753     header_pos = ftell(tng_data->output_file) - header_size;
14754     frame_set = &tng_data->current_trajectory_frame_set;
14755
14756     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14757     {
14758         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14759         tng_block_destroy(&block);
14760         return(TNG_CRITICAL);
14761     }
14762
14763     data.datatype = datatype;
14764
14765     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14766     {
14767         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14768         tng_block_destroy(&block);
14769         return(TNG_CRITICAL);
14770     }
14771
14772     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14773        !(dependency & TNG_PARTICLE_DEPENDENT))
14774     {
14775         tng_block_destroy(&block);
14776         tng_data->input_file = temp;
14777
14778         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14779         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14780         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14781         return(TNG_FAILURE);
14782     }
14783
14784     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14785     {
14786         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14787         tng_block_destroy(&block);
14788         return(TNG_CRITICAL);
14789     }
14790
14791     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14792              tng_data->input_file) == 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     if(tng_data->output_endianness_swap_func_64)
14799     {
14800         if(tng_data->output_endianness_swap_func_64(tng_data,
14801             &data.n_values_per_frame)
14802             != TNG_SUCCESS)
14803         {
14804             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14805                     __FILE__, __LINE__);
14806         }
14807     }
14808
14809     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14810              tng_data->input_file) == 0)
14811     {
14812         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14813         tng_block_destroy(&block);
14814         return(TNG_CRITICAL);
14815     }
14816     if(tng_data->output_endianness_swap_func_64)
14817     {
14818         if(tng_data->output_endianness_swap_func_64(tng_data,
14819             &data.codec_id)
14820             != TNG_SUCCESS)
14821         {
14822             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14823                     __FILE__, __LINE__);
14824         }
14825     }
14826
14827     if(data.codec_id != TNG_UNCOMPRESSED)
14828     {
14829         if(fread(&data.compression_multiplier,
14830                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14831             == 0)
14832         {
14833             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14834             tng_block_destroy(&block);
14835             return(TNG_CRITICAL);
14836         }
14837
14838         if(tng_data->output_endianness_swap_func_64)
14839         {
14840             if(tng_data->output_endianness_swap_func_64(tng_data,
14841                (int64_t *)&data.compression_multiplier)
14842                 != TNG_SUCCESS)
14843             {
14844                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14845                         __FILE__, __LINE__);
14846             }
14847         }
14848     }
14849     else
14850     {
14851         data.compression_multiplier = 1;
14852     }
14853
14854     if(sparse_data)
14855     {
14856         if(fread(&data.first_frame_with_data,
14857                  sizeof(data.first_frame_with_data),
14858                  1, tng_data->input_file) == 0)
14859         {
14860             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14861             tng_block_destroy(&block);
14862             return(TNG_CRITICAL);
14863         }
14864         if(tng_data->output_endianness_swap_func_64)
14865         {
14866             if(tng_data->output_endianness_swap_func_64(tng_data,
14867                 &data.first_frame_with_data)
14868                 != TNG_SUCCESS)
14869             {
14870                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14871                         __FILE__, __LINE__);
14872             }
14873         }
14874
14875         if(fread(&data.stride_length, sizeof(data.stride_length),
14876                  1, tng_data->input_file) == 0)
14877         {
14878             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14879             tng_block_destroy(&block);
14880             return(TNG_CRITICAL);
14881         }
14882         if(tng_data->output_endianness_swap_func_64)
14883         {
14884             if(tng_data->output_endianness_swap_func_64(tng_data,
14885                 &data.stride_length)
14886                 != TNG_SUCCESS)
14887             {
14888                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14889                         __FILE__, __LINE__);
14890             }
14891         }
14892     }
14893     else
14894     {
14895         data.first_frame_with_data = 0;
14896         data.stride_length = 1;
14897     }
14898     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14899
14900     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14901              tng_data->input_file) == 0)
14902     {
14903         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14904         tng_block_destroy(&block);
14905         return(TNG_CRITICAL);
14906     }
14907     if(tng_data->output_endianness_swap_func_64)
14908     {
14909         if(tng_data->output_endianness_swap_func_64(tng_data,
14910             &num_first_particle)
14911             != TNG_SUCCESS)
14912         {
14913             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14914                     __FILE__, __LINE__);
14915         }
14916     }
14917
14918     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14919              tng_data->input_file) == 0)
14920     {
14921         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14922         tng_block_destroy(&block);
14923         return(TNG_CRITICAL);
14924     }
14925     if(tng_data->output_endianness_swap_func_64)
14926     {
14927         if(tng_data->output_endianness_swap_func_64(tng_data,
14928             &block_n_particles)
14929             != TNG_SUCCESS)
14930         {
14931             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14932                     __FILE__, __LINE__);
14933         }
14934     }
14935
14936
14937     tng_data->input_file = temp;
14938
14939     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14940     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14941     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14942
14943
14944     switch(data.datatype)
14945     {
14946         case(TNG_INT_DATA):
14947             size = sizeof(int64_t);
14948             break;
14949         case(TNG_FLOAT_DATA):
14950             size = sizeof(float);
14951             break;
14952         case(TNG_DOUBLE_DATA):
14953             size = sizeof(double);
14954             break;
14955         default:
14956             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14957                    __LINE__);
14958             tng_block_destroy(&block);
14959             return(TNG_FAILURE);
14960     }
14961
14962     n_values_per_frame = data.n_values_per_frame;
14963
14964     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14965                                data.first_frame_with_data)) /
14966                 data.stride_length;
14967     file_pos *= block_n_particles * size * n_values_per_frame;
14968
14969     if(file_pos > contents_size)
14970     {
14971         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14972                __LINE__);
14973         tng_block_destroy(&block);
14974         return(TNG_FAILURE);
14975     }
14976
14977     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14978
14979     /* If the endianness is not big endian the data needs to be swapped */
14980     if((data.datatype == TNG_INT_DATA ||
14981         data.datatype == TNG_DOUBLE_DATA) &&
14982        tng_data->output_endianness_swap_func_64)
14983     {
14984         copy = malloc(val_n_particles * n_values_per_frame * size);
14985         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14986         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14987         {
14988             if(tng_data->output_endianness_swap_func_64(tng_data,
14989                 (int64_t *) copy+i)
14990                 != TNG_SUCCESS)
14991             {
14992                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14993                         __FILE__, __LINE__);
14994             }
14995         }
14996         fwrite(copy, val_n_particles * n_values_per_frame, size,
14997                tng_data->output_file);
14998         free(copy);
14999     }
15000     else if(data.datatype == TNG_FLOAT_DATA &&
15001        tng_data->output_endianness_swap_func_32)
15002     {
15003         copy = malloc(val_n_particles * n_values_per_frame * size);
15004         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
15005         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
15006         {
15007             if(tng_data->output_endianness_swap_func_32(tng_data,
15008                 (int32_t *) copy+i)
15009                 != TNG_SUCCESS)
15010             {
15011                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15012                         __FILE__, __LINE__);
15013             }
15014         }
15015         fwrite(copy, val_n_particles * n_values_per_frame, size,
15016                tng_data->output_file);
15017         free(copy);
15018     }
15019
15020     else
15021     {
15022         fwrite(values, val_n_particles * n_values_per_frame, size,
15023                tng_data->output_file);
15024     }
15025     fflush(tng_data->output_file);
15026
15027     /* Update the number of written frames in the frame set. */
15028     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
15029     {
15030         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
15031     }
15032
15033     /* If the last frame has been written update the hash */
15034     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
15035        data.first_frame_with_data) >=
15036        frame_set->n_frames)
15037     {
15038         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
15039                             header_size);
15040     }
15041
15042     tng_block_destroy(&block);
15043     return(TNG_SUCCESS);
15044 }
15045
15046 static tng_function_status tng_data_values_alloc
15047                 (const tng_trajectory_t tng_data,
15048                  union data_values ***values,
15049                  const int64_t n_frames,
15050                  const int64_t n_values_per_frame,
15051                  const char type)
15052 {
15053     int64_t i;
15054     tng_function_status stat;
15055
15056     if(n_frames <= 0 || n_values_per_frame <= 0)
15057     {
15058         return(TNG_FAILURE);
15059     }
15060
15061     if(*values)
15062     {
15063         stat = tng_data_values_free(tng_data, *values, n_frames,
15064                                     n_values_per_frame,
15065                                     type);
15066         if(stat != TNG_SUCCESS)
15067         {
15068             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15069                    __FILE__, __LINE__);
15070             return(stat);
15071         }
15072     }
15073     *values = malloc(sizeof(union data_values *) * n_frames);
15074     if(!*values)
15075     {
15076         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15077                sizeof(union data_values **) * n_frames,
15078                __FILE__, __LINE__);
15079         return(TNG_CRITICAL);
15080
15081     }
15082
15083     for(i = 0; i < n_frames; i++)
15084     {
15085         (*values)[i] = malloc(sizeof(union data_values) *
15086                            n_values_per_frame);
15087         if(!(*values)[i])
15088         {
15089             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15090                    sizeof(union data_values) * n_values_per_frame,
15091                    __FILE__, __LINE__);
15092             free(values);
15093             values = 0;
15094             return(TNG_CRITICAL);
15095         }
15096     }
15097     return(TNG_SUCCESS);
15098 }
15099
15100 /* FIXME: This needs ***values */
15101 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15102                 (const tng_trajectory_t tng_data,
15103                  union data_values **values,
15104                  const int64_t n_frames,
15105                  const int64_t n_values_per_frame,
15106                  const char type)
15107 {
15108     int64_t i, j;
15109     (void)tng_data;
15110
15111     if(values)
15112     {
15113         for(i = 0; i < n_frames; i++)
15114         {
15115             if(values[i])
15116             {
15117                 if(type == TNG_CHAR_DATA)
15118                 {
15119                     for(j = 0; j < n_values_per_frame; j++)
15120                     {
15121                         if(values[i][j].c)
15122                         {
15123                             free(values[i][j].c);
15124                             values[i][j].c = 0;
15125                         }
15126                     }
15127                 }
15128                 free(values[i]);
15129                 values[i] = 0;
15130             }
15131         }
15132         free(values);
15133         values = 0;
15134     }
15135
15136     return(TNG_SUCCESS);
15137 }
15138
15139 static tng_function_status tng_particle_data_values_alloc
15140                 (const tng_trajectory_t tng_data,
15141                  union data_values ****values,
15142                  const int64_t n_frames,
15143                  const int64_t n_particles,
15144                  const int64_t n_values_per_frame,
15145                  const char type)
15146 {
15147     int64_t i, j;
15148     tng_function_status stat;
15149
15150     if(n_particles == 0 || n_values_per_frame == 0)
15151     {
15152         return(TNG_FAILURE);
15153     }
15154
15155     if(*values)
15156     {
15157         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15158                                              n_particles, n_values_per_frame,
15159                                              type);
15160         if(stat != TNG_SUCCESS)
15161         {
15162             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15163                    __FILE__, __LINE__);
15164             return(stat);
15165         }
15166     }
15167     *values = malloc(sizeof(union data_values **) * n_frames);
15168     if(!*values)
15169     {
15170         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15171                sizeof(union data_values **) * n_frames,
15172                __FILE__, __LINE__);
15173         return(TNG_CRITICAL);
15174
15175     }
15176
15177     for(i = 0; i < n_frames; i++)
15178     {
15179         (*values)[i] = malloc(sizeof(union data_values *) *
15180                            n_particles);
15181         if(!(*values)[i])
15182         {
15183             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15184                    sizeof(union data_values *) * n_particles,
15185                    __FILE__, __LINE__);
15186             free(*values);
15187             *values = 0;
15188             return(TNG_CRITICAL);
15189         }
15190         for(j = 0; j < n_particles; j++)
15191         {
15192             (*values)[i][j] = malloc(sizeof(union data_values) *
15193                                   n_values_per_frame);
15194             if(!(*values)[i][j])
15195             {
15196                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15197                     sizeof(union data_values *) * n_particles,
15198                     __FILE__, __LINE__);
15199                 tng_particle_data_values_free(tng_data, *values, n_frames,
15200                                               n_particles, n_values_per_frame,
15201                                               type);
15202                 *values = 0;
15203                 return(TNG_CRITICAL);
15204             }
15205         }
15206     }
15207     return(TNG_SUCCESS);
15208 }
15209
15210 /* FIXME: This needs ****values */
15211 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15212                 (const tng_trajectory_t tng_data,
15213                  union data_values ***values,
15214                  const int64_t n_frames,
15215                  const int64_t n_particles,
15216                  const int64_t n_values_per_frame,
15217                  const char type)
15218 {
15219     int64_t i, j, k;
15220     (void)tng_data;
15221
15222     if(values)
15223     {
15224         for(i = 0; i < n_frames; i++)
15225         {
15226             if(values[i])
15227             {
15228                 for(j = 0; j < n_particles; j++)
15229                 {
15230                     if(type == TNG_CHAR_DATA)
15231                     {
15232                         for(k = 0; k < n_values_per_frame; k++)
15233                         {
15234                             if(values[i][j][k].c)
15235                             {
15236                                 free(values[i][j][k].c);
15237                                 values[i][j][k].c = 0;
15238                             }
15239                         }
15240                     }
15241                     free(values[i][j]);
15242                     values[i][j] = 0;
15243                 }
15244                 free(values[i]);
15245                 values[i] = 0;
15246             }
15247         }
15248         free(values);
15249         values = 0;
15250     }
15251
15252     return(TNG_SUCCESS);
15253 }
15254
15255
15256 tng_function_status DECLSPECDLLEXPORT tng_data_get
15257                 (tng_trajectory_t tng_data,
15258                  const int64_t block_id,
15259                  union data_values ***values,
15260                  int64_t *n_frames,
15261                  int64_t *n_values_per_frame,
15262                  char *type)
15263 {
15264     int64_t i, j, file_pos, block_index;
15265     int size;
15266     size_t len;
15267     tng_non_particle_data_t data;
15268     tng_trajectory_frame_set_t frame_set;
15269     tng_gen_block_t block;
15270     tng_function_status stat;
15271
15272     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15273     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15274     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15275     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15276
15277     frame_set = &tng_data->current_trajectory_frame_set;
15278
15279     block_index = -1;
15280     data = 0;
15281
15282     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15283     {
15284         tng_block_init(&block);
15285         file_pos = ftell(tng_data->input_file);
15286         /* Read all blocks until next frame set block */
15287         stat = tng_block_header_read(tng_data, block);
15288         while(file_pos < tng_data->input_file_len &&
15289                 stat != TNG_CRITICAL &&
15290                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15291                 block->id != -1)
15292         {
15293             /* Use hash by default */
15294             stat = tng_block_read_next(tng_data, block,
15295                                     TNG_USE_HASH);
15296             if(stat != TNG_CRITICAL)
15297             {
15298                 file_pos = ftell(tng_data->input_file);
15299                 if(file_pos < tng_data->input_file_len)
15300                 {
15301                     stat = tng_block_header_read(tng_data, block);
15302                 }
15303             }
15304         }
15305         tng_block_destroy(&block);
15306         if(stat == TNG_CRITICAL)
15307         {
15308             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15309                     file_pos, __FILE__, __LINE__);
15310             return(stat);
15311         }
15312
15313         for(i = 0; i < frame_set->n_data_blocks; i++)
15314         {
15315             data = &frame_set->tr_data[i];
15316             if(data->block_id == block_id)
15317             {
15318                 block_index = i;
15319                 break;
15320             }
15321         }
15322         if(block_index < 0)
15323         {
15324             return(TNG_FAILURE);
15325         }
15326     }
15327
15328     *n_frames = tng_max_i64(1, data->n_frames);
15329     *n_values_per_frame = data->n_values_per_frame;
15330     *type = data->datatype;
15331
15332     if(*values == 0)
15333     {
15334         if(tng_data_values_alloc(tng_data, values, *n_frames,
15335                                  *n_values_per_frame,
15336                                  *type)
15337         != TNG_SUCCESS)
15338         {
15339             return(TNG_CRITICAL);
15340         }
15341     }
15342
15343     switch(*type)
15344     {
15345     case TNG_CHAR_DATA:
15346         for(i = 0; i < *n_frames; i++)
15347         {
15348             for(j = 0; j < *n_values_per_frame; j++)
15349             {
15350                 len = strlen(data->strings[i][j]) + 1;
15351                 (*values)[i][j].c = malloc(len);
15352                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15353             }
15354         }
15355         break;
15356     case TNG_INT_DATA:
15357         size = sizeof(int);
15358         for(i = 0; i < *n_frames; i++)
15359         {
15360             for(j = 0; j < *n_values_per_frame; j++)
15361             {
15362                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15363                                              (i*(*n_values_per_frame) + j));
15364             }
15365         }
15366         break;
15367     case TNG_FLOAT_DATA:
15368         size = sizeof(float);
15369         for(i = 0; i < *n_frames; i++)
15370         {
15371             for(j = 0; j < *n_values_per_frame; j++)
15372             {
15373                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15374                                                (i*(*n_values_per_frame) + j));
15375             }
15376         }
15377         break;
15378     case TNG_DOUBLE_DATA:
15379     default:
15380         size = sizeof(double);
15381         for(i = 0; i < *n_frames; i++)
15382         {
15383             for(j = 0; j < *n_values_per_frame; j++)
15384             {
15385                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15386                                                 (i*(*n_values_per_frame) + j));
15387             }
15388         }
15389     }
15390
15391     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15392
15393     return(TNG_SUCCESS);
15394 }
15395
15396 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15397                                         const int64_t block_id,
15398                                         void **values,
15399                                         int64_t *n_frames,
15400                                         int64_t *stride_length,
15401                                         int64_t *n_values_per_frame,
15402                                         char *type)
15403 {
15404     int64_t file_pos, data_size, n_frames_div, block_index;
15405     int i, size;
15406     tng_non_particle_data_t data;
15407     tng_trajectory_frame_set_t frame_set;
15408     tng_gen_block_t block;
15409     void *temp;
15410     tng_function_status stat;
15411
15412     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15413     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15414     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15415     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15416     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15417
15418     frame_set = &tng_data->current_trajectory_frame_set;
15419
15420     block_index = -1;
15421     data = 0;
15422
15423     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15424     {
15425         tng_block_init(&block);
15426         file_pos = ftell(tng_data->input_file);
15427         /* Read all blocks until next frame set block */
15428         stat = tng_block_header_read(tng_data, block);
15429         while(file_pos < tng_data->input_file_len &&
15430                 stat != TNG_CRITICAL &&
15431                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15432                 block->id != -1)
15433         {
15434             /* Use hash by default */
15435             stat = tng_block_read_next(tng_data, block,
15436                                     TNG_USE_HASH);
15437             if(stat != TNG_CRITICAL)
15438             {
15439                 file_pos = ftell(tng_data->input_file);
15440                 if(file_pos < tng_data->input_file_len)
15441                 {
15442                     stat = tng_block_header_read(tng_data, block);
15443                 }
15444             }
15445         }
15446         tng_block_destroy(&block);
15447         if(stat == TNG_CRITICAL)
15448         {
15449             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15450                     file_pos, __FILE__, __LINE__);
15451             return(stat);
15452         }
15453
15454         for(i = 0; i < frame_set->n_data_blocks; i++)
15455         {
15456             data = &frame_set->tr_data[i];
15457             if(data->block_id == block_id)
15458             {
15459                 block_index = i;
15460                 break;
15461             }
15462         }
15463         if(block_index < 0)
15464         {
15465             return(TNG_FAILURE);
15466         }
15467     }
15468
15469     *type = data->datatype;
15470
15471     switch(*type)
15472     {
15473     case TNG_CHAR_DATA:
15474         return(TNG_FAILURE);
15475     case TNG_INT_DATA:
15476         size = sizeof(int64_t);
15477         break;
15478     case TNG_FLOAT_DATA:
15479         size = sizeof(float);
15480         break;
15481     case TNG_DOUBLE_DATA:
15482     default:
15483         size = sizeof(double);
15484     }
15485
15486     *n_frames = data->n_frames;
15487     *n_values_per_frame = data->n_values_per_frame;
15488     *stride_length = data->stride_length;
15489     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15490                    *n_frames / *stride_length;
15491
15492     data_size = n_frames_div * size *
15493                 *n_values_per_frame;
15494
15495     temp = realloc(*values, data_size);
15496     if(!temp)
15497     {
15498         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15499                data_size, __FILE__, __LINE__);
15500         free(*values);
15501         *values = 0;
15502         return(TNG_CRITICAL);
15503     }
15504
15505     *values = temp;
15506
15507     memcpy(*values, data->values, data_size);
15508
15509     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15510
15511     return(TNG_SUCCESS);
15512 }
15513
15514 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15515                 (tng_trajectory_t tng_data,
15516                  const int64_t block_id,
15517                  const int64_t start_frame_nr,
15518                  const int64_t end_frame_nr,
15519                  const char hash_mode,
15520                  union data_values ***values,
15521                  int64_t *n_values_per_frame,
15522                  char *type)
15523 {
15524     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15525     int64_t block_index;
15526     int size;
15527     size_t len;
15528     tng_non_particle_data_t data;
15529     tng_trajectory_frame_set_t frame_set;
15530     tng_gen_block_t block;
15531     tng_function_status stat;
15532
15533     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15534     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15535     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15536     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15537
15538     block_index = -1;
15539
15540     frame_set = &tng_data->current_trajectory_frame_set;
15541     first_frame = frame_set->first_frame;
15542
15543     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15544     if(stat != TNG_SUCCESS)
15545     {
15546         return(stat);
15547     }
15548
15549
15550     /* Do not re-read the frame set. */
15551     if(first_frame != frame_set->first_frame ||
15552        frame_set->n_data_blocks <= 0)
15553     {
15554         tng_block_init(&block);
15555         file_pos = ftell(tng_data->input_file);
15556         /* Read all blocks until next frame set block */
15557         stat = tng_block_header_read(tng_data, block);
15558         while(file_pos < tng_data->input_file_len &&
15559             stat != TNG_CRITICAL &&
15560             block->id != TNG_TRAJECTORY_FRAME_SET &&
15561             block->id != -1)
15562         {
15563             stat = tng_block_read_next(tng_data, block,
15564                                     hash_mode);
15565             if(stat != TNG_CRITICAL)
15566             {
15567                 file_pos = ftell(tng_data->input_file);
15568                 if(file_pos < tng_data->input_file_len)
15569                 {
15570                     stat = tng_block_header_read(tng_data, block);
15571                 }
15572             }
15573         }
15574         tng_block_destroy(&block);
15575         if(stat == TNG_CRITICAL)
15576         {
15577             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15578                     file_pos, __FILE__, __LINE__);
15579             return(stat);
15580         }
15581     }
15582
15583
15584     /* See if there is a data block of this ID.
15585      * Start checking the last read frame set */
15586     for(i = 0; i < frame_set->n_data_blocks; i++)
15587     {
15588         data = &frame_set->tr_data[i];
15589         if(data->block_id == block_id)
15590         {
15591             block_index = i;
15592             break;
15593         }
15594     }
15595
15596     if(block_index < 0)
15597     {
15598         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15599                 block_id, __FILE__, __LINE__);
15600         return(TNG_FAILURE);
15601     }
15602
15603     n_frames = end_frame_nr - start_frame_nr + 1;
15604     *n_values_per_frame = data->n_values_per_frame;
15605     *type = data->datatype;
15606
15607     if(*values == 0)
15608     {
15609         if(tng_data_values_alloc(tng_data, values, n_frames,
15610                                  *n_values_per_frame,
15611                                  *type) != TNG_SUCCESS)
15612         {
15613             return(TNG_CRITICAL);
15614         }
15615     }
15616
15617     current_frame_pos = start_frame_nr - frame_set->first_frame;
15618     /* It's not very elegant to reuse so much of the code in the different case
15619      * statements, but it's unnecessarily slow to have the switch-case block
15620      * inside the for loops. */
15621     switch(*type)
15622     {
15623     case TNG_CHAR_DATA:
15624         for(i=0; i<n_frames; i++)
15625         {
15626             if(current_frame_pos == frame_set->n_frames)
15627             {
15628                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15629                 if(stat != TNG_SUCCESS)
15630                 {
15631                     return(stat);
15632                 }
15633                 current_frame_pos = 0;
15634             }
15635             for(j = 0; j < *n_values_per_frame; j++)
15636             {
15637                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15638                 (*values)[i][j].c = malloc(len);
15639                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15640             }
15641             current_frame_pos++;
15642         }
15643         break;
15644     case TNG_INT_DATA:
15645         size = sizeof(int);
15646         for(i=0; i<n_frames; i++)
15647         {
15648             if(current_frame_pos == frame_set->n_frames)
15649             {
15650                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15651                 if(stat != TNG_SUCCESS)
15652                 {
15653                     return(stat);
15654                 }
15655                 current_frame_pos = 0;
15656             }
15657             for(j = 0; j < *n_values_per_frame; j++)
15658             {
15659                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15660                                             (current_frame_pos *
15661                                              (*n_values_per_frame) + j));
15662             }
15663             current_frame_pos++;
15664         }
15665         break;
15666     case TNG_FLOAT_DATA:
15667         size = sizeof(float);
15668         for(i=0; i<n_frames; i++)
15669         {
15670             if(current_frame_pos == frame_set->n_frames)
15671             {
15672                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15673                 if(stat != TNG_SUCCESS)
15674                 {
15675                     return(stat);
15676                 }
15677                 current_frame_pos = 0;
15678             }
15679             for(j = 0; j < *n_values_per_frame; j++)
15680             {
15681                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15682                                                (current_frame_pos *
15683                                                 (*n_values_per_frame) + j));
15684             }
15685             current_frame_pos++;
15686         }
15687         break;
15688     case TNG_DOUBLE_DATA:
15689     default:
15690         size = sizeof(double);
15691         for(i=0; i<n_frames; i++)
15692         {
15693             if(current_frame_pos == frame_set->n_frames)
15694             {
15695                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15696                 if(stat != TNG_SUCCESS)
15697                 {
15698                     return(stat);
15699                 }
15700                 current_frame_pos = 0;
15701             }
15702             for(j = 0; j < *n_values_per_frame; j++)
15703             {
15704                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15705                                                 (current_frame_pos *
15706                                                  (*n_values_per_frame) + j));
15707             }
15708             current_frame_pos++;
15709         }
15710     }
15711
15712     data->last_retrieved_frame = end_frame_nr;
15713
15714     return(TNG_SUCCESS);
15715 }
15716
15717 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15718                 (tng_trajectory_t tng_data,
15719                  const int64_t block_id,
15720                  const int64_t start_frame_nr,
15721                  const int64_t end_frame_nr,
15722                  const char hash_mode,
15723                  void **values,
15724                  int64_t *stride_length,
15725                  int64_t *n_values_per_frame,
15726                  char *type)
15727 {
15728     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15729     int64_t file_pos, current_frame_pos, data_size, frame_size;
15730     int64_t last_frame_pos;
15731     int size;
15732     tng_trajectory_frame_set_t frame_set;
15733     tng_non_particle_data_t np_data;
15734     tng_gen_block_t block;
15735     void *current_values = 0, *temp;
15736     tng_function_status stat;
15737
15738     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15739     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15740     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15741     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15742     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15743
15744     frame_set = &tng_data->current_trajectory_frame_set;
15745     first_frame = frame_set->first_frame;
15746
15747     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15748     if(stat != TNG_SUCCESS)
15749     {
15750         return(stat);
15751     }
15752
15753     /* Do not re-read the frame set and only need the requested block. */
15754     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15755     stat = tng_data_find(tng_data, block_id, &np_data);
15756     if(first_frame != frame_set->first_frame ||
15757        stat != TNG_SUCCESS)
15758     {
15759         tng_block_init(&block);
15760         if(stat != TNG_SUCCESS)
15761         {
15762             fseek(tng_data->input_file,
15763                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15764                   SEEK_SET);
15765             stat = tng_block_header_read(tng_data, block);
15766             if(stat != TNG_SUCCESS)
15767             {
15768                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15769                         __FILE__, __LINE__);
15770                 return(stat);
15771             }
15772
15773             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15774         }
15775         file_pos = ftell(tng_data->input_file);
15776         /* Read until next frame set block */
15777         stat = tng_block_header_read(tng_data, block);
15778         while(file_pos < tng_data->input_file_len &&
15779             stat != TNG_CRITICAL &&
15780             block->id != TNG_TRAJECTORY_FRAME_SET &&
15781             block->id != -1)
15782         {
15783             if(block->id == block_id)
15784             {
15785                 stat = tng_block_read_next(tng_data, block,
15786                                         hash_mode);
15787                 if(stat != TNG_CRITICAL)
15788                 {
15789                     file_pos = ftell(tng_data->input_file);
15790                     if(file_pos < tng_data->input_file_len)
15791                     {
15792                         stat = tng_block_header_read(tng_data, block);
15793                     }
15794                 }
15795             }
15796             else
15797             {
15798                 file_pos += block->block_contents_size + block->header_contents_size;
15799                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15800                 if(file_pos < tng_data->input_file_len)
15801                 {
15802                     stat = tng_block_header_read(tng_data, block);
15803                 }
15804             }
15805         }
15806         tng_block_destroy(&block);
15807         if(stat == TNG_CRITICAL)
15808         {
15809             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15810                     file_pos, __FILE__, __LINE__);
15811             return(stat);
15812         }
15813     }
15814
15815     stat = tng_data_find(tng_data, block_id, &np_data);
15816     if(stat != TNG_SUCCESS)
15817     {
15818         return(stat);
15819     }
15820
15821     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15822                                &n_frames, stride_length,
15823                                n_values_per_frame, type);
15824
15825     if(stat != TNG_SUCCESS)
15826     {
15827         if(current_values)
15828         {
15829             free(current_values);
15830         }
15831         return(stat);
15832     }
15833
15834     if(n_frames == 1 && n_frames < frame_set->n_frames)
15835     {
15836         tot_n_frames = 1;
15837     }
15838     else
15839     {
15840         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15841     }
15842
15843     switch(*type)
15844     {
15845     case TNG_CHAR_DATA:
15846         return(TNG_FAILURE);
15847     case TNG_INT_DATA:
15848         size = sizeof(int64_t);
15849         break;
15850     case TNG_FLOAT_DATA:
15851         size = sizeof(float);
15852         break;
15853     case TNG_DOUBLE_DATA:
15854     default:
15855         size = sizeof(double);
15856     }
15857
15858     n_frames_div = (tot_n_frames % *stride_length) ?
15859                  tot_n_frames / *stride_length + 1:
15860                  tot_n_frames / *stride_length;
15861     data_size = n_frames_div * size * (*n_values_per_frame);
15862
15863 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15864               size, n_frames_div, data_size);
15865 */
15866     temp = realloc(*values, data_size);
15867     if(!temp)
15868     {
15869         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15870                data_size, __FILE__, __LINE__);
15871         free(*values);
15872         *values = 0;
15873         return(TNG_CRITICAL);
15874     }
15875
15876     *values = temp;
15877
15878     if( n_frames == 1 && n_frames < frame_set->n_frames)
15879     {
15880         memcpy(*values, current_values, size * (*n_values_per_frame));
15881     }
15882     else
15883     {
15884         current_frame_pos = start_frame_nr - frame_set->first_frame;
15885
15886         frame_size = size * (*n_values_per_frame);
15887
15888         last_frame_pos = tng_min_i64(n_frames,
15889                                      end_frame_nr - start_frame_nr);
15890
15891         n_frames_div = current_frame_pos / *stride_length;
15892         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15893                        last_frame_pos / *stride_length + 1:
15894                        last_frame_pos / *stride_length;
15895         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15896
15897         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15898                n_frames_div_2 * frame_size);
15899
15900         current_frame_pos += n_frames - current_frame_pos;
15901
15902         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15903         {
15904             stat = tng_frame_set_read_next(tng_data, hash_mode);
15905             if(stat != TNG_SUCCESS)
15906             {
15907                 if(current_values)
15908                 {
15909                     free(current_values);
15910                 }
15911                 free(*values);
15912                 *values = 0;
15913                 return(stat);
15914             }
15915
15916             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15917                                     &n_frames, stride_length,
15918                                     n_values_per_frame, type);
15919
15920             if(stat != TNG_SUCCESS)
15921             {
15922                 if(current_values)
15923                 {
15924                     free(current_values);
15925                 }
15926                 free(*values);
15927                 *values = 0;
15928                 return(stat);
15929             }
15930
15931             last_frame_pos = tng_min_i64(n_frames,
15932                                          end_frame_nr - current_frame_pos);
15933
15934             n_frames_div = current_frame_pos / *stride_length;
15935             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15936                            last_frame_pos / *stride_length + 1:
15937                            last_frame_pos / *stride_length;
15938             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15939
15940             memcpy(((char *)*values) + n_frames_div * frame_size,
15941                    current_values,
15942                    n_frames_div_2 * frame_size);
15943
15944             current_frame_pos += n_frames;
15945         }
15946     }
15947
15948     if(current_values)
15949     {
15950         free(current_values);
15951     }
15952
15953     np_data->last_retrieved_frame = end_frame_nr;
15954
15955     return(TNG_SUCCESS);
15956 }
15957
15958 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15959                 (tng_trajectory_t tng_data,
15960                  const int64_t block_id,
15961                  union data_values ****values,
15962                  int64_t *n_frames,
15963                  int64_t *n_particles,
15964                  int64_t *n_values_per_frame,
15965                  char *type)
15966 {
15967     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15968     int size;
15969     size_t len;
15970     tng_particle_data_t data;
15971     tng_trajectory_frame_set_t frame_set;
15972     tng_gen_block_t block;
15973     char block_type_flag;
15974     tng_function_status stat;
15975
15976     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15977     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15978     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15979     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15980     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15981
15982     frame_set = &tng_data->current_trajectory_frame_set;
15983
15984     block_index = -1;
15985     data = 0;
15986
15987     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15988     {
15989         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15990         {
15991             block_type_flag = TNG_TRAJECTORY_BLOCK;
15992         }
15993         else
15994         {
15995             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15996         }
15997
15998         tng_block_init(&block);
15999         file_pos = ftell(tng_data->input_file);
16000         /* Read all blocks until next frame set block */
16001         stat = tng_block_header_read(tng_data, block);
16002         while(file_pos < tng_data->input_file_len &&
16003                 stat != TNG_CRITICAL &&
16004                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16005                 block->id != -1)
16006         {
16007             /* Use hash by default */
16008             stat = tng_block_read_next(tng_data, block,
16009                                     TNG_USE_HASH);
16010             if(stat != TNG_CRITICAL)
16011             {
16012                 file_pos = ftell(tng_data->input_file);
16013                 if(file_pos < tng_data->input_file_len)
16014                 {
16015                     stat = tng_block_header_read(tng_data, block);
16016                 }
16017             }
16018         }
16019         tng_block_destroy(&block);
16020         if(stat == TNG_CRITICAL)
16021         {
16022             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16023                     file_pos, __FILE__, __LINE__);
16024             return(stat);
16025         }
16026
16027         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16028         {
16029             data = &frame_set->tr_particle_data[i];
16030             if(data->block_id == block_id)
16031             {
16032                 block_index = i;
16033                 block_type_flag = TNG_TRAJECTORY_BLOCK;
16034                 break;
16035             }
16036         }
16037         if(block_index < 0)
16038         {
16039             return(TNG_FAILURE);
16040         }
16041     }
16042     else
16043     {
16044         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16045         {
16046             block_type_flag = TNG_TRAJECTORY_BLOCK;
16047         }
16048         else
16049         {
16050             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16051         }
16052     }
16053
16054     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16055        tng_data->var_num_atoms_flag)
16056     {
16057         *n_particles = frame_set->n_particles;
16058     }
16059     else
16060     {
16061         *n_particles = tng_data->n_particles;
16062     }
16063
16064     *n_frames = tng_max_i64(1, data->n_frames);
16065     *n_values_per_frame = data->n_values_per_frame;
16066     *type = data->datatype;
16067
16068     if(*values == 0)
16069     {
16070         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
16071                                          *n_particles, *n_values_per_frame,
16072                                          *type)
16073             != TNG_SUCCESS)
16074         {
16075             return(TNG_CRITICAL);
16076         }
16077     }
16078
16079     /* It's not very elegant to reuse so much of the code in the different case
16080      * statements, but it's unnecessarily slow to have the switch-case block
16081      * inside the for loops. */
16082     switch(*type)
16083     {
16084     case TNG_CHAR_DATA:
16085         for(i = 0; i < *n_frames; i++)
16086         {
16087             for(j = 0; j < *n_particles; j++)
16088             {
16089                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16090                 for(k = 0; k < *n_values_per_frame; k++)
16091                 {
16092                     len = strlen(data->strings[i][j][k]) + 1;
16093                     (*values)[i][mapping][k].c = malloc(len);
16094                     strncpy((*values)[i][mapping][k].c,
16095                             data->strings[i][j][k], len);
16096                 }
16097             }
16098         }
16099         break;
16100     case TNG_INT_DATA:
16101         size = sizeof(int);
16102         i_step = (*n_particles) * (*n_values_per_frame);
16103         for(i = 0; i < *n_frames; i++)
16104         {
16105             for(j = 0; j < *n_particles; j++)
16106             {
16107                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16108                 for(k = 0; k < *n_values_per_frame; k++)
16109                 {
16110                     (*values)[i][mapping][k].i = *(int *)
16111                                                  ((char *)data->values + size *
16112                                                  (i * i_step + j *
16113                                                   (*n_values_per_frame) + k));
16114                 }
16115             }
16116         }
16117         break;
16118     case TNG_FLOAT_DATA:
16119         size = sizeof(float);
16120         i_step = (*n_particles) * (*n_values_per_frame);
16121         for(i = 0; i < *n_frames; i++)
16122         {
16123             for(j = 0; j < *n_particles; j++)
16124             {
16125                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16126                 for(k = 0; k < *n_values_per_frame; k++)
16127                 {
16128                     (*values)[i][mapping][k].f = *(float *)
16129                                                  ((char *)data->values + size *
16130                                                  (i * i_step + j *
16131                                                   (*n_values_per_frame) + k));
16132                 }
16133             }
16134         }
16135         break;
16136     case TNG_DOUBLE_DATA:
16137     default:
16138         size = sizeof(double);
16139         i_step = (*n_particles) * (*n_values_per_frame);
16140         for(i = 0; i < *n_frames; i++)
16141         {
16142             for(j = 0; j < *n_particles; j++)
16143             {
16144                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16145                 for(k = 0; k < *n_values_per_frame; k++)
16146                 {
16147                     (*values)[i][mapping][k].d = *(double *)
16148                                                  ((char *)data->values + size *
16149                                                  (i * i_step + j *
16150                                                   (*n_values_per_frame) + k));
16151                 }
16152             }
16153         }
16154     }
16155
16156     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16157
16158     return(TNG_SUCCESS);
16159 }
16160
16161 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16162                 (tng_trajectory_t tng_data,
16163                  const int64_t block_id,
16164                  void **values,
16165                  int64_t *n_frames,
16166                  int64_t *stride_length,
16167                  int64_t *n_particles,
16168                  int64_t *n_values_per_frame,
16169                  char *type)
16170 {
16171     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16172     int64_t block_index;
16173     int size;
16174     tng_particle_data_t data;
16175     tng_trajectory_frame_set_t frame_set;
16176     tng_gen_block_t block;
16177     void *temp;
16178     char block_type_flag;
16179     tng_function_status stat;
16180
16181     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16182     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16183     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16184     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16185     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16186
16187     frame_set = &tng_data->current_trajectory_frame_set;
16188
16189     block_index = -1;
16190     data = 0;
16191
16192     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16193     {
16194         tng_block_init(&block);
16195         file_pos = ftell(tng_data->input_file);
16196         /* Read all blocks until next frame set block */
16197         stat = tng_block_header_read(tng_data, block);
16198         while(file_pos < tng_data->input_file_len &&
16199                 stat != TNG_CRITICAL &&
16200                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16201                 block->id != -1)
16202         {
16203             /* Use hash by default */
16204             stat = tng_block_read_next(tng_data, block,
16205                                     TNG_USE_HASH);
16206             if(stat != TNG_CRITICAL)
16207             {
16208                 file_pos = ftell(tng_data->input_file);
16209                 if(file_pos < tng_data->input_file_len)
16210                 {
16211                     stat = tng_block_header_read(tng_data, block);
16212                 }
16213             }
16214         }
16215         tng_block_destroy(&block);
16216         if(stat == TNG_CRITICAL)
16217         {
16218             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16219                     file_pos, __FILE__, __LINE__);
16220             return(stat);
16221         }
16222
16223         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16224         {
16225             data = &frame_set->tr_particle_data[i];
16226             if(data->block_id == block_id)
16227             {
16228                 block_index = i;
16229                 break;
16230             }
16231         }
16232         if(block_index < 0)
16233         {
16234             return(TNG_FAILURE);
16235         }
16236     }
16237
16238     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16239     {
16240         block_type_flag = TNG_TRAJECTORY_BLOCK;
16241     }
16242     else
16243     {
16244         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16245     }
16246
16247    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16248       tng_data->var_num_atoms_flag)
16249     {
16250         *n_particles = frame_set->n_particles;
16251     }
16252     else
16253     {
16254         *n_particles = tng_data->n_particles;
16255     }
16256
16257     *type = data->datatype;
16258
16259     switch(*type)
16260     {
16261     case TNG_CHAR_DATA:
16262         return(TNG_FAILURE);
16263     case TNG_INT_DATA:
16264         size = sizeof(int64_t);
16265         break;
16266     case TNG_FLOAT_DATA:
16267         size = sizeof(float);
16268         break;
16269     case TNG_DOUBLE_DATA:
16270     default:
16271         size = sizeof(double);
16272     }
16273
16274     *n_frames = tng_max_i64(1, data->n_frames);
16275     *n_values_per_frame = data->n_values_per_frame;
16276     *stride_length = data->stride_length;
16277
16278     n_frames_div = (*n_frames % *stride_length) ?
16279                    *n_frames / *stride_length + 1:
16280                    *n_frames / *stride_length;
16281
16282     data_size = n_frames_div * size * (*n_particles) *
16283                 (*n_values_per_frame);
16284
16285     temp = realloc(*values, data_size);
16286     if(!temp)
16287     {
16288         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16289                data_size, __FILE__, __LINE__);
16290         free(*values);
16291         *values = 0;
16292         return(TNG_CRITICAL);
16293     }
16294
16295     *values = temp;
16296
16297     if(frame_set->n_mapping_blocks <= 0)
16298     {
16299         memcpy(*values, data->values, data_size);
16300     }
16301     else
16302     {
16303         i_step = (*n_particles) * (*n_values_per_frame);
16304         for(i = 0; i < *n_frames; i++)
16305         {
16306             for(j = 0; j < *n_particles; j++)
16307             {
16308                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16309                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16310                        (*n_values_per_frame)),
16311                        (char *)data->values + size *
16312                        (i * i_step + j * (*n_values_per_frame)),
16313                        size * (*n_values_per_frame));
16314             }
16315         }
16316     }
16317
16318     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16319
16320     return(TNG_SUCCESS);
16321 }
16322
16323 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16324                 (tng_trajectory_t tng_data,
16325                  const int64_t block_id,
16326                  const int64_t start_frame_nr,
16327                  const int64_t end_frame_nr,
16328                  const char hash_mode,
16329                  union data_values ****values,
16330                  int64_t *n_particles,
16331                  int64_t *n_values_per_frame,
16332                  char *type)
16333 {
16334     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16335     int64_t first_frame, block_index;
16336     int size;
16337     size_t len;
16338     tng_particle_data_t data;
16339     tng_trajectory_frame_set_t frame_set;
16340     tng_gen_block_t block;
16341     char block_type_flag;
16342     tng_function_status stat;
16343
16344     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16345     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16346     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16347     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16348     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16349
16350     block_index = -1;
16351
16352     frame_set = &tng_data->current_trajectory_frame_set;
16353     first_frame = frame_set->first_frame;
16354
16355     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16356     if(stat != TNG_SUCCESS)
16357     {
16358         return(stat);
16359     }
16360
16361     /* Do not re-read the frame set. */
16362     if(first_frame != frame_set->first_frame ||
16363        frame_set->n_particle_data_blocks <= 0)
16364     {
16365         tng_block_init(&block);
16366         file_pos = ftell(tng_data->input_file);
16367         /* Read all blocks until next frame set block */
16368         stat = tng_block_header_read(tng_data, block);
16369         while(file_pos < tng_data->input_file_len &&
16370                 stat != TNG_CRITICAL &&
16371                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16372                 block->id != -1)
16373         {
16374             stat = tng_block_read_next(tng_data, block,
16375                                     hash_mode);
16376             if(stat != TNG_CRITICAL)
16377             {
16378                 file_pos = ftell(tng_data->input_file);
16379                 if(file_pos < tng_data->input_file_len)
16380                 {
16381                     stat = tng_block_header_read(tng_data, block);
16382                 }
16383             }
16384         }
16385         tng_block_destroy(&block);
16386         if(stat == TNG_CRITICAL)
16387         {
16388             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16389                     file_pos, __FILE__, __LINE__);
16390             return(stat);
16391         }
16392     }
16393
16394     /* See if there is already a data block of this ID.
16395      * Start checking the last read frame set */
16396     for(i = frame_set->n_particle_data_blocks; i-- ;)
16397     {
16398         data = &frame_set->tr_particle_data[i];
16399         if(data->block_id == block_id)
16400         {
16401             block_index = i;
16402             block_type_flag = TNG_TRAJECTORY_BLOCK;
16403             break;
16404         }
16405     }
16406
16407     if(block_index < 0)
16408     {
16409         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16410                 block_id, __FILE__, __LINE__);
16411         return(TNG_FAILURE);
16412     }
16413
16414     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16415        tng_data->var_num_atoms_flag)
16416     {
16417         *n_particles = frame_set->n_particles;
16418     }
16419     else
16420     {
16421         *n_particles = tng_data->n_particles;
16422     }
16423
16424     n_frames = end_frame_nr - start_frame_nr + 1;
16425     *n_values_per_frame = data->n_values_per_frame;
16426     *type = data->datatype;
16427
16428     if(*values == 0)
16429     {
16430         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16431                                          *n_particles, *n_values_per_frame,
16432                                          *type)
16433             != TNG_SUCCESS)
16434         {
16435             return(TNG_CRITICAL);
16436         }
16437     }
16438
16439     current_frame_pos = start_frame_nr - frame_set->first_frame;
16440     /* It's not very elegant to reuse so much of the code in the different case
16441      * statements, but it's unnecessarily slow to have the switch-case block
16442      * inside the for loops. */
16443     switch(*type)
16444     {
16445     case TNG_CHAR_DATA:
16446         for(i=0; i<n_frames; i++)
16447         {
16448             if(current_frame_pos == frame_set->n_frames)
16449             {
16450                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16451                 if(stat != TNG_SUCCESS)
16452                 {
16453                     return(stat);
16454                 }
16455                 current_frame_pos = 0;
16456             }
16457             for(j = 0; j < *n_particles; j++)
16458             {
16459                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16460                 for(k = 0; k < *n_values_per_frame; k++)
16461                 {
16462                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16463                     (*values)[i][mapping][k].c = malloc(len);
16464                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16465                 }
16466             }
16467             current_frame_pos++;
16468         }
16469         break;
16470     case TNG_INT_DATA:
16471         size = sizeof(int);
16472         i_step = (*n_particles) * (*n_values_per_frame);
16473         for(i=0; i<n_frames; i++)
16474         {
16475             if(current_frame_pos == frame_set->n_frames)
16476             {
16477                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16478                 if(stat != TNG_SUCCESS)
16479                 {
16480                     return(stat);
16481                 }
16482                 current_frame_pos = 0;
16483             }
16484             for(j = 0; j < *n_particles; j++)
16485             {
16486                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16487                 for(k = 0; k < *n_values_per_frame; k++)
16488                 {
16489                     (*values)[i][mapping][k].i = *(int *)
16490                                                  ((char *)data->values + size *
16491                                                   (current_frame_pos *
16492                                                    i_step + j *
16493                                                    (*n_values_per_frame) + k));
16494                 }
16495             }
16496             current_frame_pos++;
16497         }
16498         break;
16499     case TNG_FLOAT_DATA:
16500         size = sizeof(float);
16501         i_step = (*n_particles) * (*n_values_per_frame);
16502         for(i=0; i<n_frames; i++)
16503         {
16504             if(current_frame_pos == frame_set->n_frames)
16505             {
16506                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16507                 if(stat != TNG_SUCCESS)
16508                 {
16509                     return(stat);
16510                 }
16511                 current_frame_pos = 0;
16512             }
16513             for(j=0; j<*n_particles; j++)
16514             {
16515                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16516                 for(k=0; k<*n_values_per_frame; k++)
16517                 {
16518                     (*values)[i][mapping][k].f = *(float *)
16519                                                  ((char *)data->values + size *
16520                                                   (current_frame_pos *
16521                                                    i_step + j *
16522                                                    (*n_values_per_frame) + k));
16523                 }
16524             }
16525             current_frame_pos++;
16526         }
16527         break;
16528     case TNG_DOUBLE_DATA:
16529     default:
16530         size = sizeof(double);
16531         i_step = (*n_particles) * (*n_values_per_frame);
16532         for(i=0; i<n_frames; i++)
16533         {
16534             if(current_frame_pos == frame_set->n_frames)
16535             {
16536                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16537                 if(stat != TNG_SUCCESS)
16538                 {
16539                     return(stat);
16540                 }
16541                 current_frame_pos = 0;
16542             }
16543             for(j=0; j<*n_particles; j++)
16544             {
16545                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16546                 for(k=0; k<*n_values_per_frame; k++)
16547                 {
16548                     (*values)[i][mapping][k].d = *(double *)
16549                                                  ((char *)data->values + size *
16550                                                   (current_frame_pos *
16551                                                    i_step + j *
16552                                                    (*n_values_per_frame) + k));
16553                 }
16554             }
16555             current_frame_pos++;
16556         }
16557     }
16558
16559     data->last_retrieved_frame = end_frame_nr;
16560
16561     return(TNG_SUCCESS);
16562 }
16563
16564 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16565                 (tng_trajectory_t tng_data,
16566                  const int64_t block_id,
16567                  const int64_t start_frame_nr,
16568                  const int64_t end_frame_nr,
16569                  const char hash_mode,
16570                  void **values,
16571                  int64_t *n_particles,
16572                  int64_t *stride_length,
16573                  int64_t *n_values_per_frame,
16574                  char *type)
16575 {
16576     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16577     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16578     int size;
16579     tng_trajectory_frame_set_t frame_set;
16580     tng_particle_data_t p_data;
16581     tng_gen_block_t block;
16582     void *current_values = 0, *temp;
16583     tng_function_status stat;
16584
16585     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16586     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16587     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16588     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16589     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16590     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16591
16592     frame_set = &tng_data->current_trajectory_frame_set;
16593     first_frame = frame_set->first_frame;
16594
16595     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16596     if(stat != TNG_SUCCESS)
16597     {
16598         return(stat);
16599     }
16600
16601     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16602     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16603     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16604     if(first_frame != frame_set->first_frame ||
16605        stat != TNG_SUCCESS)
16606     {
16607         tng_block_init(&block);
16608         if(stat != TNG_SUCCESS)
16609         {
16610             fseek(tng_data->input_file,
16611                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
16612                   SEEK_SET);
16613             stat = tng_block_header_read(tng_data, block);
16614             if(stat != TNG_SUCCESS)
16615             {
16616                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16617                         __FILE__, __LINE__);
16618                 return(stat);
16619             }
16620
16621             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16622         }
16623         file_pos = ftell(tng_data->input_file);
16624         /* Read until next frame set block */
16625         stat = tng_block_header_read(tng_data, block);
16626         while(file_pos < tng_data->input_file_len &&
16627             stat != TNG_CRITICAL &&
16628             block->id != TNG_TRAJECTORY_FRAME_SET &&
16629             block->id != -1)
16630         {
16631             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16632             {
16633                 stat = tng_block_read_next(tng_data, block,
16634                                         hash_mode);
16635                 if(stat != TNG_CRITICAL)
16636                 {
16637                     file_pos = ftell(tng_data->input_file);
16638                     if(file_pos < tng_data->input_file_len)
16639                     {
16640                         stat = tng_block_header_read(tng_data, block);
16641                     }
16642                 }
16643             }
16644             else
16645             {
16646                 file_pos += block->block_contents_size + block->header_contents_size;
16647                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16648                 if(file_pos < tng_data->input_file_len)
16649                 {
16650                     stat = tng_block_header_read(tng_data, block);
16651                 }
16652             }
16653         }
16654         tng_block_destroy(&block);
16655         if(stat == TNG_CRITICAL)
16656         {
16657             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16658                     file_pos, __FILE__, __LINE__);
16659             return(stat);
16660         }
16661     }
16662     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16663     if(stat != TNG_SUCCESS)
16664     {
16665         return(stat);
16666     }
16667
16668     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16669                                         &n_frames, stride_length, n_particles,
16670                                         n_values_per_frame, type);
16671
16672     if(stat != TNG_SUCCESS || *n_particles == 0)
16673     {
16674         if(current_values)
16675         {
16676             free(current_values);
16677         }
16678         return(stat);
16679     }
16680
16681     if(n_frames == 1 && n_frames < frame_set->n_frames)
16682     {
16683         tot_n_frames = 1;
16684     }
16685     else
16686     {
16687         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16688     }
16689
16690     switch(*type)
16691     {
16692     case TNG_CHAR_DATA:
16693         return(TNG_FAILURE);
16694     case TNG_INT_DATA:
16695         size = sizeof(int64_t);
16696         break;
16697     case TNG_FLOAT_DATA:
16698         size = sizeof(float);
16699         break;
16700     case TNG_DOUBLE_DATA:
16701     default:
16702         size = sizeof(double);
16703     }
16704
16705     n_frames_div = (tot_n_frames % *stride_length) ?
16706                  tot_n_frames / *stride_length + 1:
16707                  tot_n_frames / *stride_length;
16708
16709     data_size = n_frames_div * size * (*n_particles) *
16710                 (*n_values_per_frame);
16711
16712     temp = realloc(*values, data_size);
16713     if(!temp)
16714     {
16715         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16716                data_size, __FILE__, __LINE__);
16717         free(*values);
16718         *values = 0;
16719         return(TNG_CRITICAL);
16720     }
16721
16722     *values = temp;
16723
16724     if( n_frames == 1 && n_frames < frame_set->n_frames)
16725     {
16726         memcpy(*values, current_values, size * (*n_particles) *
16727                (*n_values_per_frame));
16728     }
16729     else
16730     {
16731         current_frame_pos = start_frame_nr - frame_set->first_frame;
16732
16733         frame_size = size * (*n_particles) * (*n_values_per_frame);
16734
16735         last_frame_pos = tng_min_i64(n_frames,
16736                                      end_frame_nr - start_frame_nr);
16737
16738         n_frames_div = current_frame_pos / *stride_length;
16739         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16740                        last_frame_pos / *stride_length + 1:
16741                        last_frame_pos / *stride_length;
16742         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16743
16744         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16745                n_frames_div_2 * frame_size);
16746
16747         current_frame_pos += n_frames - current_frame_pos;
16748
16749         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16750         {
16751             stat = tng_frame_set_read_next(tng_data, hash_mode);
16752             if(stat != TNG_SUCCESS)
16753             {
16754                 if(current_values)
16755                 {
16756                     free(current_values);
16757                 }
16758                 free(*values);
16759                 *values = 0;
16760                 return(stat);
16761             }
16762
16763             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16764                                                 &n_frames, stride_length, n_particles,
16765                                                 n_values_per_frame, type);
16766
16767             if(stat != TNG_SUCCESS)
16768             {
16769                 if(current_values)
16770                 {
16771                     free(current_values);
16772                 }
16773                 free(*values);
16774                 *values = 0;
16775                 return(stat);
16776             }
16777
16778             last_frame_pos = tng_min_i64(n_frames,
16779                                          end_frame_nr - current_frame_pos);
16780
16781             n_frames_div = current_frame_pos / *stride_length;
16782             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16783                            last_frame_pos / *stride_length + 1:
16784                            last_frame_pos / *stride_length;
16785             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16786
16787             memcpy(((char *)*values) + n_frames_div * frame_size,
16788                    current_values,
16789                    n_frames_div_2 * frame_size);
16790
16791             current_frame_pos += n_frames;
16792         }
16793     }
16794
16795     if(current_values)
16796     {
16797         free(current_values);
16798     }
16799
16800     p_data->last_retrieved_frame = end_frame_nr;
16801
16802     return(TNG_SUCCESS);
16803 }
16804
16805 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16806                 (const tng_trajectory_t tng_data,
16807                  const int64_t block_id,
16808                  int64_t frame,
16809                  int64_t *stride_length)
16810 {
16811     tng_function_status stat;
16812     tng_non_particle_data_t np_data;
16813     tng_particle_data_t p_data;
16814     long orig_file_pos, file_pos;
16815     int is_particle_data;
16816
16817     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16818     {
16819         frame = 0;
16820     }
16821
16822     if(frame >= 0)
16823     {
16824         stat = tng_frame_set_of_frame_find(tng_data, frame);
16825         if(stat != TNG_SUCCESS)
16826         {
16827             return(stat);
16828         }
16829     }
16830     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16831     stat = tng_data_find(tng_data, block_id, &np_data);
16832     if(stat != TNG_SUCCESS)
16833     {
16834         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16835         if(stat != TNG_SUCCESS)
16836         {
16837             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16838             /* If no specific frame was required read until this data block is found */
16839             if(frame < 0)
16840             {
16841                 file_pos = ftell(tng_data->input_file);
16842                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16843                 {
16844                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16845                     file_pos = ftell(tng_data->input_file);
16846                 }
16847             }
16848             if(stat != TNG_SUCCESS)
16849             {
16850                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16851
16852                 return(stat);
16853             }
16854             stat = tng_data_find(tng_data, block_id, &np_data);
16855             if(stat != TNG_SUCCESS)
16856             {
16857                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16858                 if(stat != TNG_SUCCESS)
16859                 {
16860                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16861
16862                     return(stat);
16863                 }
16864                 else
16865                 {
16866                     is_particle_data = 1;
16867                 }
16868             }
16869             else
16870             {
16871                 is_particle_data = 0;
16872             }
16873         }
16874         else
16875         {
16876             is_particle_data = 1;
16877         }
16878     }
16879     else
16880     {
16881         is_particle_data = 0;
16882     }
16883     if(is_particle_data)
16884     {
16885         *stride_length = p_data->stride_length;
16886     }
16887     else
16888     {
16889         *stride_length = np_data->stride_length;
16890     }
16891     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16892
16893     return(TNG_SUCCESS);
16894 }
16895
16896 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16897                 (const tng_trajectory_t tng_data,
16898                  char *time)
16899 {
16900     struct tm *time_data;
16901     time_t secs;
16902
16903     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16904     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16905
16906     secs = tng_data->time;
16907
16908     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16909     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16910              "%4d-%02d-%02d %02d:%02d:%02d",
16911              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16912              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16913
16914     return(TNG_SUCCESS);
16915 }
16916
16917
16918 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16919                 (const char *filename,
16920                  const char mode,
16921                  tng_trajectory_t *tng_data_p)
16922 {
16923     tng_function_status stat;
16924
16925     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16926
16927     if(mode != 'r' && mode != 'w' && mode != 'a')
16928     {
16929         return(TNG_FAILURE);
16930     }
16931
16932     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16933     {
16934         tng_trajectory_destroy(tng_data_p);
16935         return(TNG_CRITICAL);
16936     }
16937
16938     if(mode == 'r' || mode == 'a')
16939     {
16940         tng_input_file_set(*tng_data_p, filename);
16941
16942         /* Read the file headers */
16943         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16944
16945         stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16946
16947         if(stat != TNG_SUCCESS)
16948         {
16949             return(stat);
16950         }
16951     }
16952
16953     if(mode == 'w')
16954     {
16955         tng_output_file_set(*tng_data_p, filename);
16956     }
16957     else if(mode == 'a')
16958     {
16959         if((*tng_data_p)->output_file)
16960         {
16961             fclose((*tng_data_p)->output_file);
16962         }
16963         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
16964         fseek((*tng_data_p)->input_file,
16965                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16966                 SEEK_SET);
16967
16968         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16969         if(stat != TNG_SUCCESS)
16970         {
16971             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16972                    __FILE__, __LINE__);
16973         }
16974         (*tng_data_p)->output_file = 0;
16975
16976         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16977         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16978         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16979         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16980         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16981         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16982         if((*tng_data_p)->input_file)
16983         {
16984             fclose((*tng_data_p)->input_file);
16985             (*tng_data_p)->input_file = 0;
16986         }
16987         if((*tng_data_p)->input_file_path)
16988         {
16989             free((*tng_data_p)->input_file_path);
16990             (*tng_data_p)->input_file_path = 0;
16991         }
16992         tng_output_append_file_set(*tng_data_p, filename);
16993
16994         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16995     }
16996
16997     return(TNG_SUCCESS);
16998 }
16999
17000 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
17001                 (tng_trajectory_t *tng_data_p)
17002 {
17003     tng_trajectory_frame_set_t frame_set;
17004
17005     if(tng_data_p == 0)
17006     {
17007         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
17008                __FILE__, __LINE__);
17009         return(TNG_FAILURE);
17010     }
17011
17012     if(*tng_data_p == 0)
17013     {
17014         return(TNG_SUCCESS);
17015     }
17016
17017     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
17018
17019     if(frame_set->n_unwritten_frames > 0)
17020     {
17021         frame_set->n_frames = frame_set->n_unwritten_frames;
17022         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
17023     }
17024
17025     return(tng_trajectory_destroy(tng_data_p));
17026 }
17027
17028 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
17029                 (tng_trajectory_t tng_data,
17030                  const int64_t frame_nr,
17031                  double *time)
17032 {
17033     int64_t first_frame;
17034     tng_trajectory_frame_set_t frame_set;
17035     tng_function_status stat;
17036
17037     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17038     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
17039
17040     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
17041     if(stat != TNG_SUCCESS)
17042     {
17043         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
17044                frame_nr, __FILE__, __LINE__);
17045         return(stat);
17046     }
17047
17048     frame_set = &tng_data->current_trajectory_frame_set;
17049     first_frame = frame_set->first_frame;
17050
17051     if(tng_data->time_per_frame <= 0)
17052     {
17053         return(TNG_FAILURE);
17054     }
17055
17056     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
17057
17058     return(TNG_SUCCESS);
17059 }
17060
17061 /*
17062 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
17063                 (tng_trajectory_t tng_data,
17064                  int64_t *n_mols,
17065                  int64_t **molecule_cnt_list,
17066                  tng_molecule_t *mols)
17067 {
17068     tng_trajectory_frame_set_t frame_set;
17069
17070     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17071     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
17072
17073     *n_mols = tng_data->n_molecules;
17074
17075     frame_set = &tng_data->current_trajectory_frame_set;
17076     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
17077     {
17078         *molecule_cnt_list = frame_set->molecule_cnt_list;
17079     }
17080     else
17081     {
17082         *molecule_cnt_list = tng_data->molecule_cnt_list;
17083     }
17084
17085     *mols = tng_data->molecules;
17086
17087     return(TNG_SUCCESS);
17088 }
17089 */
17090 /*
17091 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17092                 (tng_trajectory_t tng_data,
17093                  const char *name,
17094                  const int64_t cnt,
17095                  tng_molecule_t *mol)
17096 {
17097     tng_function_status stat;
17098
17099     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17100     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17101
17102     stat = tng_molecule_add(tng_data, name, mol);
17103     if(stat != TNG_SUCCESS)
17104     {
17105         return(stat);
17106     }
17107     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17108
17109     return(stat);
17110 }
17111 */
17112 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17113                 (tng_trajectory_t tng_data,
17114                  const tng_molecule_t mol,
17115                  int64_t *n_particles,
17116                  char ***names,
17117                  char ***types,
17118                  char ***res_names,
17119                  int64_t **res_ids,
17120                  char ***chain_names,
17121                  int64_t **chain_ids)
17122 {
17123     tng_atom_t atom;
17124     tng_residue_t res;
17125     tng_chain_t chain;
17126     int64_t i;
17127     (void)tng_data;
17128
17129     *n_particles = mol->n_atoms;
17130
17131     *names = malloc(sizeof(char *) * *n_particles);
17132     *types = malloc(sizeof(char *) * *n_particles);
17133     *res_names = malloc(sizeof(char *) * *n_particles);
17134     *chain_names = malloc(sizeof(char *) * *n_particles);
17135     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17136     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17137
17138     for(i = 0; i < *n_particles; i++)
17139     {
17140         atom = &mol->atoms[i];
17141         res = atom->residue;
17142         chain = res->chain;
17143         (*names)[i] = malloc(strlen(atom->name));
17144         strcpy(*names[i], atom->name);
17145         (*types)[i] = malloc(strlen(atom->atom_type));
17146         strcpy(*types[i], atom->atom_type);
17147         (*res_names)[i] = malloc(strlen(res->name));
17148         strcpy(*res_names[i], res->name);
17149         (*chain_names)[i] = malloc(strlen(chain->name));
17150         strcpy(*chain_names[i], chain->name);
17151         (*res_ids)[i] = res->id;
17152         (*chain_ids)[i] = chain->id;
17153     }
17154
17155     return(TNG_SUCCESS);
17156 }
17157
17158 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17159                 (tng_trajectory_t tng_data,
17160                  tng_molecule_t mol,
17161                  const int64_t n_particles,
17162                  const char **names,
17163                  const char **types,
17164                  const char **res_names,
17165                  const int64_t *res_ids,
17166                  const char **chain_names,
17167                  const int64_t *chain_ids)
17168 {
17169     int64_t i;
17170     tng_chain_t chain;
17171     tng_residue_t residue;
17172     tng_atom_t atom;
17173     tng_function_status stat;
17174
17175     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17176     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17177     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17178     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17179     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17180     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17181     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17182
17183     for(i = 0; i < n_particles; i++)
17184     {
17185         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17186            &chain) == TNG_FAILURE)
17187         {
17188             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17189                                           &chain);
17190             if(stat != TNG_SUCCESS)
17191             {
17192                 return(stat);
17193             }
17194         }
17195         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17196            &residue) == TNG_FAILURE)
17197         {
17198             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17199                                          &residue);
17200             if(stat != TNG_SUCCESS)
17201             {
17202                 return(stat);
17203             }
17204         }
17205         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17206         if(stat != TNG_SUCCESS)
17207         {
17208             return(stat);
17209         }
17210     }
17211     return(TNG_SUCCESS);
17212 }
17213
17214 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17215                 (tng_trajectory_t tng_data,
17216                  float **positions, int64_t *stride_length)
17217 {
17218     int64_t n_frames, n_particles, n_values_per_frame;
17219     char type;
17220     tng_function_status stat;
17221
17222     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17223     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17224     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17225
17226     stat = tng_num_frames_get(tng_data, &n_frames);
17227     if(stat != TNG_SUCCESS)
17228     {
17229         return(stat);
17230     }
17231
17232     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17233                                                  0, n_frames - 1, TNG_USE_HASH,
17234                                                  (void **)positions,
17235                                                  &n_particles,
17236                                                  stride_length,
17237                                                  &n_values_per_frame,
17238                                                  &type);
17239
17240     return(stat);
17241 }
17242
17243 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17244                 (tng_trajectory_t tng_data,
17245                  float **velocities, int64_t *stride_length)
17246 {
17247     int64_t n_frames, n_particles, n_values_per_frame;
17248     char type;
17249     tng_function_status stat;
17250
17251     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17252     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17253     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17254
17255     stat = tng_num_frames_get(tng_data, &n_frames);
17256     if(stat != TNG_SUCCESS)
17257     {
17258         return(stat);
17259     }
17260
17261     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17262                                                  0, n_frames - 1, TNG_USE_HASH,
17263                                                  (void **)velocities,
17264                                                  &n_particles,
17265                                                  stride_length,
17266                                                  &n_values_per_frame,
17267                                                  &type);
17268
17269     return(stat);
17270 }
17271
17272 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17273                 (tng_trajectory_t tng_data,
17274                  float **forces, int64_t *stride_length)
17275 {
17276     int64_t n_frames, n_particles, n_values_per_frame;
17277     char type;
17278     tng_function_status stat;
17279
17280     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17281     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17282     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17283
17284     stat = tng_num_frames_get(tng_data, &n_frames);
17285     if(stat != TNG_SUCCESS)
17286     {
17287         return(stat);
17288     }
17289
17290     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17291                                                  0, n_frames - 1, TNG_USE_HASH,
17292                                                  (void **)forces,
17293                                                  &n_particles,
17294                                                  stride_length,
17295                                                  &n_values_per_frame,
17296                                                  &type);
17297
17298     return(stat);
17299 }
17300
17301 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17302                 (tng_trajectory_t tng_data,
17303                  float **box_shape,
17304                  int64_t *stride_length)
17305 {
17306     int64_t n_frames, n_values_per_frame;
17307     char type;
17308     tng_function_status stat;
17309
17310     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17311     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17312     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17313
17314     stat = tng_num_frames_get(tng_data, &n_frames);
17315     if(stat != TNG_SUCCESS)
17316     {
17317         return(stat);
17318     }
17319
17320     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17321                                         0, n_frames - 1, TNG_USE_HASH,
17322                                         (void **)box_shape,
17323                                         stride_length,
17324                                         &n_values_per_frame,
17325                                         &type);
17326
17327     return(stat);
17328 }
17329
17330 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17331                 (tng_trajectory_t tng_data,
17332                  const int64_t block_id,
17333                  void **values,
17334                  char *data_type,
17335                  int64_t *retrieved_frame_number,
17336                  double *retrieved_time)
17337 {
17338     tng_trajectory_frame_set_t frame_set;
17339     tng_particle_data_t data = 0;
17340     tng_function_status stat;
17341     int size;
17342     int64_t i, data_size, n_particles;
17343     void *temp;
17344     long file_pos;
17345
17346     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17347     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17348     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17349     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17350     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17351
17352     frame_set = &tng_data->current_trajectory_frame_set;
17353
17354     stat = tng_particle_data_find(tng_data, block_id, &data);
17355     if(stat != TNG_SUCCESS)
17356     {
17357         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17358         file_pos = ftell(tng_data->input_file);
17359         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17360         {
17361             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17362             file_pos = ftell(tng_data->input_file);
17363         }
17364         if(stat != TNG_SUCCESS)
17365         {
17366             return(stat);
17367         }
17368         stat = tng_particle_data_find(tng_data, block_id, &data);
17369         if(stat != TNG_SUCCESS)
17370         {
17371             return(stat);
17372         }
17373     }
17374     if(data->last_retrieved_frame < 0)
17375     {
17376         fseek(tng_data->input_file,
17377               (long)tng_data->first_trajectory_frame_set_input_file_pos,
17378               SEEK_SET);
17379         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17380         if(stat != TNG_SUCCESS)
17381         {
17382             return(stat);
17383         }
17384         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17385         if(stat != TNG_SUCCESS)
17386         {
17387             return(stat);
17388         }
17389
17390         i = data->first_frame_with_data;
17391     }
17392     else
17393     {
17394         if(data->n_frames == 1)
17395         {
17396             i = data->last_retrieved_frame + 1;
17397         }
17398         else
17399         {
17400             i = data->last_retrieved_frame + data->stride_length;
17401         }
17402         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17403         {
17404             stat = tng_frame_set_of_frame_find(tng_data, i);
17405             if(stat != TNG_SUCCESS)
17406             {
17407                 /* If the frame set search found the frame set after the starting
17408                  * frame set there is a gap in the frame sets. So, even if the frame
17409                  * was not found the next frame with data is still in the found
17410                  * frame set. */
17411                 if(stat == TNG_CRITICAL)
17412                 {
17413                     return(stat);
17414                 }
17415                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17416                 {
17417                     return(TNG_FAILURE);
17418                 }
17419                 i = frame_set->first_frame;
17420             }
17421         }
17422         if(data->last_retrieved_frame < frame_set->first_frame)
17423         {
17424             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17425             if(stat != TNG_SUCCESS)
17426             {
17427                 return(stat);
17428             }
17429         }
17430     }
17431     data->last_retrieved_frame = i;
17432     *retrieved_frame_number = i;
17433     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17434     {
17435         *retrieved_time = frame_set->first_frame_time +
17436                         (i - frame_set->first_frame) *
17437                         tng_data->time_per_frame;
17438     }
17439     else
17440     {
17441         *retrieved_time = 0;
17442     }
17443
17444     if(data->stride_length > 1)
17445     {
17446         i = (i - data->first_frame_with_data) / data->stride_length;
17447     }
17448     else
17449     {
17450         i = (i - frame_set->first_frame);
17451     }
17452
17453     tng_num_particles_get(tng_data, &n_particles);
17454
17455     *data_type = data->datatype;
17456
17457     switch(*data_type)
17458     {
17459     case TNG_CHAR_DATA:
17460         return(TNG_FAILURE);
17461     case TNG_INT_DATA:
17462         size = sizeof(int64_t);
17463         break;
17464     case TNG_FLOAT_DATA:
17465         size = sizeof(float);
17466         break;
17467     case TNG_DOUBLE_DATA:
17468     default:
17469         size = sizeof(double);
17470     }
17471
17472     data_size = size * n_particles * data->n_values_per_frame;
17473
17474 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17475 //            i, data_size, size, n_particles, data->n_values_per_frame);
17476
17477     temp = realloc(*values, data_size);
17478     if(!temp)
17479     {
17480         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17481                data_size, __FILE__, __LINE__);
17482         free(*values);
17483         *values = 0;
17484         return(TNG_CRITICAL);
17485     }
17486
17487     *values = temp;
17488
17489     memcpy(*values, (char *)data->values + i * data_size, data_size);
17490
17491     return(TNG_SUCCESS);
17492 }
17493
17494 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17495                 (tng_trajectory_t tng_data,
17496                  const int64_t block_id,
17497                  void **values,
17498                  char *data_type,
17499                  int64_t *retrieved_frame_number,
17500                  double *retrieved_time)
17501 {
17502     tng_trajectory_frame_set_t frame_set;
17503     tng_non_particle_data_t data = 0;
17504     tng_function_status stat;
17505     int size;
17506     int64_t i, data_size;
17507     void *temp;
17508     long file_pos;
17509
17510     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17511     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17512     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17513     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17514     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17515
17516     frame_set = &tng_data->current_trajectory_frame_set;
17517
17518     stat = tng_data_find(tng_data, block_id, &data);
17519     if(stat != TNG_SUCCESS)
17520     {
17521         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17522         file_pos = ftell(tng_data->input_file);
17523         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17524         {
17525             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17526             file_pos = ftell(tng_data->input_file);
17527         }
17528         if(stat != TNG_SUCCESS)
17529         {
17530             return(stat);
17531         }
17532         stat = tng_data_find(tng_data, block_id, &data);
17533         if(stat != TNG_SUCCESS)
17534         {
17535             return(stat);
17536         }
17537     }
17538     if(data->last_retrieved_frame < 0)
17539     {
17540         fseek(tng_data->input_file,
17541                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
17542                 SEEK_SET);
17543         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17544         if(stat != TNG_SUCCESS)
17545         {
17546             return(stat);
17547         }
17548         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17549         if(stat != TNG_SUCCESS)
17550         {
17551             return(stat);
17552         }
17553
17554         i = data->first_frame_with_data;
17555     }
17556     else
17557     {
17558         if(data->n_frames == 1)
17559         {
17560             i = data->last_retrieved_frame + 1;
17561         }
17562         else
17563         {
17564             i = data->last_retrieved_frame + data->stride_length;
17565         }
17566         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17567         {
17568             stat = tng_frame_set_of_frame_find(tng_data, i);
17569             if(stat != TNG_SUCCESS)
17570             {
17571                 /* If the frame set search found the frame set after the starting
17572                  * frame set there is a gap in the frame sets. So, even if the frame
17573                  * was not found the next frame with data is still in the found
17574                  * frame set. */
17575                 if(stat == TNG_CRITICAL)
17576                 {
17577                     return(stat);
17578                 }
17579                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17580                 {
17581                     return(TNG_FAILURE);
17582                 }
17583                 i = frame_set->first_frame;
17584             }
17585         }
17586         if(data->last_retrieved_frame < frame_set->first_frame)
17587         {
17588             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17589             if(stat != TNG_SUCCESS)
17590             {
17591                 return(stat);
17592             }
17593         }
17594     }
17595     data->last_retrieved_frame = i;
17596     *retrieved_frame_number = i;
17597     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17598     {
17599         *retrieved_time = frame_set->first_frame_time +
17600                         (i - frame_set->first_frame) *
17601                         tng_data->time_per_frame;
17602     }
17603     else
17604     {
17605         *retrieved_time = 0;
17606     }
17607
17608     if(data->stride_length > 1)
17609     {
17610         i = (i - data->first_frame_with_data) / data->stride_length;
17611     }
17612     else
17613     {
17614         i = (i - frame_set->first_frame);
17615     }
17616
17617     *data_type = data->datatype;
17618
17619     switch(*data_type)
17620     {
17621     case TNG_CHAR_DATA:
17622         return(TNG_FAILURE);
17623     case TNG_INT_DATA:
17624         size = sizeof(int64_t);
17625         break;
17626     case TNG_FLOAT_DATA:
17627         size = sizeof(float);
17628         break;
17629     case TNG_DOUBLE_DATA:
17630     default:
17631         size = sizeof(double);
17632     }
17633
17634     data_size = size * data->n_values_per_frame;
17635
17636     temp = realloc(*values, data_size);
17637     if(!temp)
17638     {
17639         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17640                data_size, __FILE__, __LINE__);
17641         free(*values);
17642         *values = 0;
17643         return(TNG_CRITICAL);
17644     }
17645
17646     *values = temp;
17647
17648     memcpy(*values, (char *)data->values + i * data_size, data_size);
17649
17650     return(TNG_SUCCESS);
17651 }
17652
17653 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17654                 (tng_trajectory_t tng_data,
17655                  const int64_t first_frame,
17656                  const int64_t last_frame,
17657                  float **positions,
17658                  int64_t *stride_length)
17659 {
17660     int64_t n_particles, n_values_per_frame;
17661     char type;
17662     tng_function_status stat;
17663
17664     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17665     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17666     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17667     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17668
17669     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17670                                                  first_frame, last_frame,
17671                                                  TNG_USE_HASH,
17672                                                  (void **)positions,
17673                                                  &n_particles,
17674                                                  stride_length,
17675                                                  &n_values_per_frame,
17676                                                  &type);
17677
17678     return(stat);
17679 }
17680
17681 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17682                 (tng_trajectory_t tng_data,
17683                  const int64_t first_frame,
17684                  const int64_t last_frame,
17685                  float **velocities,
17686                  int64_t *stride_length)
17687 {
17688     int64_t n_particles, n_values_per_frame;
17689     char type;
17690     tng_function_status stat;
17691
17692     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17693     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17694     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17695     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17696
17697     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17698                                                  first_frame, last_frame,
17699                                                  TNG_USE_HASH,
17700                                                  (void **)velocities,
17701                                                  &n_particles,
17702                                                  stride_length,
17703                                                  &n_values_per_frame,
17704                                                  &type);
17705
17706     return(stat);
17707 }
17708
17709 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17710                 (tng_trajectory_t tng_data,
17711                  const int64_t first_frame,
17712                  const int64_t last_frame,
17713                  float **forces,
17714                  int64_t *stride_length)
17715 {
17716     int64_t n_particles, n_values_per_frame;
17717     char type;
17718     tng_function_status stat;
17719
17720     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17721     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17722     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17723     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17724
17725     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17726                                                  first_frame, last_frame,
17727                                                  TNG_USE_HASH,
17728                                                  (void **)forces,
17729                                                  &n_particles,
17730                                                  stride_length,
17731                                                  &n_values_per_frame,
17732                                                  &type);
17733
17734     return(stat);
17735 }
17736
17737 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17738                 (tng_trajectory_t tng_data,
17739                  const int64_t first_frame,
17740                  const int64_t last_frame,
17741                  float **box_shape,
17742                  int64_t *stride_length)
17743 {
17744     int64_t n_values_per_frame;
17745     char type;
17746     tng_function_status stat;
17747
17748     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17749     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17750     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17751     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17752
17753     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17754                                         first_frame, last_frame,
17755                                         TNG_USE_HASH,
17756                                         (void **)box_shape,
17757                                         stride_length,
17758                                         &n_values_per_frame,
17759                                         &type);
17760
17761     return(stat);
17762 }
17763
17764 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17765                 (tng_trajectory_t tng_data,
17766                  const int64_t i,
17767                  const int64_t n_values_per_frame,
17768                  const int64_t block_id,
17769                  const char *block_name,
17770                  const char particle_dependency,
17771                  const char compression)
17772 {
17773     tng_trajectory_frame_set_t frame_set;
17774     tng_particle_data_t p_data;
17775     tng_non_particle_data_t np_data;
17776     int64_t n_particles, n_frames;
17777     tng_function_status stat;
17778
17779     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17780     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17781
17782     if(i <= 0)
17783     {
17784         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17785                i, __FILE__, __LINE__);
17786         return(TNG_FAILURE);
17787     }
17788
17789     frame_set = &tng_data->current_trajectory_frame_set;
17790
17791     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17792     {
17793         n_frames = tng_data->frame_set_n_frames;
17794
17795         stat = tng_frame_set_new(tng_data, 0, n_frames);
17796         if(stat != TNG_SUCCESS)
17797         {
17798             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17799                 __LINE__);
17800             return(stat);
17801         }
17802     }
17803     else
17804     {
17805         n_frames = frame_set->n_frames;
17806     }
17807
17808     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17809     {
17810         tng_num_particles_get(tng_data, &n_particles);
17811         if(n_particles <= 0)
17812         {
17813             return(TNG_FAILURE);
17814         }
17815
17816         if(tng_particle_data_find(tng_data, block_id, &p_data)
17817         != TNG_SUCCESS)
17818         {
17819             stat = tng_particle_data_block_add(tng_data, block_id,
17820                                                block_name,
17821                                                TNG_FLOAT_DATA,
17822                                                TNG_TRAJECTORY_BLOCK,
17823                                                n_frames, n_values_per_frame, i,
17824                                                0, n_particles,
17825                                                compression, 0);
17826             if(stat != TNG_SUCCESS)
17827             {
17828                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17829                        __FILE__, __LINE__);
17830                 return(stat);
17831             }
17832             p_data = &frame_set->tr_particle_data[frame_set->
17833                                                   n_particle_data_blocks - 1];
17834             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17835                                                   i, n_particles,
17836                                                   n_values_per_frame);
17837             if(stat != TNG_SUCCESS)
17838             {
17839                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17840                        __FILE__, __LINE__);
17841                 return(stat);
17842             }
17843         }
17844         else
17845         {
17846             if(p_data->stride_length != i)
17847             {
17848                 p_data->stride_length = i;
17849                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17850                                                       i, n_particles,
17851                                                       n_values_per_frame);
17852                 if(stat != TNG_SUCCESS)
17853                 {
17854                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17855                            __FILE__, __LINE__);
17856                     return(stat);
17857                 }
17858             }
17859         }
17860     }
17861     else
17862     {
17863         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17864         {
17865             stat = tng_data_block_add(tng_data, block_id, block_name,
17866                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17867                                       n_frames, n_values_per_frame,
17868                                       i, compression, 0);
17869             if(stat != TNG_SUCCESS)
17870             {
17871                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17872                        __FILE__, __LINE__);
17873                 return(stat);
17874             }
17875             np_data = &frame_set->tr_data[frame_set->
17876                                           n_data_blocks - 1];
17877             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17878                                          i, n_values_per_frame);
17879             if(stat != TNG_SUCCESS)
17880             {
17881                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17882                        __FILE__, __LINE__);
17883                 return(stat);
17884             }
17885         }
17886         else
17887         {
17888             if(np_data->stride_length != i)
17889             {
17890                 np_data->stride_length = i;
17891                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17892                                              i, n_values_per_frame);
17893                 if(stat != TNG_SUCCESS)
17894                 {
17895                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17896                            __FILE__, __LINE__);
17897                     return(stat);
17898                 }
17899             }
17900         }
17901     }
17902
17903     return(TNG_SUCCESS);
17904 }
17905
17906 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17907                 (tng_trajectory_t tng_data,
17908                  const int64_t i,
17909                  const int64_t n_values_per_frame,
17910                  const int64_t block_id,
17911                  const char *block_name,
17912                  const char particle_dependency,
17913                  const char compression)
17914 {
17915     tng_trajectory_frame_set_t frame_set;
17916     tng_particle_data_t p_data;
17917     tng_non_particle_data_t np_data;
17918     int64_t n_particles, n_frames;
17919     tng_function_status stat;
17920
17921     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17922     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17923
17924     if(i <= 0)
17925     {
17926         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17927                i, __FILE__, __LINE__);
17928         return(TNG_FAILURE);
17929     }
17930
17931     frame_set = &tng_data->current_trajectory_frame_set;
17932
17933     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17934     {
17935         n_frames = tng_data->frame_set_n_frames;
17936
17937         stat = tng_frame_set_new(tng_data, 0, n_frames);
17938         if(stat != TNG_SUCCESS)
17939         {
17940             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17941                 __LINE__);
17942             return(stat);
17943         }
17944     }
17945     else
17946     {
17947         n_frames = frame_set->n_frames;
17948     }
17949
17950     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17951     {
17952         tng_num_particles_get(tng_data, &n_particles);
17953
17954         if(n_particles <= 0)
17955         {
17956             return(TNG_FAILURE);
17957         }
17958
17959         if(tng_particle_data_find(tng_data, block_id, &p_data)
17960         != TNG_SUCCESS)
17961         {
17962             stat = tng_particle_data_block_add(tng_data, block_id,
17963                                             block_name,
17964                                             TNG_DOUBLE_DATA,
17965                                             TNG_TRAJECTORY_BLOCK,
17966                                             n_frames, n_values_per_frame, i,
17967                                             0, n_particles,
17968                                             compression, 0);
17969             if(stat != TNG_SUCCESS)
17970             {
17971                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17972                        __FILE__, __LINE__);
17973                 return(stat);
17974             }
17975             p_data = &frame_set->tr_particle_data[frame_set->
17976                                                   n_particle_data_blocks - 1];
17977             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17978                                                   i, n_particles,
17979                                                   n_values_per_frame);
17980             if(stat != TNG_SUCCESS)
17981             {
17982                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17983                        __FILE__, __LINE__);
17984                 return(stat);
17985             }
17986         }
17987         else
17988         {
17989             p_data->stride_length = i;
17990         }
17991     }
17992     else
17993     {
17994         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17995         {
17996             stat = tng_data_block_add(tng_data, block_id, block_name,
17997                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17998                                       n_frames, n_values_per_frame,
17999                                       i, compression, 0);
18000             if(stat != TNG_SUCCESS)
18001             {
18002                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18003                        __FILE__, __LINE__);
18004                 return(stat);
18005             }
18006             np_data = &frame_set->tr_data[frame_set->
18007                                           n_data_blocks - 1];
18008             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18009                                          i, n_values_per_frame);
18010             if(stat != TNG_SUCCESS)
18011             {
18012                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18013                        __FILE__, __LINE__);
18014                 return(stat);
18015             }
18016         }
18017         else
18018         {
18019             np_data->stride_length = i;
18020         }
18021     }
18022
18023     return(TNG_SUCCESS);
18024 }
18025
18026 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
18027                 (tng_trajectory_t tng_data,
18028                  const int64_t i,
18029                  const int64_t n_values_per_frame,
18030                  const int64_t block_id,
18031                  const char *block_name,
18032                  const char particle_dependency,
18033                  const char compression)
18034 {
18035     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
18036            "See documentation. %s: %d", __FILE__, __LINE__);
18037     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
18038                                                block_id, block_name,
18039                                                particle_dependency,
18040                                                compression));
18041 }
18042 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
18043                 (tng_trajectory_t tng_data,
18044                  const int64_t i)
18045 {
18046     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18047     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18048
18049     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18050                                                TNG_TRAJ_POSITIONS,
18051                                                "POSITIONS",
18052                                                TNG_PARTICLE_BLOCK_DATA,
18053                                                TNG_TNG_COMPRESSION));
18054 }
18055
18056 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
18057                 (tng_trajectory_t tng_data,
18058                  const int64_t i)
18059 {
18060     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18061     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18062
18063     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18064                                                       TNG_TRAJ_POSITIONS,
18065                                                       "POSITIONS",
18066                                                       TNG_PARTICLE_BLOCK_DATA,
18067                                                       TNG_TNG_COMPRESSION));
18068 }
18069
18070 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
18071                 (tng_trajectory_t tng_data,
18072                  const int64_t i)
18073 {
18074     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
18075            "See documentation. %s: %d", __FILE__, __LINE__);
18076     return(tng_util_pos_write_interval_set(tng_data, i));
18077 }
18078
18079 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
18080                 (tng_trajectory_t tng_data,
18081                  const int64_t i)
18082 {
18083     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18084     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18085
18086     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18087                                                TNG_TRAJ_VELOCITIES,
18088                                                "VELOCITIES",
18089                                                TNG_PARTICLE_BLOCK_DATA,
18090                                                TNG_TNG_COMPRESSION));
18091 }
18092
18093 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
18094                 (tng_trajectory_t tng_data,
18095                  const int64_t i)
18096 {
18097     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18098     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18099
18100     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18101                                                       TNG_TRAJ_VELOCITIES,
18102                                                       "VELOCITIES",
18103                                                       TNG_PARTICLE_BLOCK_DATA,
18104                                                       TNG_TNG_COMPRESSION));
18105 }
18106
18107 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18108                 (tng_trajectory_t tng_data,
18109                  const int64_t i)
18110 {
18111     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18112            "See documentation. %s: %d", __FILE__, __LINE__);
18113     return(tng_util_vel_write_interval_set(tng_data, i));
18114 }
18115
18116 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18117                 (tng_trajectory_t tng_data,
18118                  const int64_t i)
18119 {
18120     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18121     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18122
18123     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18124                                                TNG_TRAJ_FORCES,
18125                                                "FORCES",
18126                                                TNG_PARTICLE_BLOCK_DATA,
18127                                                TNG_GZIP_COMPRESSION));
18128 }
18129
18130 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18131                 (tng_trajectory_t tng_data,
18132                  const int64_t i)
18133 {
18134     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18135     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18136
18137     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18138                                                       TNG_TRAJ_FORCES,
18139                                                       "FORCES",
18140                                                       TNG_PARTICLE_BLOCK_DATA,
18141                                                       TNG_GZIP_COMPRESSION));
18142 }
18143
18144 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18145                 (tng_trajectory_t tng_data,
18146                  const int64_t i)
18147 {
18148     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18149            "See documentation. %s: %d", __FILE__, __LINE__);
18150     return(tng_util_force_write_interval_set(tng_data, i));
18151 }
18152
18153 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18154                 (tng_trajectory_t tng_data,
18155                  const int64_t i)
18156 {
18157     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18158     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18159
18160     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18161                                                TNG_TRAJ_BOX_SHAPE,
18162                                                "BOX SHAPE",
18163                                                TNG_NON_PARTICLE_BLOCK_DATA,
18164                                                TNG_GZIP_COMPRESSION));
18165 }
18166
18167 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18168                 (tng_trajectory_t tng_data,
18169                  const int64_t i)
18170 {
18171     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18172     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18173
18174     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18175                                                       TNG_TRAJ_BOX_SHAPE,
18176                                                       "BOX SHAPE",
18177                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18178                                                       TNG_GZIP_COMPRESSION));
18179 }
18180
18181 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18182                 (tng_trajectory_t tng_data,
18183                  const int64_t i)
18184 {
18185     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18186            "See documentation. %s: %d", __FILE__, __LINE__);
18187     return(tng_util_box_shape_write_interval_set(tng_data, i));
18188 }
18189
18190 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18191                 (tng_trajectory_t tng_data,
18192                  const int64_t frame_nr,
18193                  const float *values,
18194                  const int64_t n_values_per_frame,
18195                  const int64_t block_id,
18196                  const char *block_name,
18197                  const char particle_dependency,
18198                  const char compression)
18199 {
18200     tng_trajectory_frame_set_t frame_set;
18201     tng_particle_data_t p_data;
18202     tng_non_particle_data_t np_data;
18203     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18204     int64_t last_frame;
18205     int is_first_frame_flag = 0;
18206     char block_type_flag;
18207     tng_function_status stat;
18208
18209     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18210     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18211     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18212
18213     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18214     {
18215         tng_num_particles_get(tng_data, &n_particles);
18216         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18217     }
18218
18219     if(values == 0)
18220     {
18221         return(TNG_FAILURE);
18222     }
18223
18224     frame_set = &tng_data->current_trajectory_frame_set;
18225
18226     if(frame_nr < 0)
18227     {
18228         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18229         n_frames = stride_length = 1;
18230     }
18231     else
18232     {
18233         block_type_flag = TNG_TRAJECTORY_BLOCK;
18234
18235         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18236         {
18237             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18238             if(stat != TNG_SUCCESS)
18239             {
18240                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18241                     __LINE__);
18242                 return(stat);
18243             }
18244         }
18245         last_frame = frame_set->first_frame +
18246                      frame_set->n_frames - 1;
18247         if(frame_nr > last_frame)
18248         {
18249             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18250             if(stat != TNG_SUCCESS)
18251             {
18252                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18253                     __LINE__);
18254                 return(stat);
18255             }
18256             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18257             {
18258                 last_frame = frame_nr - 1;
18259             }
18260             stat = tng_frame_set_new(tng_data, last_frame + 1,
18261                                      tng_data->frame_set_n_frames);
18262             if(stat != TNG_SUCCESS)
18263             {
18264                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18265                     __LINE__);
18266                 return(stat);
18267             }
18268         }
18269         if(frame_set->n_unwritten_frames == 0)
18270         {
18271             is_first_frame_flag = 1;
18272         }
18273         frame_set->n_unwritten_frames = frame_nr -
18274                                         frame_set->first_frame + 1;
18275
18276         n_frames = frame_set->n_frames;
18277     }
18278
18279     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18280     {
18281         if(tng_particle_data_find(tng_data, block_id, &p_data)
18282         != TNG_SUCCESS)
18283         {
18284             stat = tng_particle_data_block_add(tng_data, block_id,
18285                                                block_name,
18286                                                TNG_FLOAT_DATA,
18287                                                block_type_flag,
18288                                                n_frames, n_values_per_frame,
18289                                                stride_length,
18290                                                0, n_particles,
18291                                                compression, 0);
18292             if(stat != TNG_SUCCESS)
18293             {
18294                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18295                        __FILE__, __LINE__);
18296                 return(stat);
18297             }
18298             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18299             {
18300                 p_data = &frame_set->tr_particle_data[frame_set->
18301                                                     n_particle_data_blocks - 1];
18302             }
18303             else
18304             {
18305                 p_data = &tng_data->non_tr_particle_data[tng_data->
18306                                                     n_particle_data_blocks - 1];
18307             }
18308             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18309                                                   stride_length, n_particles,
18310                                                   n_values_per_frame);
18311             if(stat != TNG_SUCCESS)
18312             {
18313                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18314                        __FILE__, __LINE__);
18315                 return(stat);
18316             }
18317         }
18318
18319         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18320         {
18321             stride_length = p_data->stride_length;
18322
18323             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18324             {
18325                 p_data->first_frame_with_data = frame_nr;
18326                 frame_pos = 0;
18327             }
18328             else
18329             {
18330                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18331             }
18332
18333             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18334                    n_values_per_frame, values, sizeof(float) *
18335                    n_particles * n_values_per_frame);
18336         }
18337         else
18338         {
18339             memcpy(p_data->values, values, sizeof(float) * n_particles *
18340                    n_values_per_frame);
18341         }
18342     }
18343     else
18344     {
18345         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18346         {
18347             stat = tng_data_block_add(tng_data, block_id, block_name,
18348                                       TNG_FLOAT_DATA, block_type_flag,
18349                                       n_frames, n_values_per_frame,
18350                                       stride_length, compression, 0);
18351             if(stat != TNG_SUCCESS)
18352             {
18353                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18354                        __FILE__, __LINE__);
18355                 return(stat);
18356             }
18357             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18358             {
18359                 np_data = &frame_set->tr_data[frame_set->
18360                                               n_data_blocks - 1];
18361             }
18362             else
18363             {
18364                 np_data = &tng_data->non_tr_data[tng_data->
18365                                                  n_data_blocks - 1];
18366             }
18367             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18368                                          stride_length, n_values_per_frame);
18369             if(stat != TNG_SUCCESS)
18370             {
18371                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18372                        __FILE__, __LINE__);
18373                 return(stat);
18374             }
18375         }
18376
18377         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18378         {
18379             stride_length = np_data->stride_length;
18380
18381             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18382             {
18383                 np_data->first_frame_with_data = frame_nr;
18384                 frame_pos = 0;
18385             }
18386             else
18387             {
18388                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18389             }
18390
18391             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18392                    n_values_per_frame, values, sizeof(float) *
18393                    n_values_per_frame);
18394         }
18395         else
18396         {
18397             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18398         }
18399     }
18400
18401     return(TNG_SUCCESS);
18402 }
18403
18404 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18405                 (tng_trajectory_t tng_data,
18406                  const int64_t frame_nr,
18407                  const double *values,
18408                  const int64_t n_values_per_frame,
18409                  const int64_t block_id,
18410                  const char *block_name,
18411                  const char particle_dependency,
18412                  const char compression)
18413 {
18414     tng_trajectory_frame_set_t frame_set;
18415     tng_particle_data_t p_data;
18416     tng_non_particle_data_t np_data;
18417     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18418     int64_t last_frame;
18419     int is_first_frame_flag = 0;
18420     char block_type_flag;
18421     tng_function_status stat;
18422
18423     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18424     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18425     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18426
18427     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18428     {
18429         tng_num_particles_get(tng_data, &n_particles);
18430         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18431     }
18432
18433     if(values == 0)
18434     {
18435         return(TNG_FAILURE);
18436     }
18437
18438     frame_set = &tng_data->current_trajectory_frame_set;
18439
18440     if(frame_nr < 0)
18441     {
18442         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18443         n_frames = stride_length = 1;
18444     }
18445     else
18446     {
18447         block_type_flag = TNG_TRAJECTORY_BLOCK;
18448
18449         n_frames = tng_data->frame_set_n_frames;
18450
18451         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18452         {
18453             stat = tng_frame_set_new(tng_data, 0, n_frames);
18454             if(stat != TNG_SUCCESS)
18455             {
18456                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18457                     __LINE__);
18458                 return(stat);
18459             }
18460         }
18461         else
18462         {
18463             n_frames = frame_set->n_frames;
18464         }
18465         last_frame = frame_set->first_frame +
18466                      frame_set->n_frames - 1;
18467         if(frame_nr > last_frame)
18468         {
18469             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18470             if(stat != TNG_SUCCESS)
18471             {
18472                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18473                     __LINE__);
18474                 return(stat);
18475             }
18476             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18477             {
18478                 last_frame = frame_nr - 1;
18479             }
18480             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18481             if(stat != TNG_SUCCESS)
18482             {
18483                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18484                     __LINE__);
18485                 return(stat);
18486             }
18487         }
18488         if(frame_set->n_unwritten_frames == 0)
18489         {
18490             is_first_frame_flag = 1;
18491         }
18492         frame_set->n_unwritten_frames = frame_nr -
18493                                         frame_set->first_frame + 1;
18494     }
18495
18496     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18497     {
18498         if(tng_particle_data_find(tng_data, block_id, &p_data)
18499         != TNG_SUCCESS)
18500         {
18501             stat = tng_particle_data_block_add(tng_data, block_id,
18502                                             block_name,
18503                                             TNG_DOUBLE_DATA,
18504                                             block_type_flag,
18505                                             n_frames, n_values_per_frame,
18506                                             stride_length,
18507                                             0, n_particles,
18508                                             compression, 0);
18509             if(stat != TNG_SUCCESS)
18510             {
18511                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18512                        __FILE__, __LINE__);
18513                 return(stat);
18514             }
18515             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18516             {
18517                 p_data = &frame_set->tr_particle_data[frame_set->
18518                                                     n_particle_data_blocks - 1];
18519             }
18520             else
18521             {
18522                 p_data = &tng_data->non_tr_particle_data[tng_data->
18523                                                     n_particle_data_blocks - 1];
18524             }
18525             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18526                                                   stride_length, n_particles,
18527                                                   n_values_per_frame);
18528             if(stat != TNG_SUCCESS)
18529             {
18530                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18531                        __FILE__, __LINE__);
18532                 return(stat);
18533             }
18534         }
18535
18536         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18537         {
18538             stride_length = p_data->stride_length;
18539
18540             if(is_first_frame_flag)
18541             {
18542                 p_data->first_frame_with_data = frame_nr;
18543                 frame_pos = 0;
18544             }
18545             else
18546             {
18547                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18548             }
18549
18550             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18551                    n_values_per_frame, values, sizeof(double) *
18552                    n_particles * n_values_per_frame);
18553         }
18554         else
18555         {
18556             memcpy(p_data->values, values, sizeof(double) * n_particles *
18557                    n_values_per_frame);
18558         }
18559     }
18560     else
18561     {
18562         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18563         {
18564             stat = tng_data_block_add(tng_data, block_id, block_name,
18565                                       TNG_DOUBLE_DATA, block_type_flag,
18566                                       n_frames, n_values_per_frame,
18567                                       stride_length, compression, 0);
18568             if(stat != TNG_SUCCESS)
18569             {
18570                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18571                        __FILE__, __LINE__);
18572                 return(stat);
18573             }
18574             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18575             {
18576                 np_data = &frame_set->tr_data[frame_set->
18577                                               n_data_blocks - 1];
18578             }
18579             else
18580             {
18581                 np_data = &tng_data->non_tr_data[tng_data->
18582                                                  n_data_blocks - 1];
18583             }
18584             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18585                                          stride_length, n_values_per_frame);
18586             if(stat != TNG_SUCCESS)
18587             {
18588                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18589                        __FILE__, __LINE__);
18590                 return(stat);
18591             }
18592         }
18593
18594         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18595         {
18596             stride_length = np_data->stride_length;
18597
18598             if(is_first_frame_flag)
18599             {
18600                 np_data->first_frame_with_data = frame_nr;
18601                 frame_pos = 0;
18602             }
18603             else
18604             {
18605                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18606             }
18607
18608             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18609                    n_values_per_frame, values, sizeof(double) *
18610                    n_values_per_frame);
18611         }
18612         else
18613         {
18614             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18615         }
18616     }
18617
18618     return(TNG_SUCCESS);
18619 }
18620
18621 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18622                 (tng_trajectory_t tng_data,
18623                  const int64_t frame_nr,
18624                  const float *positions)
18625 {
18626     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18627     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18628     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18629
18630     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18631                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18632                                   TNG_PARTICLE_BLOCK_DATA,
18633                                   TNG_TNG_COMPRESSION));
18634 }
18635
18636 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18637                 (tng_trajectory_t tng_data,
18638                  const int64_t frame_nr,
18639                  const double *positions)
18640 {
18641     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18642     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18643     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18644
18645     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18646                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18647                                          TNG_PARTICLE_BLOCK_DATA,
18648                                          TNG_TNG_COMPRESSION));
18649 }
18650
18651 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18652                 (tng_trajectory_t tng_data,
18653                  const int64_t frame_nr,
18654                  const float *velocities)
18655 {
18656     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18657     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18658     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18659
18660     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18661                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18662                                   TNG_PARTICLE_BLOCK_DATA,
18663                                   TNG_TNG_COMPRESSION));
18664 }
18665
18666 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18667                 (tng_trajectory_t tng_data,
18668                  const int64_t frame_nr,
18669                  const double *velocities)
18670 {
18671     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18672     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18673     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18674
18675     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18676                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18677                                          TNG_PARTICLE_BLOCK_DATA,
18678                                          TNG_TNG_COMPRESSION));
18679 }
18680
18681 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18682                 (tng_trajectory_t tng_data,
18683                  const int64_t frame_nr,
18684                  const float *forces)
18685 {
18686     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18687     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18688     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18689
18690     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18691                                   TNG_TRAJ_FORCES, "FORCES",
18692                                   TNG_PARTICLE_BLOCK_DATA,
18693                                   TNG_GZIP_COMPRESSION));
18694 }
18695
18696 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18697                 (tng_trajectory_t tng_data,
18698                  const int64_t frame_nr,
18699                  const double *forces)
18700 {
18701     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18702     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18703     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18704
18705     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18706                                          TNG_TRAJ_FORCES, "FORCES",
18707                                          TNG_PARTICLE_BLOCK_DATA,
18708                                          TNG_GZIP_COMPRESSION));
18709 }
18710
18711 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18712                 (tng_trajectory_t tng_data,
18713                  const int64_t frame_nr,
18714                  const float *box_shape)
18715 {
18716     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18717     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18718     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18719
18720     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18721                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18722                                   TNG_NON_PARTICLE_BLOCK_DATA,
18723                                   TNG_GZIP_COMPRESSION));
18724 }
18725
18726 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18727                 (tng_trajectory_t tng_data,
18728                  const int64_t frame_nr,
18729                  const double *box_shape)
18730 {
18731     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18732     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18733     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18734
18735     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18736                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18737                                          TNG_NON_PARTICLE_BLOCK_DATA,
18738                                          TNG_GZIP_COMPRESSION));
18739 }
18740
18741 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18742                 (tng_trajectory_t tng_data,
18743                  const int64_t frame_nr,
18744                  const double time,
18745                  const float *values,
18746                  const int64_t n_values_per_frame,
18747                  const int64_t block_id,
18748                  const char *block_name,
18749                  const char particle_dependency,
18750                  const char compression)
18751 {
18752     tng_trajectory_frame_set_t frame_set;
18753     tng_function_status stat;
18754
18755     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18756     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18757     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18758     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18759
18760     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18761                                   block_id, block_name,
18762                                   particle_dependency,
18763                                   compression);
18764
18765     if(stat != TNG_SUCCESS)
18766     {
18767         return(stat);
18768     }
18769
18770     frame_set = &tng_data->current_trajectory_frame_set;
18771
18772     /* first_frame_time is -1 when it is not yet set. */
18773     if(frame_set->first_frame_time < -0.1)
18774     {
18775         if(frame_nr > frame_set->first_frame)
18776         {
18777             stat = tng_frame_set_first_frame_time_set(tng_data,
18778                                                       time -
18779                                                       (frame_nr -
18780                                                        frame_set->first_frame) *
18781                                                       tng_data->time_per_frame);
18782         }
18783         else
18784         {
18785             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18786         }
18787     }
18788     return(stat);
18789 }
18790
18791 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18792                 (tng_trajectory_t tng_data,
18793                  const int64_t frame_nr,
18794                  const double time,
18795                  const double *values,
18796                  const int64_t n_values_per_frame,
18797                  const int64_t block_id,
18798                  const char *block_name,
18799                  const char particle_dependency,
18800                  const char compression)
18801 {
18802     tng_trajectory_frame_set_t frame_set;
18803     tng_function_status stat;
18804
18805     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18806     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18807     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18808     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18809
18810     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18811                                          block_id, block_name,
18812                                          particle_dependency,
18813                                          compression);
18814
18815     if(stat != TNG_SUCCESS)
18816     {
18817         return(stat);
18818     }
18819
18820     frame_set = &tng_data->current_trajectory_frame_set;
18821
18822     /* first_frame_time is -1 when it is not yet set. */
18823     if(frame_set->first_frame_time < -0.1)
18824     {
18825         if(frame_nr > frame_set->first_frame)
18826         {
18827             stat = tng_frame_set_first_frame_time_set(tng_data,
18828                                                       time -
18829                                                       (frame_nr -
18830                                                        frame_set->first_frame) *
18831                                                       tng_data->time_per_frame);
18832         }
18833         else
18834         {
18835             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18836         }
18837     }
18838     return(stat);
18839 }
18840
18841 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18842                 (tng_trajectory_t tng_data,
18843                  const int64_t frame_nr,
18844                  const double time,
18845                  const float *positions)
18846 {
18847     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18848     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18849     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18850     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18851
18852     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18853                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18854                                             TNG_PARTICLE_BLOCK_DATA,
18855                                             TNG_TNG_COMPRESSION));
18856 }
18857
18858 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18859                 (tng_trajectory_t tng_data,
18860                  const int64_t frame_nr,
18861                  const double time,
18862                  const double *positions)
18863 {
18864     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18865     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18866     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18867     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18868
18869     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18870                                                    positions, 3,
18871                                                    TNG_TRAJ_POSITIONS,
18872                                                    "POSITIONS",
18873                                                    TNG_PARTICLE_BLOCK_DATA,
18874                                                    TNG_TNG_COMPRESSION));
18875 }
18876
18877 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18878                 (tng_trajectory_t tng_data,
18879                  const int64_t frame_nr,
18880                  const double time,
18881                  const float *velocities)
18882 {
18883     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18884     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18885     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18886     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18887
18888     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18889                                             velocities, 3,
18890                                             TNG_TRAJ_VELOCITIES,
18891                                             "VELOCITIES",
18892                                             TNG_PARTICLE_BLOCK_DATA,
18893                                             TNG_TNG_COMPRESSION));
18894 }
18895
18896 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18897                 (tng_trajectory_t tng_data,
18898                  const int64_t frame_nr,
18899                  const double time,
18900                  const double *velocities)
18901 {
18902     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18903     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18904     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18905     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18906
18907     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18908                                                    velocities, 3,
18909                                                    TNG_TRAJ_VELOCITIES,
18910                                                    "VELOCITIES",
18911                                                    TNG_PARTICLE_BLOCK_DATA,
18912                                                    TNG_TNG_COMPRESSION));
18913 }
18914
18915 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18916                 (tng_trajectory_t tng_data,
18917                  const int64_t frame_nr,
18918                  const double time,
18919                  const float *forces)
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(forces, "TNG library: forces must not be a NULL pointer");
18925
18926     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18927                                             3, TNG_TRAJ_FORCES, "FORCES",
18928                                             TNG_PARTICLE_BLOCK_DATA,
18929                                             TNG_GZIP_COMPRESSION));
18930 }
18931
18932 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18933                 (tng_trajectory_t tng_data,
18934                  const int64_t frame_nr,
18935                  const double time,
18936                  const double *forces)
18937 {
18938     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18939     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18940     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18941     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18942
18943     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18944                                                    forces, 3,
18945                                                    TNG_TRAJ_FORCES, "FORCES",
18946                                                    TNG_PARTICLE_BLOCK_DATA,
18947                                                    TNG_GZIP_COMPRESSION));
18948 }
18949
18950 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18951                 (tng_trajectory_t tng_data,
18952                  const int64_t frame_nr,
18953                  const double time,
18954                  const float *box_shape)
18955 {
18956     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18957     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18958     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18959     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18960
18961     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18962                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18963                                             TNG_NON_PARTICLE_BLOCK_DATA,
18964                                             TNG_GZIP_COMPRESSION));
18965 }
18966
18967 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18968                 (tng_trajectory_t tng_data,
18969                  const int64_t frame_nr,
18970                  const double time,
18971                  const double *box_shape)
18972 {
18973     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18974     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18975     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18976     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18977
18978     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18979                                                    time, box_shape, 9,
18980                                                    TNG_TRAJ_BOX_SHAPE,
18981                                                    "BOX SHAPE",
18982                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18983                                                    TNG_GZIP_COMPRESSION));
18984 }
18985
18986 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18987                 (tng_trajectory_t tng_data,
18988                  const int64_t block_id,
18989                  int64_t *codec_id,
18990                  double *factor)
18991 {
18992     tng_trajectory_frame_set_t frame_set;
18993     tng_particle_data_t p_data = 0;
18994     tng_non_particle_data_t np_data = 0;
18995     tng_function_status stat;
18996     int64_t i;
18997     int block_type = -1;
18998
18999     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19000     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
19001     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
19002
19003     frame_set = &tng_data->current_trajectory_frame_set;
19004
19005     stat = tng_particle_data_find(tng_data, block_id, &p_data);
19006     if(stat == TNG_SUCCESS)
19007     {
19008         block_type = TNG_PARTICLE_BLOCK_DATA;
19009     }
19010     else
19011     {
19012         stat = tng_data_find(tng_data, block_id, &np_data);
19013         if(stat == TNG_SUCCESS)
19014         {
19015             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19016         }
19017         else
19018         {
19019             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19020             if(stat != TNG_SUCCESS)
19021             {
19022                 return(stat);
19023             }
19024             stat = tng_particle_data_find(tng_data, block_id, &p_data);
19025             if(stat == TNG_SUCCESS)
19026             {
19027                 block_type = TNG_PARTICLE_BLOCK_DATA;
19028             }
19029             else
19030             {
19031                 stat = tng_data_find(tng_data, block_id, &np_data);
19032                 if(stat == TNG_SUCCESS)
19033                 {
19034                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19035                 }
19036                 else
19037                 {
19038                     return(stat);
19039                 }
19040             }
19041         }
19042     }
19043     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19044     {
19045         if(p_data->last_retrieved_frame < 0)
19046         {
19047             i = p_data->first_frame_with_data;
19048         }
19049         else
19050         {
19051             i = p_data->last_retrieved_frame;
19052         }
19053     }
19054     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19055     {
19056         if(np_data->last_retrieved_frame < 0)
19057         {
19058             i = np_data->first_frame_with_data;
19059         }
19060         else
19061         {
19062             i = np_data->last_retrieved_frame;
19063         }
19064     }
19065     else
19066     {
19067         return(TNG_FAILURE);
19068     }
19069     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
19070     {
19071         stat = tng_frame_set_of_frame_find(tng_data, i);
19072         if(stat != TNG_SUCCESS)
19073         {
19074             return(stat);
19075         }
19076         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19077         if(stat != TNG_SUCCESS)
19078         {
19079             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19080                 __FILE__, __LINE__);
19081             return(stat);
19082         }
19083     }
19084     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19085     {
19086         *codec_id = p_data->codec_id;
19087         *factor   = p_data->compression_multiplier;
19088     }
19089     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19090     {
19091         *codec_id = np_data->codec_id;
19092         *factor   = np_data->compression_multiplier;
19093     }
19094     return(TNG_SUCCESS);
19095 }
19096
19097 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19098                 (tng_trajectory_t tng_data,
19099                  int64_t current_frame,
19100                  const int64_t n_requested_data_block_ids,
19101                  const int64_t *requested_data_block_ids,
19102                  int64_t *next_frame,
19103                  int64_t *n_data_blocks_in_next_frame,
19104                  int64_t **data_block_ids_in_next_frame)
19105 {
19106     tng_trajectory_frame_set_t frame_set;
19107     tng_function_status stat;
19108     tng_particle_data_t p_data;
19109     tng_non_particle_data_t np_data;
19110     tng_gen_block_t block;
19111     int64_t i, j, block_id, *temp;
19112     int64_t data_frame, frame_diff, min_diff;
19113     int64_t size, frame_set_file_pos;
19114     int found, read_all = 0;
19115     long file_pos;
19116
19117     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19118     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19119     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19120     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19121
19122     if(n_requested_data_block_ids)
19123     {
19124         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.");
19125         size = sizeof(int64_t) * n_requested_data_block_ids;
19126         temp = realloc(*data_block_ids_in_next_frame, size);
19127         if(!temp)
19128         {
19129             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19130                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19131                     __FILE__, __LINE__);
19132             free(*data_block_ids_in_next_frame);
19133             *data_block_ids_in_next_frame = 0;
19134             return(TNG_CRITICAL);
19135         }
19136         *data_block_ids_in_next_frame = temp;
19137     }
19138
19139     frame_set = &tng_data->current_trajectory_frame_set;
19140
19141     current_frame += 1;
19142
19143     if(current_frame < frame_set->first_frame ||
19144        current_frame >= frame_set->first_frame + frame_set->n_frames)
19145     {
19146         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19147         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19148         if(stat != TNG_SUCCESS)
19149         {
19150             /* If the frame set search found the frame set after the starting
19151              * frame set there is a gap in the frame sets. So, even if the frame
19152              * was not found the next frame with data is still in the found
19153              * frame set. */
19154             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19155                frame_set_file_pos)
19156             {
19157                 return(stat);
19158             }
19159             current_frame = frame_set->first_frame;
19160         }
19161     }
19162
19163     /* Check for data blocks only if they have not already been found. */
19164     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19165     {
19166         file_pos = ftell(tng_data->input_file);
19167         if(file_pos < tng_data->input_file_len)
19168         {
19169             tng_block_init(&block);
19170             stat = tng_block_header_read(tng_data, block);
19171             while(file_pos < tng_data->input_file_len &&
19172                 stat != TNG_CRITICAL &&
19173                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19174                 block->id != -1)
19175             {
19176                 stat = tng_block_read_next(tng_data, block,
19177                                         TNG_USE_HASH);
19178                 if(stat != TNG_CRITICAL)
19179                 {
19180                     file_pos = ftell(tng_data->input_file);
19181                     if(file_pos < tng_data->input_file_len)
19182                     {
19183                         stat = tng_block_header_read(tng_data, block);
19184                     }
19185                 }
19186             }
19187             tng_block_destroy(&block);
19188             if(stat == TNG_CRITICAL)
19189             {
19190                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
19191                         file_pos, __FILE__, __LINE__);
19192                 return(stat);
19193             }
19194         }
19195         read_all = 1;
19196     }
19197
19198     min_diff = -1;
19199
19200     *n_data_blocks_in_next_frame = 0;
19201
19202     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19203     {
19204         p_data = &frame_set->tr_particle_data[i];
19205         block_id = p_data->block_id;
19206
19207         if(n_requested_data_block_ids > 0)
19208         {
19209             found = 0;
19210             for(j = 0; j < n_requested_data_block_ids; j++)
19211             {
19212                 if(block_id == requested_data_block_ids[j])
19213                 {
19214                     found = 1;
19215                     break;
19216                 }
19217             }
19218             if(!found)
19219             {
19220                 continue;
19221             }
19222         }
19223
19224         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19225            p_data->last_retrieved_frame >=
19226            frame_set->first_frame + frame_set->n_frames))
19227         {
19228             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19229                                                                       TNG_USE_HASH, block_id);
19230             if(stat == TNG_CRITICAL)
19231             {
19232                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19233                     __FILE__, __LINE__);
19234                 return(stat);
19235             }
19236             if(stat == TNG_FAILURE)
19237             {
19238                 continue;
19239             }
19240         }
19241         if(frame_set->first_frame != current_frame &&
19242            p_data->last_retrieved_frame >= 0)
19243         {
19244             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19245         }
19246         else
19247         {
19248             data_frame = p_data->first_frame_with_data;
19249         }
19250         frame_diff = data_frame - current_frame;
19251         if(frame_diff < 0)
19252         {
19253             continue;
19254         }
19255         if(min_diff == -1 || frame_diff <= min_diff)
19256         {
19257             if(frame_diff < min_diff)
19258             {
19259                 *n_data_blocks_in_next_frame = 1;
19260             }
19261             else
19262             {
19263                 *n_data_blocks_in_next_frame += 1;
19264             }
19265             if(n_requested_data_block_ids <= 0)
19266             {
19267                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19268                 temp = realloc(*data_block_ids_in_next_frame, size);
19269                 if(!temp)
19270                 {
19271                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19272                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19273                            __FILE__, __LINE__);
19274                     free(*data_block_ids_in_next_frame);
19275                     *data_block_ids_in_next_frame = 0;
19276                     return(TNG_CRITICAL);
19277                 }
19278                 *data_block_ids_in_next_frame = temp;
19279             }
19280             else
19281             {
19282                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19283             }
19284             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19285
19286             min_diff = frame_diff;
19287         }
19288     }
19289     for(i = 0; i < frame_set->n_data_blocks; i++)
19290     {
19291         np_data = &frame_set->tr_data[i];
19292         block_id = np_data->block_id;
19293
19294         if(n_requested_data_block_ids > 0)
19295         {
19296             found = 0;
19297             for(j = 0; j < n_requested_data_block_ids; j++)
19298             {
19299                 if(block_id == requested_data_block_ids[j])
19300                 {
19301                     found = 1;
19302                     break;
19303                 }
19304             }
19305             if(!found)
19306             {
19307                 continue;
19308             }
19309         }
19310
19311         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19312            np_data->last_retrieved_frame >=
19313            frame_set->first_frame + frame_set->n_frames))
19314         {
19315             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19316                                                                       TNG_USE_HASH, block_id);
19317             if(stat == TNG_CRITICAL)
19318             {
19319                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19320                     __FILE__, __LINE__);
19321                 return(stat);
19322             }
19323             if(stat == TNG_FAILURE)
19324             {
19325                 continue;
19326             }
19327         }
19328         if(frame_set->first_frame != current_frame &&
19329            np_data->last_retrieved_frame >= 0)
19330         {
19331             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19332         }
19333         else
19334         {
19335             data_frame = np_data->first_frame_with_data;
19336         }
19337         frame_diff = data_frame - current_frame;
19338         if(frame_diff < 0)
19339         {
19340             continue;
19341         }
19342         if(min_diff == -1 || frame_diff <= min_diff)
19343         {
19344             if(frame_diff < min_diff)
19345             {
19346                 *n_data_blocks_in_next_frame = 1;
19347             }
19348             else
19349             {
19350                 *n_data_blocks_in_next_frame += 1;
19351             }
19352             if(n_requested_data_block_ids <= 0)
19353             {
19354                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19355                 temp = realloc(*data_block_ids_in_next_frame, size);
19356                 if(!temp)
19357                 {
19358                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19359                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19360                            __FILE__, __LINE__);
19361                     free(*data_block_ids_in_next_frame);
19362                     *data_block_ids_in_next_frame = 0;
19363                     return(TNG_CRITICAL);
19364                 }
19365                 *data_block_ids_in_next_frame = temp;
19366             }
19367             else
19368             {
19369                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19370             }
19371             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19372
19373             min_diff = frame_diff;
19374         }
19375     }
19376     if(min_diff < 0)
19377     {
19378         return(TNG_FAILURE);
19379     }
19380     *next_frame = current_frame + min_diff;
19381
19382     return(TNG_SUCCESS);
19383 }
19384
19385 /*
19386 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19387                 (tng_trajectory_t tng_data,
19388                  int64_t *n_data_blocks,
19389                  int64_t **data_block_ids,
19390                  char ***data_block_names,
19391                  int64_t **stride_lengths,
19392                  int64_t **n_values_per_frame,
19393                  char **block_types,
19394                  char **dependencies,
19395                  char **compressions)
19396 {
19397     tng_gen_block_t block;
19398     long orig_file_pos, file_pos;
19399
19400     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19401     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19402     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19403     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19404     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19405
19406     orig_file_pos = ftell(tng_data->input_file);
19407
19408     if(!tng_data->input_file_len)
19409     {
19410         fseek(tng_data->input_file, 0, SEEK_END);
19411         tng_data->input_file_len = ftell(tng_data->input_file);
19412     }
19413
19414     fseek(tng_data->input_file, 0, SEEK_SET);
19415     file_pos = 0;
19416
19417     *n_data_blocks = 0;
19418
19419     tng_block_init(&block);
19420
19421     while(file_pos < tng_data->input_file_len &&
19422           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19423     {
19424         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19425         {
19426
19427         }
19428         file_pos += (long)(block->block_contents_size + block->header_contents_size);
19429         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
19430     }
19431
19432     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
19433
19434     return(TNG_SUCCESS);
19435 }
19436 */
19437 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19438                 (tng_trajectory_t tng_data,
19439                  const int64_t prev_frame)
19440 {
19441     tng_function_status stat;
19442     FILE *temp = tng_data->input_file;
19443
19444     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19445     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19446
19447     tng_data->input_file = tng_data->output_file;
19448
19449     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19450     if(stat != TNG_SUCCESS)
19451     {
19452         return(stat);
19453     }
19454
19455     tng_data->current_trajectory_frame_set_output_file_pos =
19456     tng_data->current_trajectory_frame_set_input_file_pos;
19457
19458     tng_data->input_file = temp;
19459
19460     return(TNG_SUCCESS);
19461 }