Bumped the TNG library to the latest version.
[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 "../../include/tng_io.h"
26 #include "../../include/md5.h"
27 #include "../../include/compression/tng_compress.h"
28 #include "../include/version.h"
29
30
31 struct tng_bond {
32     /** One of the atoms of the bond */
33     int64_t from_atom_id;
34     /** The other atom of the bond */
35     int64_t to_atom_id;
36 };
37
38 struct tng_atom {
39     /** The residue containing this atom */
40     tng_residue_t residue;
41     /** A unique (per molecule) ID number of the atom */
42     int64_t id;
43     /** The atom_type (depending on the forcefield) */
44     char *atom_type;
45     /** The name of the atom */
46     char *name;
47 };
48
49 struct tng_residue {
50     /** The chain containing this residue */
51     tng_chain_t chain;
52     /** A unique (per chain) ID number of the residue */
53     int64_t id;
54     /** The name of the residue */
55     char *name;
56     /** The number of atoms in the residue */
57     int64_t n_atoms;
58     /** A list of atoms in the residue */
59     int64_t atoms_offset;
60 };
61
62 struct tng_chain {
63     /** The molecule containing this chain */
64     tng_molecule_t molecule;
65     /** A unique (per molecule) ID number of the chain */
66     int64_t id;
67     /** The name of the chain */
68     char *name;
69     /** The number of residues in the chain */
70     int64_t n_residues;
71     /** A list of residues in the chain */
72     tng_residue_t residues;
73 };
74
75 struct tng_molecule {
76     /** A unique ID number of the molecule */
77     int64_t id;
78     /** Quaternary structure of the molecule.
79      *  1 => monomeric
80      *  2 => dimeric
81      *  3 => trimeric
82      *  etc */
83     int64_t quaternary_str;
84     /** The number of chains in the molecule */
85     int64_t n_chains;
86     /** The number of residues in the molecule */
87     int64_t n_residues;
88     /** The number of atoms in the molecule */
89     int64_t n_atoms;
90     /** The number of bonds in the molecule. If the bonds are not specified this
91      * value can be 0. */
92     int64_t n_bonds;
93     /** The name of the molecule */
94     char *name;
95     /** A list of chains in the molecule */
96     tng_chain_t chains;
97     /** A list of residues in the molecule */
98     tng_residue_t residues;
99     /** A list of the atoms in the molecule */
100     tng_atom_t atoms;
101     /** A list of the bonds in the molecule */
102     tng_bond_t bonds;
103 };
104
105 struct tng_gen_block {
106     /** The size of the block header in bytes */
107     int64_t header_contents_size;
108     /** The size of the block contents in bytes */
109     int64_t block_contents_size;
110     /** The ID of the block to determine its type */
111     int64_t id;
112     /** The MD5 hash of the block to verify integrity */
113     char md5_hash[TNG_MD5_HASH_LEN];
114     /** The name of the block */
115     char *name;
116     /** The library version used to write the block */
117     int64_t block_version;
118     int64_t alt_hash_type;
119     int64_t alt_hash_len;
120     char *alt_hash;
121     int64_t signature_type;
122     int64_t signature_len;
123     char *signature;
124     /** The full block header contents */
125     char *header_contents;
126     /** The full block contents */
127     char *block_contents;
128 };
129
130 struct tng_particle_mapping {
131     /** The index number of the first particle in this mapping block */
132     int64_t num_first_particle;
133     /** The number of particles list in this mapping block */
134     int64_t n_particles;
135     /** the mapping of index numbers to the real particle numbers in the
136      * trajectory. real_particle_numbers[0] is the real particle number
137      * (as it is numbered in the molecular system) of the first particle
138      * in the data blocks covered by this particle mapping block */
139     int64_t *real_particle_numbers;
140 };
141
142 struct tng_trajectory_frame_set {
143     /** The number of different particle mapping blocks present. */
144     int64_t n_mapping_blocks;
145     /** The atom mappings of this frame set */
146     struct tng_particle_mapping *mappings;
147     /** The first frame of this frame set */
148     int64_t first_frame;
149     /** The number of frames in this frame set */
150     int64_t n_frames;
151     /** The number of written frames in this frame set (used when writing one
152      * frame at a time). */
153     int64_t n_written_frames;
154     /** The number of frames not yet written to file in this frame set
155      * (used from the utility functions to finish the writing properly. */
156     int64_t n_unwritten_frames;
157
158
159     /** A list of the number of each molecule type - only used when using
160      * variable number of atoms */
161     int64_t *molecule_cnt_list;
162     /** The number of particles/atoms - only used when using variable number
163      * of atoms */
164     int64_t n_particles;
165     /** The file position of the next frame set */
166     int64_t next_frame_set_file_pos;
167     /** The file position of the previous frame set */
168     int64_t prev_frame_set_file_pos;
169     /** The file position of the frame set one long stride step ahead */
170     int64_t medium_stride_next_frame_set_file_pos;
171     /** The file position of the frame set one long stride step behind */
172     int64_t medium_stride_prev_frame_set_file_pos;
173     /** The file position of the frame set one long stride step ahead */
174     int64_t long_stride_next_frame_set_file_pos;
175     /** The file position of the frame set one long stride step behind */
176     int64_t long_stride_prev_frame_set_file_pos;
177     /** Time stamp (in seconds) of first frame in frame set */
178     double first_frame_time;
179
180     /* The data blocks in a frame set are trajectory data blocks */
181     /** The number of trajectory data blocks of particle dependent data */
182     int n_particle_data_blocks;
183     /** A list of data blocks containing particle dependent data */
184     struct tng_particle_data *tr_particle_data;
185     /** The number of trajectory data blocks independent of particles */
186     int n_data_blocks;
187     /** A list of data blocks containing particle indepdendent data */
188     struct tng_non_particle_data *tr_data;
189 };
190
191 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
192 /* FIXME: Make only one data block struct */
193 struct tng_particle_data {
194     /** The block ID of the data block containing this particle data.
195      *  This is used to determine the kind of data that is stored */
196     int64_t block_id;
197     /** The name of the data block. This is used to determine the kind of
198      *  data that is stored */
199     char *block_name;
200     /** The type of data stored. */
201     char datatype;
202     /** The frame number of the first data value */
203     int64_t first_frame_with_data;
204     /** The number of frames in this frame set */
205     int64_t n_frames;
206     /** The number of values stored per frame */
207     int64_t n_values_per_frame;
208     /** The number of frames between each data point - e.g. when
209      *  storing sparse data. */
210     int64_t stride_length;
211     /** ID of the CODEC used for compression 0 == no compression. */
212     int64_t codec_id;
213     /** If reading one frame at a time this is the last read frame */
214     int64_t last_retrieved_frame;
215     /** The multiplier used for getting integer values for compression */
216     double compression_multiplier;
217     /** A 1-dimensional array of values of length
218      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
219     void *values;
220     /** If storing character data store it in a 3-dimensional array */
221     char ****strings;
222 };
223
224 struct tng_non_particle_data {
225     /** The ID of the data block */
226     int64_t block_id;
227     /** The name of the data block. This is used to determine the kind of
228      *  data that is stored */
229     char *block_name;
230     /** The type of data stored. */
231     char datatype;
232     /** The first frame number of the first data value */
233     int64_t first_frame_with_data;
234     /** The number of frames in this data block */
235     int64_t n_frames;
236     /** The number of values stored per frame */
237     int64_t n_values_per_frame;
238     /** The number of frames between each data value, e.g. if storing data
239      *  that is not saved every frame. */
240     int64_t stride_length;
241     /** ID of the CODEC used for compression. 0 == no compression. */
242     int64_t codec_id;
243     /** If reading one frame at a time this is the last read frame */
244     int64_t last_retrieved_frame;
245     /** Compressed data is stored as integers. This compression multiplier is
246      *  the multiplication factor to convert from integer to float/double */
247     double compression_multiplier;
248     /** A 1-dimensional array of values of length
249      *  [sizeof (datatype)] * n_frames * n_values_per_frame */
250     void *values;
251     /** If storing character data store it in a 2-dimensional array */
252     char ***strings;
253 };
254
255
256
257 struct tng_trajectory {
258     /** The path of the input trajectory file */
259     char *input_file_path;
260     /** A handle to the input file */
261     FILE *input_file;
262     /** The length of the input file */
263     long input_file_len;
264     /** The path of the output trajectory file */
265     char *output_file_path;
266     /** A handle to the output file */
267     FILE *output_file;
268     /** Function to swap 32 bit values to and from the endianness of the
269      * input file */
270     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
271     /** Function to swap 64 bit values to and from the endianness of the
272      * input file */
273     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
274     /** Function to swap 32 bit values to and from the endianness of the
275      * input file */
276     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
277     /** Function to swap 64 bit values to and from the endianness of the
278      * input file */
279     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
280     /** The endianness of 32 bit values of the current computer */
281     char endianness_32;
282     /** The endianness of 64 bit values of the current computer */
283     char endianness_64;
284
285     /** The name of the program producing this trajectory */
286     char *first_program_name;
287     /** The forcefield used in the simulations */
288     char *forcefield_name;
289     /** The name of the user running the simulations */
290     char *first_user_name;
291     /** The name of the computer on which the simulations were performed */
292     char *first_computer_name;
293     /** The PGP signature of the user creating the file. */
294     char *first_pgp_signature;
295     /** The name of the program used when making last modifications to the
296      *  file */
297     char *last_program_name;
298     /** The name of the user making the last modifications to the file */
299     char *last_user_name;
300     /** The name of the computer on which the last modifications were made */
301     char *last_computer_name;
302     /** The PGP signature of the user making the last modifications to the
303      *  file. */
304     char *last_pgp_signature;
305     /** The time (n seconds since 1970) when the file was created */
306     int64_t time;
307     /** The exponential of the value of the distance unit used. The default
308      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
309      * the measurements are in Ã… the distance_unit_exponential = -10. */
310     int64_t distance_unit_exponential;
311
312     /** A flag indicating if the number of atoms can vary throughout the
313      *  simulation, e.g. using a grand canonical ensemble */
314     char var_num_atoms_flag;
315     /** The number of frames in a frame set. It is allowed to have frame sets
316      *  with fewer frames, but this will help searching for specific frames */
317     int64_t frame_set_n_frames;
318     /** The number of frame sets in a medium stride step */
319     int64_t medium_stride_length;
320     /** The number of frame sets in a long stride step */
321     int64_t long_stride_length;
322     /** The current (can change from one frame set to another) time length
323      *  (in seconds) of one frame */
324     double time_per_frame;
325
326     /** The number of different kinds of molecules in the trajectory */
327     int64_t n_molecules;
328     /** A list of molecules in the trajectory */
329     tng_molecule_t molecules;
330     /** A list of the count of each molecule - if using variable number of
331      *  particles this will be specified in each frame set */
332     int64_t *molecule_cnt_list;
333     /** The total number of particles/atoms. If using variable number of
334      *  particles this will be specified in each frame set */
335     int64_t n_particles;
336
337      /** The pos in the src file of the first frame set */
338     int64_t first_trajectory_frame_set_input_file_pos;
339     /** The pos in the dest file of the first frame set */
340     int64_t first_trajectory_frame_set_output_file_pos;
341     /** The pos in the src file of the last frame set */
342     int64_t last_trajectory_frame_set_input_file_pos;
343     /** The pos in the dest file of the last frame set */
344     int64_t last_trajectory_frame_set_output_file_pos;
345     /** The currently active frame set */
346     struct tng_trajectory_frame_set current_trajectory_frame_set;
347     /** The pos in the src file of the current frame set */
348     long current_trajectory_frame_set_input_file_pos;
349     /** The pos in the dest file of the current frame set */
350     long current_trajectory_frame_set_output_file_pos;
351     /** The number of frame sets in the trajectory N.B. Not saved in file and
352      *  cannot be trusted to be up-to-date */
353     int64_t n_trajectory_frame_sets;
354
355     /* These data blocks are non-trajectory data blocks */
356     /** The number of non-frame dependent particle dependent data blocks */
357     int n_particle_data_blocks;
358     /** A list of data blocks containing particle dependent data */
359     struct tng_particle_data *non_tr_particle_data;
360
361     /** The number of frame and particle independent data blocks */
362     int n_data_blocks;
363     /** A list of frame and particle indepdendent data blocks */
364     struct tng_non_particle_data *non_tr_data;
365
366     /** TNG compression algorithm for compressing positions */
367     int *compress_algo_pos;
368     /** TNG compression algorithm for compressing velocities */
369     int *compress_algo_vel;
370     /** The precision used for lossy compression */
371     double compression_precision;
372 };
373
374 #ifndef USE_WINDOWS
375 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
376 #define USE_WINDOWS
377 #endif /* win32... */
378 #endif /* not defined USE_WINDOWS */
379
380 #ifdef USE_WINDOWS
381 #define TNG_INLINE __inline
382 #define TNG_SNPRINTF _snprintf
383 #else
384 #define TNG_INLINE inline
385 #define TNG_SNPRINTF snprintf
386 #endif
387
388 static TNG_INLINE int tng_min_i(int a, int b)
389 {
390     return (a < b ? a : b);
391 }
392
393 /*
394 static TNG_INLINE int tng_max_i(int a, int b)
395 {
396     return (a > b ? a : b);
397 }
398 */
399 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
400 {
401     return (a < b ? a : b);
402 }
403
404 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
405 {
406     return (a > b ? a : b);
407 }
408
409 /*
410 static TNG_INLINE float tng_min_f(float a, float b)
411 {
412     return (a < b ? a : b);
413 }
414
415 static TNG_INLINE float tng_max_f(float a, float b)
416 {
417     return (a > b ? a : b);
418 }
419
420 static TNG_INLINE double tng_min_d(double a, double b)
421 {
422     return (a < b ? a : b);
423 }
424
425 static TNG_INLINE double tng_max_d(double a, double b)
426 {
427     return (a > b ? a : b);
428 }
429 */
430
431 /** This function swaps the byte order of a 32 bit numerical variable
432  * to big endian.
433  * It does not only work with integer, but e.g. floats need casting.
434  * If the byte order is already big endian no change is needed.
435  * @param tng_data is a trajectory data container.
436  * @param v is a pointer to a 32 bit numerical value (float or integer).
437  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
438  * byte order is not recognised.
439  */
440 static tng_function_status tng_swap_byte_order_big_endian_32
441                 (const tng_trajectory_t tng_data, int32_t *v)
442 {
443     switch(tng_data->endianness_32)
444     {
445     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
446         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
447              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
448              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
449              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
450
451         return(TNG_SUCCESS);
452
453     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
454         *v = ((*v & 0xFFFF0000) >> 16) |
455              ((*v & 0x0000FFFF) << 16);
456
457         return(TNG_SUCCESS);
458
459     case TNG_BIG_ENDIAN_32: /* Already correct */
460         return(TNG_SUCCESS);
461
462     default:
463         return(TNG_FAILURE);
464     }
465 }
466
467 /** This function swaps the byte order of a 64 bit numerical variable
468  * to big endian.
469  * It does not only work with integer, but e.g. floats need casting.
470  * The byte order swapping routine can convert four different byte
471  * orders to big endian.
472  * If the byte order is already big endian no change is needed.
473  * @param tng_data is a trajectory data container.
474  * @param v is a pointer to a 64 bit numerical value (double or integer).
475  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
476  * byte order is not recognised.
477  */
478 static tng_function_status tng_swap_byte_order_big_endian_64
479                 (const tng_trajectory_t tng_data, int64_t *v)
480 {
481     switch(tng_data->endianness_64)
482     {
483     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
484         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
485              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
486              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
487              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
488              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
489              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
490              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
491              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
492
493         return(TNG_SUCCESS);
494
495     case TNG_QUAD_SWAP_64: /* Byte quad swap */
496         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
497              ((*v & 0x00000000FFFFFFFFLL) << 32);
498
499         return(TNG_SUCCESS);
500
501     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
502         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
503              ((*v & 0x0000FFFF0000FFFFLL) << 16);
504
505         return(TNG_SUCCESS);
506
507     case TNG_BYTE_SWAP_64: /* Byte swap */
508         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
509              ((*v & 0x00FF00FF00FF00FFLL) << 8);
510
511         return(TNG_SUCCESS);
512
513     case TNG_BIG_ENDIAN_64: /* Already correct */
514         return(TNG_SUCCESS);
515
516     default:
517         return(TNG_FAILURE);
518     }
519 }
520
521 /** This function swaps the byte order of a 32 bit numerical variable
522  * to little endian.
523  * It does not only work with integer, but e.g. floats need casting.
524  * If the byte order is already little endian no change is needed.
525  * @param tng_data is a trajectory data container.
526  * @param v is a pointer to a 32 bit numerical value (float or integer).
527  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
528  * byte order is not recognised.
529  */
530 static tng_function_status tng_swap_byte_order_little_endian_32
531                 (const tng_trajectory_t tng_data, int32_t *v)
532 {
533     switch(tng_data->endianness_32)
534     {
535     case TNG_LITTLE_ENDIAN_32: /* Already correct */
536         return(TNG_SUCCESS);
537
538     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
539         *v = ((*v & 0xFF00FF00) >> 8) |
540              ((*v & 0x00FF00FF) << 8);
541
542         return(TNG_SUCCESS);
543
544     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
545         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
546              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
547              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
548              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
549
550         return(TNG_SUCCESS);
551
552     default:
553         return(TNG_FAILURE);
554     }
555 }
556
557 /** This function swaps the byte order of a 64 bit numerical variable
558  * to little endian.
559  * It does not only work with integer, but e.g. floats need casting.
560  * The byte order swapping routine can convert four different byte
561  * orders to little endian.
562  * If the byte order is already little endian no change is needed.
563  * @param tng_data is a trajectory data container.
564  * @param v is a pointer to a 64 bit numerical value (double or integer).
565  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
566  * byte order is not recognised.
567  */
568 static tng_function_status tng_swap_byte_order_little_endian_64
569                 (const tng_trajectory_t tng_data, int64_t *v)
570 {
571     switch(tng_data->endianness_64)
572     {
573     case TNG_LITTLE_ENDIAN_64: /* Already correct */
574         return(TNG_SUCCESS);
575
576     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
577         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
578              ((*v & 0x00FF000000FF0000LL) >> 8) |
579              ((*v & 0x0000FF000000FF00LL) << 8) |
580              ((*v & 0x000000FF000000FFLL) << 24);
581
582         return(TNG_SUCCESS);
583
584     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
585         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
586              ((*v & 0x00FF00FF00000000LL) >> 24) |
587              ((*v & 0x00000000FF00FF00LL) << 24) |
588              ((*v & 0x0000000000FF00FFLL) << 40);
589
590         return(TNG_SUCCESS);
591
592     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
593         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
594              ((*v & 0x0000FFFF00000000LL) >> 16) |
595              ((*v & 0x00000000FFFF0000LL) << 16) |
596              ((*v & 0x000000000000FFFFLL) << 48);
597
598         return(TNG_SUCCESS);
599
600     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
601         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
602              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
603              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
604              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
605              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
606              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
607              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
608              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
609
610         return(TNG_SUCCESS);
611
612     default:
613         return(TNG_FAILURE);
614     }
615 }
616 /** Generate the md5 hash of a block.
617  * The hash is created based on the actual block contents.
618  * @param block is a general block container.
619  * @return TNG_SUCCESS (0) if successful.
620  */
621 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
622 {
623     md5_state_t md5_state;
624
625     md5_init(&md5_state);
626     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
627                (int)block->block_contents_size);
628     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
629
630     return(TNG_SUCCESS);
631 }
632
633 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
634  * calculated from the current contents.
635  * If the current md5 hash is not set skip the comparison.
636  * @param block is a general block container.
637  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
638  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
639  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
640  * set.
641  */
642 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
643                                                      tng_bool *results)
644 {
645     md5_state_t md5_state;
646     char hash[TNG_MD5_HASH_LEN];
647
648     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
649
650     *results = TNG_TRUE;
651     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
652     {
653         return(TNG_FAILURE);
654     }
655     md5_init(&md5_state);
656     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
657                (int)block->block_contents_size);
658     md5_finish(&md5_state, (md5_byte_t *)hash);
659
660     if(strncmp(block->md5_hash, hash, 16) != 0)
661     {
662         *results = TNG_FALSE;
663     }
664
665     return(TNG_SUCCESS);
666 }
667
668 /** Open the input file if it is not already opened.
669  * @param tng_data is a trajectory data container.
670  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
671  * error has occured.
672  */
673 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
674 {
675     if(!tng_data->input_file)
676     {
677         if(!tng_data->input_file_path)
678         {
679             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
680                    __FILE__, __LINE__);
681             return(TNG_CRITICAL);
682         }
683         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
684         if(!tng_data->input_file)
685         {
686             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
687                    tng_data->input_file_path, __FILE__, __LINE__);
688             return(TNG_CRITICAL);
689         }
690     }
691     return(TNG_SUCCESS);
692 }
693
694 /** Open the output file if it is not already opened
695  * @param tng_data is a trajectory data container.
696  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
697  * error has occured.
698  */
699 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
700 {
701     if(!tng_data->output_file)
702     {
703         if(!tng_data->output_file_path)
704         {
705             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
706                    __FILE__, __LINE__);
707             return(TNG_CRITICAL);
708         }
709
710         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
711
712         if(!tng_data->output_file)
713         {
714             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
715                    tng_data->output_file_path, __FILE__, __LINE__);
716             return(TNG_CRITICAL);
717         }
718     }
719     return(TNG_SUCCESS);
720 }
721
722 /** Setup a file block container.
723  * @param block_p a pointer to memory to initialise as a file block container.
724  * @details Memory is allocated during initialisation.
725  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
726  * error has occured.
727  */
728 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
729 {
730     tng_gen_block_t block;
731
732     *block_p = malloc(sizeof(struct tng_gen_block));
733     if(!*block_p)
734     {
735         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
736                sizeof(struct tng_gen_block), __FILE__, __LINE__);
737         return(TNG_CRITICAL);
738     }
739
740     block = *block_p;
741
742     block->id = -1;
743     /* Reset the md5_hash */
744     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
745     block->name = 0;
746     block->block_version = TNG_API_VERSION;
747     block->header_contents = 0;
748     block->header_contents_size = 0;
749     block->block_contents = 0;
750     block->block_contents_size = 0;
751
752     return(TNG_SUCCESS);
753 }
754
755 /**
756  * @brief Clean up a file block container.
757  * @param block_p a pointer to the file block container to destroy.
758  * @details All allocated memory in the data structure is freed, as well as
759  * block_p itself.
760  * @return TNG_SUCCESS (0) if successful.
761  */
762 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
763 {
764     tng_gen_block_t block = *block_p;
765
766     if(!*block_p)
767     {
768         return(TNG_SUCCESS);
769     }
770
771 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
772     if(block->name)
773     {
774         free(block->name);
775         block->name = 0;
776     }
777     if(block->header_contents)
778     {
779         free(block->header_contents);
780         block->header_contents = 0;
781     }
782     if(block->block_contents)
783     {
784         free(block->block_contents);
785         block->block_contents = 0;
786     }
787
788     free(*block_p);
789     *block_p = 0;
790
791     return(TNG_SUCCESS);
792 }
793
794 /** Read the header of a data block, regardless of its type
795  * @param tng_data is a trajectory data container.
796  * @param block is a general block container.
797  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
798  * error has occured (not able to read the header size, thus skipping
799  * the block) or TNG_CRITICAL (2) if a major error has occured.
800  */
801 static tng_function_status tng_block_header_read
802                 (tng_trajectory_t tng_data, tng_gen_block_t block)
803 {
804     int len, offset = 0;
805
806     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
807
808     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
809     {
810         return(TNG_CRITICAL);
811     }
812
813     /* First read the header size to be able to read the whole header. */
814     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
815         1, tng_data->input_file) == 0)
816     {
817         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
818                __FILE__, __LINE__);
819         return(TNG_CRITICAL);
820     }
821
822     if(block->header_contents_size == 0)
823     {
824         block->id = -1;
825         return(TNG_FAILURE);
826     }
827
828     /* If this was the size of the general info block check the endianness */
829     if(ftell(tng_data->input_file) < 9)
830     {
831         /* File is little endian */
832         if ( *((const char*)&block->header_contents_size) != 0x00 &&
833              *((const char*)(&block->header_contents_size) + 7) == 0x00)
834         {
835             /* If the architecture endianness is little endian no byte swap
836              * will be needed. Otherwise use the functions to swap to little
837              * endian */
838             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
839             {
840                 tng_data->input_endianness_swap_func_32 = 0;
841             }
842             else
843             {
844                 tng_data->input_endianness_swap_func_32 =
845                 &tng_swap_byte_order_little_endian_32;
846             }
847             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
848             {
849                 tng_data->input_endianness_swap_func_64 = 0;
850             }
851             else
852             {
853                 tng_data->input_endianness_swap_func_64 =
854                 &tng_swap_byte_order_little_endian_64;
855             }
856         }
857         /* File is big endian */
858         else
859         {
860             /* If the architecture endianness is big endian no byte swap
861              * will be needed. Otherwise use the functions to swap to big
862              * endian */
863             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
864             {
865                 tng_data->input_endianness_swap_func_32 = 0;
866             }
867             else
868             {
869                 tng_data->input_endianness_swap_func_32 =
870                 &tng_swap_byte_order_big_endian_32;
871             }
872             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
873             {
874                 tng_data->input_endianness_swap_func_64 = 0;
875             }
876             else
877             {
878                 tng_data->input_endianness_swap_func_64 =
879                 &tng_swap_byte_order_big_endian_64;
880             }
881         }
882     }
883
884     if(tng_data->input_endianness_swap_func_64)
885     {
886         if(tng_data->input_endianness_swap_func_64(tng_data,
887                                                    &block->header_contents_size)
888             != TNG_SUCCESS)
889         {
890             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
891                     __FILE__, __LINE__);
892         }
893     }
894
895     /* Move the reading position to the beginning of the header. */
896     fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
897           SEEK_CUR);
898
899     /* If there is already memory allocated for the contents free it (we do not
900      * know if the size is correct). */
901     if(block->header_contents)
902     {
903         free(block->header_contents);
904     }
905
906     block->header_contents = malloc(block->header_contents_size);
907     if(!block->header_contents)
908     {
909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
910                block->header_contents_size, __FILE__, __LINE__);
911         return(TNG_CRITICAL);
912     }
913
914     /* Read the whole header into header_contents. This way it can be saved
915      * even if it cannot be interpreted
916      * for one reason or another. */
917     if(fread(block->header_contents, block->header_contents_size, 1,
918         tng_data->input_file) == 0)
919     {
920         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
921         return(TNG_CRITICAL);
922     }
923
924     /* The header contents size has already been read. Skip ahead. */
925     offset = sizeof(block->header_contents_size);
926
927
928     /* Copy the respective parameters from the header contents block */
929     memcpy(&block->block_contents_size, block->header_contents+offset,
930            sizeof(block->block_contents_size));
931     if(tng_data->input_endianness_swap_func_64)
932     {
933         if(tng_data->input_endianness_swap_func_64(tng_data,
934                                                    &block->block_contents_size)
935             != TNG_SUCCESS)
936         {
937             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
938                     __FILE__, __LINE__);
939         }
940     }
941
942     offset += sizeof(block->block_contents_size);
943
944     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
945     if(tng_data->input_endianness_swap_func_64)
946     {
947         if(tng_data->input_endianness_swap_func_64(tng_data,
948                                                    &block->id)
949             != TNG_SUCCESS)
950         {
951             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
952                     __FILE__, __LINE__);
953         }
954     }
955
956     offset += sizeof(block->id);
957
958     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
959     offset += TNG_MD5_HASH_LEN;
960
961     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
962     {
963         free(block->name);
964         block->name = 0;
965     }
966     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
967     if(!block->name)
968     {
969         block->name = malloc(len);
970         if(!block->name)
971         {
972             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
973                     __FILE__, __LINE__);
974             return(TNG_CRITICAL);
975         }
976         strncpy(block->name, block->header_contents+offset, len);
977     }
978     offset += len;
979
980     memcpy(&block->block_version, block->header_contents+offset,
981            sizeof(block->block_version));
982     if(tng_data->input_endianness_swap_func_64)
983     {
984         if(tng_data->input_endianness_swap_func_64(tng_data,
985                                                    &block->block_version)
986             != TNG_SUCCESS)
987         {
988             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
989                     __FILE__, __LINE__);
990         }
991     }
992
993     return(TNG_SUCCESS);
994 }
995
996 /** Write a whole block, both header and contents, regardless of it type
997  * @param tng_data is a trajectory data container.
998  * @param block is a general block container.
999  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1000  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1001  */
1002 /* Disabled until it is used.*/
1003 /*
1004 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1005 //                                                     tng_gen_block_t block)
1006 // {
1007 //     if(!block->header_contents)
1008 //     {
1009 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1010 //         return(TNG_FAILURE);
1011 //     }
1012 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1013 //                 tng_data->output_file) != 1)
1014 //     {
1015 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1016 //                 __FILE__, __LINE__);
1017 //         return(TNG_CRITICAL);
1018 //     }
1019 //
1020 //     if(!block->block_contents)
1021 //     {
1022 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1023 //                 __FILE__, __LINE__);
1024 //         return(TNG_FAILURE);
1025 //     }
1026 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1027 //                 tng_data->output_file) != 1)
1028 //     {
1029 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1030 //                 __FILE__, __LINE__);
1031 //         return(TNG_CRITICAL);
1032 //     }
1033 //     return(TNG_SUCCESS);
1034 // }
1035 */
1036
1037 /** Update the md5 hash of a block already written to the file
1038  * @param tng_data is a trajectory data container.
1039  * @param block is the block, of which to update the md5 hash.
1040  * @param header_start_pos is the file position where the block header starts.
1041  * @param contents_start_pos is the file position where the block contents
1042  * start.
1043  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1044  * error has occured.
1045  */
1046 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
1047                                                tng_gen_block_t block,
1048                                                const int64_t header_start_pos,
1049                                                const int64_t contents_start_pos)
1050 {
1051     if(block->block_contents)
1052     {
1053         free(block->block_contents);
1054     }
1055
1056     block->block_contents = malloc(block->block_contents_size);
1057     if(!block->block_contents)
1058     {
1059         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1060                block->block_contents_size, __FILE__, __LINE__);
1061         return(TNG_CRITICAL);
1062     }
1063
1064     fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
1065     if(fread(block->block_contents, block->block_contents_size, 1,
1066             tng_data->output_file) == 0)
1067     {
1068         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1069         return(TNG_CRITICAL);
1070     }
1071
1072     tng_block_md5_hash_generate(block);
1073
1074     fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
1075           SEEK_SET);
1076     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1077
1078     return(TNG_SUCCESS);
1079 }
1080
1081 /** Update the frame set pointers in the file header (general info block),
1082  * already written to disk
1083  * @param tng_data is a trajectory data container.
1084  * @param hash_mode specifies whether to update the block md5 hash when
1085  * updating the pointers.
1086  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1087  * error has occured.
1088  */
1089 static tng_function_status tng_header_pointers_update
1090                 (tng_trajectory_t tng_data, const char hash_mode)
1091 {
1092     tng_gen_block_t block;
1093     FILE *temp = tng_data->input_file;
1094     int64_t output_file_pos, pos, contents_start_pos;
1095
1096     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1097     {
1098         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1099                __FILE__, __LINE__);
1100         return(TNG_CRITICAL);
1101     }
1102
1103     tng_data->input_file = tng_data->output_file;
1104
1105     tng_block_init(&block);
1106
1107     output_file_pos = ftell(tng_data->output_file);
1108     fseek(tng_data->output_file, 0, SEEK_SET);
1109
1110     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1111     {
1112         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1113                __FILE__, __LINE__);
1114         tng_data->input_file = temp;
1115         tng_block_destroy(&block);
1116         return(TNG_CRITICAL);
1117     }
1118
1119     contents_start_pos = ftell(tng_data->output_file);
1120
1121     fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
1122           sizeof(int64_t), SEEK_CUR);
1123
1124     tng_data->input_file = temp;
1125
1126     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1127
1128     if(tng_data->input_endianness_swap_func_64)
1129     {
1130         if(tng_data->input_endianness_swap_func_64(tng_data,
1131                                                     &pos)
1132             != TNG_SUCCESS)
1133         {
1134             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1135                     __FILE__, __LINE__);
1136         }
1137     }
1138
1139     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1140     {
1141         tng_block_destroy(&block);
1142         return(TNG_CRITICAL);
1143     }
1144
1145     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1146
1147     if(tng_data->input_endianness_swap_func_64)
1148     {
1149         if(tng_data->input_endianness_swap_func_64(tng_data,
1150                                                     &pos)
1151             != TNG_SUCCESS)
1152         {
1153             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1154                     __FILE__, __LINE__);
1155         }
1156     }
1157
1158     if(fwrite(&pos,
1159         sizeof(int64_t), 1, tng_data->output_file) != 1)
1160     {
1161         tng_block_destroy(&block);
1162         return(TNG_CRITICAL);
1163     }
1164
1165     if(hash_mode == TNG_USE_HASH)
1166     {
1167         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1168     }
1169
1170     tng_block_destroy(&block);
1171
1172     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1173
1174     return(TNG_SUCCESS);
1175 }
1176
1177 /** Update the frame set pointers in the current frame set block, already
1178  * written to disk. It also updates the pointers of the blocks pointing to
1179  * the current frame set block.
1180  * @param tng_data is a trajectory data container.
1181  * @param hash_mode specifies whether to update the block md5 hash when
1182  * updating the pointers.
1183  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1184  * error has occured.
1185  */
1186 static tng_function_status tng_frame_set_pointers_update
1187                 (tng_trajectory_t tng_data, const char hash_mode)
1188 {
1189     tng_gen_block_t block;
1190     tng_trajectory_frame_set_t frame_set;
1191     FILE *temp = tng_data->input_file;
1192     int64_t pos, output_file_pos, contents_start_pos;
1193
1194     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1195     {
1196         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1197                __FILE__, __LINE__);
1198         return(TNG_CRITICAL);
1199     }
1200
1201     tng_block_init(&block);
1202     output_file_pos = ftell(tng_data->output_file);
1203
1204     tng_data->input_file = tng_data->output_file;
1205
1206     frame_set = &tng_data->current_trajectory_frame_set;
1207
1208     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1209
1210     /* Update next frame set */
1211     if(frame_set->next_frame_set_file_pos > 0)
1212     {
1213         fseek(tng_data->output_file, (long)frame_set->next_frame_set_file_pos,
1214               SEEK_SET);
1215
1216         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1217         {
1218             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1219                 __FILE__, __LINE__);
1220             tng_data->input_file = temp;
1221             tng_block_destroy(&block);
1222             return(TNG_CRITICAL);
1223         }
1224
1225         contents_start_pos = ftell(tng_data->output_file);
1226
1227         fseek(tng_data->output_file, (long)block->block_contents_size - (5 *
1228             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1229
1230         if(tng_data->input_endianness_swap_func_64)
1231         {
1232             if(tng_data->input_endianness_swap_func_64(tng_data,
1233                                                         &pos)
1234                 != TNG_SUCCESS)
1235             {
1236                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1237                         __FILE__, __LINE__);
1238             }
1239         }
1240
1241         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1242         {
1243             tng_data->input_file = temp;
1244             tng_block_destroy(&block);
1245             return(TNG_CRITICAL);
1246         }
1247
1248         if(hash_mode == TNG_USE_HASH)
1249         {
1250             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1251                                 contents_start_pos);
1252         }
1253         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1254     }
1255     /* Update previous frame set */
1256     if(frame_set->prev_frame_set_file_pos > 0)
1257     {
1258         fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
1259               SEEK_SET);
1260
1261         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1262         {
1263             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1264                 __FILE__, __LINE__);
1265             tng_data->input_file = temp;
1266             tng_block_destroy(&block);
1267             return(TNG_CRITICAL);
1268         }
1269
1270         contents_start_pos = ftell(tng_data->output_file);
1271
1272         fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
1273             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1274
1275         if(tng_data->input_endianness_swap_func_64)
1276         {
1277             if(tng_data->input_endianness_swap_func_64(tng_data,
1278                                                         &pos)
1279                 != TNG_SUCCESS)
1280             {
1281                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1282                         __FILE__, __LINE__);
1283             }
1284         }
1285
1286         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1287         {
1288             tng_data->input_file = temp;
1289             tng_block_destroy(&block);
1290             return(TNG_CRITICAL);
1291         }
1292
1293         if(hash_mode == TNG_USE_HASH)
1294         {
1295             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1296                                 contents_start_pos);
1297         }
1298         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1299     }
1300
1301     /* Update the frame set one medium stride step after */
1302     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1303     {
1304         fseek(tng_data->output_file,
1305               (long)frame_set->medium_stride_next_frame_set_file_pos,
1306               SEEK_SET);
1307
1308         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1309         {
1310             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1311                 __FILE__, __LINE__);
1312             tng_data->input_file = temp;
1313             tng_block_destroy(&block);
1314             return(TNG_CRITICAL);
1315         }
1316
1317         contents_start_pos = ftell(tng_data->output_file);
1318
1319         fseek(tng_data->output_file, (long)block->block_contents_size - (3 *
1320             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1321
1322         if(tng_data->input_endianness_swap_func_64)
1323         {
1324             if(tng_data->input_endianness_swap_func_64(tng_data,
1325                                                         &pos)
1326                 != TNG_SUCCESS)
1327             {
1328                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1329                         __FILE__, __LINE__);
1330             }
1331         }
1332
1333         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1334         {
1335             tng_data->input_file = temp;
1336             tng_block_destroy(&block);
1337             return(TNG_CRITICAL);
1338         }
1339
1340         if(hash_mode == TNG_USE_HASH)
1341         {
1342             tng_md5_hash_update(tng_data, block,
1343                                 frame_set->medium_stride_next_frame_set_file_pos,
1344                                 contents_start_pos);
1345         }
1346     }
1347     /* Update the frame set one medium stride step before */
1348     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1349     {
1350         fseek(tng_data->output_file,
1351               (long)frame_set->medium_stride_prev_frame_set_file_pos,
1352               SEEK_SET);
1353
1354         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1355         {
1356             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1357                 __FILE__, __LINE__);
1358             tng_data->input_file = temp;
1359             tng_block_destroy(&block);
1360             return(TNG_CRITICAL);
1361         }
1362
1363         contents_start_pos = ftell(tng_data->output_file);
1364
1365         fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
1366             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1367
1368         if(tng_data->input_endianness_swap_func_64)
1369         {
1370             if(tng_data->input_endianness_swap_func_64(tng_data,
1371                                                         &pos)
1372                 != TNG_SUCCESS)
1373             {
1374                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1375                         __FILE__, __LINE__);
1376             }
1377         }
1378
1379         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1380         {
1381             tng_data->input_file = temp;
1382             tng_block_destroy(&block);
1383             return(TNG_CRITICAL);
1384         }
1385
1386         if(hash_mode == TNG_USE_HASH)
1387         {
1388             tng_md5_hash_update(tng_data, block,
1389                                 frame_set->medium_stride_prev_frame_set_file_pos,
1390                                 contents_start_pos);
1391         }
1392     }
1393
1394     /* Update the frame set one long stride step after */
1395     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1396     {
1397         fseek(tng_data->output_file,
1398               (long)frame_set->long_stride_next_frame_set_file_pos,
1399               SEEK_SET);
1400
1401         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1402         {
1403             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1404                 __FILE__, __LINE__);
1405             tng_data->input_file = temp;
1406             tng_block_destroy(&block);
1407             return(TNG_CRITICAL);
1408         }
1409
1410         contents_start_pos = ftell(tng_data->output_file);
1411
1412         fseek(tng_data->output_file, (long)block->block_contents_size - (1 *
1413             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1414
1415         if(tng_data->input_endianness_swap_func_64)
1416         {
1417             if(tng_data->input_endianness_swap_func_64(tng_data,
1418                                                         &pos)
1419                 != TNG_SUCCESS)
1420             {
1421                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1422                         __FILE__, __LINE__);
1423             }
1424         }
1425
1426         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1427         {
1428             tng_data->input_file = temp;
1429             tng_block_destroy(&block);
1430             return(TNG_CRITICAL);
1431         }
1432
1433         if(hash_mode == TNG_USE_HASH)
1434         {
1435             tng_md5_hash_update(tng_data, block,
1436                                 frame_set->long_stride_next_frame_set_file_pos,
1437                                 contents_start_pos);
1438         }
1439     }
1440     /* Update the frame set one long stride step before */
1441     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1442     {
1443         fseek(tng_data->output_file,
1444               (long)frame_set->long_stride_prev_frame_set_file_pos,
1445               SEEK_SET);
1446
1447         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1448         {
1449             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1450                 __FILE__, __LINE__);
1451             tng_data->input_file = temp;
1452             tng_block_destroy(&block);
1453             return(TNG_CRITICAL);
1454         }
1455
1456         contents_start_pos = ftell(tng_data->output_file);
1457
1458         fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
1459             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1460
1461         if(tng_data->input_endianness_swap_func_64)
1462         {
1463             if(tng_data->input_endianness_swap_func_64(tng_data,
1464                                                         &pos)
1465                 != TNG_SUCCESS)
1466             {
1467                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1468                         __FILE__, __LINE__);
1469             }
1470         }
1471
1472         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1473         {
1474             tng_data->input_file = temp;
1475             tng_block_destroy(&block);
1476             return(TNG_CRITICAL);
1477         }
1478
1479         if(hash_mode == TNG_USE_HASH)
1480         {
1481             tng_md5_hash_update(tng_data, block,
1482                                 frame_set->long_stride_prev_frame_set_file_pos,
1483                                 contents_start_pos);
1484         }
1485     }
1486
1487     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
1488
1489     tng_data->input_file = temp;
1490
1491     tng_block_destroy(&block);
1492
1493     return(TNG_SUCCESS);
1494 }
1495
1496 static tng_function_status tng_reread_frame_set_at_file_pos
1497                 (tng_trajectory_t tng_data,
1498                  const int64_t pos)
1499 {
1500     tng_gen_block_t block;
1501     tng_function_status stat;
1502
1503     tng_block_init(&block);
1504
1505     fseek(tng_data->input_file, pos, SEEK_SET);
1506     if(pos > 0)
1507     {
1508         stat = tng_block_header_read(tng_data, block);
1509         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1510         {
1511             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1512                     __FILE__, __LINE__);
1513             tng_block_destroy(&block);
1514             return(TNG_FAILURE);
1515         }
1516
1517         if(tng_block_read_next(tng_data, block,
1518                                TNG_SKIP_HASH) != TNG_SUCCESS)
1519         {
1520             tng_block_destroy(&block);
1521             return(TNG_CRITICAL);
1522         }
1523     }
1524
1525     tng_block_destroy(&block);
1526
1527     return(TNG_SUCCESS);
1528 }
1529
1530 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1531                 (tng_trajectory_t tng_data,
1532                  int64_t *pos)
1533 {
1534     int64_t orig_pos, curr_frame_set_pos;
1535     tng_gen_block_t block;
1536     tng_function_status stat;
1537     tng_trajectory_frame_set_t frame_set =
1538     &tng_data->current_trajectory_frame_set;
1539
1540     orig_pos = ftell(tng_data->input_file);
1541     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1542
1543     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1544
1545     if(*pos <= 0)
1546     {
1547         return(TNG_SUCCESS);
1548     }
1549
1550     fseek(tng_data->input_file, *pos, SEEK_SET);
1551
1552     tng_block_init(&block);
1553     /* Read block headers first to see that a frame set block is found. */
1554     stat = tng_block_header_read(tng_data, block);
1555     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1556     {
1557         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1558                 __FILE__, __LINE__);
1559         tng_block_destroy(&block);
1560         return(TNG_FAILURE);
1561     }
1562
1563     if(tng_block_read_next(tng_data, block,
1564                            TNG_SKIP_HASH) != TNG_SUCCESS)
1565     {
1566         tng_block_destroy(&block);
1567         return(TNG_CRITICAL);
1568     }
1569
1570     /* Read all frame set blocks (not the blocks between them) */
1571     while(frame_set->next_frame_set_file_pos > 0)
1572     {
1573         fseek(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1574         stat = tng_block_header_read(tng_data, block);
1575         if(stat == TNG_CRITICAL)
1576         {
1577             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1578                     __FILE__, __LINE__);
1579             tng_block_destroy(&block);
1580             return(TNG_CRITICAL);
1581         }
1582         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1583         {
1584             return(TNG_FAILURE);
1585         }
1586
1587         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1588         if(stat != TNG_SUCCESS)
1589         {
1590             tng_block_destroy(&block);
1591             return(stat);
1592         }
1593         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1594         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1595            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1596         {
1597             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1598         }
1599     }
1600
1601     /* Re-read the frame set that used to be the current one */
1602     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1603
1604     fseek(tng_data->input_file, orig_pos, SEEK_SET);
1605
1606     tng_block_destroy(&block);
1607
1608     return(TNG_SUCCESS);
1609 }
1610
1611 static tng_function_status tng_frame_set_complete_migrate
1612                 (tng_trajectory_t tng_data,
1613                  int64_t block_start_pos,
1614                  int64_t block_len,
1615                  int64_t new_pos)
1616 {
1617     int64_t i;
1618     tng_bool updated = TNG_FALSE;
1619
1620     char *contents;
1621
1622     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1623     {
1624         return(TNG_CRITICAL);
1625     }
1626
1627     fseek(tng_data->input_file, block_start_pos, SEEK_SET);
1628
1629     contents = malloc(block_len);
1630     if(!contents)
1631     {
1632         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1633                 block_len, __FILE__, __LINE__);
1634         return(TNG_CRITICAL);
1635     }
1636
1637     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1638     {
1639         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1640                __FILE__, __LINE__);
1641         free(contents);
1642         return(TNG_CRITICAL);
1643     }
1644     fseek(tng_data->output_file, new_pos, SEEK_SET);
1645
1646     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1647     {
1648         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1649                 __FILE__, __LINE__);
1650         free(contents);
1651         return(TNG_CRITICAL);
1652     }
1653
1654     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1655
1656     tng_frame_set_pointers_update(tng_data, TNG_USE_HASH);
1657
1658     /* Update the general info block if needed */
1659     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1660     {
1661         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1662         updated = TNG_TRUE;
1663     }
1664     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1665     {
1666         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1667         updated = TNG_TRUE;
1668     }
1669     if(updated)
1670     {
1671         tng_header_pointers_update(tng_data, TNG_USE_HASH);
1672     }
1673
1674     /* Fill the block with NULL to avoid confusion. */
1675     for(i = 0; i < block_len; i++)
1676     {
1677         contents[i] = '\0';
1678     }
1679     fseek(tng_data->output_file, block_start_pos, SEEK_SET);
1680
1681     /* FIXME: casting block_len to size_t is dangerous */
1682     fwrite(contents, 1, block_len, tng_data->output_file);
1683
1684     free(contents);
1685
1686     return(TNG_SUCCESS);
1687 }
1688
1689 static tng_function_status tng_length_of_current_frame_set_contents_get
1690                 (tng_trajectory_t tng_data,
1691                  int64_t *len)
1692 {
1693     int64_t orig_pos, pos, curr_frame_set_pos;
1694     tng_gen_block_t block;
1695     tng_function_status stat;
1696
1697     orig_pos = ftell(tng_data->input_file);
1698     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1699
1700     *len = 0;
1701
1702     fseek(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1703
1704     tng_block_init(&block);
1705     /* Read block headers first to see that a frame set block is found. */
1706     stat = tng_block_header_read(tng_data, block);
1707     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1708     {
1709         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
1710                 curr_frame_set_pos, __FILE__, __LINE__);
1711         tng_block_destroy(&block);
1712         return(TNG_FAILURE);
1713     }
1714
1715     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1716     while(stat == TNG_SUCCESS)
1717     {
1718         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1719         *len += block->header_contents_size + block->block_contents_size;
1720         pos += block->header_contents_size + block->block_contents_size;
1721         if(pos >= tng_data->input_file_len)
1722         {
1723             break;
1724         }
1725         stat = tng_block_header_read(tng_data, block);
1726         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1727         {
1728             break;
1729         }
1730     }
1731
1732     /* Re-read the frame set that used to be the current one */
1733     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1734
1735     fseek(tng_data->input_file, orig_pos, SEEK_SET);
1736
1737     tng_block_destroy(&block);
1738
1739     return(TNG_SUCCESS);
1740 }
1741
1742 /** Migrate blocks in the file to make room for new data in a block. This
1743  * is required e.g. when adding data to a block or extending strings in a
1744  * block.
1745  * @param tng_data is a trajectory data container.
1746  * @param start_pos is the position from which to start moving data, usually
1747  * the byte after the end of the block to which data was added.
1748  * @param offset is the number of bytes that were inserted.
1749  * @details Trajectory blocks (frame sets and their related blocks) are moved
1750  * to the end of the file (if needed) in order to make room for non-trajectory
1751  * data.
1752  */
1753 static tng_function_status tng_migrate_data_in_file
1754                 (tng_trajectory_t tng_data,
1755                  int64_t start_pos,
1756                  int64_t offset)
1757 {
1758     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1759     tng_gen_block_t block;
1760     tng_function_status stat;
1761     FILE *temp;
1762
1763     if(offset <= 0)
1764     {
1765         return(TNG_SUCCESS);
1766     }
1767
1768     temp = tng_data->input_file;
1769
1770     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1771     if(stat != TNG_SUCCESS)
1772     {
1773         tng_data->input_file = temp;
1774         return(stat);
1775     }
1776
1777     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1778
1779     empty_space = traj_start_pos - (start_pos - 1);
1780
1781     if(empty_space >= offset)
1782     {
1783         return(TNG_SUCCESS);
1784     }
1785
1786     orig_file_pos = ftell(tng_data->input_file);
1787     tng_block_init(&block);
1788
1789     while(empty_space < offset)
1790     {
1791         fseek(tng_data->input_file, traj_start_pos, SEEK_SET);
1792         stat = tng_block_header_read(tng_data, block);
1793         if(stat == TNG_CRITICAL)
1794         {
1795             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1796                     __FILE__, __LINE__);
1797             tng_block_destroy(&block);
1798             tng_data->input_file = temp;
1799             return(TNG_CRITICAL);
1800         }
1801         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1802         {
1803             tng_data->input_file = temp;
1804             tng_block_destroy(&block);
1805             return(TNG_FAILURE);
1806         }
1807         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1808         if(stat != TNG_SUCCESS)
1809         {
1810             tng_data->input_file = temp;
1811             tng_block_destroy(&block);
1812             return(stat);
1813         }
1814         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1815                                               frame_set_length, tng_data->input_file_len);
1816         if(stat != TNG_SUCCESS)
1817         {
1818             tng_data->input_file = temp;
1819             tng_block_destroy(&block);
1820             return(stat);
1821         }
1822
1823         empty_space += frame_set_length;
1824     }
1825     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
1826     tng_block_destroy(&block);
1827
1828     return(TNG_SUCCESS);
1829 }
1830
1831 static tng_function_status tng_block_header_len_calculate
1832                 (const tng_trajectory_t tng_data,
1833                  tng_gen_block_t block,
1834                  int64_t *len)
1835 {
1836     int name_len;
1837     (void)tng_data;
1838
1839     /* If the string is unallocated allocate memory for just string
1840      * termination */
1841     if(!block->name)
1842     {
1843         block->name = malloc(1);
1844         if(!block->name)
1845         {
1846             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1847                    __FILE__, __LINE__);
1848             return(TNG_CRITICAL);
1849         }
1850         block->name[0] = 0;
1851     }
1852
1853     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1854
1855     /* Calculate the size of the header to write */
1856     *len = sizeof(block->header_contents_size) +
1857                   sizeof(block->block_contents_size) +
1858                   sizeof(block->id) +
1859                   sizeof(block->block_version) +
1860                   TNG_MD5_HASH_LEN +
1861                   name_len;
1862
1863     return (TNG_SUCCESS);
1864 }
1865
1866 /** Write the header of a data block, regardless of its type
1867  * @param tng_data is a trajectory data container.
1868  * @param block is a general block container.
1869  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1870  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1871  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1872  * error has occured.
1873  */
1874 static tng_function_status tng_block_header_write
1875                 (tng_trajectory_t tng_data,
1876                  tng_gen_block_t block,
1877                  const char hash_mode)
1878 {
1879     int name_len, offset = 0;
1880
1881     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1882
1883     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1884     {
1885         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1886                __FILE__, __LINE__);
1887         return(TNG_CRITICAL);
1888     }
1889
1890     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
1891         TNG_SUCCESS)
1892     {
1893         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
1894                 __FILE__, __LINE__);
1895         return(TNG_CRITICAL);
1896     }
1897
1898     if(hash_mode == TNG_USE_HASH)
1899     {
1900         tng_block_md5_hash_generate(block);
1901     }
1902
1903     if(block->header_contents)
1904     {
1905         free(block->header_contents);
1906     }
1907
1908     block->header_contents = malloc(block->header_contents_size);
1909     if(!block->header_contents)
1910     {
1911         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1912                block->header_contents_size, __FILE__, __LINE__);
1913         return(TNG_CRITICAL);
1914     }
1915
1916     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1917
1918     /* First copy all data into the header_contents block and finally write
1919      * the whole block at once. */
1920     memcpy(block->header_contents, &block->header_contents_size,
1921            sizeof(block->header_contents_size));
1922     if(tng_data->output_endianness_swap_func_64)
1923     {
1924         if(tng_data->output_endianness_swap_func_64(tng_data,
1925                                       (int64_t *)block->header_contents+offset)
1926             != TNG_SUCCESS)
1927         {
1928             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1929                     __FILE__, __LINE__);
1930         }
1931     }
1932     offset += sizeof(block->header_contents_size);
1933
1934     memcpy(block->header_contents+offset, &block->block_contents_size,
1935            sizeof(block->block_contents_size));
1936     if(tng_data->output_endianness_swap_func_64)
1937     {
1938         if(tng_data->output_endianness_swap_func_64(tng_data,
1939                                       (int64_t *)block->header_contents+offset)
1940             != TNG_SUCCESS)
1941         {
1942             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1943                     __FILE__, __LINE__);
1944         }
1945     }
1946     offset += sizeof(block->block_contents_size);
1947
1948     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1949     if(tng_data->output_endianness_swap_func_64)
1950     {
1951         if(tng_data->output_endianness_swap_func_64(tng_data,
1952                                       (int64_t *)block->header_contents+offset)
1953             != TNG_SUCCESS)
1954         {
1955             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1956                     __FILE__, __LINE__);
1957         }
1958     }
1959     offset += sizeof(block->id);
1960
1961     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1962     offset += TNG_MD5_HASH_LEN;
1963
1964     strncpy(block->header_contents+offset, block->name, name_len);
1965     offset += name_len;
1966
1967     memcpy(block->header_contents+offset, &block->block_version,
1968            sizeof(block->block_version));
1969     if(tng_data->output_endianness_swap_func_64)
1970     {
1971         if(tng_data->output_endianness_swap_func_64(tng_data,
1972                                       (int64_t *)block->header_contents+offset)
1973             != TNG_SUCCESS)
1974         {
1975             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1976                     __FILE__, __LINE__);
1977         }
1978     }
1979
1980     if(fwrite(block->header_contents, block->header_contents_size,
1981        1, tng_data->output_file) != 1)
1982     {
1983         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1984         return(TNG_CRITICAL);
1985     }
1986     return(TNG_SUCCESS);
1987 }
1988
1989 static tng_function_status tng_general_info_block_len_calculate
1990                 (tng_trajectory_t tng_data,
1991                  int64_t *len)
1992 {
1993     int first_program_name_len, first_user_name_len;
1994     int first_computer_name_len, first_pgp_signature_len;
1995     int last_program_name_len, last_user_name_len;
1996     int last_computer_name_len, last_pgp_signature_len;
1997     int forcefield_name_len;
1998
1999     /* If the strings are unallocated allocate memory for just string
2000      * termination */
2001     if(!tng_data->first_program_name)
2002     {
2003         tng_data->first_program_name = malloc(1);
2004         if(!tng_data->first_program_name)
2005         {
2006             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2007                    __FILE__, __LINE__);
2008             return(TNG_CRITICAL);
2009         }
2010         tng_data->first_program_name[0] = 0;
2011     }
2012     if(!tng_data->last_program_name)
2013     {
2014         tng_data->last_program_name = malloc(1);
2015         if(!tng_data->last_program_name)
2016         {
2017             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2018                    __FILE__, __LINE__);
2019             return(TNG_CRITICAL);
2020         }
2021         tng_data->last_program_name[0] = 0;
2022     }
2023     if(!tng_data->first_user_name)
2024     {
2025         tng_data->first_user_name = malloc(1);
2026         if(!tng_data->first_user_name)
2027         {
2028             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2029                    __FILE__, __LINE__);
2030             return(TNG_CRITICAL);
2031         }
2032         tng_data->first_user_name[0] = 0;
2033     }
2034     if(!tng_data->last_user_name)
2035     {
2036         tng_data->last_user_name = malloc(1);
2037         if(!tng_data->last_user_name)
2038         {
2039             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2040                    __FILE__, __LINE__);
2041             return(TNG_CRITICAL);
2042         }
2043         tng_data->last_user_name[0] = 0;
2044     }
2045     if(!tng_data->first_computer_name)
2046     {
2047         tng_data->first_computer_name = malloc(1);
2048         if(!tng_data->first_computer_name)
2049         {
2050             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2051                    __FILE__, __LINE__);
2052             return(TNG_CRITICAL);
2053         }
2054         tng_data->first_computer_name[0] = 0;
2055     }
2056     if(!tng_data->last_computer_name)
2057     {
2058         tng_data->last_computer_name = malloc(1);
2059         if(!tng_data->last_computer_name)
2060         {
2061             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2062                    __FILE__, __LINE__);
2063             return(TNG_CRITICAL);
2064         }
2065         tng_data->last_computer_name[0] = 0;
2066     }
2067     if(!tng_data->first_pgp_signature)
2068     {
2069         tng_data->first_pgp_signature = malloc(1);
2070         if(!tng_data->first_pgp_signature)
2071         {
2072             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2073                    __FILE__, __LINE__);
2074             return(TNG_CRITICAL);
2075         }
2076         tng_data->first_pgp_signature[0] = 0;
2077     }
2078     if(!tng_data->last_pgp_signature)
2079     {
2080         tng_data->last_pgp_signature = malloc(1);
2081         if(!tng_data->last_pgp_signature)
2082         {
2083             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2084                    __FILE__, __LINE__);
2085             return(TNG_CRITICAL);
2086         }
2087         tng_data->last_pgp_signature[0] = 0;
2088     }
2089     if(!tng_data->forcefield_name)
2090     {
2091         tng_data->forcefield_name = malloc(1);
2092         if(!tng_data->forcefield_name)
2093         {
2094             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2095                    __FILE__, __LINE__);
2096             return(TNG_CRITICAL);
2097         }
2098         tng_data->forcefield_name[0] = 0;
2099     }
2100
2101     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2102                            TNG_MAX_STR_LEN);
2103     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2104                            TNG_MAX_STR_LEN);
2105     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2106                         TNG_MAX_STR_LEN);
2107     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2108                         TNG_MAX_STR_LEN);
2109     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2110                             TNG_MAX_STR_LEN);
2111     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2112                             TNG_MAX_STR_LEN);
2113     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2114                             TNG_MAX_STR_LEN);
2115     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2116                             TNG_MAX_STR_LEN);
2117     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2118                               TNG_MAX_STR_LEN);
2119
2120     *len = sizeof(tng_data->time) +
2121                   sizeof(tng_data->var_num_atoms_flag) +
2122                   sizeof(tng_data->frame_set_n_frames) +
2123                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2124                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2125                   sizeof(tng_data->medium_stride_length) +
2126                   sizeof(tng_data->long_stride_length) +
2127                   sizeof(tng_data->distance_unit_exponential) +
2128                   first_program_name_len +
2129                   last_program_name_len +
2130                   first_user_name_len +
2131                   last_user_name_len +
2132                   first_computer_name_len +
2133                   last_computer_name_len +
2134                   first_pgp_signature_len +
2135                   last_pgp_signature_len +
2136                   forcefield_name_len;
2137
2138     return(TNG_SUCCESS);
2139 }
2140
2141 /** Read a general info block. This is the first block of a TNG file.
2142  *  Populate the fields in tng_data.
2143  * @param tng_data is a trajectory data container.
2144  * @param block is a general block container.
2145  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2146  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2147  * compared to the md5 hash of the read contents to ensure valid data.
2148  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2149  * error has occured.
2150  */
2151 static tng_function_status tng_general_info_block_read
2152                 (tng_trajectory_t tng_data, tng_gen_block_t block,
2153                  const char hash_mode)
2154 {
2155     int len, offset = 0;
2156     tng_bool same_hash;
2157
2158     void *temp;
2159
2160     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2161
2162     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2163     {
2164         return(TNG_CRITICAL);
2165     }
2166
2167     temp = realloc(block->block_contents, block->block_contents_size);
2168     if(!temp)
2169     {
2170         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2171                block->block_contents_size, __FILE__, __LINE__);
2172         free(block->block_contents);
2173         block->block_contents = 0;
2174         return(TNG_CRITICAL);
2175     }
2176     block->block_contents = temp;
2177
2178     /* Read the whole block into block_contents to be able to write it to disk
2179      * even if it cannot be interpreted. */
2180     if(fread(block->block_contents, block->block_contents_size, 1,
2181              tng_data->input_file) == 0)
2182     {
2183         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2184         return(TNG_CRITICAL);
2185     }
2186
2187     /* FIXME: Does not check if the size of the contents matches the expected
2188      * size or if the contents can be read. */
2189
2190     if(hash_mode == TNG_USE_HASH)
2191     {
2192         tng_md5_hash_match_verify(block, &same_hash);
2193         if(same_hash != TNG_TRUE)
2194         {
2195             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2196                 "%s: %d\n",
2197                 __FILE__, __LINE__);
2198     /*         return(TNG_FAILURE); */
2199         }
2200     }
2201
2202     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
2203     temp = realloc(tng_data->first_program_name, len);
2204     if(!temp)
2205     {
2206         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2207                __FILE__, __LINE__);
2208         free(tng_data->first_program_name);
2209         tng_data->first_program_name = 0;
2210         return(TNG_CRITICAL);
2211     }
2212     tng_data->first_program_name = temp;
2213     strncpy(tng_data->first_program_name, block->block_contents, len);
2214     offset += len;
2215
2216     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
2217     temp = realloc(tng_data->last_program_name, len);
2218     if(!temp)
2219     {
2220         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2221                __FILE__, __LINE__);
2222         free(tng_data->last_program_name);
2223         tng_data->last_program_name = 0;
2224         return(TNG_CRITICAL);
2225     }
2226     tng_data->last_program_name = temp;
2227     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
2228     offset += len;
2229
2230     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2231     temp = realloc(tng_data->first_user_name, len);
2232     if(!temp)
2233     {
2234         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2235                __FILE__, __LINE__);
2236         free(tng_data->first_user_name);
2237         tng_data->first_user_name = 0;
2238         return(TNG_CRITICAL);
2239     }
2240     tng_data->first_user_name = temp;
2241     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
2242     offset += len;
2243
2244     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2245     temp = realloc(tng_data->last_user_name, len);
2246     if(!temp)
2247     {
2248         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2249                __FILE__, __LINE__);
2250         free(tng_data->last_user_name);
2251         tng_data->last_user_name = 0;
2252         return(TNG_CRITICAL);
2253     }
2254     tng_data->last_user_name = temp;
2255     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
2256     offset += len;
2257
2258     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2259     temp = realloc(tng_data->first_computer_name, len);
2260     if(!temp)
2261     {
2262         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2263                __FILE__, __LINE__);
2264         free(tng_data->first_computer_name);
2265         tng_data->first_computer_name = 0;
2266         return(TNG_CRITICAL);
2267     }
2268     tng_data->first_computer_name = temp;
2269     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
2270     offset += len;
2271
2272     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2273     temp = realloc(tng_data->last_computer_name, len);
2274     if(!temp)
2275     {
2276         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2277                __FILE__, __LINE__);
2278         free(tng_data->last_computer_name);
2279         tng_data->last_computer_name = 0;
2280         return(TNG_CRITICAL);
2281     }
2282     tng_data->last_computer_name = temp;
2283     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
2284     offset += len;
2285
2286     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2287     temp = realloc(tng_data->first_pgp_signature, len);
2288     if(!temp)
2289     {
2290         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2291                __FILE__, __LINE__);
2292         free(tng_data->first_pgp_signature);
2293         tng_data->first_pgp_signature = 0;
2294         return(TNG_CRITICAL);
2295     }
2296     tng_data->first_pgp_signature = temp;
2297     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
2298     offset += len;
2299
2300     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2301     temp = realloc(tng_data->last_pgp_signature, len);
2302     if(!temp)
2303     {
2304         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2305                __FILE__, __LINE__);
2306         free(tng_data->last_pgp_signature);
2307         tng_data->last_pgp_signature = 0;
2308         return(TNG_CRITICAL);
2309     }
2310     tng_data->last_pgp_signature = temp;
2311     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
2312     offset += len;
2313
2314     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2315     temp = realloc(tng_data->forcefield_name, len);
2316     if(!temp)
2317     {
2318         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2319                __FILE__, __LINE__);
2320         free(tng_data->forcefield_name);
2321         tng_data->forcefield_name = 0;
2322         return(TNG_CRITICAL);
2323     }
2324     tng_data->forcefield_name = temp;
2325     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
2326     offset += len;
2327
2328     memcpy(&tng_data->time, block->block_contents+offset,
2329            sizeof(tng_data->time));
2330     if(tng_data->input_endianness_swap_func_64)
2331     {
2332         if(tng_data->input_endianness_swap_func_64(tng_data,
2333                                                    &tng_data->time)
2334             != TNG_SUCCESS)
2335         {
2336             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2337                     __FILE__, __LINE__);
2338         }
2339     }
2340     offset += sizeof(tng_data->time);
2341
2342     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
2343            sizeof(tng_data->var_num_atoms_flag));
2344     offset += sizeof(tng_data->var_num_atoms_flag);
2345
2346     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
2347            sizeof(tng_data->frame_set_n_frames));
2348     if(tng_data->input_endianness_swap_func_64)
2349     {
2350         if(tng_data->input_endianness_swap_func_64(tng_data,
2351                                                  &tng_data->frame_set_n_frames)
2352             != TNG_SUCCESS)
2353         {
2354             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2355                     __FILE__, __LINE__);
2356         }
2357     }
2358     offset += sizeof(tng_data->frame_set_n_frames);
2359
2360     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
2361            block->block_contents+offset,
2362            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
2363     if(tng_data->input_endianness_swap_func_64)
2364     {
2365         if(tng_data->input_endianness_swap_func_64(tng_data,
2366                           &tng_data->first_trajectory_frame_set_input_file_pos)
2367             != TNG_SUCCESS)
2368         {
2369             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2370                     __FILE__, __LINE__);
2371         }
2372     }
2373     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
2374
2375     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2376     tng_data->first_trajectory_frame_set_input_file_pos;
2377
2378
2379     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
2380            block->block_contents+offset,
2381            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
2382     if(tng_data->input_endianness_swap_func_64)
2383     {
2384         if(tng_data->input_endianness_swap_func_64(tng_data,
2385                           &tng_data->last_trajectory_frame_set_input_file_pos)
2386             != TNG_SUCCESS)
2387         {
2388             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2389                     __FILE__, __LINE__);
2390         }
2391     }
2392     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
2393
2394     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
2395            sizeof(tng_data->medium_stride_length));
2396     if(tng_data->input_endianness_swap_func_64)
2397     {
2398         if(tng_data->input_endianness_swap_func_64(tng_data,
2399                                                &tng_data->medium_stride_length)
2400             != TNG_SUCCESS)
2401         {
2402             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2403                     __FILE__, __LINE__);
2404         }
2405     }
2406     offset += sizeof(tng_data->medium_stride_length);
2407
2408     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
2409            sizeof(tng_data->long_stride_length));
2410     if(tng_data->input_endianness_swap_func_64)
2411     {
2412         if(tng_data->input_endianness_swap_func_64(tng_data,
2413                                                  &tng_data->long_stride_length)
2414             != TNG_SUCCESS)
2415         {
2416             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2417                     __FILE__, __LINE__);
2418         }
2419     }
2420     offset += sizeof(tng_data->long_stride_length);
2421
2422     if(block->block_version >= 3)
2423     {
2424         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
2425             sizeof(tng_data->distance_unit_exponential));
2426         if(tng_data->input_endianness_swap_func_64)
2427         {
2428             if(tng_data->input_endianness_swap_func_64(tng_data,
2429                                           &tng_data->distance_unit_exponential)
2430                 != TNG_SUCCESS)
2431             {
2432                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2433                         __FILE__, __LINE__);
2434             }
2435         }
2436     }
2437
2438     return(TNG_SUCCESS);
2439 }
2440
2441 /** Write a general info block. This is the first block of a TNG file.
2442  * @param tng_data is a trajectory data container.
2443  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2444  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2445  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2446  * error has occured.
2447  */
2448 static tng_function_status tng_general_info_block_write
2449                 (tng_trajectory_t tng_data,
2450                  const char hash_mode)
2451 {
2452     int first_program_name_len, first_user_name_len;
2453     int first_computer_name_len, first_pgp_signature_len;
2454     int last_program_name_len, last_user_name_len;
2455     int last_computer_name_len, last_pgp_signature_len;
2456     int forcefield_name_len, name_len;
2457     int offset = 0;
2458     tng_gen_block_t block;
2459
2460     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2461     {
2462         return(TNG_CRITICAL);
2463     }
2464
2465     fseek(tng_data->output_file, 0, SEEK_SET);
2466
2467     tng_block_init(&block);
2468
2469     name_len = (int)strlen("GENERAL INFO");
2470
2471     block->name = malloc(name_len + 1);
2472     if(!block->name)
2473     {
2474         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2475                 name_len+1, __FILE__, __LINE__);
2476         tng_block_destroy(&block);
2477         return(TNG_CRITICAL);
2478     }
2479
2480     strcpy(block->name, "GENERAL INFO");
2481     block->id = TNG_GENERAL_INFO;
2482
2483     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2484         TNG_SUCCESS)
2485     {
2486         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2487                 __FILE__, __LINE__);
2488         tng_block_destroy(&block);
2489         return(TNG_CRITICAL);
2490     }
2491
2492     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2493                            TNG_MAX_STR_LEN);
2494     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2495                            TNG_MAX_STR_LEN);
2496     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2497                         TNG_MAX_STR_LEN);
2498     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2499                         TNG_MAX_STR_LEN);
2500     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2501                             TNG_MAX_STR_LEN);
2502     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2503                             TNG_MAX_STR_LEN);
2504     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2505                             TNG_MAX_STR_LEN);
2506     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2507                             TNG_MAX_STR_LEN);
2508     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2509                               TNG_MAX_STR_LEN);
2510
2511     if(block->block_contents)
2512     {
2513         free(block->block_contents);
2514     }
2515     block->block_contents = malloc(block->block_contents_size);
2516     if(!block->block_contents)
2517     {
2518         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2519                block->block_contents_size, __FILE__, __LINE__);
2520         tng_block_destroy(&block);
2521         return(TNG_CRITICAL);
2522     }
2523
2524     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
2525     offset += first_program_name_len;
2526
2527     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
2528     offset += last_program_name_len;
2529
2530     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
2531     offset += first_user_name_len;
2532
2533     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
2534     offset += last_user_name_len;
2535
2536     strncpy(block->block_contents+offset, tng_data->first_computer_name,
2537             first_computer_name_len);
2538     offset += first_computer_name_len;
2539
2540     strncpy(block->block_contents+offset, tng_data->last_computer_name,
2541             last_computer_name_len);
2542     offset += last_computer_name_len;
2543
2544     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
2545             first_pgp_signature_len);
2546     offset += first_pgp_signature_len;
2547
2548     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
2549             last_pgp_signature_len);
2550     offset += last_pgp_signature_len;
2551
2552     strncpy(block->block_contents+offset, tng_data->forcefield_name,
2553             forcefield_name_len);
2554     offset += forcefield_name_len;
2555
2556     memcpy(block->block_contents+offset, &tng_data->time,
2557            sizeof(tng_data->time));
2558     if(tng_data->output_endianness_swap_func_64)
2559     {
2560         if(tng_data->output_endianness_swap_func_64(tng_data,
2561                                       (int64_t *)block->header_contents+offset)
2562             != TNG_SUCCESS)
2563         {
2564             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2565                     __FILE__, __LINE__);
2566         }
2567     }
2568     offset += sizeof(tng_data->time);
2569
2570     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
2571            sizeof(tng_data->var_num_atoms_flag));
2572     offset += sizeof(tng_data->var_num_atoms_flag);
2573
2574     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
2575            sizeof(tng_data->frame_set_n_frames));
2576     if(tng_data->output_endianness_swap_func_64)
2577     {
2578         if(tng_data->output_endianness_swap_func_64(tng_data,
2579                                       (int64_t *)block->header_contents+offset)
2580             != TNG_SUCCESS)
2581         {
2582             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2583                     __FILE__, __LINE__);
2584         }
2585     }
2586     offset += sizeof(tng_data->frame_set_n_frames);
2587
2588     memcpy(block->block_contents+offset,
2589            &tng_data->first_trajectory_frame_set_output_file_pos,
2590            sizeof(tng_data->first_trajectory_frame_set_output_file_pos));
2591     if(tng_data->output_endianness_swap_func_64)
2592     {
2593         if(tng_data->output_endianness_swap_func_64(tng_data,
2594                                       (int64_t *)block->header_contents+offset)
2595             != TNG_SUCCESS)
2596         {
2597             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2598                     __FILE__, __LINE__);
2599         }
2600     }
2601     offset += sizeof(tng_data->first_trajectory_frame_set_output_file_pos);
2602
2603     memcpy(block->block_contents+offset,
2604            &tng_data->last_trajectory_frame_set_output_file_pos,
2605            sizeof(tng_data->last_trajectory_frame_set_output_file_pos));
2606     if(tng_data->output_endianness_swap_func_64)
2607     {
2608         if(tng_data->output_endianness_swap_func_64(tng_data,
2609                                       (int64_t *)block->header_contents+offset)
2610             != TNG_SUCCESS)
2611         {
2612             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2613                     __FILE__, __LINE__);
2614         }
2615     }
2616     offset += sizeof(tng_data->last_trajectory_frame_set_output_file_pos);
2617
2618     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
2619            sizeof(tng_data->medium_stride_length));
2620     if(tng_data->output_endianness_swap_func_64)
2621     {
2622         if(tng_data->output_endianness_swap_func_64(tng_data,
2623                                       (int64_t *)block->header_contents+offset)
2624             != TNG_SUCCESS)
2625         {
2626             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2627                     __FILE__, __LINE__);
2628         }
2629     }
2630     offset += sizeof(tng_data->medium_stride_length);
2631
2632     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
2633            sizeof(tng_data->long_stride_length));
2634     if(tng_data->output_endianness_swap_func_64)
2635     {
2636         if(tng_data->output_endianness_swap_func_64(tng_data,
2637                                       (int64_t *)block->header_contents+offset)
2638             != TNG_SUCCESS)
2639         {
2640             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2641                     __FILE__, __LINE__);
2642         }
2643     }
2644     offset += sizeof(tng_data->long_stride_length);
2645
2646     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
2647            sizeof(tng_data->distance_unit_exponential));
2648     if(tng_data->output_endianness_swap_func_64)
2649     {
2650         if(tng_data->output_endianness_swap_func_64(tng_data,
2651                                       (int64_t *)block->header_contents+offset)
2652             != TNG_SUCCESS)
2653         {
2654             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2655                     __FILE__, __LINE__);
2656         }
2657     }
2658
2659     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2660     {
2661         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2662                tng_data->output_file_path, __FILE__, __LINE__);
2663         tng_block_destroy(&block);
2664         return(TNG_CRITICAL);
2665     }
2666
2667     if(fwrite(block->block_contents, block->block_contents_size, 1,
2668         tng_data->output_file) != 1)
2669     {
2670         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
2671         tng_block_destroy(&block);
2672         return(TNG_CRITICAL);
2673     }
2674
2675     tng_block_destroy(&block);
2676
2677     return(TNG_SUCCESS);
2678 }
2679
2680 /** Read the chain data of a molecules block.
2681  * @param tng_data is a trajectory data container.
2682  * @param block is a general block container.
2683  * @param chain is the chain data container.
2684  * @param offset is the offset of the block input and is updated when reading.
2685  * @return TNG_SUCCESS(0) is successful.
2686  */
2687 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
2688                                                tng_gen_block_t block,
2689                                                tng_chain_t chain,
2690                                                int *offset)
2691 {
2692     int len;
2693
2694     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2695
2696     memcpy(&chain->id, block->block_contents+*offset,
2697             sizeof(chain->id));
2698     if(tng_data->input_endianness_swap_func_64)
2699     {
2700         if(tng_data->input_endianness_swap_func_64(tng_data,
2701                                                    &chain->id)
2702             != TNG_SUCCESS)
2703         {
2704             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2705                     __FILE__, __LINE__);
2706         }
2707     }
2708     *offset += sizeof(chain->id);
2709
2710     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2711             TNG_MAX_STR_LEN);
2712     chain->name = malloc(len);
2713     strncpy(chain->name,
2714             block->block_contents+*offset, len);
2715     *offset += len;
2716
2717     memcpy(&chain->n_residues, block->block_contents+*offset,
2718         sizeof(chain->n_residues));
2719     if(tng_data->input_endianness_swap_func_64)
2720     {
2721         if(tng_data->input_endianness_swap_func_64(tng_data,
2722                                                    &chain->n_residues)
2723             != TNG_SUCCESS)
2724         {
2725             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2726                     __FILE__, __LINE__);
2727         }
2728     }
2729     *offset += sizeof(chain->n_residues);
2730
2731     return(TNG_SUCCESS);
2732 }
2733
2734 /** Write the chain data of a molecules block.
2735  * @param tng_data is a trajectory data container.
2736  * @param block is a general block container.
2737  * @param chain is the chain data container.
2738  * @param offset is the offset of the block output and is updated when writing.
2739  * @return TNG_SUCCESS(0) is successful.
2740  */
2741 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
2742                                                 tng_gen_block_t block,
2743                                                 tng_chain_t chain,
2744                                                 int *offset)
2745 {
2746     int len;
2747
2748     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2749
2750     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
2751     if(tng_data->output_endianness_swap_func_64)
2752     {
2753         if(tng_data->output_endianness_swap_func_64(tng_data,
2754                                     (int64_t *)block->header_contents+*offset)
2755             != TNG_SUCCESS)
2756         {
2757             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2758                     __FILE__, __LINE__);
2759         }
2760     }
2761     *offset += sizeof(chain->id);
2762
2763     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2764     strncpy(block->block_contents + *offset, chain->name, len);
2765     *offset += len;
2766
2767     memcpy(block->block_contents+*offset, &chain->n_residues,
2768         sizeof(chain->n_residues));
2769     if(tng_data->output_endianness_swap_func_64)
2770     {
2771         if(tng_data->output_endianness_swap_func_64(tng_data,
2772                                     (int64_t *)block->header_contents+*offset)
2773             != TNG_SUCCESS)
2774         {
2775             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2776                     __FILE__, __LINE__);
2777         }
2778     }
2779     *offset += sizeof(chain->n_residues);
2780
2781     return(TNG_SUCCESS);
2782 }
2783
2784 /** Read the residue data of a molecules block.
2785  * @param tng_data is a trajectory data container.
2786  * @param block is a general block container.
2787  * @param residue is the residue data container.
2788  * @param offset is the offset of the block input and is updated when reading.
2789  * @return TNG_SUCCESS(0) is successful.
2790  */
2791 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
2792                                                  tng_gen_block_t block,
2793                                                  tng_residue_t residue,
2794                                                  int *offset)
2795 {
2796     int len;
2797
2798     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2799
2800     memcpy(&residue->id, block->block_contents+*offset,
2801         sizeof(residue->id));
2802     if(tng_data->input_endianness_swap_func_64)
2803     {
2804         if(tng_data->input_endianness_swap_func_64(tng_data,
2805                                                    &residue->id)
2806             != TNG_SUCCESS)
2807         {
2808             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2809                     __FILE__, __LINE__);
2810         }
2811     }
2812     *offset += sizeof(residue->id);
2813
2814     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2815             TNG_MAX_STR_LEN);
2816     residue->name = malloc(len);
2817     strncpy(residue->name,
2818             block->block_contents+*offset, len);
2819     *offset += len;
2820
2821     memcpy(&residue->n_atoms, block->block_contents+*offset,
2822             sizeof(residue->n_atoms));
2823     if(tng_data->input_endianness_swap_func_64)
2824     {
2825         if(tng_data->input_endianness_swap_func_64(tng_data,
2826                                                    &residue->n_atoms)
2827             != TNG_SUCCESS)
2828         {
2829             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2830                     __FILE__, __LINE__);
2831         }
2832     }
2833     *offset += sizeof(residue->n_atoms);
2834
2835     return(TNG_SUCCESS);
2836 }
2837
2838 /** Write the residue data of a molecules block.
2839  * @param tng_data is a trajectory data container.
2840  * @param block is a general block container.
2841  * @param residue is the residue data container.
2842  * @param offset is the offset of the block output and is updated when writing.
2843  * @return TNG_SUCCESS(0) is successful.
2844  */
2845 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
2846                                                   tng_gen_block_t block,
2847                                                   tng_residue_t residue,
2848                                                   int *offset)
2849 {
2850     int len;
2851
2852     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2853
2854     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
2855     if(tng_data->output_endianness_swap_func_64)
2856     {
2857         if(tng_data->output_endianness_swap_func_64(tng_data,
2858                                     (int64_t *)block->header_contents+*offset)
2859             != TNG_SUCCESS)
2860         {
2861             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2862                     __FILE__, __LINE__);
2863         }
2864     }
2865     *offset += sizeof(residue->id);
2866
2867     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2868     strncpy(block->block_contents + *offset, residue->name, len);
2869     *offset += len;
2870
2871     memcpy(block->block_contents+*offset, &residue->n_atoms,
2872         sizeof(residue->n_atoms));
2873     if(tng_data->output_endianness_swap_func_64)
2874     {
2875         if(tng_data->output_endianness_swap_func_64(tng_data,
2876                                     (int64_t *)block->header_contents+*offset)
2877             != TNG_SUCCESS)
2878         {
2879             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2880                     __FILE__, __LINE__);
2881         }
2882     }
2883     *offset += sizeof(residue->n_atoms);
2884
2885     return(TNG_SUCCESS);
2886 }
2887
2888 /** Read the atom data of a molecules block.
2889  * @param tng_data is a trajectory data container.
2890  * @param block is a general block container.
2891  * @param atom is the atom data container.
2892  * @param offset is the offset of the block input and is updated when reading.
2893  * @return TNG_SUCCESS(0) is successful.
2894  */
2895 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2896                                               tng_gen_block_t block,
2897                                               tng_atom_t atom,
2898                                               int *offset)
2899 {
2900     int len;
2901
2902     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2903
2904     memcpy(&atom->id, block->block_contents+*offset,
2905         sizeof(atom->id));
2906     if(tng_data->input_endianness_swap_func_64)
2907     {
2908         if(tng_data->input_endianness_swap_func_64(tng_data,
2909                                                     &atom->id)
2910             != TNG_SUCCESS)
2911         {
2912             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2913                     __FILE__, __LINE__);
2914         }
2915     }
2916     *offset += sizeof(atom->id);
2917
2918     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2919             TNG_MAX_STR_LEN);
2920     atom->name = malloc(len);
2921     strncpy(atom->name,
2922             block->block_contents+*offset, len);
2923     *offset += len;
2924
2925     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2926             TNG_MAX_STR_LEN);
2927     atom->atom_type = malloc(len);
2928     strncpy(atom->atom_type,
2929             block->block_contents+*offset, len);
2930     *offset += len;
2931
2932     return(TNG_SUCCESS);
2933 }
2934
2935 /** Write the atom data of a molecules block.
2936  * @param tng_data is a trajectory data container.
2937  * @param block is a general block container.
2938  * @param atom is the atom data container.
2939  * @param offset is the offset of the block output and is updated when writing.
2940  * @return TNG_SUCCESS(0) is successful.
2941  */
2942 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2943                                                tng_gen_block_t block,
2944                                                tng_atom_t atom,
2945                                                int *offset)
2946 {
2947     int len;
2948
2949     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2950
2951     memcpy(block->block_contents+*offset, &atom->id,
2952             sizeof(atom->id));
2953     if(tng_data->output_endianness_swap_func_64)
2954     {
2955         if(tng_data->output_endianness_swap_func_64(tng_data,
2956                                     (int64_t *)block->header_contents+*offset)
2957             != TNG_SUCCESS)
2958         {
2959             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2960                     __FILE__, __LINE__);
2961         }
2962     }
2963     *offset += sizeof(atom->id);
2964
2965     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2966     strncpy(block->block_contents + *offset, atom->name, len);
2967     *offset += len;
2968
2969     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2970     strncpy(block->block_contents + *offset, atom->atom_type, len);
2971     *offset += len;
2972
2973     return(TNG_SUCCESS);
2974 }
2975
2976 static tng_function_status tng_molecules_block_len_calculate
2977                 (const tng_trajectory_t tng_data,
2978                  int64_t *len)
2979 {
2980     int64_t i, j;
2981     tng_molecule_t molecule;
2982     tng_chain_t chain;
2983     tng_residue_t residue;
2984     tng_atom_t atom;
2985     tng_bond_t bond;
2986
2987     *len = 0;
2988
2989     for(i = 0; i < tng_data->n_molecules; i++)
2990     {
2991         molecule = &tng_data->molecules[i];
2992         if(!molecule->name)
2993         {
2994             molecule->name = malloc(1);
2995             if(!molecule->name)
2996             {
2997                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2998                        __FILE__, __LINE__);
2999                 return(TNG_CRITICAL);
3000             }
3001             molecule->name[0] = 0;
3002         }
3003         *len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3004
3005         chain = molecule->chains;
3006         for(j = 0; j < molecule->n_chains; j++)
3007         {
3008             *len += sizeof(chain->id);
3009
3010             if(!chain->name)
3011             {
3012                 chain->name = malloc(1);
3013                 if(!chain->name)
3014                 {
3015                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3016                            __FILE__, __LINE__);
3017                     return(TNG_CRITICAL);
3018                 }
3019                 chain->name[0] = 0;
3020             }
3021             *len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
3022
3023             *len += sizeof(chain->n_residues);
3024
3025             chain++;
3026         }
3027
3028         residue = molecule->residues;
3029         for(j = 0; j < molecule->n_residues; j++)
3030         {
3031             *len += sizeof(residue->id);
3032
3033             if(!residue->name)
3034             {
3035                 residue->name = malloc(1);
3036                 if(!residue->name)
3037                 {
3038                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3039                            __FILE__, __LINE__);
3040                     return(TNG_CRITICAL);
3041                 }
3042                 residue->name[0] = 0;
3043             }
3044             *len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
3045
3046             *len += sizeof(residue->n_atoms);
3047
3048             residue++;
3049         }
3050
3051         atom = molecule->atoms;
3052         for(j = 0; j < molecule->n_atoms; j++)
3053         {
3054             *len += sizeof(atom->id);
3055             if(!atom->name)
3056             {
3057                 atom->name = malloc(1);
3058                 if(!atom->name)
3059                 {
3060                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3061                            __FILE__, __LINE__);
3062                     return(TNG_CRITICAL);
3063                 }
3064                 atom->name[0] = 0;
3065             }
3066             *len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
3067
3068             if(!atom->atom_type)
3069             {
3070                 atom->atom_type = malloc(1);
3071                 if(!atom->atom_type)
3072                 {
3073                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3074                            __FILE__, __LINE__);
3075                     return(TNG_CRITICAL);
3076                 }
3077                 atom->atom_type[0] = 0;
3078             }
3079             *len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
3080
3081             atom++;
3082         }
3083
3084         for(j = 0; j < molecule->n_bonds; j++)
3085         {
3086             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
3087         }
3088     }
3089     *len += sizeof(tng_data->n_molecules) +
3090             (sizeof(molecule->id) +
3091             sizeof(molecule->quaternary_str) +
3092             sizeof(molecule->n_chains) +
3093             sizeof(molecule->n_residues) +
3094             sizeof(molecule->n_atoms) +
3095             sizeof(molecule->n_bonds)) *
3096             tng_data->n_molecules;
3097
3098     if(!tng_data->var_num_atoms_flag)
3099     {
3100         *len += tng_data->n_molecules * sizeof(int64_t);
3101     }
3102
3103     return(TNG_SUCCESS);
3104 }
3105
3106 /** Read a molecules block. Contains chain, residue and atom data
3107  * @param tng_data is a trajectory data container.
3108  * @param block is a general block container.
3109  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3110  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3111  * compared to the md5 hash of the read contents to ensure valid data.
3112  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3113  * error has occured.
3114  */
3115 static tng_function_status tng_molecules_block_read
3116                 (tng_trajectory_t tng_data,
3117                  tng_gen_block_t block,
3118                  const char hash_mode)
3119 {
3120     int64_t i, j, k, l;
3121     int len, offset = 0;
3122     tng_molecule_t molecule;
3123     tng_chain_t chain;
3124     tng_residue_t residue;
3125     tng_atom_t atom;
3126     tng_bond_t bond;
3127     tng_bool same_hash;
3128
3129     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3130     {
3131         return(TNG_CRITICAL);
3132     }
3133
3134     if(block->block_contents)
3135     {
3136         free(block->block_contents);
3137     }
3138
3139     block->block_contents = malloc(block->block_contents_size);
3140     if(!block->block_contents)
3141     {
3142         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3143                block->block_contents_size, __FILE__, __LINE__);
3144         return(TNG_CRITICAL);
3145     }
3146
3147     /* Read the whole block into block_contents to be able to write it to disk
3148      * even if it cannot be interpreted. */
3149     if(fread(block->block_contents, block->block_contents_size, 1,
3150              tng_data->input_file) == 0)
3151     {
3152         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3153     }
3154
3155     /* FIXME: Does not check if the size of the contents matches the expected
3156      * size or if the contents can be read. */
3157
3158     if(hash_mode == TNG_USE_HASH)
3159     {
3160         tng_md5_hash_match_verify(block, &same_hash);
3161         if(same_hash != TNG_TRUE)
3162         {
3163             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3164                 "%s: %d\n",
3165                 __FILE__, __LINE__);
3166         }
3167     }
3168
3169     if(tng_data->molecules)
3170     {
3171         for(i=0; i<tng_data->n_molecules; i++)
3172         {
3173             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
3174         }
3175         free(tng_data->molecules);
3176         tng_data->molecules = 0;
3177         tng_data->n_molecules = 0;
3178     }
3179
3180     memcpy(&tng_data->n_molecules, block->block_contents,
3181            sizeof(tng_data->n_molecules));
3182     if(tng_data->input_endianness_swap_func_64)
3183     {
3184         if(tng_data->input_endianness_swap_func_64(tng_data,
3185                                                    &tng_data->n_molecules)
3186             != TNG_SUCCESS)
3187         {
3188             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3189                     __FILE__, __LINE__);
3190         }
3191     }
3192     offset += sizeof(tng_data->n_molecules);
3193
3194     if(tng_data->molecules)
3195     {
3196         free(tng_data->molecules);
3197     }
3198
3199     tng_data->n_particles = 0;
3200
3201     tng_data->molecules = malloc(tng_data->n_molecules *
3202                           sizeof(struct tng_molecule));
3203     if(!tng_data->molecules)
3204     {
3205         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3206                tng_data->n_molecules * sizeof(struct tng_molecule),
3207                __FILE__, __LINE__);
3208         return(TNG_CRITICAL);
3209     }
3210
3211     if(!tng_data->var_num_atoms_flag)
3212     {
3213         if(tng_data->molecule_cnt_list)
3214         {
3215             free(tng_data->molecule_cnt_list);
3216         }
3217         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
3218                                       tng_data->n_molecules);
3219         if(!tng_data->molecule_cnt_list)
3220         {
3221             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3222                    tng_data->n_molecules * sizeof(struct tng_molecule),
3223                    __FILE__, __LINE__);
3224             return(TNG_CRITICAL);
3225         }
3226     }
3227
3228     /* Read each molecule from file */
3229     for(i=0; i < tng_data->n_molecules; i++)
3230     {
3231         molecule = &tng_data->molecules[i];
3232
3233         memcpy(&molecule->id, block->block_contents+offset,
3234                sizeof(molecule->id));
3235         if(tng_data->input_endianness_swap_func_64)
3236         {
3237             if(tng_data->input_endianness_swap_func_64(tng_data,
3238                                                        &molecule->id)
3239                 != TNG_SUCCESS)
3240             {
3241                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3242                         __FILE__, __LINE__);
3243             }
3244         }
3245         offset += sizeof(molecule->id);
3246
3247 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
3248         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
3249         molecule->name = malloc(len);
3250         strncpy(molecule->name, block->block_contents+offset, len);
3251         offset += len;
3252
3253         memcpy(&molecule->quaternary_str, block->block_contents+offset,
3254                sizeof(molecule->quaternary_str));
3255         if(tng_data->input_endianness_swap_func_64)
3256         {
3257             if(tng_data->input_endianness_swap_func_64(tng_data,
3258                                                      &molecule->quaternary_str)
3259                 != TNG_SUCCESS)
3260             {
3261                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3262                         __FILE__, __LINE__);
3263             }
3264         }
3265         offset += sizeof(molecule->quaternary_str);
3266
3267         if(!tng_data->var_num_atoms_flag)
3268         {
3269             memcpy(&tng_data->molecule_cnt_list[i],
3270                    block->block_contents+offset,
3271                    sizeof(int64_t));
3272             if(tng_data->input_endianness_swap_func_64)
3273             {
3274                 if(tng_data->input_endianness_swap_func_64(tng_data,
3275                                                &tng_data->molecule_cnt_list[i])
3276                     != TNG_SUCCESS)
3277                 {
3278                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3279                             __FILE__, __LINE__);
3280                 }
3281             }
3282             offset += sizeof(int64_t);
3283         }
3284
3285
3286         memcpy(&molecule->n_chains, block->block_contents+offset,
3287                sizeof(molecule->n_chains));
3288         if(tng_data->input_endianness_swap_func_64)
3289         {
3290             if(tng_data->input_endianness_swap_func_64(tng_data,
3291                                                        &molecule->n_chains)
3292                 != TNG_SUCCESS)
3293             {
3294                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3295                         __FILE__, __LINE__);
3296             }
3297         }
3298         offset += sizeof(molecule->n_chains);
3299
3300         memcpy(&molecule->n_residues, block->block_contents+offset,
3301                sizeof(molecule->n_residues));
3302         if(tng_data->input_endianness_swap_func_64)
3303         {
3304             if(tng_data->input_endianness_swap_func_64(tng_data,
3305                                                        &molecule->n_residues)
3306                 != TNG_SUCCESS)
3307             {
3308                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3309                         __FILE__, __LINE__);
3310             }
3311         }
3312         offset += sizeof(molecule->n_residues);
3313
3314         memcpy(&molecule->n_atoms, block->block_contents+offset,
3315                sizeof(molecule->n_atoms));
3316         if(tng_data->input_endianness_swap_func_64)
3317         {
3318             if(tng_data->input_endianness_swap_func_64(tng_data,
3319                                                        &molecule->n_atoms)
3320                 != TNG_SUCCESS)
3321             {
3322                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3323                         __FILE__, __LINE__);
3324             }
3325         }
3326         offset += sizeof(molecule->n_atoms);
3327
3328         tng_data->n_particles += molecule->n_atoms *
3329                                  tng_data->molecule_cnt_list[i];
3330
3331         if(molecule->n_chains > 0)
3332         {
3333             molecule->chains = malloc(molecule->n_chains *
3334                                     sizeof(struct tng_chain));
3335             if(!molecule->chains)
3336             {
3337                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3338                     molecule->n_chains * sizeof(struct tng_chain),
3339                     __FILE__, __LINE__);
3340                 return(TNG_CRITICAL);
3341             }
3342
3343             chain = molecule->chains;
3344         }
3345         else
3346         {
3347             chain = 0;
3348         }
3349
3350         if(molecule->n_residues > 0)
3351         {
3352             molecule->residues = malloc(molecule->n_residues *
3353                                 sizeof(struct tng_residue));
3354             if(!molecule->residues)
3355             {
3356                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3357                     molecule->n_residues * sizeof(struct tng_residue),
3358                     __FILE__, __LINE__);
3359                 if(molecule->chains)
3360                 {
3361                     free(molecule->chains);
3362                     molecule->chains = 0;
3363                 }
3364                 return(TNG_CRITICAL);
3365             }
3366
3367             residue = molecule->residues;
3368         }
3369         else
3370         {
3371             residue = 0;
3372         }
3373
3374         molecule->atoms = malloc(molecule->n_atoms *
3375                                  sizeof(struct tng_atom));
3376         if(!molecule->atoms)
3377         {
3378             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3379                    molecule->n_atoms * sizeof(struct tng_atom),
3380                    __FILE__, __LINE__);
3381             if(molecule->chains)
3382             {
3383                 free(molecule->chains);
3384                 molecule->chains = 0;
3385             }
3386             if(molecule->residues)
3387             {
3388                 free(molecule->residues);
3389                 molecule->residues = 0;
3390             }
3391             return(TNG_CRITICAL);
3392         }
3393
3394         atom = molecule->atoms;
3395
3396         if(molecule->n_chains > 0)
3397         {
3398             /* Read the chains of the molecule */
3399             for(j=0; j<molecule->n_chains; j++)
3400             {
3401                 chain->molecule = molecule;
3402
3403                 tng_chain_data_read(tng_data, block, chain, &offset);
3404
3405                 chain->residues = molecule->residues;
3406                 residue = chain->residues;
3407
3408                 /* Read the residues of the chain */
3409                 for(k=0; k<chain->n_residues; k++)
3410                 {
3411                     residue->chain = chain;
3412
3413                     tng_residue_data_read(tng_data, block, residue, &offset);
3414
3415                     residue->atoms_offset = atom - molecule->atoms;
3416                     /* Read the atoms of the residue */
3417                     for(l=0; l<residue->n_atoms; l++)
3418                     {
3419                         atom->residue = residue;
3420
3421                         tng_atom_data_read(tng_data, block, atom, &offset);
3422
3423                         atom++;
3424                     }
3425                     residue++;
3426                 }
3427                 chain++;
3428             }
3429         }
3430         else
3431         {
3432             if(molecule->n_residues > 0)
3433             {
3434                 for(k=0; k<molecule->n_residues; k++)
3435                 {
3436                     residue->chain = 0;
3437
3438                     tng_residue_data_read(tng_data, block, residue, &offset);
3439
3440                     residue->atoms_offset = atom - molecule->atoms;
3441                     /* Read the atoms of the residue */
3442                     for(l=0; l<residue->n_atoms; l++)
3443                     {
3444                         atom->residue = residue;
3445
3446                         tng_atom_data_read(tng_data, block, atom, &offset);
3447
3448                         atom++;
3449                     }
3450                     residue++;
3451                 }
3452             }
3453             else
3454             {
3455                 for(l=0; l<molecule->n_atoms; l++)
3456                 {
3457                     atom->residue = 0;
3458
3459                     tng_atom_data_read(tng_data, block, atom, &offset);
3460
3461                     atom++;
3462                 }
3463             }
3464         }
3465
3466         memcpy(&molecule->n_bonds, block->block_contents+offset,
3467                sizeof(molecule->n_bonds));
3468         if(tng_data->input_endianness_swap_func_64)
3469         {
3470             if(tng_data->input_endianness_swap_func_64(tng_data,
3471                                                        &molecule->n_bonds)
3472                 != TNG_SUCCESS)
3473             {
3474                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3475                         __FILE__, __LINE__);
3476             }
3477         }
3478         offset += sizeof(molecule->n_bonds);
3479
3480         if(molecule->n_bonds > 0)
3481         {
3482             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
3483                                            sizeof(struct tng_bond));
3484             if(!molecule->bonds)
3485             {
3486                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3487                        molecule->n_bonds * sizeof(struct tng_bond),
3488                        __FILE__, __LINE__);
3489                 if(molecule->chains)
3490                 {
3491                     free(molecule->chains);
3492                     molecule->chains = 0;
3493                 }
3494                 if(molecule->residues)
3495                 {
3496                     free(molecule->residues);
3497                     molecule->residues = 0;
3498                 }
3499                 if(molecule->atoms)
3500                 {
3501                     free(molecule->atoms);
3502                     molecule->atoms = 0;
3503                 }
3504                 return(TNG_CRITICAL);
3505             }
3506
3507             bond = molecule->bonds;
3508
3509             for(j=0; j<molecule->n_bonds; j++)
3510             {
3511                 memcpy(&bond->from_atom_id, block->block_contents+offset,
3512                     sizeof(bond->from_atom_id));
3513                 if(tng_data->input_endianness_swap_func_64)
3514                 {
3515                     if(tng_data->input_endianness_swap_func_64(tng_data,
3516                                                                &bond->from_atom_id)
3517                         != TNG_SUCCESS)
3518                     {
3519                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3520                                 __FILE__, __LINE__);
3521                     }
3522                 }
3523                 offset += sizeof(bond->from_atom_id);
3524
3525                 memcpy(&bond->to_atom_id, block->block_contents+offset,
3526                     sizeof(bond->to_atom_id));
3527                 if(tng_data->input_endianness_swap_func_64)
3528                 {
3529                     if(tng_data->input_endianness_swap_func_64(tng_data,
3530                                                                &bond->to_atom_id)
3531                         != TNG_SUCCESS)
3532                     {
3533                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3534                                 __FILE__, __LINE__);
3535                     }
3536                 }
3537                 offset += sizeof(bond->to_atom_id);
3538
3539                 bond++;
3540             }
3541         }
3542         else
3543         {
3544             molecule->bonds = 0;
3545         }
3546     }
3547
3548     return(TNG_SUCCESS);
3549 }
3550
3551 /** Write a molecules block.
3552  * @param tng_data is a trajectory data container.
3553  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3554  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3555  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3556  * error has occured.
3557  */
3558 static tng_function_status tng_molecules_block_write
3559                 (tng_trajectory_t tng_data,
3560                  const char hash_mode)
3561 {
3562     int len = 0, name_len, offset = 0;
3563     int64_t i, j, k, l;
3564     tng_molecule_t molecule;
3565     tng_chain_t chain;
3566     tng_residue_t residue;
3567     tng_atom_t atom;
3568     tng_bond_t bond;
3569     tng_gen_block_t block;
3570
3571     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3572     {
3573         return(TNG_CRITICAL);
3574     }
3575
3576     tng_block_init(&block);
3577
3578     name_len = (int)strlen("MOLECULES");
3579
3580     block->name = malloc(name_len + 1);
3581     if(!block->name)
3582     {
3583         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3584                 name_len+1, __FILE__, __LINE__);
3585         tng_block_destroy(&block);
3586         return(TNG_CRITICAL);
3587     }
3588
3589     strcpy(block->name, "MOLECULES");
3590     block->id = TNG_MOLECULES;
3591
3592     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3593         TNG_SUCCESS)
3594     {
3595         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3596                 __FILE__, __LINE__);
3597         tng_block_destroy(&block);
3598         return(TNG_CRITICAL);
3599     }
3600
3601     block->block_contents = malloc(block->block_contents_size);
3602     if(!block->block_contents)
3603     {
3604         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3605                block->block_contents_size, __FILE__, __LINE__);
3606         tng_block_destroy(&block);
3607         return(TNG_CRITICAL);
3608     }
3609
3610     memcpy(block->block_contents+offset, &tng_data->n_molecules,
3611            sizeof(tng_data->n_molecules));
3612     if(tng_data->output_endianness_swap_func_64)
3613     {
3614         if(tng_data->output_endianness_swap_func_64(tng_data,
3615                                       (int64_t *)block->header_contents+offset)
3616             != TNG_SUCCESS)
3617         {
3618             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3619                     __FILE__, __LINE__);
3620         }
3621     }
3622     offset += sizeof(tng_data->n_molecules);
3623
3624     for(i = 0; i < tng_data->n_molecules; i++)
3625     {
3626         molecule = &tng_data->molecules[i];
3627         memcpy(block->block_contents+offset, &molecule->id,
3628                sizeof(molecule->id));
3629         if(tng_data->output_endianness_swap_func_64)
3630         {
3631             if(tng_data->output_endianness_swap_func_64(tng_data,
3632                                         (int64_t *)block->header_contents+offset)
3633                 != TNG_SUCCESS)
3634             {
3635                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3636                         __FILE__, __LINE__);
3637             }
3638         }
3639         offset += sizeof(molecule->id);
3640
3641 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
3642         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3643         strncpy(block->block_contents + offset, molecule->name, len);
3644         offset += len;
3645
3646         memcpy(block->block_contents+offset, &molecule->quaternary_str,
3647                sizeof(molecule->quaternary_str));
3648         if(tng_data->output_endianness_swap_func_64)
3649         {
3650             if(tng_data->output_endianness_swap_func_64(tng_data,
3651                                         (int64_t *)block->header_contents+offset)
3652                 != TNG_SUCCESS)
3653             {
3654                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3655                         __FILE__, __LINE__);
3656             }
3657         }
3658         offset += sizeof(molecule->quaternary_str);
3659
3660         if(!tng_data->var_num_atoms_flag)
3661         {
3662             memcpy(block->block_contents+offset,
3663                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
3664             if(tng_data->output_endianness_swap_func_64)
3665             {
3666                 if(tng_data->output_endianness_swap_func_64(tng_data,
3667                                             (int64_t *)block->header_contents+offset)
3668                     != TNG_SUCCESS)
3669                 {
3670                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3671                             __FILE__, __LINE__);
3672                 }
3673             }
3674             offset += sizeof(int64_t);
3675         }
3676
3677         memcpy(block->block_contents+offset, &molecule->n_chains,
3678                sizeof(molecule->n_chains));
3679         if(tng_data->output_endianness_swap_func_64)
3680         {
3681             if(tng_data->output_endianness_swap_func_64(tng_data,
3682                                         (int64_t *)block->header_contents+offset)
3683                 != TNG_SUCCESS)
3684             {
3685                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3686                         __FILE__, __LINE__);
3687             }
3688         }
3689         offset += sizeof(molecule->n_chains);
3690
3691         memcpy(block->block_contents+offset, &molecule->n_residues,
3692                sizeof(molecule->n_residues));
3693         if(tng_data->output_endianness_swap_func_64)
3694         {
3695             if(tng_data->output_endianness_swap_func_64(tng_data,
3696                                         (int64_t *)block->header_contents+offset)
3697                 != TNG_SUCCESS)
3698             {
3699                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3700                         __FILE__, __LINE__);
3701             }
3702         }
3703         offset += sizeof(molecule->n_residues);
3704
3705         memcpy(block->block_contents+offset, &molecule->n_atoms,
3706                sizeof(molecule->n_atoms));
3707         if(tng_data->output_endianness_swap_func_64)
3708         {
3709             if(tng_data->output_endianness_swap_func_64(tng_data,
3710                                         (int64_t *)block->header_contents+offset)
3711                 != TNG_SUCCESS)
3712             {
3713                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3714                         __FILE__, __LINE__);
3715             }
3716         }
3717         offset += sizeof(molecule->n_atoms);
3718
3719         if(molecule->n_chains > 0)
3720         {
3721             chain = molecule->chains;
3722             for(j = 0; j < molecule->n_chains; j++)
3723             {
3724                 tng_chain_data_write(tng_data, block, chain, &offset);
3725
3726                 residue = chain->residues;
3727                 for(k = 0; k < chain->n_residues; k++)
3728                 {
3729                     tng_residue_data_write(tng_data, block, residue, &offset);
3730
3731                     atom = molecule->atoms + residue->atoms_offset;
3732                     for(l = 0; l < residue->n_atoms; l++)
3733                     {
3734                         tng_atom_data_write(tng_data, block, atom, &offset);
3735
3736                         atom++;
3737                     }
3738                     residue++;
3739                 }
3740                 chain++;
3741             }
3742         }
3743         else
3744         {
3745             if(molecule->n_residues > 0)
3746             {
3747                 residue = molecule->residues;
3748                 for(k = 0; k < molecule->n_residues; k++)
3749                 {
3750                     tng_residue_data_write(tng_data, block, residue, &offset);
3751
3752                     atom = molecule->atoms + residue->atoms_offset;
3753                     for(l = 0; l < residue->n_atoms; l++)
3754                     {
3755                         tng_atom_data_write(tng_data, block, atom, &offset);
3756
3757                         atom++;
3758                     }
3759                     residue++;
3760                 }
3761             }
3762             else
3763             {
3764                 atom = molecule->atoms;
3765                 for(l = 0; l < molecule->n_atoms; l++)
3766                 {
3767                     tng_atom_data_write(tng_data, block, atom, &offset);
3768
3769                     atom++;
3770                 }
3771             }
3772         }
3773
3774         memcpy(block->block_contents+offset, &molecule->n_bonds,
3775                sizeof(molecule->n_bonds));
3776         if(tng_data->output_endianness_swap_func_64)
3777         {
3778             if(tng_data->output_endianness_swap_func_64(tng_data,
3779                                         (int64_t *)block->header_contents+offset)
3780                 != TNG_SUCCESS)
3781             {
3782                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3783                         __FILE__, __LINE__);
3784             }
3785         }
3786         offset += sizeof(molecule->n_bonds);
3787
3788         bond = molecule->bonds;
3789         for(j = 0; j < molecule->n_bonds; j++)
3790         {
3791             memcpy(block->block_contents+offset, &bond->from_atom_id,
3792                    sizeof(bond->from_atom_id));
3793             if(tng_data->output_endianness_swap_func_64)
3794             {
3795                 if(tng_data->output_endianness_swap_func_64(tng_data,
3796                                             (int64_t *)block->header_contents+offset)
3797                     != TNG_SUCCESS)
3798                 {
3799                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3800                             __FILE__, __LINE__);
3801                 }
3802             }
3803             offset += sizeof(bond->from_atom_id);
3804
3805             memcpy(block->block_contents+offset, &bond->to_atom_id,
3806                    sizeof(bond->to_atom_id));
3807             if(tng_data->output_endianness_swap_func_64)
3808             {
3809                 if(tng_data->output_endianness_swap_func_64(tng_data,
3810                                             (int64_t *)block->header_contents+offset)
3811                     != TNG_SUCCESS)
3812                 {
3813                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3814                             __FILE__, __LINE__);
3815                 }
3816             }
3817             offset += sizeof(bond->to_atom_id);
3818
3819             bond++;
3820         }
3821     }
3822
3823     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3824     {
3825         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3826                tng_data->output_file_path, __FILE__, __LINE__);
3827         tng_block_destroy(&block);
3828         return(TNG_CRITICAL);
3829     }
3830
3831     if(fwrite(block->block_contents, block->block_contents_size, 1,
3832               tng_data->output_file) != 1)
3833     {
3834         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
3835                __FILE__, __LINE__);
3836         tng_block_destroy(&block);
3837         return(TNG_CRITICAL);
3838     }
3839
3840     tng_block_destroy(&block);
3841
3842     return(TNG_SUCCESS);
3843 }
3844
3845 static tng_function_status tng_frame_set_block_len_calculate
3846                 (const tng_trajectory_t tng_data,
3847                  int64_t *len)
3848 {
3849     *len = sizeof(int64_t) * 8;
3850     *len += sizeof(double) * 2;
3851
3852     if(tng_data->var_num_atoms_flag)
3853     {
3854         *len += sizeof(int64_t) * tng_data->n_molecules;
3855     }
3856     return(TNG_SUCCESS);
3857 }
3858
3859 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
3860  * @param tng_data is a trajectory data container.
3861  * @param block is a general block container.
3862  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3863  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3864  * compared to the md5 hash of the read contents to ensure valid data.
3865  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3866  * error has occured.
3867  */
3868 static tng_function_status tng_frame_set_block_read
3869                 (tng_trajectory_t tng_data,
3870                  tng_gen_block_t block,
3871                  const char hash_mode)
3872 {
3873     long file_pos;
3874     int offset = 0;
3875     int64_t i, prev_n_particles;
3876     tng_bool same_hash;
3877     tng_trajectory_frame_set_t frame_set =
3878     &tng_data->current_trajectory_frame_set;
3879
3880     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3881     {
3882         return(TNG_CRITICAL);
3883     }
3884
3885     if(block->block_contents)
3886     {
3887         free(block->block_contents);
3888     }
3889
3890     block->block_contents = malloc(block->block_contents_size);
3891     if(!block->block_contents)
3892     {
3893         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3894                block->block_contents_size, __FILE__, __LINE__);
3895         return(TNG_CRITICAL);
3896     }
3897
3898     /* Read the whole block into block_contents to be able to write it to
3899      * disk even if it cannot be interpreted. */
3900     if(fread(block->block_contents, block->block_contents_size, 1,
3901              tng_data->input_file) == 0)
3902     {
3903         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3904         return(TNG_CRITICAL);
3905     }
3906
3907     /* FIXME: Does not check if the size of the contents matches the expected
3908      * size or if the contents can be read. */
3909
3910     file_pos = (int64_t)ftell(tng_data->input_file) -
3911                (long)(block->block_contents_size + block->header_contents_size);
3912
3913     if(hash_mode == TNG_USE_HASH)
3914     {
3915         tng_md5_hash_match_verify(block, &same_hash);
3916         if(same_hash != TNG_TRUE)
3917         {
3918             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
3919                 "%s: %d\n",
3920                 file_pos, __FILE__, __LINE__);
3921     /*         return(TNG_FAILURE); */
3922         }
3923     }
3924
3925     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3926
3927     tng_frame_set_particle_mapping_free(tng_data);
3928
3929     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3930     {
3931         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3932     }
3933     /* FIXME: Should check the frame number instead of the file_pos, in case
3934      * frame sets are not in order */
3935     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3936     {
3937         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3938     }
3939
3940     memcpy(&frame_set->first_frame, block->block_contents,
3941            sizeof(frame_set->first_frame));
3942     if(tng_data->input_endianness_swap_func_64)
3943     {
3944         if(tng_data->input_endianness_swap_func_64(tng_data,
3945                                                    &frame_set->first_frame)
3946             != TNG_SUCCESS)
3947         {
3948             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3949                     __FILE__, __LINE__);
3950         }
3951     }
3952     offset += sizeof(frame_set->first_frame);
3953
3954     memcpy(&frame_set->n_frames, block->block_contents + offset,
3955            sizeof(frame_set->n_frames));
3956     if(tng_data->input_endianness_swap_func_64)
3957     {
3958         if(tng_data->input_endianness_swap_func_64(tng_data,
3959                                                    &frame_set->n_frames)
3960             != TNG_SUCCESS)
3961         {
3962             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3963                     __FILE__, __LINE__);
3964         }
3965     }
3966     offset += sizeof(frame_set->n_frames);
3967
3968     if(tng_data->var_num_atoms_flag)
3969     {
3970         prev_n_particles = frame_set->n_particles;
3971         frame_set->n_particles = 0;
3972         /* If the list of molecule counts has already been created assume that
3973          * it is of correct size. */
3974         if(!frame_set->molecule_cnt_list)
3975         {
3976                 frame_set->molecule_cnt_list =
3977                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3978
3979                 if(!frame_set->molecule_cnt_list)
3980                 {
3981                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3982                            sizeof(int64_t) * tng_data->n_molecules,
3983                            __FILE__, __LINE__);
3984                     return(TNG_CRITICAL);
3985                 }
3986         }
3987         for(i = 0; i < tng_data->n_molecules; i++)
3988         {
3989             memcpy(&frame_set->molecule_cnt_list[i],
3990                    block->block_contents + offset,
3991                    sizeof(int64_t));
3992             if(tng_data->input_endianness_swap_func_64)
3993             {
3994                 if(tng_data->input_endianness_swap_func_64(tng_data,
3995                                               &frame_set->molecule_cnt_list[i])
3996                     != TNG_SUCCESS)
3997                 {
3998                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3999                             __FILE__, __LINE__);
4000                 }
4001             }
4002             offset += sizeof(int64_t);
4003             frame_set->n_particles += tng_data->molecules[i].n_atoms *
4004                                       frame_set->molecule_cnt_list[i];
4005         }
4006         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
4007         {
4008             /* FIXME: Particle dependent data memory management */
4009         }
4010     }
4011
4012     memcpy(&frame_set->next_frame_set_file_pos,
4013            block->block_contents + offset,
4014            sizeof(frame_set->next_frame_set_file_pos));
4015     if(tng_data->input_endianness_swap_func_64)
4016     {
4017         if(tng_data->input_endianness_swap_func_64(tng_data,
4018                                            &frame_set->next_frame_set_file_pos)
4019             != TNG_SUCCESS)
4020         {
4021             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4022                     __FILE__, __LINE__);
4023         }
4024     }
4025     offset += sizeof(frame_set->next_frame_set_file_pos);
4026
4027     memcpy(&frame_set->prev_frame_set_file_pos,
4028            block->block_contents + offset,
4029            sizeof(frame_set->prev_frame_set_file_pos));
4030     if(tng_data->input_endianness_swap_func_64)
4031     {
4032         if(tng_data->input_endianness_swap_func_64(tng_data,
4033                                            &frame_set->prev_frame_set_file_pos)
4034             != TNG_SUCCESS)
4035         {
4036             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4037                     __FILE__, __LINE__);
4038         }
4039     }
4040     offset += sizeof(frame_set->prev_frame_set_file_pos);
4041
4042     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
4043            block->block_contents + offset,
4044            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4045     if(tng_data->input_endianness_swap_func_64)
4046     {
4047         if(tng_data->input_endianness_swap_func_64(tng_data,
4048                              &frame_set->medium_stride_next_frame_set_file_pos)
4049             != TNG_SUCCESS)
4050         {
4051             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4052                     __FILE__, __LINE__);
4053         }
4054     }
4055     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4056
4057     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
4058            block->block_contents + offset,
4059            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4060     if(tng_data->input_endianness_swap_func_64)
4061     {
4062         if(tng_data->input_endianness_swap_func_64(tng_data,
4063                              &frame_set->medium_stride_prev_frame_set_file_pos)
4064             != TNG_SUCCESS)
4065         {
4066             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4067                     __FILE__, __LINE__);
4068         }
4069     }
4070     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4071
4072     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
4073            block->block_contents + offset,
4074            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4075     if(tng_data->input_endianness_swap_func_64)
4076     {
4077         if(tng_data->input_endianness_swap_func_64(tng_data,
4078                                &frame_set->long_stride_next_frame_set_file_pos)
4079             != TNG_SUCCESS)
4080         {
4081             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4082                     __FILE__, __LINE__);
4083         }
4084     }
4085     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4086
4087     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
4088            block->block_contents + offset,
4089            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4090     if(tng_data->input_endianness_swap_func_64)
4091     {
4092         if(tng_data->input_endianness_swap_func_64(tng_data,
4093                                &frame_set->long_stride_prev_frame_set_file_pos)
4094             != TNG_SUCCESS)
4095         {
4096             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4097                     __FILE__, __LINE__);
4098         }
4099     }
4100     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4101
4102     if(block->block_version >= 3)
4103     {
4104         memcpy(&frame_set->first_frame_time,
4105             block->block_contents + offset,
4106             sizeof(frame_set->first_frame_time));
4107         if(tng_data->input_endianness_swap_func_64)
4108         {
4109             if(tng_data->input_endianness_swap_func_64(tng_data,
4110                                 (int64_t *)&frame_set->first_frame_time)
4111                 != TNG_SUCCESS)
4112             {
4113                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4114                         __FILE__, __LINE__);
4115             }
4116         }
4117         offset += sizeof(frame_set->first_frame_time);
4118
4119         memcpy(&tng_data->time_per_frame,
4120             block->block_contents + offset,
4121             sizeof(tng_data->time_per_frame));
4122         if(tng_data->input_endianness_swap_func_64)
4123         {
4124             if(tng_data->input_endianness_swap_func_64(tng_data,
4125                                 (int64_t *)&tng_data->time_per_frame)
4126                 != TNG_SUCCESS)
4127             {
4128                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4129                         __FILE__, __LINE__);
4130             }
4131         }
4132     }
4133     else
4134     {
4135         frame_set->first_frame_time = -1;
4136         tng_data->time_per_frame = -1;
4137     }
4138
4139     /* If the output file and the input files are the same the number of
4140      * frames in the file are the same number as has just been read.
4141      * This is updated here to later on see if there have been new frames
4142      * added and thereby the frame set needs to be rewritten. */
4143     if(tng_data->output_file == tng_data->input_file)
4144     {
4145         frame_set->n_written_frames = frame_set->n_frames;
4146     }
4147
4148     return(TNG_SUCCESS);
4149 }
4150
4151 /** Write tng_data->current_trajectory_frame_set to file
4152  * @param tng_data is a trajectory data container.
4153  * @param block is a general block container.
4154  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4155  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4156  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4157  * error has occured.
4158  */
4159 static tng_function_status tng_frame_set_block_write
4160                 (tng_trajectory_t tng_data,
4161                  tng_gen_block_t block,
4162                  const char hash_mode)
4163 {
4164     char *temp_name;
4165     int64_t i;
4166     int offset = 0;
4167     unsigned int name_len;
4168     tng_trajectory_frame_set_t frame_set =
4169     &tng_data->current_trajectory_frame_set;
4170
4171     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4172     {
4173         return(TNG_CRITICAL);
4174     }
4175
4176     name_len = (int)strlen("TRAJECTORY FRAME SET");
4177
4178     if(!block->name || strlen(block->name) < name_len)
4179     {
4180         temp_name = realloc(block->name, name_len + 1);
4181         if(!temp_name)
4182         {
4183             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4184                    name_len+1, __FILE__, __LINE__);
4185             free(block->name);
4186             block->name = 0;
4187             return(TNG_CRITICAL);
4188         }
4189         block->name = temp_name;
4190     }
4191     strcpy(block->name, "TRAJECTORY FRAME SET");
4192     block->id = TNG_TRAJECTORY_FRAME_SET;
4193
4194     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
4195         TNG_SUCCESS)
4196     {
4197         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
4198                 __FILE__, __LINE__);
4199         return(TNG_CRITICAL);
4200     }
4201
4202     if(block->block_contents)
4203     {
4204         free(block->block_contents);
4205     }
4206     block->block_contents = malloc(block->block_contents_size);
4207     if(!block->block_contents)
4208     {
4209         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4210                block->block_contents_size, __FILE__, __LINE__);
4211         return(TNG_CRITICAL);
4212     }
4213
4214     memcpy(block->block_contents, &frame_set->first_frame,
4215            sizeof(frame_set->first_frame));
4216     if(tng_data->output_endianness_swap_func_64)
4217     {
4218         if(tng_data->output_endianness_swap_func_64(tng_data,
4219                                       (int64_t *)block->header_contents+offset)
4220             != TNG_SUCCESS)
4221         {
4222             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4223                     __FILE__, __LINE__);
4224         }
4225     }
4226     offset += sizeof(frame_set->first_frame);
4227
4228     memcpy(block->block_contents+offset, &frame_set->n_frames,
4229            sizeof(frame_set->n_frames));
4230     if(tng_data->output_endianness_swap_func_64)
4231     {
4232         if(tng_data->output_endianness_swap_func_64(tng_data,
4233                                       (int64_t *)block->header_contents+offset)
4234             != TNG_SUCCESS)
4235         {
4236             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4237                     __FILE__, __LINE__);
4238         }
4239     }
4240     offset += sizeof(frame_set->n_frames);
4241
4242     if(tng_data->var_num_atoms_flag)
4243     {
4244         for(i = 0; i < tng_data->n_molecules; i++)
4245         {
4246             memcpy(block->block_contents+offset,
4247                    &frame_set->molecule_cnt_list[i],
4248                    sizeof(int64_t));
4249             if(tng_data->output_endianness_swap_func_64)
4250             {
4251                 if(tng_data->output_endianness_swap_func_64(tng_data,
4252                                             (int64_t *)block->header_contents+offset)
4253                     != TNG_SUCCESS)
4254                 {
4255                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4256                             __FILE__, __LINE__);
4257                 }
4258             }
4259             offset += sizeof(int64_t);
4260         }
4261     }
4262
4263
4264     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
4265            sizeof(frame_set->next_frame_set_file_pos));
4266     if(tng_data->output_endianness_swap_func_64)
4267     {
4268         if(tng_data->output_endianness_swap_func_64(tng_data,
4269                                       (int64_t *)block->header_contents+offset)
4270             != TNG_SUCCESS)
4271         {
4272             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4273                     __FILE__, __LINE__);
4274         }
4275     }
4276     offset += sizeof(frame_set->next_frame_set_file_pos);
4277
4278     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
4279            sizeof(frame_set->prev_frame_set_file_pos));
4280     if(tng_data->output_endianness_swap_func_64)
4281     {
4282         if(tng_data->output_endianness_swap_func_64(tng_data,
4283                                       (int64_t *)block->header_contents+offset)
4284             != TNG_SUCCESS)
4285         {
4286             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4287                     __FILE__, __LINE__);
4288         }
4289     }
4290     offset += sizeof(frame_set->prev_frame_set_file_pos);
4291
4292     memcpy(block->block_contents+offset,
4293            &frame_set->medium_stride_next_frame_set_file_pos,
4294            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4295     if(tng_data->output_endianness_swap_func_64)
4296     {
4297         if(tng_data->output_endianness_swap_func_64(tng_data,
4298                                       (int64_t *)block->header_contents+offset)
4299             != TNG_SUCCESS)
4300         {
4301             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4302                     __FILE__, __LINE__);
4303         }
4304     }
4305     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4306
4307     memcpy(block->block_contents+offset,
4308            &frame_set->medium_stride_prev_frame_set_file_pos,
4309            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4310     if(tng_data->output_endianness_swap_func_64)
4311     {
4312         if(tng_data->output_endianness_swap_func_64(tng_data,
4313                                       (int64_t *)block->header_contents+offset)
4314             != TNG_SUCCESS)
4315         {
4316             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4317                     __FILE__, __LINE__);
4318         }
4319     }
4320     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4321
4322     memcpy(block->block_contents+offset,
4323            &frame_set->long_stride_next_frame_set_file_pos,
4324            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4325     if(tng_data->output_endianness_swap_func_64)
4326     {
4327         if(tng_data->output_endianness_swap_func_64(tng_data,
4328                                       (int64_t *)block->header_contents+offset)
4329             != TNG_SUCCESS)
4330         {
4331             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4332                     __FILE__, __LINE__);
4333         }
4334     }
4335     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4336
4337     memcpy(block->block_contents+offset,
4338            &frame_set->long_stride_prev_frame_set_file_pos,
4339            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4340     if(tng_data->output_endianness_swap_func_64)
4341     {
4342         if(tng_data->output_endianness_swap_func_64(tng_data,
4343                                       (int64_t *)block->header_contents+offset)
4344             != TNG_SUCCESS)
4345         {
4346             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4347                     __FILE__, __LINE__);
4348         }
4349     }
4350     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4351
4352     memcpy(block->block_contents+offset,
4353            &frame_set->first_frame_time,
4354            sizeof(frame_set->first_frame_time));
4355     if(tng_data->output_endianness_swap_func_64)
4356     {
4357         if(tng_data->output_endianness_swap_func_64(tng_data,
4358                                       (int64_t *)block->header_contents+offset)
4359             != TNG_SUCCESS)
4360         {
4361             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4362                     __FILE__, __LINE__);
4363         }
4364     }
4365     offset += sizeof(frame_set->first_frame_time);
4366
4367     memcpy(block->block_contents+offset,
4368            &tng_data->time_per_frame,
4369            sizeof(tng_data->time_per_frame));
4370     if(tng_data->output_endianness_swap_func_64)
4371     {
4372         if(tng_data->output_endianness_swap_func_64(tng_data,
4373                                       (int64_t *)block->header_contents+offset)
4374             != TNG_SUCCESS)
4375         {
4376             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4377                     __FILE__, __LINE__);
4378         }
4379     }
4380
4381     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4382     {
4383         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4384                tng_data->output_file_path, __FILE__, __LINE__);
4385         return(TNG_CRITICAL);
4386     }
4387
4388     if(fwrite(block->block_contents, block->block_contents_size, 1,
4389               tng_data->output_file) != 1)
4390     {
4391         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4392         return(TNG_CRITICAL);
4393     }
4394
4395     return(TNG_SUCCESS);
4396 }
4397
4398 static tng_function_status tng_trajectory_mapping_block_len_calculate
4399                 (const tng_trajectory_t tng_data,
4400                  const int64_t n_particles,
4401                  int64_t *len)
4402 {
4403     (void)tng_data;
4404     *len = sizeof(int64_t) * (2 + n_particles);
4405
4406     return(TNG_SUCCESS);
4407 }
4408
4409 /** Read an atom mappings block (translating between real atom indexes and how
4410  *  the atom info is written in this frame set).
4411  * @param tng_data is a trajectory data container.
4412  * @param block is a general block container.
4413  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4414  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
4415  * compared to the md5 hash of the read contents to ensure valid data.
4416  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4417  * error has occured.
4418  */
4419 static tng_function_status tng_trajectory_mapping_block_read
4420                 (tng_trajectory_t tng_data,
4421                  tng_gen_block_t block,
4422                  const char hash_mode)
4423 {
4424     int64_t i;
4425     int offset = 0;
4426     tng_bool same_hash;
4427     tng_trajectory_frame_set_t frame_set =
4428     &tng_data->current_trajectory_frame_set;
4429
4430     tng_particle_mapping_t mapping, mappings;
4431
4432     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
4433     {
4434         return(TNG_CRITICAL);
4435     }
4436
4437     if(block->block_contents)
4438     {
4439         free(block->block_contents);
4440     }
4441
4442     block->block_contents = malloc(block->block_contents_size);
4443     if(!block->block_contents)
4444     {
4445         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4446                block->block_contents_size, __FILE__, __LINE__);
4447         return(TNG_CRITICAL);
4448     }
4449
4450     /* Read the whole block into block_contents to be able to write it to disk
4451      *  even if it cannot be interpreted. */
4452     if(fread(block->block_contents, block->block_contents_size, 1,
4453         tng_data->input_file) == 0)
4454     {
4455         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
4456         return(TNG_CRITICAL);
4457     }
4458
4459     /* FIXME: Does not check if the size of the contents matches the expected
4460      * size or if the contents can be read. */
4461
4462     if(hash_mode == TNG_USE_HASH)
4463     {
4464         tng_md5_hash_match_verify(block, &same_hash);
4465         if(same_hash != TNG_TRUE)
4466         {
4467             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4468                 "%s: %d\n",
4469                 __FILE__, __LINE__);
4470     /*         return(TNG_FAILURE); */
4471         }
4472     }
4473
4474     frame_set->n_mapping_blocks++;
4475     mappings = realloc(frame_set->mappings,
4476                        sizeof(struct tng_particle_mapping) *
4477                        frame_set->n_mapping_blocks);
4478     if(!mappings)
4479     {
4480         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4481                block->block_contents_size, __FILE__, __LINE__);
4482         free(frame_set->mappings);
4483         frame_set->mappings = 0;
4484         return(TNG_CRITICAL);
4485     }
4486     frame_set->mappings = mappings;
4487     mapping = &mappings[frame_set->n_mapping_blocks - 1];
4488
4489
4490     memcpy(&mapping->num_first_particle, block->block_contents+offset,
4491            sizeof(mapping->num_first_particle));
4492     if(tng_data->input_endianness_swap_func_64)
4493     {
4494         if(tng_data->input_endianness_swap_func_64(tng_data,
4495                                                    &mapping->num_first_particle)
4496             != TNG_SUCCESS)
4497         {
4498             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4499                     __FILE__, __LINE__);
4500         }
4501     }
4502     offset += sizeof(mapping->num_first_particle);
4503
4504     memcpy(&mapping->n_particles, block->block_contents+offset,
4505            sizeof(mapping->n_particles));
4506     if(tng_data->input_endianness_swap_func_64)
4507     {
4508         if(tng_data->input_endianness_swap_func_64(tng_data,
4509                                                    &mapping->n_particles)
4510             != TNG_SUCCESS)
4511         {
4512             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4513                     __FILE__, __LINE__);
4514         }
4515     }
4516     offset += sizeof(mapping->n_particles);
4517
4518     mapping->real_particle_numbers = malloc(mapping->n_particles *
4519                                             sizeof(int64_t));
4520     if(!mapping->real_particle_numbers)
4521     {
4522         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4523                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
4524         return(TNG_CRITICAL);
4525     }
4526
4527     /* If the byte order needs to be swapped the data must be read one value at
4528      * a time and swapped */
4529     if(tng_data->input_endianness_swap_func_64)
4530     {
4531         for(i = 0; i < mapping->n_particles; i++)
4532         {
4533             memcpy(&mapping->real_particle_numbers[i],
4534                     block->block_contents + offset,
4535                     sizeof(int64_t));
4536             if(tng_data->input_endianness_swap_func_64(tng_data,
4537                                             &mapping->real_particle_numbers[i])
4538                 != TNG_SUCCESS)
4539             {
4540                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4541                         __FILE__, __LINE__);
4542             }
4543             offset += sizeof(int64_t);
4544         }
4545     }
4546     /* Otherwise the data can be read all at once */
4547     else
4548     {
4549         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
4550                mapping->n_particles * sizeof(int64_t));
4551     }
4552
4553
4554     return(TNG_SUCCESS);
4555 }
4556
4557 /** Write the atom mappings of the current trajectory frame set
4558  * @param tng_data is a trajectory data container.
4559  * @param block is a general block container.
4560  * @param mapping_block_nr is the index of the mapping block to write.
4561  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4562  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4563  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4564  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4565  */
4566 static tng_function_status tng_trajectory_mapping_block_write
4567                 (tng_trajectory_t tng_data,
4568                  tng_gen_block_t block,
4569                  int mapping_block_nr,
4570                  const char hash_mode)
4571 {
4572     char *temp_name;
4573     int i, offset = 0;
4574     unsigned int name_len;
4575     tng_particle_mapping_t mapping =
4576     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4577
4578     if(mapping_block_nr >=
4579        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4580     {
4581         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4582                __FILE__, __LINE__);
4583         return(TNG_FAILURE);
4584     }
4585
4586     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4587     {
4588         return(TNG_CRITICAL);
4589     }
4590
4591     name_len = (int)strlen("PARTICLE MAPPING");
4592
4593     if(!block->name || strlen(block->name) < name_len)
4594     {
4595         temp_name = realloc(block->name, name_len + 1);
4596         if(!temp_name)
4597         {
4598             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4599                    name_len+1, __FILE__, __LINE__);
4600             free(block->name);
4601             block->name = 0;
4602             return(TNG_CRITICAL);
4603         }
4604         block->name = temp_name;
4605     }
4606     strcpy(block->name, "PARTICLE MAPPING");
4607     block->id = TNG_PARTICLE_MAPPING;
4608
4609     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4610                                                   mapping->n_particles,
4611                                                   &block->block_contents_size) !=
4612         TNG_SUCCESS)
4613     {
4614         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4615                 __FILE__, __LINE__);
4616         return(TNG_CRITICAL);
4617     }
4618
4619     if(block->block_contents)
4620     {
4621         free(block->block_contents);
4622     }
4623     block->block_contents = malloc(block->block_contents_size);
4624     if(!block->block_contents)
4625     {
4626         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4627                block->block_contents_size, __FILE__, __LINE__);
4628         return(TNG_CRITICAL);
4629     }
4630
4631     memcpy(block->block_contents, &mapping->num_first_particle,
4632            sizeof(mapping->num_first_particle));
4633     if(tng_data->output_endianness_swap_func_64)
4634     {
4635         if(tng_data->output_endianness_swap_func_64(tng_data,
4636                                       (int64_t *)block->header_contents+offset)
4637             != TNG_SUCCESS)
4638         {
4639             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4640                     __FILE__, __LINE__);
4641         }
4642     }
4643     offset += sizeof(mapping->num_first_particle);
4644
4645     memcpy(block->block_contents+offset, &mapping->n_particles,
4646            sizeof(mapping->n_particles));
4647     if(tng_data->output_endianness_swap_func_64)
4648     {
4649         if(tng_data->output_endianness_swap_func_64(tng_data,
4650                                       (int64_t *)block->header_contents+offset)
4651             != TNG_SUCCESS)
4652         {
4653             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4654                     __FILE__, __LINE__);
4655         }
4656     }
4657     offset += sizeof(mapping->n_particles);
4658
4659     if(tng_data->output_endianness_swap_func_64)
4660     {
4661         for(i = 0; i < mapping->n_particles; i++)
4662         {
4663             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
4664                 sizeof(int64_t));
4665             if(tng_data->output_endianness_swap_func_64(tng_data,
4666                                         (int64_t *)block->header_contents+offset)
4667                 != TNG_SUCCESS)
4668             {
4669                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4670                         __FILE__, __LINE__);
4671             }
4672             offset += sizeof(int64_t);
4673         }
4674     }
4675     else
4676     {
4677         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
4678                mapping->n_particles * sizeof(int64_t));
4679     }
4680
4681
4682     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4683     {
4684         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4685                tng_data->output_file_path, __FILE__, __LINE__);
4686         return(TNG_CRITICAL);
4687     }
4688
4689     if(fwrite(block->block_contents, block->block_contents_size, 1,
4690               tng_data->output_file) != 1)
4691     {
4692         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4693         return(TNG_CRITICAL);
4694     }
4695
4696     return(TNG_SUCCESS);
4697 }
4698
4699 /** Prepare a block for storing particle data
4700  * @param tng_data is a trajectory data container.
4701  * @param block_type_flag specifies if this is a trajectory block or a
4702  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4703  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4704  * error has occured.
4705  */
4706 static tng_function_status tng_particle_data_block_create
4707                 (tng_trajectory_t tng_data,
4708                  const char block_type_flag)
4709 {
4710     tng_trajectory_frame_set_t frame_set =
4711     &tng_data->current_trajectory_frame_set;
4712
4713     tng_particle_data_t data;
4714
4715     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4716     {
4717         frame_set->n_particle_data_blocks++;
4718         data = realloc(frame_set->tr_particle_data,
4719                     sizeof(struct tng_particle_data) *
4720                     frame_set->n_particle_data_blocks);
4721         if(!data)
4722         {
4723             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4724                 sizeof(struct tng_particle_data) *
4725                 frame_set->n_particle_data_blocks,
4726                 __FILE__, __LINE__);
4727             free(frame_set->tr_particle_data);
4728             frame_set->tr_particle_data = 0;
4729             return(TNG_CRITICAL);
4730         }
4731         frame_set->tr_particle_data = data;
4732     }
4733     else
4734     {
4735         tng_data->n_particle_data_blocks++;
4736         data = realloc(tng_data->non_tr_particle_data,
4737                         sizeof(struct tng_particle_data) *
4738                         tng_data->n_particle_data_blocks);
4739         if(!data)
4740         {
4741             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4742                     sizeof(struct tng_particle_data) *
4743                     tng_data->n_particle_data_blocks,
4744                     __FILE__, __LINE__);
4745             free(tng_data->non_tr_particle_data);
4746             tng_data->non_tr_particle_data = 0;
4747             return(TNG_CRITICAL);
4748         }
4749         tng_data->non_tr_particle_data = data;
4750     }
4751
4752     return(TNG_SUCCESS);
4753 }
4754
4755 static tng_function_status tng_compress(tng_trajectory_t tng_data,
4756                                         tng_gen_block_t block,
4757                                         const int64_t n_frames,
4758                                         const int64_t n_particles,
4759                                         const char type,
4760                                         void *start_pos)
4761 {
4762     int nalgo;
4763     int new_len;
4764     int *alt_algo = 0;
4765     char *dest, *temp;
4766     int64_t algo_find_n_frames;
4767     unsigned long offset;
4768     float f_precision;
4769     double d_precision;
4770
4771     if(block->id != TNG_TRAJ_POSITIONS &&
4772        block->id != TNG_TRAJ_VELOCITIES)
4773     {
4774         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4775                "TNG method. %s: %d\n", __FILE__, __LINE__);
4776         return(TNG_FAILURE);
4777     }
4778     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4779     {
4780         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4781         return(TNG_FAILURE);
4782     }
4783
4784     if(n_frames <= 0 || n_particles <= 0)
4785     {
4786         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4787                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4788         return(TNG_FAILURE);
4789     }
4790
4791     f_precision = 1/(float)tng_data->compression_precision;
4792     d_precision = 1/tng_data->compression_precision;
4793
4794     if(block->id == TNG_TRAJ_POSITIONS)
4795     {
4796         /* If there is only one frame in this frame set and there might be more
4797          * do not store the algorithm as the compression algorithm, but find
4798          * the best one without storing it */
4799         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4800         {
4801             nalgo = tng_compress_nalgo();
4802             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4803             if(type == TNG_FLOAT_DATA)
4804             {
4805                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
4806                                                         (int)n_frames,
4807                                                         f_precision,
4808                                                         0, alt_algo,
4809                                                         &new_len);
4810
4811             }
4812             else
4813             {
4814                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
4815                                            (int)n_frames,
4816                                            d_precision,
4817                                            0, alt_algo,
4818                                            &new_len);
4819             }
4820         }
4821         else if(!tng_data->compress_algo_pos)
4822         {
4823             if(n_frames > 10)
4824             {
4825                 algo_find_n_frames = 5;
4826             }
4827             else
4828             {
4829                 algo_find_n_frames = n_frames;
4830             }
4831
4832             nalgo = tng_compress_nalgo();
4833             tng_data->compress_algo_pos=malloc(nalgo *
4834                                            sizeof *tng_data->compress_algo_pos);
4835             if(type == TNG_FLOAT_DATA)
4836             {
4837                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
4838                                                         (int)algo_find_n_frames,
4839                                                         f_precision,
4840                                                         0, tng_data->
4841                                                         compress_algo_pos,
4842                                                         &new_len);
4843
4844                 if(algo_find_n_frames < n_frames)
4845                 {
4846                     dest = tng_compress_pos_float(start_pos, (int)n_particles,
4847                                                   (int)n_frames,
4848                                                   f_precision,
4849                                                   0, tng_data->compress_algo_pos,
4850                                                   &new_len);
4851                 }
4852             }
4853             else
4854             {
4855                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
4856                                            (int)algo_find_n_frames,
4857                                            d_precision,
4858                                            0, tng_data->
4859                                            compress_algo_pos,
4860                                            &new_len);
4861
4862                 if(algo_find_n_frames < n_frames)
4863                 {
4864                     dest = tng_compress_pos(start_pos, (int)n_particles,
4865                                             (int)n_frames,
4866                                             d_precision, 0,
4867                                             tng_data->compress_algo_pos,
4868                                             &new_len);
4869                 }
4870             }
4871         }
4872         else
4873         {
4874             if(type == TNG_FLOAT_DATA)
4875             {
4876                 dest = tng_compress_pos_float(start_pos, (int)n_particles,
4877                                               (int)n_frames,
4878                                               f_precision, 0,
4879                                               tng_data->compress_algo_pos, &new_len);
4880             }
4881             else
4882             {
4883                 dest = tng_compress_pos(start_pos, (int)n_particles,
4884                                         (int)n_frames,
4885                                         d_precision, 0,
4886                                         tng_data->compress_algo_pos,
4887                                         &new_len);
4888             }
4889         }
4890     }
4891     else if(block->id == TNG_TRAJ_VELOCITIES)
4892     {
4893         /* If there is only one frame in this frame set and there might be more
4894          * do not store the algorithm as the compression algorithm, but find
4895          * the best one without storing it */
4896         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4897         {
4898             nalgo = tng_compress_nalgo();
4899             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4900             if(type == TNG_FLOAT_DATA)
4901             {
4902                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4903                                                         (int)n_frames,
4904                                                         f_precision,
4905                                                         0, alt_algo,
4906                                                         &new_len);
4907
4908             }
4909             else
4910             {
4911                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4912                                                   (int)n_frames,
4913                                                   d_precision,
4914                                                   0, alt_algo,
4915                                                   &new_len);
4916             }
4917         }
4918         else if(!tng_data->compress_algo_vel)
4919         {
4920             if(n_frames > 10)
4921             {
4922                 algo_find_n_frames = 5;
4923             }
4924             else
4925             {
4926                 algo_find_n_frames = n_frames;
4927             }
4928
4929             nalgo = tng_compress_nalgo();
4930             tng_data->compress_algo_vel=malloc(nalgo *
4931                                            sizeof *tng_data->compress_algo_vel);
4932
4933             if(type == TNG_FLOAT_DATA)
4934             {
4935                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4936                                                         (int)algo_find_n_frames,
4937                                                         f_precision,
4938                                                         0, tng_data->
4939                                                         compress_algo_vel,
4940                                                         &new_len);
4941                 if(algo_find_n_frames < n_frames)
4942                 {
4943                     dest = tng_compress_vel_float(start_pos, (int)n_particles,
4944                                                   (int)n_frames,
4945                                                   f_precision,
4946                                                   0, tng_data->compress_algo_vel,
4947                                                   &new_len);
4948                 }
4949             }
4950             else
4951             {
4952                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4953                                                   (int)algo_find_n_frames,
4954                                                   d_precision,
4955                                                   0, tng_data->
4956                                                   compress_algo_vel,
4957                                                   &new_len);
4958                 if(algo_find_n_frames < n_frames)
4959                 {
4960                     dest = tng_compress_vel(start_pos, (int)n_particles,
4961                                             (int)n_frames,
4962                                             d_precision,
4963                                             0, tng_data->compress_algo_vel,
4964                                             &new_len);
4965                 }
4966             }
4967         }
4968         else
4969         {
4970             if(type == TNG_FLOAT_DATA)
4971             {
4972                 dest = tng_compress_vel_float(start_pos, (int)n_particles,
4973                                               (int)n_frames,
4974                                               f_precision,
4975                                               0, tng_data->
4976                                               compress_algo_vel,
4977                                               &new_len);
4978             }
4979             else
4980             {
4981                 dest = tng_compress_vel(start_pos, (int)n_particles,
4982                                         (int)n_frames,
4983                                         d_precision,
4984                                         0, tng_data->
4985                                         compress_algo_vel,
4986                                         &new_len);
4987             }
4988         }
4989     }
4990     else
4991     {
4992         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4993         return(TNG_FAILURE);
4994     }
4995
4996     offset = (unsigned long)((char *)start_pos - block->block_contents);
4997
4998     if(alt_algo)
4999     {
5000         free(alt_algo);
5001     }
5002
5003     block->block_contents_size = new_len + offset;
5004
5005     temp = realloc(block->block_contents, block->block_contents_size);
5006     if(!temp)
5007     {
5008         free(block->block_contents);
5009         block->block_contents = 0;
5010         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5011                block->block_contents_size, __FILE__, __LINE__);
5012         return(TNG_CRITICAL);
5013     }
5014     block->block_contents = temp;
5015     if(dest)
5016     {
5017         memcpy(temp + offset, dest, new_len);
5018         free(dest);
5019     }
5020     else
5021     {
5022         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
5023         return(TNG_FAILURE);
5024     }
5025
5026     return(TNG_SUCCESS);
5027 }
5028
5029 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
5030                                           tng_gen_block_t block,
5031                                           const char type,
5032                                           void *start_pos,
5033                                           const unsigned long uncompressed_len)
5034 {
5035     char *temp;
5036     double *d_dest = 0;
5037     float *f_dest = 0;
5038     unsigned long offset;
5039     int result;
5040     (void)tng_data;
5041
5042     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5043
5044     if(block->id != TNG_TRAJ_POSITIONS &&
5045        block->id != TNG_TRAJ_VELOCITIES)
5046     {
5047         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5048                "TNG method.\n");
5049         return(TNG_FAILURE);
5050     }
5051     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5052     {
5053         fprintf(stderr, "TNG library: Data type not supported.\n");
5054         return(TNG_FAILURE);
5055     }
5056
5057     if(type == TNG_FLOAT_DATA)
5058     {
5059         f_dest = malloc(uncompressed_len);
5060         if(!f_dest)
5061         {
5062             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5063                 uncompressed_len, __FILE__, __LINE__);
5064             return(TNG_CRITICAL);
5065         }
5066         result = tng_compress_uncompress_float(start_pos, f_dest);
5067     }
5068     else
5069     {
5070         d_dest = malloc(uncompressed_len);
5071         if(!d_dest)
5072         {
5073             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5074                 uncompressed_len, __FILE__, __LINE__);
5075             return(TNG_CRITICAL);
5076         }
5077         result = tng_compress_uncompress(start_pos, d_dest);
5078     }
5079
5080     if(result == 1)
5081     {
5082         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5083         return(TNG_FAILURE);
5084     }
5085
5086     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5087
5088     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5089
5090     temp = realloc(block->block_contents, uncompressed_len + offset);
5091     if(!temp)
5092     {
5093         free(block->block_contents);
5094         block->block_contents = 0;
5095         if(d_dest)
5096         {
5097             free(d_dest);
5098         }
5099         if(f_dest)
5100         {
5101             free(f_dest);
5102         }
5103         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5104                block->block_contents_size, __FILE__, __LINE__);
5105         return(TNG_CRITICAL);
5106     }
5107
5108     if(type == TNG_FLOAT_DATA)
5109     {
5110         memcpy(temp + offset, f_dest, uncompressed_len);
5111     }
5112     else
5113     {
5114         memcpy(temp + offset, d_dest, uncompressed_len);
5115     }
5116
5117     block->block_contents = temp;
5118
5119     if(d_dest)
5120     {
5121         free(d_dest);
5122     }
5123     if(f_dest)
5124     {
5125         free(f_dest);
5126     }
5127     return(TNG_SUCCESS);
5128 }
5129
5130 #ifdef USE_ZLIB
5131 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5132                                              tng_gen_block_t block,
5133                                              void *start_pos, const int len)
5134 {
5135     Bytef *dest;
5136     char *temp;
5137     unsigned long max_len, stat, offset;
5138     (void)tng_data;
5139
5140     max_len = compressBound(len);
5141     dest = malloc(max_len);
5142     if(!dest)
5143     {
5144         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
5145                max_len, __FILE__, __LINE__);
5146         return(TNG_CRITICAL);
5147     }
5148
5149     stat = compress(dest, &max_len, start_pos, len);
5150     if(stat != (unsigned long)Z_OK)
5151     {
5152         free(dest);
5153         if(stat == (unsigned long)Z_MEM_ERROR)
5154         {
5155             fprintf(stderr, "TNG library: Not enough memory. ");
5156         }
5157         else if(stat == (unsigned long)Z_BUF_ERROR)
5158         {
5159             fprintf(stderr, "TNG library: Destination buffer too small. ");
5160         }
5161         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5162         return(TNG_FAILURE);
5163     }
5164
5165     offset = (char *)start_pos - block->block_contents;
5166
5167     block->block_contents_size = max_len + offset;
5168
5169     temp = realloc(block->block_contents, block->block_contents_size);
5170     if(!temp)
5171     {
5172         free(block->block_contents);
5173         free(dest);
5174         block->block_contents = 0;
5175         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5176                block->block_contents_size, __FILE__, __LINE__);
5177         return(TNG_CRITICAL);
5178     }
5179
5180     block->block_contents = temp;
5181
5182     memcpy(temp + offset, dest, max_len);
5183
5184     free(dest);
5185
5186     return(TNG_SUCCESS);
5187 }
5188
5189 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5190                                                tng_gen_block_t block,
5191                                                void *start_pos,
5192                                                unsigned long uncompressed_len)
5193 {
5194     Bytef *dest;
5195     char *temp;
5196     unsigned long stat;
5197     int offset;
5198     (void)tng_data;
5199
5200     offset = (char *)start_pos - (char *)block->block_contents;
5201
5202     dest = malloc(uncompressed_len);
5203     if(!dest)
5204     {
5205         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5206                uncompressed_len, __FILE__, __LINE__);
5207         return(TNG_CRITICAL);
5208     }
5209
5210     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5211                       block->block_contents_size - offset);
5212
5213     if(stat != Z_OK)
5214     {
5215         free(dest);
5216         if(stat == (unsigned long)Z_MEM_ERROR)
5217         {
5218             fprintf(stderr, "TNG library: Not enough memory. ");
5219         }
5220         else if(stat == (unsigned long)Z_BUF_ERROR)
5221         {
5222             fprintf(stderr, "TNG library: Destination buffer too small. ");
5223         }
5224         else if(stat == (unsigned long)Z_DATA_ERROR)
5225         {
5226             fprintf(stderr, "TNG library: Data corrupt. ");
5227         }
5228         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5229                __LINE__);
5230         return(TNG_FAILURE);
5231     }
5232
5233
5234     block->block_contents_size = uncompressed_len + offset;
5235
5236     temp = realloc(block->block_contents, uncompressed_len + offset);
5237     if(!temp)
5238     {
5239         free(block->block_contents);
5240         block->block_contents = 0;
5241         free(dest);
5242         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5243                block->block_contents_size, __FILE__, __LINE__);
5244         return(TNG_CRITICAL);
5245     }
5246
5247     memcpy(temp + offset, dest, uncompressed_len);
5248
5249     block->block_contents = temp;
5250
5251     free(dest);
5252     return(TNG_SUCCESS);
5253 }
5254 #endif
5255
5256 /** Allocate memory for storing particle data.
5257  * The allocated block will be refered to by data->values.
5258  * @param tng_data is a trajectory data container.
5259  * @param data is the data struct, which will contain the allocated memory in
5260  * data->values.
5261  * @param n_frames is the number of frames of data to store.
5262  * @param n_particles is the number of particles with data.
5263  * @param n_values_per_frame is the number of data values per particle and
5264  * frame.
5265  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5266  * error has occured.
5267  */
5268 static tng_function_status tng_allocate_particle_data_mem
5269                 (tng_trajectory_t tng_data,
5270                  tng_particle_data_t data,
5271                  int64_t n_frames,
5272                  int64_t stride_length,
5273                  const int64_t n_particles,
5274                  const int64_t n_values_per_frame)
5275 {
5276     void ***values;
5277     int64_t i, j, k, size, frame_alloc;
5278     (void)tng_data;
5279
5280     if(n_particles == 0 || n_values_per_frame == 0)
5281     {
5282         return(TNG_FAILURE);
5283     }
5284
5285     if(data->strings && data->datatype == TNG_CHAR_DATA)
5286     {
5287         for(i = 0; i < data->n_frames; i++)
5288         {
5289             for(j = 0; j < n_particles; j++)
5290             {
5291                 for(k = 0; k < data->n_values_per_frame; k++)
5292                 {
5293                     if(data->strings[i][j][k])
5294                     {
5295                         free(data->strings[i][j][k]);
5296                     }
5297                 }
5298                 free(data->strings[i][j]);
5299             }
5300             free(data->strings[i]);
5301         }
5302         free(data->strings);
5303     }
5304     data->n_frames = n_frames;
5305     n_frames = tng_max_i64(1, n_frames);
5306     data->stride_length = tng_max_i64(1, stride_length);
5307     data->n_values_per_frame = n_values_per_frame;
5308     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5309
5310     if(data->datatype == TNG_CHAR_DATA)
5311     {
5312         data->strings = malloc(sizeof(char ***) * frame_alloc);
5313         for(i = 0; i < frame_alloc; i++)
5314         {
5315             data->strings[i] = malloc(sizeof(char **) *
5316                                     n_particles);
5317             if(!data->strings[i])
5318             {
5319                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5320                     sizeof(union data_values *) * n_particles,
5321                     __FILE__, __LINE__);
5322                 return(TNG_CRITICAL);
5323             }
5324             for(j = 0; j < n_particles; j++)
5325             {
5326                 data->strings[i][j] = malloc(sizeof(char *) *
5327                                             n_values_per_frame);
5328                 if(!data->strings[i][j])
5329                 {
5330                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5331                         sizeof(union data_values) * n_values_per_frame,
5332                         __FILE__, __LINE__);
5333                     return(TNG_CRITICAL);
5334                 }
5335                 for(k = 0; k < n_values_per_frame; k++)
5336                 {
5337                     data->strings[i][j][k] = 0;
5338                 }
5339             }
5340         }
5341     }
5342     else
5343     {
5344         switch(data->datatype)
5345         {
5346         case TNG_INT_DATA:
5347             size = sizeof(int64_t);
5348             break;
5349         case TNG_FLOAT_DATA:
5350             size = sizeof(float);
5351             break;
5352         case TNG_DOUBLE_DATA:
5353         default:
5354             size = sizeof(double);
5355         }
5356
5357         values = realloc(data->values,
5358                          size * frame_alloc *
5359                          n_particles * n_values_per_frame);
5360         if(!values)
5361         {
5362             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5363                    size * frame_alloc *
5364                    n_particles * n_values_per_frame,
5365                    __FILE__, __LINE__);
5366             free(data->values);
5367             data->values = 0;
5368             return(TNG_CRITICAL);
5369         }
5370         data->values = values;
5371     }
5372     return(TNG_SUCCESS);
5373 }
5374
5375 static tng_function_status tng_particle_data_find
5376                 (tng_trajectory_t tng_data,
5377                  const int64_t id,
5378                  tng_particle_data_t *data)
5379 {
5380     int64_t block_index, i;
5381     tng_trajectory_frame_set_t frame_set = &tng_data->
5382                                            current_trajectory_frame_set;
5383     char block_type_flag;
5384
5385     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5386        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5387     {
5388         block_type_flag = TNG_TRAJECTORY_BLOCK;
5389     }
5390     else
5391     {
5392         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5393     }
5394
5395     block_index = -1;
5396     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5397     {
5398         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5399         {
5400             *data = &frame_set->tr_particle_data[i];
5401             if((*data)->block_id == id)
5402             {
5403                 block_index = i;
5404                 break;
5405             }
5406         }
5407     }
5408     else
5409     {
5410         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5411         {
5412             *data = &tng_data->non_tr_particle_data[i];
5413             if((*data)->block_id == id)
5414             {
5415                 block_index = i;
5416                 break;
5417             }
5418         }
5419     }
5420     if(block_index == -1)
5421     {
5422         return(TNG_FAILURE);
5423     }
5424     return(TNG_SUCCESS);
5425 }
5426
5427 static tng_function_status tng_data_find
5428                 (tng_trajectory_t tng_data,
5429                  const int64_t id,
5430                  tng_non_particle_data_t *data)
5431 {
5432     int64_t block_index, i;
5433     tng_trajectory_frame_set_t frame_set = &tng_data->
5434                                            current_trajectory_frame_set;
5435     char block_type_flag;
5436
5437     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5438        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5439     {
5440         block_type_flag = TNG_TRAJECTORY_BLOCK;
5441     }
5442     else
5443     {
5444         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5445     }
5446
5447     block_index = -1;
5448     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5449     {
5450         for(i = 0; i < frame_set->n_data_blocks; i++)
5451         {
5452             *data = &frame_set->tr_data[i];
5453             if((*data)->block_id == id)
5454             {
5455                 block_index = i;
5456                 break;
5457             }
5458         }
5459         if(block_index == -1)
5460         {
5461             for(i = 0; i < tng_data->n_data_blocks; i++)
5462             {
5463                 *data = &tng_data->non_tr_data[i];
5464                 if((*data)->block_id == id)
5465                 {
5466                     block_index = i;
5467                     break;
5468                 }
5469             }
5470         }
5471     }
5472     else
5473     {
5474         for(i = 0; i < tng_data->n_data_blocks; i++)
5475         {
5476             *data = &tng_data->non_tr_data[i];
5477             if((*data)->block_id == id)
5478             {
5479                 block_index = i;
5480                 break;
5481             }
5482         }
5483     }
5484     if(block_index == -1)
5485     {
5486         return(TNG_FAILURE);
5487     }
5488     return(TNG_SUCCESS);
5489 }
5490
5491 static tng_function_status tng_data_block_len_calculate
5492                 (const tng_trajectory_t tng_data,
5493                  const tng_particle_data_t data,
5494                  const tng_bool is_particle_data,
5495                  const int64_t n_frames,
5496                  const int64_t frame_step,
5497                  const int64_t stride_length,
5498                  const int64_t num_first_particle,
5499                  const int64_t n_particles,
5500                  const char dependency,
5501                  int64_t *data_start_pos,
5502                  int64_t *len)
5503 {
5504     int size;
5505     int64_t i, j, k;
5506     char ***first_dim_values, **second_dim_values;
5507     (void)tng_data;
5508
5509     if(data == 0)
5510     {
5511         return(TNG_SUCCESS);
5512     }
5513
5514     switch(data->datatype)
5515     {
5516     case TNG_CHAR_DATA:
5517         size = 1;
5518         break;
5519     case TNG_INT_DATA:
5520         size = sizeof(int64_t);
5521         break;
5522     case TNG_FLOAT_DATA:
5523         size = sizeof(float);
5524         break;
5525     case TNG_DOUBLE_DATA:
5526     default:
5527         size = sizeof(double);
5528     }
5529
5530     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5531            sizeof(data->codec_id);
5532     if(is_particle_data)
5533     {
5534         *len += sizeof(num_first_particle) + sizeof(n_particles);
5535     }
5536
5537     if(stride_length > 1)
5538     {
5539         *len += sizeof(data->first_frame_with_data) +
5540                 sizeof(data->stride_length);
5541     }
5542
5543     if(data->codec_id != TNG_UNCOMPRESSED)
5544     {
5545         *len += sizeof(data->compression_multiplier);
5546     }
5547
5548     if(dependency & TNG_FRAME_DEPENDENT)
5549     {
5550         *len += sizeof(char);
5551     }
5552
5553     *data_start_pos = *len;
5554
5555     if(data->datatype == TNG_CHAR_DATA)
5556     {
5557         if(is_particle_data)
5558         {
5559             for(i = 0; i < n_frames; i++)
5560             {
5561                 first_dim_values = data->strings[i];
5562                 for(j = num_first_particle; j < num_first_particle + n_particles;
5563                     j++)
5564                 {
5565                     second_dim_values = first_dim_values[j];
5566                     for(k = 0; k < data->n_values_per_frame; k++)
5567                     {
5568                         *len += strlen(second_dim_values[k]) + 1;
5569                     }
5570                 }
5571             }
5572         }
5573         else
5574         {
5575             for(i = 0; i < n_frames; i++)
5576             {
5577                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5578                 for(j = 0; j < data->n_values_per_frame; j++)
5579                 {
5580                     *len += strlen(second_dim_values[j]) + 1;
5581                 }
5582             }
5583         }
5584     }
5585     else
5586     {
5587         *len += size * frame_step * n_particles * data->n_values_per_frame;
5588     }
5589
5590     return(TNG_SUCCESS);
5591 }
5592
5593 /** Read the values of a particle data block
5594  * @param tng_data is a trajectory data container.
5595  * @param block is the block to store the data (should already contain
5596  * the block headers and the block contents).
5597  * @param offset is the reading offset to point at the place where the actual
5598  * values are stored, starting from the beginning of the block_contents. The
5599  * offset is changed during the reading.
5600  * @param datatype is the type of data of the data block (char, int, float or
5601  * double).
5602  * @param num_first_particle is the number of the first particle in the data
5603  * block. This should be the same as in the corresponding particle mapping
5604  * block.
5605  * @param n_particles is the number of particles in the data block. This should
5606  * be the same as in the corresponding particle mapping block.
5607  * @param first_frame_with_data is the frame number of the first frame with data
5608  * in this data block.
5609  * @param stride_length is the number of frames between each data entry.
5610  * @param n_frames is the number of frames in this data block.
5611  * @param n_values is the number of values per particle and frame stored in this
5612  * data block.
5613  * @param codec_id is the ID of the codec to compress the data.
5614  * @param multiplier is the multiplication factor applied to each data value
5615  * before compression. This factor is applied since some compression algorithms
5616  * work only on integers.
5617  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5618  * error has occured.
5619  */
5620 static tng_function_status tng_particle_data_read
5621                 (tng_trajectory_t tng_data,
5622                  tng_gen_block_t block,
5623                  int *offset,
5624                  const char datatype,
5625                  const int64_t num_first_particle,
5626                  const int64_t n_particles,
5627                  const int64_t first_frame_with_data,
5628                  const int64_t stride_length,
5629                  int64_t n_frames,
5630                  const int64_t n_values,
5631                  const int64_t codec_id,
5632                  const double multiplier)
5633 {
5634     int64_t i, j, k, tot_n_particles, n_frames_div;
5635     int size, len;
5636     unsigned long data_size;
5637     char ***first_dim_values, **second_dim_values;
5638     tng_particle_data_t data;
5639     tng_trajectory_frame_set_t frame_set =
5640     &tng_data->current_trajectory_frame_set;
5641     char block_type_flag;
5642
5643     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5644
5645     switch(datatype)
5646     {
5647     case TNG_CHAR_DATA:
5648         size = 1;
5649         break;
5650     case TNG_INT_DATA:
5651         size = sizeof(int64_t);
5652         break;
5653     case TNG_FLOAT_DATA:
5654         size = sizeof(float);
5655         break;
5656     case TNG_DOUBLE_DATA:
5657     default:
5658         size = sizeof(double);
5659     }
5660
5661     /* If the block does not exist, create it */
5662     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5663     {
5664         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5665         {
5666             block_type_flag = TNG_TRAJECTORY_BLOCK;
5667         }
5668         else
5669         {
5670             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5671         }
5672
5673         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5674            TNG_SUCCESS)
5675         {
5676             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5677                    __FILE__, __LINE__);
5678             return(TNG_CRITICAL);
5679         }
5680         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5681         {
5682             data = &frame_set->tr_particle_data[frame_set->
5683                                                 n_particle_data_blocks - 1];
5684         }
5685         else
5686         {
5687             data = &tng_data->non_tr_particle_data[tng_data->
5688                                                    n_particle_data_blocks - 1];
5689         }
5690         data->block_id = block->id;
5691
5692         data->block_name = malloc(strlen(block->name) + 1);
5693         if(!data->block_name)
5694         {
5695             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5696                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5697             return(TNG_CRITICAL);
5698         }
5699         strcpy(data->block_name, block->name);
5700
5701         data->datatype = datatype;
5702
5703         data->values = 0;
5704         /* FIXME: Memory leak from strings. */
5705         data->strings = 0;
5706         data->n_frames = 0;
5707         data->codec_id = codec_id;
5708         data->compression_multiplier = multiplier;
5709         data->last_retrieved_frame = -1;
5710     }
5711
5712     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5713        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5714        tng_data->var_num_atoms_flag)
5715     {
5716         tot_n_particles = frame_set->n_particles;
5717     }
5718     else
5719     {
5720         tot_n_particles = tng_data->n_particles;
5721     }
5722
5723     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5724
5725     if(codec_id != TNG_UNCOMPRESSED)
5726     {
5727         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5728         switch(codec_id)
5729         {
5730         case TNG_XTC_COMPRESSION:
5731             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5732             break;
5733         case TNG_TNG_COMPRESSION:
5734 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5735             if(tng_uncompress(tng_data, block, datatype,
5736                               block->block_contents + *offset,
5737                               data_size) != TNG_SUCCESS)
5738             {
5739                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5740                        __FILE__, __LINE__);
5741                 return(TNG_CRITICAL);
5742             }
5743 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5744             break;
5745 #ifdef USE_ZLIB
5746         case TNG_GZIP_COMPRESSION:
5747 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5748             if(tng_gzip_uncompress(tng_data, block,
5749                                    block->block_contents + *offset,
5750                                    data_size) != TNG_SUCCESS)
5751             {
5752                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5753                     __LINE__);
5754                 return(TNG_CRITICAL);
5755             }
5756 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5757             break;
5758 #endif
5759         }
5760     }
5761     /* Allocate memory */
5762     if(!data->values || data->n_frames != n_frames ||
5763        data->n_values_per_frame != n_values)
5764     {
5765         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5766                                           stride_length,
5767                                           tot_n_particles, n_values) !=
5768            TNG_SUCCESS)
5769         {
5770             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5771                    __FILE__, __LINE__);
5772             return(TNG_CRITICAL);
5773         }
5774     }
5775
5776     data->first_frame_with_data = first_frame_with_data;
5777
5778     if(datatype == TNG_CHAR_DATA)
5779     {
5780         for(i = 0; i < n_frames_div; i++)
5781         {
5782             first_dim_values = data->strings[i];
5783             for(j = num_first_particle; j < num_first_particle + n_particles;
5784                 j++)
5785             {
5786                 second_dim_values = first_dim_values[j];
5787                 for(k = 0; k < n_values; k++)
5788                 {
5789                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5790                               TNG_MAX_STR_LEN);
5791                     if(second_dim_values[k])
5792                     {
5793                         free(second_dim_values[k]);
5794                     }
5795                     second_dim_values[k] = malloc(len);
5796                     if(!second_dim_values[k])
5797                     {
5798                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5799                             len, __FILE__, __LINE__);
5800                         return(TNG_CRITICAL);
5801                     }
5802                     strncpy(second_dim_values[k],
5803                             block->block_contents+*offset, len);
5804                     *offset += len;
5805                 }
5806             }
5807         }
5808     }
5809     else
5810     {
5811         memcpy((char *)data->values + n_frames_div * size * n_values *
5812                num_first_particle,
5813                block->block_contents + *offset,
5814                block->block_contents_size - *offset);
5815         switch(datatype)
5816         {
5817         case TNG_FLOAT_DATA:
5818             if(tng_data->input_endianness_swap_func_32)
5819             {
5820                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5821                 {
5822                     if(tng_data->input_endianness_swap_func_32(tng_data,
5823                         (int32_t *)((char *)data->values + i))
5824                         != TNG_SUCCESS)
5825                     {
5826                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5827                                 __FILE__, __LINE__);
5828                     }
5829                 }
5830             }
5831             break;
5832         case TNG_INT_DATA:
5833         case TNG_DOUBLE_DATA:
5834             if(tng_data->input_endianness_swap_func_64)
5835             {
5836                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5837                 {
5838                     if(tng_data->input_endianness_swap_func_64(tng_data,
5839                         (int64_t *)((char *)data->values + i))
5840                         != TNG_SUCCESS)
5841                     {
5842                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5843                                 __FILE__, __LINE__);
5844                     }
5845                 }
5846             }
5847             break;
5848         case TNG_CHAR_DATA:
5849             break;
5850         }
5851     }
5852     return(TNG_SUCCESS);
5853 }
5854
5855 /** Write a particle data block
5856  * @param tng_data is a trajectory data container.
5857  * @param block is the block to store the data (should already contain
5858  * the block headers and the block contents).
5859  * @param block_index is the index number of the data block in the frame set.
5860  * @param mapping is the particle mapping that is relevant for the data block.
5861  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5862  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5863  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5864  * error has occured.
5865  */
5866 static tng_function_status tng_particle_data_block_write
5867                 (tng_trajectory_t tng_data,
5868                  tng_gen_block_t block,
5869                  const int64_t block_index,
5870                  const tng_particle_mapping_t mapping,
5871                  const char hash_mode)
5872 {
5873     int64_t n_particles, num_first_particle, n_frames, stride_length;
5874     int64_t frame_step, data_start_pos;
5875     int64_t i, j, k;
5876     int size;
5877     size_t len, offset = 0;
5878     char dependency, temp, *temp_name;
5879     double multiplier;
5880     char ***first_dim_values, **second_dim_values;
5881     tng_trajectory_frame_set_t frame_set;
5882     tng_function_status stat;
5883
5884     tng_particle_data_t data;
5885     char block_type_flag;
5886
5887     frame_set = &tng_data->current_trajectory_frame_set;
5888
5889     /* If we have already started writing frame sets it is too late to write
5890      * non-trajectory data blocks */
5891     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5892     {
5893         block_type_flag = TNG_TRAJECTORY_BLOCK;
5894     }
5895     else
5896     {
5897         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5898     }
5899
5900     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5901     {
5902         return(TNG_CRITICAL);
5903     }
5904
5905     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5906     {
5907         data = &frame_set->tr_particle_data[block_index];
5908
5909         /* If this data block has not had any data added in this frame set
5910          * do not write it. */
5911         if(data->first_frame_with_data < frame_set->first_frame)
5912         {
5913             return(TNG_SUCCESS);
5914         }
5915
5916         stride_length = tng_max_i64(1, data->stride_length);
5917     }
5918     else
5919     {
5920         data = &tng_data->non_tr_particle_data[block_index];
5921         stride_length = 1;
5922     }
5923
5924     switch(data->datatype)
5925     {
5926     case TNG_CHAR_DATA:
5927         size = 1;
5928         break;
5929     case TNG_INT_DATA:
5930         size = sizeof(int64_t);
5931         break;
5932     case TNG_FLOAT_DATA:
5933         size = sizeof(float);
5934         break;
5935     case TNG_DOUBLE_DATA:
5936     default:
5937         size = sizeof(double);
5938     }
5939
5940     len = strlen(data->block_name) + 1;
5941
5942     if(!block->name || strlen(block->name) < len)
5943     {
5944         temp_name = realloc(block->name, len);
5945         if(!temp_name)
5946         {
5947             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
5948                    __FILE__, __LINE__);
5949             free(block->name);
5950             block->name = 0;
5951             return(TNG_CRITICAL);
5952         }
5953         block->name = temp_name;
5954     }
5955     strncpy(block->name, data->block_name, len);
5956     block->id = data->block_id;
5957
5958     /* If writing frame independent data data->n_frames is 0, but n_frames
5959        is used for the loop writing the data (and reserving memory) and needs
5960        to be at least 1 */
5961     n_frames = tng_max_i64(1, data->n_frames);
5962
5963     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5964     {
5965         /* If the frame set is finished before writing the full number of frames
5966            make sure the data block is not longer than the frame set. */
5967         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5968
5969         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5970     }
5971
5972     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5973                  n_frames / stride_length;
5974
5975     /* TNG compression will use compression precision to get integers from
5976      * floating point data. The compression multiplier stores that information
5977      * to be able to return the precision of the compressed data. */
5978     if(data->codec_id == TNG_TNG_COMPRESSION)
5979     {
5980         data->compression_multiplier = tng_data->compression_precision;
5981     }
5982     /* Uncompressed data blocks do not use compression multipliers at all.
5983      * GZip compression does not need it either. */
5984     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5985     {
5986         data->compression_multiplier = 1.0;
5987     }
5988
5989     if(mapping && mapping->n_particles != 0)
5990     {
5991         n_particles = mapping->n_particles;
5992         num_first_particle = mapping->num_first_particle;
5993     }
5994     else
5995     {
5996         num_first_particle = 0;
5997         if(tng_data->var_num_atoms_flag)
5998         {
5999             n_particles = frame_set->n_particles;
6000         }
6001         else
6002         {
6003             n_particles = tng_data->n_particles;
6004         }
6005     }
6006
6007     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6008     {
6009         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6010     }
6011     else
6012     {
6013         dependency = TNG_PARTICLE_DEPENDENT;
6014     }
6015
6016     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6017                                     frame_step, stride_length, num_first_particle,
6018                                     n_particles, dependency, &data_start_pos,
6019                                     &block->block_contents_size) != TNG_SUCCESS)
6020     {
6021         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6022                 __FILE__, __LINE__);
6023         return(TNG_CRITICAL);
6024     }
6025
6026     if(block->block_contents)
6027     {
6028         free(block->block_contents);
6029     }
6030     block->block_contents = malloc(block->block_contents_size);
6031     if(!block->block_contents)
6032     {
6033         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6034                block->block_contents_size, __FILE__, __LINE__);
6035         return(TNG_CRITICAL);
6036     }
6037
6038
6039     memcpy(block->block_contents, &data->datatype, sizeof(char));
6040     offset += sizeof(char);
6041
6042     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6043     offset += sizeof(char);
6044
6045     if(dependency & TNG_FRAME_DEPENDENT)
6046     {
6047         if(stride_length > 1)
6048         {
6049             temp = 1;
6050         }
6051         else
6052         {
6053             temp = 0;
6054         }
6055         memcpy(block->block_contents+offset, &temp, sizeof(char));
6056         offset += sizeof(char);
6057     }
6058
6059     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6060            sizeof(data->n_values_per_frame));
6061     if(tng_data->output_endianness_swap_func_64)
6062     {
6063         if(tng_data->output_endianness_swap_func_64(tng_data,
6064            (int64_t *)block->header_contents+offset)
6065             != TNG_SUCCESS)
6066         {
6067             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6068                     __FILE__, __LINE__);
6069         }
6070     }
6071     offset += sizeof(data->n_values_per_frame);
6072
6073     memcpy(block->block_contents+offset, &data->codec_id,
6074            sizeof(data->codec_id));
6075     if(tng_data->output_endianness_swap_func_64)
6076     {
6077         if(tng_data->output_endianness_swap_func_64(tng_data,
6078            (int64_t *)block->header_contents+offset)
6079             != TNG_SUCCESS)
6080         {
6081             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6082                     __FILE__, __LINE__);
6083         }
6084     }
6085     offset += sizeof(data->codec_id);
6086
6087     if(data->codec_id != TNG_UNCOMPRESSED)
6088     {
6089         memcpy(block->block_contents+offset, &data->compression_multiplier,
6090                sizeof(data->compression_multiplier));
6091         if(tng_data->output_endianness_swap_func_64)
6092         {
6093             if(tng_data->output_endianness_swap_func_64(tng_data,
6094                (int64_t *)block->header_contents+offset)
6095                 != TNG_SUCCESS)
6096             {
6097                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6098                         __FILE__, __LINE__);
6099             }
6100         }
6101         offset += sizeof(data->compression_multiplier);
6102     }
6103
6104     if(data->n_frames > 0 && stride_length > 1)
6105     {
6106         /* FIXME: first_frame_with_data is not reliably set */
6107         if(data->first_frame_with_data == 0)
6108         {
6109             data->first_frame_with_data = frame_set->first_frame;
6110         }
6111         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6112                sizeof(data->first_frame_with_data));
6113         if(tng_data->output_endianness_swap_func_64)
6114         {
6115             if(tng_data->output_endianness_swap_func_64(tng_data,
6116                (int64_t *)block->header_contents+offset)
6117                 != TNG_SUCCESS)
6118             {
6119                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6120                         __FILE__, __LINE__);
6121             }
6122         }
6123         offset += sizeof(data->first_frame_with_data);
6124
6125         memcpy(block->block_contents+offset, &stride_length,
6126                sizeof(stride_length));
6127         if(tng_data->output_endianness_swap_func_64)
6128         {
6129             if(tng_data->output_endianness_swap_func_64(tng_data,
6130                (int64_t *)block->header_contents+offset)
6131                 != TNG_SUCCESS)
6132             {
6133                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6134                         __FILE__, __LINE__);
6135             }
6136         }
6137         offset += sizeof(stride_length);
6138     }
6139
6140
6141     memcpy(block->block_contents+offset, &num_first_particle,
6142            sizeof(num_first_particle));
6143     if(tng_data->output_endianness_swap_func_64)
6144     {
6145         if(tng_data->output_endianness_swap_func_64(tng_data,
6146            (int64_t *)block->header_contents+offset)
6147             != TNG_SUCCESS)
6148         {
6149             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6150                     __FILE__, __LINE__);
6151         }
6152     }
6153     offset += sizeof(num_first_particle);
6154
6155     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6156     if(tng_data->output_endianness_swap_func_64)
6157     {
6158         if(tng_data->output_endianness_swap_func_64(tng_data,
6159            (int64_t *)block->header_contents+offset)
6160             != TNG_SUCCESS)
6161         {
6162             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6163                     __FILE__, __LINE__);
6164         }
6165     }
6166     offset += sizeof(n_particles);
6167
6168     if(data->datatype == TNG_CHAR_DATA)
6169     {
6170         if(data->strings)
6171         {
6172             for(i = 0; i < frame_step; i++)
6173             {
6174                 first_dim_values = data->strings[i];
6175                 for(j = num_first_particle; j < num_first_particle + n_particles;
6176                     j++)
6177                 {
6178                     second_dim_values = first_dim_values[j];
6179                     for(k = 0; k < data->n_values_per_frame; k++)
6180                     {
6181                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6182                         strncpy(block->block_contents+offset,
6183                                 second_dim_values[k], len);
6184                         offset += len;
6185                     }
6186                 }
6187             }
6188         }
6189     }
6190     else if(data->values)
6191     {
6192         memcpy(block->block_contents + offset, data->values,
6193                block->block_contents_size - offset);
6194
6195         switch(data->datatype)
6196         {
6197         case TNG_FLOAT_DATA:
6198             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6199                data->codec_id == TNG_TNG_COMPRESSION)
6200             {
6201                 if(tng_data->input_endianness_swap_func_32)
6202                 {
6203                     for(i = offset; i < block->block_contents_size; i+=size)
6204                     {
6205                         if(tng_data->input_endianness_swap_func_32(tng_data,
6206                            (int32_t *)(block->block_contents + i))
6207                            != TNG_SUCCESS)
6208                         {
6209                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6210                                     __FILE__, __LINE__);
6211                         }
6212                     }
6213                 }
6214             }
6215             else
6216             {
6217                 multiplier = data->compression_multiplier;
6218                 if(fabs(multiplier - 1.0) > 0.00001 ||
6219                    tng_data->input_endianness_swap_func_32)
6220                 {
6221                     for(i = offset; i < block->block_contents_size; i+=size)
6222                     {
6223                         *(float *)(block->block_contents + i) *= (float)multiplier;
6224                         if(tng_data->input_endianness_swap_func_32 &&
6225                         tng_data->input_endianness_swap_func_32(tng_data,
6226                         (int32_t *)(block->block_contents + i))
6227                         != TNG_SUCCESS)
6228                         {
6229                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6230                                     __FILE__, __LINE__);
6231                         }
6232                     }
6233                 }
6234             }
6235             break;
6236         case TNG_INT_DATA:
6237             if(tng_data->input_endianness_swap_func_64)
6238             {
6239                 for(i = offset; i < block->block_contents_size; i+=size)
6240                 {
6241                     if(tng_data->input_endianness_swap_func_64(tng_data,
6242                        (int64_t *)(block->block_contents + i))
6243                        != TNG_SUCCESS)
6244                     {
6245                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6246                                 __FILE__, __LINE__);
6247                     }
6248                 }
6249             }
6250             break;
6251         case TNG_DOUBLE_DATA:
6252             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6253                data->codec_id == TNG_TNG_COMPRESSION)
6254             {
6255                 if(tng_data->input_endianness_swap_func_64)
6256                 {
6257                     for(i = offset; i < block->block_contents_size; i+=size)
6258                     {
6259                         if(tng_data->input_endianness_swap_func_64(tng_data,
6260                            (int64_t *)(block->block_contents + i))
6261                            != TNG_SUCCESS)
6262                         {
6263                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6264                                     __FILE__, __LINE__);
6265                         }
6266                     }
6267                 }
6268             }
6269             else
6270             {
6271                 multiplier = data->compression_multiplier;
6272                 if(fabs(multiplier - 1.0) > 0.00001 ||
6273                    tng_data->input_endianness_swap_func_64)
6274                 {
6275                     for(i = offset; i < block->block_contents_size; i+=size)
6276                     {
6277                         *(double *)(block->block_contents + i) *= multiplier;
6278                         if(tng_data->input_endianness_swap_func_64 &&
6279                         tng_data->input_endianness_swap_func_64(tng_data,
6280                         (int64_t *)(block->block_contents + i))
6281                         != TNG_SUCCESS)
6282                         {
6283                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6284                                     __FILE__, __LINE__);
6285                         }
6286                     }
6287                 }
6288             }
6289             break;
6290         case TNG_CHAR_DATA:
6291             break;
6292         }
6293     }
6294     else
6295     {
6296         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6297     }
6298
6299     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6300     frame_set->n_unwritten_frames = 0;
6301
6302     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6303     {
6304         switch(data->codec_id)
6305         {
6306         case TNG_XTC_COMPRESSION:
6307             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6308             data->codec_id = TNG_UNCOMPRESSED;
6309             break;
6310         case TNG_TNG_COMPRESSION:
6311             stat = tng_compress(tng_data, block, frame_step,
6312                                 n_particles, data->datatype,
6313                                 block->block_contents + data_start_pos);
6314             if(stat != TNG_SUCCESS)
6315             {
6316                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6317                     __FILE__, __LINE__);
6318                 if(stat == TNG_CRITICAL)
6319                 {
6320                     return(TNG_CRITICAL);
6321                 }
6322                 /* Set the data again, but with no compression (to write only
6323                  * the relevant data) */
6324                 data->codec_id = TNG_UNCOMPRESSED;
6325                 stat = tng_particle_data_block_write(tng_data, block,
6326                                                      block_index, mapping,
6327                                                      hash_mode);
6328                 return(stat);
6329             }
6330             break;
6331 #ifdef USE_ZLIB
6332         case TNG_GZIP_COMPRESSION:
6333     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6334             stat = tng_gzip_compress(tng_data, block,
6335                                      block->block_contents + data_start_pos,
6336                                      block->block_contents_size - data_start_pos);
6337             if(stat != TNG_SUCCESS)
6338             {
6339                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6340                     __LINE__);
6341                 if(stat == TNG_CRITICAL)
6342                 {
6343                     return(TNG_CRITICAL);
6344                 }
6345                 /* Set the data again, but with no compression (to write only
6346                  * the relevant data) */
6347                 data->codec_id = TNG_UNCOMPRESSED;
6348                 stat = tng_particle_data_block_write(tng_data, block,
6349                                                      block_index, mapping,
6350                                                      hash_mode);
6351                 return(stat);
6352             }
6353     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6354             break;
6355 #endif
6356         }
6357     }
6358
6359     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6360     {
6361         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6362                tng_data->output_file_path, __FILE__, __LINE__);
6363         return(TNG_CRITICAL);
6364     }
6365
6366     if(fwrite(block->block_contents, block->block_contents_size, 1,
6367         tng_data->output_file) != 1)
6368     {
6369         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6370                 __LINE__);
6371         return(TNG_CRITICAL);
6372     }
6373
6374     return(TNG_SUCCESS);
6375 }
6376
6377 /* TEST: */
6378 /** Create a non-particle data block
6379  * @param tng_data is a trajectory data container.
6380  * @param block_type_flag specifies if this is a trajectory block or a
6381  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6382  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6383  * error has occured.
6384  */
6385 static tng_function_status tng_data_block_create
6386                 (tng_trajectory_t tng_data,
6387                  const char block_type_flag)
6388 {
6389     tng_trajectory_frame_set_t frame_set =
6390     &tng_data->current_trajectory_frame_set;
6391
6392     tng_non_particle_data_t data;
6393
6394     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6395     {
6396         frame_set->n_data_blocks++;
6397         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6398                        frame_set->n_data_blocks);
6399         if(!data)
6400         {
6401             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6402                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6403                 __FILE__, __LINE__);
6404             free(frame_set->tr_data);
6405             frame_set->tr_data = 0;
6406             return(TNG_CRITICAL);
6407         }
6408         frame_set->tr_data = data;
6409     }
6410     else
6411     {
6412         tng_data->n_data_blocks++;
6413         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6414                         tng_data->n_data_blocks);
6415         if(!data)
6416         {
6417             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6418                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6419                 __FILE__, __LINE__);
6420             free(tng_data->non_tr_data);
6421             tng_data->non_tr_data = 0;
6422             return(TNG_CRITICAL);
6423         }
6424         tng_data->non_tr_data = data;
6425     }
6426
6427     return(TNG_SUCCESS);
6428 }
6429
6430 /* TEST: */
6431 /** Allocate memory for storing non-particle data.
6432  * The allocated block will be refered to by data->values.
6433  * @param tng_data is a trajectory data container.
6434  * @param data is the data struct, which will contain the allocated memory in
6435  * data->values.
6436  * @param n_frames is the number of frames of data to store.
6437  * @param n_values_per_frame is the number of data values per frame.
6438  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6439  * error has occured.
6440  */
6441 static tng_function_status tng_allocate_data_mem
6442                 (tng_trajectory_t tng_data,
6443                  tng_non_particle_data_t data,
6444                  int64_t n_frames,
6445                  int64_t stride_length,
6446                  const int64_t n_values_per_frame)
6447 {
6448     void **values;
6449     int64_t i, j, size, frame_alloc;
6450     (void)tng_data;
6451
6452     if(n_values_per_frame == 0)
6453     {
6454         return(TNG_FAILURE);
6455     }
6456
6457     if(data->strings && data->datatype == TNG_CHAR_DATA)
6458     {
6459         for(i = 0; i < data->n_frames; i++)
6460         {
6461             for(j = 0; j < data->n_values_per_frame; j++)
6462             {
6463                 if(data->strings[i][j])
6464                 {
6465                     free(data->strings[i][j]);
6466                     data->strings[i][j] = 0;
6467                 }
6468             }
6469             free(data->strings[i]);
6470             data->strings[i] = 0;
6471         }
6472         free(data->strings);
6473     }
6474     data->n_frames = n_frames;
6475     data->stride_length = tng_max_i64(1, stride_length);
6476     n_frames = tng_max_i64(1, n_frames);
6477     data->n_values_per_frame = n_values_per_frame;
6478     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6479
6480     if(data->datatype == TNG_CHAR_DATA)
6481     {
6482         data->strings = malloc(sizeof(char **) * frame_alloc);
6483         for(i = 0; i < frame_alloc; i++)
6484         {
6485             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6486             if(!data->strings[i])
6487             {
6488                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6489                        n_values_per_frame,
6490                        __FILE__, __LINE__);
6491                 return(TNG_CRITICAL);
6492             }
6493             for(j = 0; j < n_values_per_frame; j++)
6494             {
6495                 data->strings[i][j] = 0;
6496             }
6497         }
6498     }
6499     else
6500     {
6501         switch(data->datatype)
6502         {
6503         case TNG_INT_DATA:
6504             size = sizeof(int64_t);
6505             break;
6506         case TNG_FLOAT_DATA:
6507             size = sizeof(float);
6508             break;
6509         case TNG_DOUBLE_DATA:
6510         default:
6511             size = sizeof(double);
6512         }
6513
6514         values = realloc(data->values,
6515                          size * frame_alloc *
6516                          n_values_per_frame);
6517         if(!values)
6518         {
6519             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6520                    size * frame_alloc *
6521                    n_values_per_frame,
6522                    __FILE__, __LINE__);
6523             free(data->values);
6524             data->values = 0;
6525             return(TNG_CRITICAL);
6526         }
6527         data->values = values;
6528     }
6529
6530     return(TNG_SUCCESS);
6531 }
6532
6533 /** Read the values of a non-particle data block
6534  * @param tng_data is a trajectory data container.
6535  * @param block is the block to store the data (should already contain
6536  * the block headers and the block contents).
6537  * @param offset is the reading offset to point at the place where the actual
6538  * values are stored, starting from the beginning of the block_contents. The
6539  * offset is changed during the reading.
6540  * @param datatype is the type of data of the data block (char, int, float or
6541  * double).
6542  * @param first_frame_with_data is the frame number of the first frame with data
6543  * in this data block.
6544  * @param stride_length is the number of frames between each data entry.
6545  * @param n_frames is the number of frames in this data block.
6546  * @param n_values is the number of values per frame stored in this data block.
6547  * @param codec_id is the ID of the codec to compress the data.
6548  * @param multiplier is the multiplication factor applied to each data value
6549  * before compression. This factor is applied since some compression algorithms
6550  * work only on integers.
6551  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6552  * error has occured.
6553  */
6554 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6555                                          tng_gen_block_t block,
6556                                          int *offset,
6557                                          const char datatype,
6558                                          const int64_t first_frame_with_data,
6559                                          const int64_t stride_length,
6560                                          int64_t n_frames,
6561                                          const int64_t n_values,
6562                                          const int64_t codec_id,
6563                                          const double multiplier)
6564 {
6565     int64_t i, j, n_frames_div;
6566     int size, len;
6567 #ifdef USE_ZLIB
6568     unsigned long data_size;
6569 #endif
6570     tng_non_particle_data_t data;
6571     tng_trajectory_frame_set_t frame_set =
6572     &tng_data->current_trajectory_frame_set;
6573     char block_type_flag;
6574
6575     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6576
6577 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6578
6579     switch(datatype)
6580     {
6581     case TNG_CHAR_DATA:
6582         size = 1;
6583         break;
6584     case TNG_INT_DATA:
6585         size = sizeof(int64_t);
6586         break;
6587     case TNG_FLOAT_DATA:
6588         size = sizeof(float);
6589         break;
6590     case TNG_DOUBLE_DATA:
6591     default:
6592         size = sizeof(double);
6593     }
6594
6595     /* If the block does not exist, create it */
6596     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6597     {
6598         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6599         {
6600             block_type_flag = TNG_TRAJECTORY_BLOCK;
6601         }
6602         else
6603         {
6604             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6605         }
6606
6607         if(tng_data_block_create(tng_data, block_type_flag) !=
6608             TNG_SUCCESS)
6609         {
6610             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6611                    __FILE__, __LINE__);
6612             return(TNG_CRITICAL);
6613         }
6614         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6615         {
6616             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6617         }
6618         else
6619         {
6620             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6621         }
6622         data->block_id = block->id;
6623
6624         data->block_name = malloc(strlen(block->name) + 1);
6625         if(!data->block_name)
6626         {
6627             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6628                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6629             return(TNG_CRITICAL);
6630         }
6631         strcpy(data->block_name, block->name);
6632
6633         data->datatype = datatype;
6634
6635         data->values = 0;
6636         /* FIXME: Memory leak from strings. */
6637         data->strings = 0;
6638         data->n_frames = 0;
6639         data->codec_id = codec_id;
6640         data->compression_multiplier = multiplier;
6641         data->last_retrieved_frame = -1;
6642     }
6643
6644     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6645
6646     if(codec_id != TNG_UNCOMPRESSED)
6647     {
6648         switch(codec_id)
6649         {
6650 #ifdef USE_ZLIB
6651         case TNG_GZIP_COMPRESSION:
6652             data_size = n_frames_div * size * n_values;
6653     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6654             if(tng_gzip_uncompress(tng_data, block,
6655                                    block->block_contents + *offset,
6656                                    data_size) != TNG_SUCCESS)
6657             {
6658                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6659                     __LINE__);
6660                 return(TNG_CRITICAL);
6661             }
6662     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6663             break;
6664 #endif
6665         }
6666     }
6667
6668     /* Allocate memory */
6669     if(!data->values || data->n_frames != n_frames ||
6670        data->n_values_per_frame != n_values)
6671     {
6672         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6673                                  n_values) !=
6674            TNG_SUCCESS)
6675         {
6676             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6677                    __FILE__, __LINE__);
6678             return(TNG_CRITICAL);
6679         }
6680     }
6681
6682     data->first_frame_with_data = first_frame_with_data;
6683
6684     if(datatype == TNG_CHAR_DATA)
6685     {
6686         for(i = 0; i < n_frames_div; i++)
6687         {
6688             for(j = 0; j < n_values; j++)
6689             {
6690                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6691                               TNG_MAX_STR_LEN);
6692                 if(data->strings[i][j])
6693                 {
6694                     free(data->strings[i][j]);
6695                 }
6696                 data->strings[i][j] = malloc(len);
6697                 if(!data->strings[i][j])
6698                 {
6699                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6700                            len, __FILE__, __LINE__);
6701                     return(TNG_CRITICAL);
6702                 }
6703                 strncpy(data->strings[i][j], block->block_contents+*offset,
6704                         len);
6705                 *offset += len;
6706             }
6707         }
6708     }
6709     else
6710     {
6711         memcpy(data->values, block->block_contents + *offset,
6712                block->block_contents_size - *offset);
6713         switch(datatype)
6714         {
6715         case TNG_FLOAT_DATA:
6716             if(tng_data->input_endianness_swap_func_32)
6717             {
6718                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6719                 {
6720                     if(tng_data->input_endianness_swap_func_32(tng_data,
6721                         (int32_t *)((char *)data->values + i))
6722                         != TNG_SUCCESS)
6723                     {
6724                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6725                                 __FILE__, __LINE__);
6726                     }
6727                 }
6728             }
6729             break;
6730         case TNG_INT_DATA:
6731         case TNG_DOUBLE_DATA:
6732             if(tng_data->input_endianness_swap_func_64)
6733             {
6734                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6735                 {
6736                     if(tng_data->input_endianness_swap_func_64(tng_data,
6737                         (int64_t *)((char *)data->values + i))
6738                         != TNG_SUCCESS)
6739                     {
6740                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6741                                 __FILE__, __LINE__);
6742                     }
6743                 }
6744             }
6745             break;
6746         case TNG_CHAR_DATA:
6747             break;
6748         }
6749     }
6750     return(TNG_SUCCESS);
6751 }
6752
6753 /** Write a non-particle data block
6754  * @param tng_data is a trajectory data container.
6755  * @param block is the block to store the data (should already contain
6756  * the block headers and the block contents).
6757  * @param block_index is the index number of the data block in the frame set.
6758  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6759  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6760  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6761  * error has occured.
6762  */
6763 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6764                                                 tng_gen_block_t block,
6765                                                 const int64_t block_index,
6766                                                 const char hash_mode)
6767 {
6768     int64_t n_frames, stride_length, frame_step, data_start_pos;
6769     int64_t i, j;
6770     int offset = 0, size;
6771     unsigned int len;
6772 #ifdef USE_ZLIB
6773     tng_function_status stat;
6774 #endif
6775     char temp, dependency, *temp_name;
6776     double multiplier;
6777     tng_trajectory_frame_set_t frame_set =
6778     &tng_data->current_trajectory_frame_set;
6779
6780     tng_non_particle_data_t data;
6781     char block_type_flag;
6782
6783     /* If we have already started writing frame sets it is too late to write
6784      * non-trajectory data blocks */
6785     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6786     {
6787         block_type_flag = TNG_TRAJECTORY_BLOCK;
6788     }
6789     else
6790     {
6791         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6792     }
6793
6794     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6795     {
6796         return(TNG_CRITICAL);
6797     }
6798
6799     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6800     {
6801         data = &frame_set->tr_data[block_index];
6802
6803         /* If this data block has not had any data added in this frame set
6804          * do not write it. */
6805         if(data->first_frame_with_data < frame_set->first_frame)
6806         {
6807             return(TNG_SUCCESS);
6808         }
6809
6810         stride_length = tng_max_i64(1, data->stride_length);
6811     }
6812     else
6813     {
6814         data = &tng_data->non_tr_data[block_index];
6815         stride_length = 1;
6816     }
6817
6818     switch(data->datatype)
6819     {
6820     case TNG_CHAR_DATA:
6821         size = 1;
6822         break;
6823     case TNG_INT_DATA:
6824         size = sizeof(int64_t);
6825         break;
6826     case TNG_FLOAT_DATA:
6827         size = sizeof(float);
6828         break;
6829     case TNG_DOUBLE_DATA:
6830     default:
6831         size = sizeof(double);
6832     }
6833
6834     len = (unsigned int)strlen(data->block_name) + 1;
6835
6836     if(!block->name || strlen(block->name) < len)
6837     {
6838         temp_name = realloc(block->name, len);
6839         if(!temp_name)
6840         {
6841             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
6842                    __FILE__, __LINE__);
6843             free(block->name);
6844             block->name = 0;
6845             return(TNG_CRITICAL);
6846         }
6847         block->name = temp_name;
6848     }
6849     strncpy(block->name, data->block_name, len);
6850     block->id = data->block_id;
6851
6852     /* If writing frame independent data data->n_frames is 0, but n_frames
6853        is used for the loop writing the data (and reserving memory) and needs
6854        to be at least 1 */
6855     n_frames = tng_max_i64(1, data->n_frames);
6856
6857     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6858     {
6859         /* If the frame set is finished before writing the full number of frames
6860            make sure the data block is not longer than the frame set. */
6861         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6862
6863         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6864     }
6865
6866     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6867                  n_frames / stride_length;
6868
6869     /* TNG compression will use compression precision to get integers from
6870      * floating point data. The compression multiplier stores that information
6871      * to be able to return the precision of the compressed data. */
6872     if(data->codec_id == TNG_TNG_COMPRESSION)
6873     {
6874         data->compression_multiplier = tng_data->compression_precision;
6875     }
6876     /* Uncompressed data blocks do not use compression multipliers at all.
6877      * GZip compression does not need it either. */
6878     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6879     {
6880         data->compression_multiplier = 1.0;
6881     }
6882
6883     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6884     {
6885         dependency = TNG_FRAME_DEPENDENT;
6886     }
6887     else
6888     {
6889         dependency = 0;
6890     }
6891
6892     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6893                                     frame_step, stride_length, 0,
6894                                     1, dependency, &data_start_pos,
6895                                     &block->block_contents_size) != TNG_SUCCESS)
6896     {
6897         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6898                 __FILE__, __LINE__);
6899         return(TNG_CRITICAL);
6900     }
6901
6902     if(block->block_contents)
6903     {
6904         free(block->block_contents);
6905     }
6906     block->block_contents = malloc(block->block_contents_size);
6907     if(!block->block_contents)
6908     {
6909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6910                block->block_contents_size, __FILE__, __LINE__);
6911         return(TNG_CRITICAL);
6912     }
6913
6914
6915     memcpy(block->block_contents, &data->datatype, sizeof(char));
6916     offset += sizeof(char);
6917
6918     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6919     offset += sizeof(char);
6920
6921     if(dependency & TNG_FRAME_DEPENDENT)
6922     {
6923         if(stride_length > 1)
6924         {
6925             temp = 1;
6926         }
6927         else
6928         {
6929             temp = 0;
6930         }
6931         memcpy(block->block_contents+offset, &temp, sizeof(char));
6932         offset += sizeof(char);
6933     }
6934
6935     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6936            sizeof(data->n_values_per_frame));
6937     if(tng_data->output_endianness_swap_func_64)
6938     {
6939         if(tng_data->output_endianness_swap_func_64(tng_data,
6940            (int64_t *)block->header_contents+offset)
6941             != TNG_SUCCESS)
6942         {
6943             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6944                     __FILE__, __LINE__);
6945         }
6946     }
6947     offset += sizeof(data->n_values_per_frame);
6948
6949     memcpy(block->block_contents+offset, &data->codec_id,
6950            sizeof(data->codec_id));
6951     if(tng_data->output_endianness_swap_func_64)
6952     {
6953         if(tng_data->output_endianness_swap_func_64(tng_data,
6954            (int64_t *)block->header_contents+offset)
6955             != TNG_SUCCESS)
6956         {
6957             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6958                     __FILE__, __LINE__);
6959         }
6960     }
6961     offset += sizeof(data->codec_id);
6962
6963     if(data->codec_id != TNG_UNCOMPRESSED)
6964     {
6965         memcpy(block->block_contents+offset, &data->compression_multiplier,
6966                sizeof(data->compression_multiplier));
6967         if(tng_data->output_endianness_swap_func_64)
6968         {
6969             if(tng_data->output_endianness_swap_func_64(tng_data,
6970             (int64_t *)block->header_contents+offset)
6971                 != TNG_SUCCESS)
6972             {
6973                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6974                         __FILE__, __LINE__);
6975             }
6976         }
6977         offset += sizeof(data->compression_multiplier);
6978     }
6979
6980     if(data->n_frames > 0 && stride_length > 1)
6981     {
6982         /* FIXME: first_frame_with_data is not reliably set */
6983         if(data->first_frame_with_data == 0)
6984         {
6985             data->first_frame_with_data = frame_set->first_frame;
6986         }
6987         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6988                sizeof(data->first_frame_with_data));
6989         if(tng_data->output_endianness_swap_func_64)
6990         {
6991             if(tng_data->output_endianness_swap_func_64(tng_data,
6992             (int64_t *)block->header_contents+offset)
6993                 != TNG_SUCCESS)
6994             {
6995                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6996                         __FILE__, __LINE__);
6997             }
6998         }
6999         offset += sizeof(data->first_frame_with_data);
7000
7001         memcpy(block->block_contents+offset, &stride_length,
7002                sizeof(data->stride_length));
7003         if(tng_data->output_endianness_swap_func_64)
7004         {
7005             if(tng_data->output_endianness_swap_func_64(tng_data,
7006             (int64_t *)block->header_contents+offset)
7007                 != TNG_SUCCESS)
7008             {
7009                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7010                         __FILE__, __LINE__);
7011             }
7012         }
7013         offset += sizeof(data->stride_length);
7014     }
7015
7016     if(data->datatype == TNG_CHAR_DATA)
7017     {
7018         if(data->strings)
7019         {
7020             for(i = 0; i < frame_step; i++)
7021             {
7022                 for(j = 0; j < data->n_values_per_frame; j++)
7023                 {
7024                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7025                     strncpy(block->block_contents+offset, data->strings[i][j],
7026                             len);
7027                     offset += len;
7028                 }
7029             }
7030         }
7031     }
7032     else if(data->values)
7033     {
7034         memcpy(block->block_contents + offset, data->values,
7035                block->block_contents_size - offset);
7036         switch(data->datatype)
7037         {
7038         case TNG_FLOAT_DATA:
7039             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7040                data->codec_id == TNG_TNG_COMPRESSION)
7041             {
7042                 if(tng_data->input_endianness_swap_func_32)
7043                 {
7044                     for(i = offset; i < block->block_contents_size; i+=size)
7045                     {
7046                         if(tng_data->input_endianness_swap_func_32(tng_data,
7047                            (int32_t *)(block->block_contents + i))
7048                            != TNG_SUCCESS)
7049                         {
7050                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7051                                     __FILE__, __LINE__);
7052                         }
7053                     }
7054                 }
7055             }
7056             else
7057             {
7058                 multiplier = data->compression_multiplier;
7059                 if(fabs(multiplier - 1.0) > 0.00001 ||
7060                    tng_data->input_endianness_swap_func_32)
7061                 {
7062                     for(i = offset; block->block_contents_size; i+=size)
7063                     {
7064                         *(float *)(block->block_contents + i) *= (float)multiplier;
7065                         if(tng_data->input_endianness_swap_func_32 &&
7066                         tng_data->input_endianness_swap_func_32(tng_data,
7067                         (int32_t *)(block->block_contents + i))
7068                         != TNG_SUCCESS)
7069                         {
7070                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7071                                     __FILE__, __LINE__);
7072                         }
7073                     }
7074                 }
7075             }
7076             break;
7077         case TNG_INT_DATA:
7078             if(tng_data->input_endianness_swap_func_64)
7079             {
7080                 for(i = offset; i < block->block_contents_size; i+=size)
7081                 {
7082                     if(tng_data->input_endianness_swap_func_64(tng_data,
7083                        (int64_t *)(block->block_contents + i))
7084                        != TNG_SUCCESS)
7085                     {
7086                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7087                                 __FILE__, __LINE__);
7088                     }
7089                 }
7090             }
7091             break;
7092         case TNG_DOUBLE_DATA:
7093             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7094                data->codec_id == TNG_TNG_COMPRESSION)
7095             {
7096                 if(tng_data->input_endianness_swap_func_64)
7097                 {
7098                     for(i = offset; i < block->block_contents_size; i+=size)
7099                     {
7100                         if(tng_data->input_endianness_swap_func_64(tng_data,
7101                            (int64_t *)(block->block_contents + i))
7102                            != TNG_SUCCESS)
7103                         {
7104                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7105                                     __FILE__, __LINE__);
7106                         }
7107                     }
7108                 }
7109             }
7110             else
7111             {
7112                 multiplier = data->compression_multiplier;
7113                 if(fabs(multiplier - 1.0) > 0.00001 ||
7114                    tng_data->input_endianness_swap_func_64)
7115                 {
7116                     for(i = offset; i < block->block_contents_size; i+=size)
7117                     {
7118                         *(double *)(block->block_contents + i) *= multiplier;
7119                         if(tng_data->input_endianness_swap_func_64 &&
7120                         tng_data->input_endianness_swap_func_64(tng_data,
7121                         (int64_t *)(block->block_contents + i))
7122                         != TNG_SUCCESS)
7123                         {
7124                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7125                                     __FILE__, __LINE__);
7126                         }
7127                     }
7128                 }
7129             }
7130             break;
7131         case TNG_CHAR_DATA:
7132             break;
7133         }
7134     }
7135     else
7136     {
7137         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7138     }
7139
7140     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7141     frame_set->n_unwritten_frames = 0;
7142
7143     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7144     {
7145         switch(data->codec_id)
7146         {
7147 #ifdef USE_ZLIB
7148         case TNG_GZIP_COMPRESSION:
7149     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7150             stat = tng_gzip_compress(tng_data, block,
7151                                      block->block_contents + data_start_pos,
7152                                      block->block_contents_size - data_start_pos);
7153             if(stat != TNG_SUCCESS)
7154             {
7155                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7156                     __LINE__);
7157                 if(stat == TNG_CRITICAL)
7158                 {
7159                     return(TNG_CRITICAL);
7160                 }
7161                 data->codec_id = TNG_UNCOMPRESSED;
7162             }
7163     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7164             break;
7165 #endif
7166         }
7167     }
7168
7169     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7170     {
7171         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7172                tng_data->output_file_path, __FILE__, __LINE__);
7173         return(TNG_CRITICAL);
7174     }
7175
7176     if(fwrite(block->block_contents, block->block_contents_size, 1,
7177               tng_data->output_file) != 1)
7178     {
7179         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7180                __FILE__, __LINE__);
7181         return(TNG_CRITICAL);
7182     }
7183
7184     return(TNG_SUCCESS);
7185 }
7186
7187 /** Read the meta information of a data block (particle or non-particle data).
7188  * @param tng_data is a trajectory data container.
7189  * @param block is the block to store the data (should already contain
7190  * the block headers).
7191  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7192  * error has occured.
7193  */
7194 static tng_function_status tng_data_block_meta_information_read
7195                 (tng_trajectory_t tng_data,
7196                  tng_gen_block_t block,
7197                  int *offset,
7198                  char *datatype,
7199                  char *dependency,
7200                  char *sparse_data,
7201                  int64_t *n_values,
7202                  int64_t *codec_id,
7203                  int64_t *first_frame_with_data,
7204                  int64_t *stride_length,
7205                  int64_t *n_frames,
7206                  int64_t *num_first_particle,
7207                  int64_t *block_n_particles,
7208                  double *multiplier)
7209 {
7210     int meta_size;
7211     char *contents;
7212
7213     if(block->block_contents)
7214     {
7215         contents = block->block_contents;
7216     }
7217     else
7218     {
7219         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7220         contents = malloc(meta_size);
7221         if(!contents)
7222         {
7223             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7224                meta_size, __FILE__, __LINE__);
7225         }
7226
7227         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7228         {
7229             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7230             free(contents);
7231             return(TNG_CRITICAL);
7232         }
7233     }
7234
7235     memcpy(datatype, contents+*offset,
7236            sizeof(*datatype));
7237     *offset += sizeof(*datatype);
7238
7239     memcpy(dependency, contents+*offset,
7240            sizeof(*dependency));
7241     *offset += sizeof(*dependency);
7242
7243     if(*dependency & TNG_FRAME_DEPENDENT)
7244     {
7245         memcpy(sparse_data, contents+*offset,
7246                sizeof(*sparse_data));
7247         *offset += sizeof(*sparse_data);
7248     }
7249
7250     memcpy(n_values, contents+*offset,
7251         sizeof(*n_values));
7252     if(tng_data->input_endianness_swap_func_64)
7253     {
7254         if(tng_data->input_endianness_swap_func_64(tng_data,
7255                                                    n_values)
7256             != TNG_SUCCESS)
7257         {
7258             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7259                     __FILE__, __LINE__);
7260         }
7261     }
7262     *offset += sizeof(*n_values);
7263
7264     memcpy(codec_id, contents+*offset,
7265         sizeof(*codec_id));
7266     if(tng_data->input_endianness_swap_func_64)
7267     {
7268         if(tng_data->input_endianness_swap_func_64(tng_data,
7269                                                    codec_id)
7270             != TNG_SUCCESS)
7271         {
7272             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7273                     __FILE__, __LINE__);
7274         }
7275     }
7276     *offset += sizeof(*codec_id);
7277
7278     if(*codec_id != TNG_UNCOMPRESSED)
7279     {
7280         memcpy(multiplier, contents+*offset,
7281             sizeof(*multiplier));
7282         if(tng_data->input_endianness_swap_func_64)
7283         {
7284             if(tng_data->input_endianness_swap_func_64(tng_data,
7285                                                        (int64_t *) multiplier)
7286                 != TNG_SUCCESS)
7287             {
7288                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7289                         __FILE__, __LINE__);
7290             }
7291         }
7292         *offset += sizeof(*multiplier);
7293     }
7294     else
7295     {
7296         *multiplier = 1;
7297     }
7298
7299     if(*dependency & TNG_FRAME_DEPENDENT)
7300     {
7301         if(*sparse_data)
7302         {
7303             memcpy(first_frame_with_data, contents+*offset,
7304                 sizeof(*first_frame_with_data));
7305             if(tng_data->input_endianness_swap_func_64)
7306             {
7307                 if(tng_data->input_endianness_swap_func_64(tng_data,
7308                                                            first_frame_with_data)
7309                     != TNG_SUCCESS)
7310                 {
7311                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7312                             __FILE__, __LINE__);
7313                 }
7314             }
7315             *offset += sizeof(*first_frame_with_data);
7316
7317             memcpy(stride_length, contents+*offset,
7318                 sizeof(*stride_length));
7319             if(tng_data->input_endianness_swap_func_64)
7320             {
7321                 if(tng_data->input_endianness_swap_func_64(tng_data,
7322                                                            stride_length)
7323                     != TNG_SUCCESS)
7324                 {
7325                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7326                             __FILE__, __LINE__);
7327                 }
7328             }
7329             *offset += sizeof(*stride_length);
7330             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7331                         (*first_frame_with_data -
7332                         tng_data->current_trajectory_frame_set.first_frame);
7333         }
7334         else
7335         {
7336             *first_frame_with_data = 0;
7337             *stride_length = 1;
7338             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7339         }
7340     }
7341     else
7342     {
7343         *first_frame_with_data = 0;
7344         *stride_length = 1;
7345         *n_frames = 1;
7346     }
7347
7348     if (*dependency & TNG_PARTICLE_DEPENDENT)
7349     {
7350         memcpy(num_first_particle, contents+*offset,
7351                sizeof(*num_first_particle));
7352         if(tng_data->input_endianness_swap_func_64)
7353         {
7354             if(tng_data->input_endianness_swap_func_64(tng_data,
7355                                                        num_first_particle)
7356                 != TNG_SUCCESS)
7357             {
7358                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7359                         __FILE__, __LINE__);
7360             }
7361         }
7362         *offset += sizeof(*num_first_particle);
7363
7364         memcpy(block_n_particles, contents+*offset,
7365             sizeof(*block_n_particles));
7366         if(tng_data->input_endianness_swap_func_64)
7367         {
7368             if(tng_data->input_endianness_swap_func_64(tng_data,
7369                                                        block_n_particles)
7370                 != TNG_SUCCESS)
7371             {
7372                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7373                         __FILE__, __LINE__);
7374             }
7375         }
7376         *offset += sizeof(*block_n_particles);
7377     }
7378
7379     if(!block->block_contents)
7380     {
7381         free(contents);
7382     }
7383     return(TNG_SUCCESS);
7384 }
7385
7386 /** Read the contents of a data block (particle or non-particle data).
7387  * @param tng_data is a trajectory data container.
7388  * @param block is the block to store the data (should already contain
7389  * the block headers).
7390  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7391  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7392  * compared to the md5 hash of the read contents to ensure valid data.
7393  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7394  * error has occured.
7395  */
7396 static tng_function_status tng_data_block_contents_read
7397                 (tng_trajectory_t tng_data,
7398                  tng_gen_block_t block,
7399                  const char hash_mode)
7400 {
7401     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7402     int64_t stride_length, block_n_particles, num_first_particle;
7403     double multiplier;
7404     char datatype, dependency, sparse_data;
7405     int offset = 0;
7406     tng_bool same_hash;
7407
7408     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7409     {
7410         return(TNG_CRITICAL);
7411     }
7412
7413     if(block->block_contents)
7414     {
7415         free(block->block_contents);
7416     }
7417
7418     block->block_contents = malloc(block->block_contents_size);
7419     if(!block->block_contents)
7420     {
7421         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7422                block->block_contents_size, __FILE__, __LINE__);
7423         return(TNG_CRITICAL);
7424     }
7425
7426     /* Read the whole block into block_contents to be able to write it to
7427      * disk even if it cannot be interpreted. */
7428     if(fread(block->block_contents, block->block_contents_size, 1,
7429              tng_data->input_file) == 0)
7430     {
7431         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7432         return(TNG_CRITICAL);
7433     }
7434
7435     /* FIXME: Does not check if the size of the contents matches the expected
7436      * size or if the contents can be read. */
7437
7438     if(hash_mode == TNG_USE_HASH)
7439     {
7440         tng_md5_hash_match_verify(block, &same_hash);
7441         if(same_hash != TNG_TRUE)
7442         {
7443             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7444                 block->name, __FILE__, __LINE__);
7445     /*         return(TNG_FAILURE); */
7446         }
7447     }
7448
7449     if(tng_data_block_meta_information_read(tng_data, block,
7450                                             &offset, &datatype,
7451                                             &dependency, &sparse_data,
7452                                             &n_values, &codec_id,
7453                                             &first_frame_with_data,
7454                                             &stride_length, &n_frames,
7455                                             &num_first_particle,
7456                                             &block_n_particles,
7457                                             &multiplier) == TNG_CRITICAL)
7458     {
7459         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7460             block->name, __FILE__, __LINE__);
7461         return(TNG_CRITICAL);
7462     }
7463
7464     if (dependency & TNG_PARTICLE_DEPENDENT)
7465     {
7466         return(tng_particle_data_read(tng_data, block,
7467                                       &offset, datatype,
7468                                       num_first_particle,
7469                                       block_n_particles,
7470                                       first_frame_with_data,
7471                                       stride_length,
7472                                       n_frames, n_values,
7473                                       codec_id, multiplier));
7474     }
7475     else
7476     {
7477         return(tng_data_read(tng_data, block,
7478                              &offset, datatype,
7479                              first_frame_with_data,
7480                              stride_length,
7481                              n_frames, n_values,
7482                              codec_id, multiplier));
7483     }
7484 }
7485
7486 /*
7487 // ** Move the blocks in a frame set so that there is no unused space between
7488 //  * them. This can only be done on the last frame set in the file and should
7489 //  * be done e.g. if the last frame set in the file has fewer frames than
7490 //  * default or after compressing data blocks in a frame set.
7491 //  * @param tng_data is a trajectory data container.
7492 //  * @details the current_trajectory_frame_set is the one that will be modified.
7493 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7494 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7495 //  * FIXME: This function is not finished!!!
7496 //  *
7497 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7498 // {
7499 //     tng_gen_block_t block;
7500 //     tng_trajectory_frame_set_t frame_set;
7501 //     FILE *temp = tng_data->input_file;
7502 //     int64_t pos, contents_start_pos, output_file_len;
7503 //
7504 //     frame_set = &tng_data->current_trajectory_frame_set;
7505 //
7506 //     if(frame_set->n_written_frames == frame_set->n_frames)
7507 //     {
7508 //         return(TNG_SUCCESS);
7509 //     }
7510 //
7511 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7512 //        tng_data->last_trajectory_frame_set_output_file_pos)
7513 //     {
7514 //     }
7515 //
7516 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7517 //     {
7518 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7519 //                __FILE__, __LINE__);
7520 //         return(TNG_CRITICAL);
7521 //     }
7522 //
7523 //     tng_block_init(&block);
7524 // //     output_file_pos = ftell(tng_data->output_file);
7525 //
7526 //     tng_data->input_file = tng_data->output_file;
7527 //
7528 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7529 //
7530 //     fseek(tng_data->output_file, pos, SEEK_SET);
7531 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7532 //     {
7533 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7534 //             __FILE__, __LINE__);
7535 //         tng_data->input_file = temp;
7536 //         tng_block_destroy(&block);
7537 //         return(TNG_CRITICAL);
7538 //     }
7539 //
7540 //     contents_start_pos = ftell(tng_data->output_file);
7541 //
7542 //     fseek(tng_data->output_file, 0, SEEK_END);
7543 //     output_file_len = ftell(tng_data->output_file);
7544 //     pos = contents_start_pos + block->block_contents_size;
7545 //     fseek(tng_data->output_file, pos,
7546 //           SEEK_SET);
7547 //
7548 //     while(pos < output_file_len)
7549 //     {
7550 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7551 //         {
7552 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7553 //                    __FILE__, __LINE__);
7554 //             tng_data->input_file = temp;
7555 //             tng_block_destroy(&block);
7556 //             return(TNG_CRITICAL);
7557 //         }
7558 //         pos += block->header_contents_size + block->block_contents_size;
7559 //         fseek(tng_data->output_file, pos, SEEK_SET);
7560 //     }
7561 //
7562 //     return(TNG_SUCCESS);
7563 // }
7564 */
7565 /** Finish writing the current frame set. Update the number of frames
7566  * and the hashes of the frame set and all its data blocks (if hash_mode
7567  * == TNG_USE_HASH).
7568  * @param tng_data is a trajectory data container.
7569  * @param hash_mode specifies whether to update the block md5 hash when
7570  * updating the pointers.
7571  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7572  * error has occured.
7573  */
7574 static tng_function_status tng_frame_set_finalize
7575                 (tng_trajectory_t tng_data, const char hash_mode)
7576 {
7577     tng_gen_block_t block;
7578     tng_trajectory_frame_set_t frame_set;
7579     FILE *temp = tng_data->input_file;
7580     int64_t pos, contents_start_pos, output_file_len;
7581
7582     frame_set = &tng_data->current_trajectory_frame_set;
7583
7584     if(frame_set->n_written_frames == frame_set->n_frames)
7585     {
7586         return(TNG_SUCCESS);
7587     }
7588
7589     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7590     {
7591         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7592                __FILE__, __LINE__);
7593         return(TNG_CRITICAL);
7594     }
7595
7596     tng_block_init(&block);
7597 /*     output_file_pos = ftell(tng_data->output_file); */
7598
7599     tng_data->input_file = tng_data->output_file;
7600
7601     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7602
7603     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7604
7605     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7606     {
7607         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7608             __FILE__, __LINE__);
7609         tng_data->input_file = temp;
7610         tng_block_destroy(&block);
7611         return(TNG_CRITICAL);
7612     }
7613
7614     contents_start_pos = ftell(tng_data->output_file);
7615
7616     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7617     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7618               1, tng_data->output_file) != 1)
7619     {
7620         tng_data->input_file = temp;
7621         tng_block_destroy(&block);
7622         return(TNG_CRITICAL);
7623     }
7624
7625
7626     if(hash_mode == TNG_USE_HASH)
7627     {
7628         tng_md5_hash_update(tng_data, block, pos,
7629                             pos + block->header_contents_size);
7630     }
7631
7632     fseek(tng_data->output_file, 0, SEEK_END);
7633     output_file_len = ftell(tng_data->output_file);
7634     pos = contents_start_pos + block->block_contents_size;
7635     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7636
7637     while(pos < output_file_len)
7638     {
7639         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7640         {
7641             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7642                    __FILE__, __LINE__);
7643             tng_data->input_file = temp;
7644             tng_block_destroy(&block);
7645             return(TNG_CRITICAL);
7646         }
7647
7648         if(hash_mode == TNG_USE_HASH)
7649         {
7650             tng_md5_hash_update(tng_data, block, pos,
7651                                 pos + block->header_contents_size);
7652         }
7653         pos += block->header_contents_size + block->block_contents_size;
7654         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7655     }
7656
7657     tng_data->input_file = temp;
7658     tng_block_destroy(&block);
7659     return(TNG_SUCCESS);
7660 }
7661
7662 /*
7663 // ** Sets the name of a file contents block
7664 //  * @param tng_data is a trajectory data container.
7665 //  * @param block is the block, of which to change names.
7666 //  * @param new_name is the new name of the block.
7667 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7668 //  * error has occured.
7669 //
7670 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7671 //                                               tng_gen_block_t block,
7672 //                                               const char *new_name)
7673 // {
7674 //     int len;
7675 //
7676 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7677 //
7678 //      * If the currently stored string length is not enough to store the new
7679 //      * string it is freed and reallocated. *
7680 //     if(block->name && strlen(block->name) < len)
7681 //     {
7682 //         free(block->name);
7683 //         block->name = 0;
7684 //     }
7685 //     if(!block->name)
7686 //     {
7687 //         block->name = malloc(len);
7688 //         if(!block->name)
7689 //         {
7690 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7691 //                    __FILE__, __LINE__);
7692 //             return(TNG_CRITICAL);
7693 //         }
7694 //     }
7695 //
7696 //     strncpy(block->name, new_name, len);
7697 //
7698 //     return(TNG_SUCCESS);
7699 // }
7700 */
7701
7702 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7703                                          const tng_atom_t atom,
7704                                          tng_residue_t *residue)
7705 {
7706     (void) tng_data;
7707
7708     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7709
7710     *residue = atom->residue;
7711
7712     return(TNG_SUCCESS);
7713 }
7714
7715 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7716                                       const tng_atom_t atom,
7717                                       char *name,
7718                                       const int max_len)
7719 {
7720     (void) tng_data;
7721     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7722     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7723
7724     strncpy(name, atom->name, max_len - 1);
7725     name[max_len - 1] = 0;
7726
7727     if(strlen(atom->name) > (unsigned int)max_len - 1)
7728     {
7729         return(TNG_FAILURE);
7730     }
7731     return(TNG_SUCCESS);
7732 }
7733
7734 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7735                                       tng_atom_t atom,
7736                                       const char *new_name)
7737 {
7738     unsigned int len;
7739     (void)tng_data;
7740
7741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7742     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7743
7744     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7745
7746     /* If the currently stored string length is not enough to store the new
7747      * string it is freed and reallocated. */
7748     if(atom->name && strlen(atom->name) < len)
7749     {
7750         free(atom->name);
7751         atom->name = 0;
7752     }
7753     if(!atom->name)
7754     {
7755         atom->name = malloc(len);
7756         if(!atom->name)
7757         {
7758             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7759                    __FILE__, __LINE__);
7760             return(TNG_CRITICAL);
7761         }
7762     }
7763
7764     strncpy(atom->name, new_name, len);
7765
7766     return(TNG_SUCCESS);
7767 }
7768
7769 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7770                                       const tng_atom_t atom,
7771                                       char *type,
7772                                       const int max_len)
7773 {
7774     (void) tng_data;
7775     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7776     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7777
7778     strncpy(type, atom->atom_type, max_len - 1);
7779     type[max_len - 1] = 0;
7780
7781     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7782     {
7783         return(TNG_FAILURE);
7784     }
7785     return(TNG_SUCCESS);
7786 }
7787
7788 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7789                                       tng_atom_t atom,
7790                                       const char *new_type)
7791 {
7792     unsigned int len;
7793     (void)tng_data;
7794
7795     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7796     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7797
7798     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7799
7800     /* If the currently stored string length is not enough to store the new
7801      * string it is freed and reallocated. */
7802     if(atom->atom_type && strlen(atom->atom_type) < len)
7803     {
7804         free(atom->atom_type);
7805         atom->atom_type = 0;
7806     }
7807     if(!atom->atom_type)
7808     {
7809         atom->atom_type = malloc(len);
7810         if(!atom->atom_type)
7811         {
7812             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7813                    __FILE__, __LINE__);
7814             return(TNG_CRITICAL);
7815         }
7816     }
7817
7818     strncpy(atom->atom_type, new_type, len);
7819
7820     return(TNG_SUCCESS);
7821 }
7822
7823 /** Initialise an atom struct
7824  * @param atom is the atom to initialise.
7825  * @return TNG_SUCCESS (0) if successful.
7826  */
7827 static tng_function_status tng_atom_init(tng_atom_t atom)
7828 {
7829     atom->name = 0;
7830     atom->atom_type = 0;
7831
7832     return(TNG_SUCCESS);
7833 }
7834
7835 /** Free the memory in an atom struct
7836  * @param atom is the atom to destroy.
7837  * @return TNG_SUCCESS (0) if successful.
7838  */
7839 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7840 {
7841     if(atom->name)
7842     {
7843         free(atom->name);
7844         atom->name = 0;
7845     }
7846     if(atom->atom_type)
7847     {
7848         free(atom->atom_type);
7849         atom->atom_type = 0;
7850     }
7851
7852     return(TNG_SUCCESS);
7853 }
7854
7855 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7856                 (tng_trajectory_t tng_data,
7857                  const char *name,
7858                  tng_molecule_t *molecule)
7859 {
7860     int64_t id;
7861
7862     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7863     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7864
7865     /* Set ID to the ID of the last molecule + 1 */
7866     if(tng_data->n_molecules)
7867     {
7868         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7869     }
7870     else
7871     {
7872         id = 1;
7873     }
7874
7875     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7876 }
7877
7878 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7879                 (tng_trajectory_t tng_data,
7880                  const char *name,
7881                  const int64_t id,
7882                  tng_molecule_t *molecule)
7883 {
7884     tng_molecule_t new_molecules;
7885     int64_t *new_molecule_cnt_list;
7886     tng_function_status stat = TNG_SUCCESS;
7887
7888     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7889     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7890
7891     new_molecules = realloc(tng_data->molecules,
7892                             sizeof(struct tng_molecule) *
7893                             (tng_data->n_molecules + 1));
7894
7895     if(!new_molecules)
7896     {
7897         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7898                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7899                __FILE__, __LINE__);
7900         free(tng_data->molecules);
7901         tng_data->molecules = 0;
7902         return(TNG_CRITICAL);
7903     }
7904
7905     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7906                                     sizeof(int64_t) *
7907                                     (tng_data->n_molecules + 1));
7908
7909     if(!new_molecule_cnt_list)
7910     {
7911         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7912                sizeof(int64_t) * (tng_data->n_molecules + 1),
7913                __FILE__, __LINE__);
7914         free(tng_data->molecule_cnt_list);
7915         tng_data->molecule_cnt_list = 0;
7916         free(new_molecules);
7917         return(TNG_CRITICAL);
7918     }
7919
7920     tng_data->molecules = new_molecules;
7921     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7922
7923     *molecule = &new_molecules[tng_data->n_molecules];
7924
7925     tng_molecule_init(tng_data, *molecule);
7926     tng_molecule_name_set(tng_data, *molecule, name);
7927
7928     /* FIXME: Should this be a function argument instead? */
7929     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7930
7931     (*molecule)->id = id;
7932
7933     tng_data->n_molecules++;
7934
7935     return(stat);
7936 }
7937
7938 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7939                 (tng_trajectory_t tng_data,
7940                  tng_molecule_t *molecule_p)
7941 {
7942     int64_t *new_molecule_cnt_list, id;
7943     tng_molecule_t new_molecules, molecule;
7944
7945     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7946
7947     /* Set ID to the ID of the last molecule + 1 */
7948     if(tng_data->n_molecules)
7949     {
7950         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7951     }
7952     else
7953     {
7954         id = 1;
7955     }
7956
7957     new_molecules = realloc(tng_data->molecules,
7958                             sizeof(struct tng_molecule) *
7959                             (tng_data->n_molecules + 1));
7960
7961     if(!new_molecules)
7962     {
7963         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7964                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7965                __FILE__, __LINE__);
7966         free(tng_data->molecules);
7967         tng_data->molecules = 0;
7968         return(TNG_CRITICAL);
7969     }
7970
7971     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7972                                     sizeof(int64_t) *
7973                                     (tng_data->n_molecules + 1));
7974
7975     if(!new_molecule_cnt_list)
7976     {
7977         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7978                sizeof(int64_t) * (tng_data->n_molecules + 1),
7979                __FILE__, __LINE__);
7980         free(tng_data->molecule_cnt_list);
7981         tng_data->molecule_cnt_list = 0;
7982         free(new_molecules);
7983         return(TNG_CRITICAL);
7984     }
7985
7986     molecule = *molecule_p;
7987
7988     tng_data->molecules = new_molecules;
7989     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7990
7991     new_molecules[tng_data->n_molecules] = *molecule;
7992
7993     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7994
7995     free(*molecule_p);
7996
7997     molecule = &new_molecules[tng_data->n_molecules];
7998
7999     *molecule_p = molecule;
8000
8001     molecule->id = id;
8002
8003     tng_data->n_molecules++;
8004
8005     return(TNG_SUCCESS);
8006 }
8007
8008 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8009                                           const tng_molecule_t molecule,
8010                                           char *name,
8011                                           const int max_len)
8012 {
8013     (void) tng_data;
8014     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8015     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8016
8017     strncpy(name, molecule->name, max_len - 1);
8018     name[max_len - 1] = 0;
8019
8020     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8021     {
8022         return(TNG_FAILURE);
8023     }
8024     return(TNG_SUCCESS);
8025 }
8026
8027 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8028                 (tng_trajectory_t tng_data,
8029                  tng_molecule_t molecule,
8030                  const char *new_name)
8031 {
8032     unsigned int len;
8033     (void)tng_data;
8034
8035     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8036     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8037
8038     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8039
8040     /* If the currently stored string length is not enough to store the new
8041      * string it is freed and reallocated. */
8042     if(molecule->name && strlen(molecule->name) < len)
8043     {
8044         free(molecule->name);
8045         molecule->name = 0;
8046     }
8047     if(!molecule->name)
8048     {
8049         molecule->name = malloc(len);
8050         if(!molecule->name)
8051         {
8052             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8053                    __FILE__, __LINE__);
8054             return(TNG_CRITICAL);
8055         }
8056     }
8057
8058     strncpy(molecule->name, new_name, len);
8059
8060     return(TNG_SUCCESS);
8061 }
8062
8063 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8064                 (const tng_trajectory_t tng_data,
8065                  const tng_molecule_t molecule,
8066                  int64_t *cnt)
8067 {
8068     int64_t i, index = -1;
8069
8070     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8071     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8072
8073     for(i = 0; i < tng_data->n_molecules; i++)
8074     {
8075         if(&tng_data->molecules[i] == molecule)
8076         {
8077             index = i;
8078             break;
8079         }
8080     }
8081     if(index == -1)
8082     {
8083         return(TNG_FAILURE);
8084     }
8085     *cnt = tng_data->molecule_cnt_list[index];
8086
8087     return(TNG_SUCCESS);
8088 }
8089
8090 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8091                 (tng_trajectory_t tng_data,
8092                  tng_molecule_t molecule,
8093                  const int64_t cnt)
8094 {
8095     int64_t i, old_cnt, index = -1;
8096
8097     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8098
8099     for(i = 0; i < tng_data->n_molecules; i++)
8100     {
8101         if(&tng_data->molecules[i] == molecule)
8102         {
8103             index = i;
8104             break;
8105         }
8106     }
8107     if(index == -1)
8108     {
8109         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8110                __FILE__, __LINE__);
8111         return(TNG_FAILURE);
8112     }
8113     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8114     {
8115         old_cnt = tng_data->molecule_cnt_list[index];
8116         tng_data->molecule_cnt_list[index] = cnt;
8117
8118         tng_data->n_particles += (cnt-old_cnt) *
8119                                  tng_data->molecules[index].n_atoms;
8120     }
8121     else
8122     {
8123         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8124         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8125
8126         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8127                 tng_data->molecules[index].n_atoms;
8128     }
8129
8130     return(TNG_SUCCESS);
8131 }
8132
8133 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8134                 (tng_trajectory_t tng_data,
8135                  const char *name,
8136                  int64_t nr,
8137                  tng_molecule_t *molecule)
8138 {
8139     int64_t i, n_molecules;
8140
8141     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8142     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8143     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8144
8145     n_molecules = tng_data->n_molecules;
8146
8147     for(i = n_molecules - 1; i >= 0; i--)
8148     {
8149         *molecule = &tng_data->molecules[i];
8150         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8151         {
8152             if(nr == -1 || nr == (*molecule)->id)
8153             {
8154                 return(TNG_SUCCESS);
8155             }
8156         }
8157     }
8158
8159     *molecule = 0;
8160
8161     return(TNG_FAILURE);
8162 }
8163
8164 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8165                 (tng_trajectory_t tng_data,
8166                  int64_t index,
8167                  tng_molecule_t *molecule)
8168 {
8169     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8170     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8171
8172     if(index >= tng_data->n_molecules)
8173     {
8174         *molecule = 0;
8175         return(TNG_FAILURE);
8176     }
8177     *molecule = &tng_data->molecules[index];
8178     return(TNG_SUCCESS);
8179 }
8180
8181 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8182                                                                tng_trajectory_t tng_data_dest)
8183 {
8184     tng_molecule_t molecule, molecule_temp;
8185     tng_chain_t chain, chain_temp;
8186     tng_residue_t residue, residue_temp;
8187     tng_atom_t atom, atom_temp;
8188     tng_bond_t bond_temp;
8189     tng_function_status stat;
8190     int64_t i, j, k, l, *list_temp;
8191
8192     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8193     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8194
8195     for(i = 0; i < tng_data_dest->n_molecules; i++)
8196     {
8197         molecule = &tng_data_dest->molecules[i];
8198         tng_molecule_destroy(tng_data_dest, molecule);
8199     }
8200
8201     tng_data_dest->n_molecules = 0;
8202     tng_data_dest->n_particles = 0;
8203
8204     molecule_temp = realloc(tng_data_dest->molecules,
8205                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8206     if(!molecule_temp)
8207     {
8208         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8209                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8210                __FILE__, __LINE__);
8211         free(tng_data_dest->molecules);
8212         tng_data_dest->molecules = 0;
8213         return(TNG_CRITICAL);
8214     }
8215     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8216                                      sizeof(int64_t) * tng_data_src->n_molecules);
8217     if(!list_temp)
8218     {
8219         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8220                sizeof(int64_t) * tng_data_src->n_molecules,
8221                __FILE__, __LINE__);
8222         free(tng_data_dest->molecule_cnt_list);
8223         tng_data_dest->molecule_cnt_list = 0;
8224         free(molecule_temp);
8225         return(TNG_CRITICAL);
8226     }
8227
8228     tng_data_dest->molecules = molecule_temp;
8229     tng_data_dest->molecule_cnt_list = list_temp;
8230
8231     for(i = 0; i < tng_data_src->n_molecules; i++)
8232     {
8233         molecule = &tng_data_src->molecules[i];
8234         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8235                                      &molecule_temp);
8236         if(stat != TNG_SUCCESS)
8237         {
8238             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8239                    __FILE__, __LINE__);
8240             return(stat);
8241         }
8242         molecule_temp->quaternary_str = molecule->quaternary_str;
8243         for(j = 0; j < molecule->n_chains; j++)
8244         {
8245             chain = &molecule->chains[j];
8246             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8247                                                chain->name, chain->id,
8248                                                &chain_temp);
8249             if(stat != TNG_SUCCESS)
8250             {
8251                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8252                        __FILE__, __LINE__);
8253                 return(stat);
8254             }
8255             for(k = 0; k < chain->n_residues; k++)
8256             {
8257                 residue = &chain->residues[k];
8258                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8259                                                   residue->name, residue->id,
8260                                                   &residue_temp);
8261                 if(stat != TNG_SUCCESS)
8262                 {
8263                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8264                            __FILE__, __LINE__);
8265                     return(stat);
8266                 }
8267                 for(l = 0; l < residue->n_atoms; l++)
8268                 {
8269                     atom = &molecule->atoms[residue->atoms_offset + l];
8270                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8271                                                      atom->name, atom->atom_type,
8272                                                      atom->id, &atom_temp);
8273                     if(stat != TNG_SUCCESS)
8274                     {
8275                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8276                            __FILE__, __LINE__);
8277                         return(stat);
8278                     }
8279                 }
8280             }
8281         }
8282         molecule_temp->n_bonds = molecule->n_bonds;
8283         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8284                             molecule->n_bonds);
8285         if(!bond_temp)
8286         {
8287             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8288                    sizeof(struct tng_bond) * molecule->n_bonds,
8289                    __FILE__, __LINE__);
8290             free(molecule_temp->bonds);
8291             molecule_temp->n_bonds = 0;
8292             return(TNG_CRITICAL);
8293         }
8294         molecule_temp->bonds = bond_temp;
8295         for(j = 0; j < molecule->n_bonds; j++)
8296         {
8297             molecule_temp->bonds[j] = molecule->bonds[j];
8298         }
8299         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8300                                     tng_data_src->molecule_cnt_list[i]);
8301         if(stat != TNG_SUCCESS)
8302         {
8303             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8304                    __FILE__, __LINE__);
8305             return(stat);
8306         }
8307     }
8308     return(TNG_SUCCESS);
8309 }
8310
8311 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8312                 (const tng_trajectory_t tng_data,
8313                  const tng_molecule_t molecule,
8314                  int64_t *n)
8315 {
8316     (void) tng_data;
8317     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8318     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8319
8320     *n = molecule->n_chains;
8321
8322     return(TNG_SUCCESS);
8323 }
8324
8325 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8326                 (tng_trajectory_t tng_data,
8327                  tng_molecule_t molecule,
8328                  int64_t index,
8329                  tng_chain_t *chain)
8330 {
8331     (void) tng_data;
8332     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8333     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8334
8335     if(index >= molecule->n_chains)
8336     {
8337         *chain = 0;
8338         return(TNG_FAILURE);
8339     }
8340     *chain = &molecule->chains[index];
8341     return(TNG_SUCCESS);
8342 }
8343
8344 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8345                 (const tng_trajectory_t tng_data,
8346                  const tng_molecule_t molecule,
8347                  int64_t *n)
8348 {
8349     (void) tng_data;
8350     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8351     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8352
8353     *n = molecule->n_residues;
8354
8355     return(TNG_SUCCESS);
8356 }
8357
8358 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8359                 (const tng_trajectory_t tng_data,
8360                  const tng_molecule_t molecule,
8361                  const int64_t index,
8362                  tng_residue_t *residue)
8363 {
8364     (void) tng_data;
8365     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8366     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8367
8368     if(index >= molecule->n_residues)
8369     {
8370         *residue = 0;
8371         return(TNG_FAILURE);
8372     }
8373     *residue = &molecule->residues[index];
8374     return(TNG_SUCCESS);
8375 }
8376
8377 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8378                 (const tng_trajectory_t tng_data,
8379                  const tng_molecule_t molecule,
8380                  int64_t *n)
8381 {
8382     (void) tng_data;
8383     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8384     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8385
8386     *n = molecule->n_atoms;
8387
8388     return(TNG_SUCCESS);
8389 }
8390
8391 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8392                 (const tng_trajectory_t tng_data,
8393                  const tng_molecule_t molecule,
8394                  const int64_t index,
8395                  tng_atom_t *atom)
8396 {
8397     (void) tng_data;
8398     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8399     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8400
8401     if(index >= molecule->n_atoms)
8402     {
8403         *atom = 0;
8404         return(TNG_FAILURE);
8405     }
8406     *atom = &molecule->atoms[index];
8407     return(TNG_SUCCESS);
8408 }
8409
8410 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8411                 (tng_trajectory_t tng_data,
8412                  tng_molecule_t molecule,
8413                  const char *name,
8414                  int64_t nr,
8415                  tng_chain_t *chain)
8416 {
8417     int64_t i, n_chains;
8418     (void)tng_data;
8419
8420     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8421     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8422
8423     n_chains = molecule->n_chains;
8424
8425     for(i = n_chains - 1; i >= 0; i--)
8426     {
8427         *chain = &molecule->chains[i];
8428         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8429         {
8430             if(nr == -1 || nr == (*chain)->id)
8431             {
8432                 return(TNG_SUCCESS);
8433             }
8434         }
8435     }
8436
8437     *chain = 0;
8438
8439     return(TNG_FAILURE);
8440 }
8441
8442 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8443                 (tng_trajectory_t tng_data,
8444                  tng_molecule_t molecule,
8445                  const char *name,
8446                  tng_chain_t *chain)
8447 {
8448     int64_t id;
8449
8450     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8451     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8452
8453     /* Set ID to the ID of the last chain + 1 */
8454     if(molecule->n_chains)
8455     {
8456         id = molecule->chains[molecule->n_chains-1].id + 1;
8457     }
8458     else
8459     {
8460         id = 1;
8461     }
8462
8463     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8464                                        id, chain));
8465 }
8466
8467 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8468                 (tng_trajectory_t tng_data,
8469                  tng_molecule_t molecule,
8470                  const char *name,
8471                  const int64_t id,
8472                  tng_chain_t *chain)
8473 {
8474     tng_chain_t new_chains;
8475     tng_function_status stat = TNG_SUCCESS;
8476
8477     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8478     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8479
8480     new_chains = realloc(molecule->chains,
8481                          sizeof(struct tng_chain) *
8482                          (molecule->n_chains + 1));
8483
8484     if(!new_chains)
8485     {
8486         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8487                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8488                __FILE__, __LINE__);
8489         free(molecule->chains);
8490         molecule->chains = 0;
8491         return(TNG_CRITICAL);
8492     }
8493
8494     molecule->chains = new_chains;
8495
8496     *chain = &new_chains[molecule->n_chains];
8497     (*chain)->name = 0;
8498
8499     tng_chain_name_set(tng_data, *chain, name);
8500
8501     (*chain)->molecule = molecule;
8502     (*chain)->n_residues = 0;
8503
8504     molecule->n_chains++;
8505
8506     (*chain)->id = id;
8507
8508     return(stat);
8509 }
8510
8511 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8512                 (const tng_trajectory_t tng_data,
8513                  tng_molecule_t molecule,
8514                  const int64_t from_atom_id,
8515                  const int64_t to_atom_id,
8516                  tng_bond_t *bond)
8517 {
8518     tng_bond_t new_bonds;
8519     (void)tng_data;
8520
8521     new_bonds = realloc(molecule->bonds,
8522                         sizeof(struct tng_bond) *
8523                         (molecule->n_bonds + 1));
8524
8525     if(!new_bonds)
8526     {
8527         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8528                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8529                __FILE__, __LINE__);
8530         *bond = 0;
8531         free(molecule->bonds);
8532         molecule->bonds = 0;
8533         return(TNG_CRITICAL);
8534     }
8535
8536     molecule->bonds = new_bonds;
8537
8538     *bond = &new_bonds[molecule->n_bonds];
8539
8540     (*bond)->from_atom_id = from_atom_id;
8541     (*bond)->to_atom_id = to_atom_id;
8542
8543     molecule->n_bonds++;
8544
8545     return(TNG_SUCCESS);
8546 }
8547
8548 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8549                 (tng_trajectory_t tng_data,
8550                  tng_molecule_t molecule,
8551                  const char *name,
8552                  int64_t id,
8553                  tng_atom_t *atom)
8554 {
8555     int64_t i, n_atoms;
8556     (void)tng_data;
8557
8558     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8559
8560     n_atoms = molecule->n_atoms;
8561
8562     for(i = n_atoms - 1; i >= 0; i--)
8563     {
8564         *atom = &molecule->atoms[i];
8565         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8566         {
8567             if(id == -1 || id == (*atom)->id)
8568             {
8569                 return(TNG_SUCCESS);
8570             }
8571         }
8572     }
8573
8574     *atom = 0;
8575
8576     return(TNG_FAILURE);
8577 }
8578
8579 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8580                                        const tng_chain_t chain,
8581                                        char *name,
8582                                        const int max_len)
8583 {
8584     (void) tng_data;
8585     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8586     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8587
8588     strncpy(name, chain->name, max_len - 1);
8589     name[max_len - 1] = 0;
8590
8591     if(strlen(chain->name) > (unsigned int)max_len - 1)
8592     {
8593         return(TNG_FAILURE);
8594     }
8595     return(TNG_SUCCESS);
8596 }
8597
8598 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8599                 (tng_trajectory_t tng_data,
8600                  tng_chain_t chain,
8601                  const char *new_name)
8602 {
8603     unsigned int len;
8604     (void)tng_data;
8605
8606     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8607
8608     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8609
8610     /* If the currently stored string length is not enough to store the new
8611      * string it is freed and reallocated. */
8612     if(chain->name && strlen(chain->name) < len)
8613     {
8614         free(chain->name);
8615         chain->name = 0;
8616     }
8617     if(!chain->name)
8618     {
8619         chain->name = malloc(len);
8620         if(!chain->name)
8621         {
8622             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8623                    __FILE__, __LINE__);
8624             return(TNG_CRITICAL);
8625         }
8626     }
8627
8628     strncpy(chain->name, new_name, len);
8629
8630     return(TNG_SUCCESS);
8631 }
8632
8633 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8634                 (const tng_trajectory_t tng_data,
8635                  const tng_chain_t chain,
8636                  int64_t *n)
8637 {
8638     (void) tng_data;
8639     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8640     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8641
8642     *n = chain->n_residues;
8643
8644     return(TNG_SUCCESS);
8645 }
8646
8647 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8648                 (const tng_trajectory_t tng_data,
8649                  const tng_chain_t chain,
8650                  const int64_t index,
8651                  tng_residue_t *residue)
8652 {
8653     (void) tng_data;
8654     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8655     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8656
8657     if(index >= chain->n_residues)
8658     {
8659         *residue = 0;
8660         return(TNG_FAILURE);
8661     }
8662     *residue = &chain->residues[index];
8663     return(TNG_SUCCESS);
8664 }
8665
8666 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8667                 (tng_trajectory_t tng_data,
8668                  tng_chain_t chain,
8669                  const char *name,
8670                  int64_t id,
8671                  tng_residue_t *residue)
8672 {
8673     int64_t i, n_residues;
8674     (void)tng_data;
8675
8676     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8677
8678     n_residues = chain->n_residues;
8679
8680     for(i = n_residues - 1; i >= 0; i--)
8681     {
8682         *residue = &chain->residues[i];
8683         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8684         {
8685             if(id == -1 || id == (*residue)->id)
8686             {
8687                 return(TNG_SUCCESS);
8688             }
8689         }
8690     }
8691
8692     *residue = 0;
8693
8694     return(TNG_FAILURE);
8695 }
8696
8697 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8698                 (tng_trajectory_t tng_data,
8699                  tng_chain_t chain,
8700                  const char *name,
8701                  tng_residue_t *residue)
8702 {
8703     int64_t id;
8704
8705     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8706     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8707
8708     /* Set ID to the ID of the last residue + 1 */
8709     if(chain->n_residues)
8710     {
8711         id = chain->residues[chain->n_residues-1].id + 1;
8712     }
8713     else
8714     {
8715         id = 0;
8716     }
8717
8718     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8719                                       id, residue));
8720 }
8721
8722 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8723                 (tng_trajectory_t tng_data,
8724                  tng_chain_t chain,
8725                  const char *name,
8726                  const int64_t id,
8727                  tng_residue_t *residue)
8728 {
8729     int64_t curr_index;
8730     tng_residue_t new_residues, temp_residue, last_residue;
8731     tng_molecule_t molecule = chain->molecule;
8732     tng_function_status stat = TNG_SUCCESS;
8733
8734     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8735     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8736
8737     if(chain->n_residues)
8738     {
8739         curr_index = chain->residues - molecule->residues;
8740     }
8741     else
8742     {
8743         curr_index = -1;
8744     }
8745
8746     new_residues = realloc(molecule->residues,
8747                            sizeof(struct tng_residue) *
8748                            (molecule->n_residues + 1));
8749
8750     if(!new_residues)
8751     {
8752         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8753                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8754                __FILE__, __LINE__);
8755         free(molecule->residues);
8756         molecule->residues = 0;
8757         return(TNG_CRITICAL);
8758     }
8759
8760     molecule->residues = new_residues;
8761
8762     if(curr_index != -1)
8763     {
8764         chain->residues = new_residues + curr_index;
8765         if(molecule->n_residues)
8766         {
8767             last_residue = &new_residues[molecule->n_residues - 1];
8768
8769             temp_residue = chain->residues + (chain->n_residues - 1);
8770             /* Make space in list of residues to add the new residues together with the other
8771             * residues of this chain */
8772             if(temp_residue != last_residue)
8773             {
8774                 ++temp_residue;
8775                 memmove(temp_residue + 1, temp_residue,
8776                         last_residue - temp_residue);
8777             }
8778         }
8779     }
8780     else
8781     {
8782         curr_index = molecule->n_residues;
8783     }
8784
8785     *residue = &molecule->residues[curr_index + chain->n_residues];
8786
8787     if(!chain->n_residues)
8788     {
8789         chain->residues = *residue;
8790     }
8791     else
8792     {
8793         chain->residues = &molecule->residues[curr_index];
8794     }
8795
8796     (*residue)->name = 0;
8797     tng_residue_name_set(tng_data, *residue, name);
8798
8799     (*residue)->chain = chain;
8800     (*residue)->n_atoms = 0;
8801     (*residue)->atoms_offset = 0;
8802
8803     chain->n_residues++;
8804     molecule->n_residues++;
8805
8806     (*residue)->id = id;
8807
8808     return(stat);
8809 }
8810
8811 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8812                                          const tng_residue_t residue,
8813                                          char *name,
8814                                          const int max_len)
8815 {
8816     (void) tng_data;
8817     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8818     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8819
8820     strncpy(name, residue->name, max_len - 1);
8821     name[max_len - 1] = 0;
8822
8823     if(strlen(residue->name) > (unsigned int)max_len - 1)
8824     {
8825         return(TNG_FAILURE);
8826     }
8827     return(TNG_SUCCESS);
8828 }
8829
8830 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8831                                                            tng_residue_t residue,
8832                                                            const char *new_name)
8833 {
8834     unsigned int len;
8835     (void)tng_data;
8836
8837     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8838     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8839
8840     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8841
8842     /* If the currently stored string length is not enough to store the new
8843      * string it is freed and reallocated. */
8844     if(residue->name && strlen(residue->name) < len)
8845     {
8846         free(residue->name);
8847         residue->name = 0;
8848     }
8849     if(!residue->name)
8850     {
8851         residue->name = malloc(len);
8852         if(!residue->name)
8853         {
8854             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8855                    __FILE__, __LINE__);
8856             return(TNG_CRITICAL);
8857         }
8858     }
8859
8860     strncpy(residue->name, new_name, len);
8861
8862     return(TNG_SUCCESS);
8863 }
8864
8865 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8866                 (const tng_trajectory_t tng_data,
8867                  const tng_residue_t residue,
8868                  int64_t *n)
8869 {
8870     (void) tng_data;
8871     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8872     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8873
8874     *n = residue->n_atoms;
8875
8876     return(TNG_SUCCESS);
8877 }
8878
8879 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8880                 (const tng_trajectory_t tng_data,
8881                  const tng_residue_t residue,
8882                  const int64_t index,
8883                  tng_atom_t *atom)
8884 {
8885     tng_chain_t chain;
8886     tng_molecule_t molecule;
8887
8888     (void) tng_data;
8889     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8890     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8891
8892     if(index >= residue->n_atoms)
8893     {
8894         *atom = 0;
8895         return(TNG_FAILURE);
8896     }
8897     chain = residue->chain;
8898     molecule = chain->molecule;
8899
8900     if(index + residue->atoms_offset >= molecule->n_atoms)
8901     {
8902         *atom = 0;
8903         return(TNG_FAILURE);
8904     }
8905
8906     *atom = &molecule->atoms[residue->atoms_offset + index];
8907     return(TNG_SUCCESS);
8908 }
8909
8910 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8911                 (tng_trajectory_t tng_data,
8912                  tng_residue_t residue,
8913                  const char *atom_name,
8914                  const char *atom_type,
8915                  tng_atom_t *atom)
8916 {
8917     int64_t id;
8918
8919     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8920     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8921     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8922
8923     /* Set ID to the ID of the last atom + 1 */
8924     if(residue->chain->molecule->n_atoms)
8925     {
8926         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
8927     }
8928     else
8929     {
8930         id = 0;
8931     }
8932
8933     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
8934                                      id, atom));
8935 }
8936
8937 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
8938                 (tng_trajectory_t tng_data,
8939                  tng_residue_t residue,
8940                  const char *atom_name,
8941                  const char *atom_type,
8942                  const int64_t id,
8943                  tng_atom_t *atom)
8944 {
8945     tng_atom_t new_atoms;
8946     tng_molecule_t molecule = residue->chain->molecule;
8947     tng_function_status stat = TNG_SUCCESS;
8948
8949     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8950     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8951     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8952
8953     if(!residue->n_atoms)
8954     {
8955         residue->atoms_offset = molecule->n_atoms;
8956     }
8957
8958     new_atoms = realloc(molecule->atoms,
8959                         sizeof(struct tng_atom) *
8960                         (molecule->n_atoms + 1));
8961
8962     if(!new_atoms)
8963     {
8964         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8965                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
8966                __FILE__, __LINE__);
8967         free(molecule->atoms);
8968         molecule->atoms = 0;
8969         return(TNG_CRITICAL);
8970     }
8971
8972     molecule->atoms = new_atoms;
8973
8974     *atom = &new_atoms[molecule->n_atoms];
8975
8976     tng_atom_init(*atom);
8977     tng_atom_name_set(tng_data, *atom, atom_name);
8978     tng_atom_type_set(tng_data, *atom, atom_type);
8979
8980     (*atom)->residue = residue;
8981
8982     residue->n_atoms++;
8983     molecule->n_atoms++;
8984
8985     (*atom)->id = id;
8986
8987     return(stat);
8988 }
8989
8990 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8991                                                          tng_molecule_t *molecule_p)
8992 {
8993     *molecule_p = malloc(sizeof(struct tng_molecule));
8994     if(!*molecule_p)
8995     {
8996         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
8997                sizeof(struct tng_molecule), __FILE__, __LINE__);
8998         return(TNG_CRITICAL);
8999     }
9000
9001     tng_molecule_init(tng_data, *molecule_p);
9002
9003     return(TNG_SUCCESS);
9004 }
9005
9006 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9007                                                         tng_molecule_t *molecule_p)
9008 {
9009     if(!*molecule_p)
9010     {
9011         return(TNG_SUCCESS);
9012     }
9013
9014     tng_molecule_destroy(tng_data, *molecule_p);
9015
9016     free(*molecule_p);
9017     *molecule_p = 0;
9018
9019     return(TNG_SUCCESS);
9020 }
9021
9022 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9023                                                         tng_molecule_t molecule)
9024 {
9025     (void)tng_data;
9026     molecule->quaternary_str = 1;
9027     molecule->name = 0;
9028     molecule->n_chains = 0;
9029     molecule->chains = 0;
9030     molecule->n_residues = 0;
9031     molecule->residues = 0;
9032     molecule->n_atoms = 0;
9033     molecule->atoms = 0;
9034     molecule->n_bonds = 0;
9035     molecule->bonds = 0;
9036
9037     return(TNG_SUCCESS);
9038 }
9039
9040 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9041                                                            tng_molecule_t molecule)
9042 {
9043     int64_t i;
9044     (void)tng_data;
9045
9046     if(molecule->name)
9047     {
9048         free(molecule->name);
9049         molecule->name = 0;
9050     }
9051
9052     if(molecule->chains)
9053     {
9054         for(i = 0; i < molecule->n_chains; i++)
9055         {
9056             if(molecule->chains[i].name)
9057             {
9058                 free(molecule->chains[i].name);
9059                 molecule->chains[i].name = 0;
9060             }
9061         }
9062         free(molecule->chains);
9063         molecule->chains = 0;
9064     }
9065     molecule->n_chains = 0;
9066
9067     if(molecule->residues)
9068     {
9069         for(i = 0; i < molecule->n_residues; i++)
9070         {
9071             if(molecule->residues[i].name)
9072             {
9073                 free(molecule->residues[i].name);
9074                 molecule->residues[i].name = 0;
9075             }
9076         }
9077         free(molecule->residues);
9078         molecule->residues = 0;
9079     }
9080     molecule->n_residues = 0;
9081
9082     if(molecule->atoms)
9083     {
9084         for(i = 0; i < molecule->n_atoms; i++)
9085         {
9086             tng_atom_destroy(&molecule->atoms[i]);
9087         }
9088         free(molecule->atoms);
9089         molecule->atoms = 0;
9090     }
9091     molecule->n_atoms = 0;
9092
9093     if(molecule->bonds)
9094     {
9095         free(molecule->bonds);
9096         molecule->bonds = 0;
9097     }
9098     molecule->n_bonds = 0;
9099
9100     return(TNG_SUCCESS);
9101 }
9102
9103 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9104                 (const tng_trajectory_t tng_data,
9105                  const int64_t nr,
9106                  char *name,
9107                  int max_len)
9108 {
9109     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9110     tng_molecule_t mol;
9111     tng_bool found = TNG_FALSE;
9112
9113     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9114     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9115
9116     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9117
9118     if(!molecule_cnt_list)
9119     {
9120         return(TNG_FAILURE);
9121     }
9122
9123     for(i = 0; i < tng_data->n_molecules; i++)
9124     {
9125         mol = &tng_data->molecules[i];
9126         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9127         {
9128             cnt += mol->n_atoms * molecule_cnt_list[i];
9129             continue;
9130         }
9131         found = TNG_TRUE;
9132         break;
9133     }
9134     if(!found)
9135     {
9136         return(TNG_FAILURE);
9137     }
9138
9139     strncpy(name, mol->name, max_len - 1);
9140     name[max_len - 1] = 0;
9141
9142     if(strlen(mol->name) > (unsigned int)max_len - 1)
9143     {
9144         return(TNG_FAILURE);
9145     }
9146     return(TNG_SUCCESS);
9147 }
9148
9149 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9150                 (const tng_trajectory_t tng_data,
9151                  const int64_t nr,
9152                  int64_t *id)
9153 {
9154     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9155     tng_molecule_t mol;
9156     tng_bool found = TNG_FALSE;
9157
9158     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9159     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9160
9161     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9162
9163     if(!molecule_cnt_list)
9164     {
9165         return(TNG_FAILURE);
9166     }
9167
9168     for(i = 0; i < tng_data->n_molecules; i++)
9169     {
9170         mol = &tng_data->molecules[i];
9171         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9172         {
9173             cnt += mol->n_atoms * molecule_cnt_list[i];
9174             continue;
9175         }
9176         found = TNG_TRUE;
9177         break;
9178     }
9179     if(!found)
9180     {
9181         return(TNG_FAILURE);
9182     }
9183
9184     *id = mol->id;
9185
9186     return(TNG_SUCCESS);
9187 }
9188
9189 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9190                 (const tng_trajectory_t tng_data,
9191                  int64_t *n_bonds,
9192                  int64_t **from_atoms,
9193                  int64_t **to_atoms)
9194 {
9195     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9196     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9197     tng_molecule_t mol;
9198     tng_bond_t bond;
9199
9200     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9201     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9202     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9203     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9204
9205     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9206
9207     if(!molecule_cnt_list)
9208     {
9209         return(TNG_FAILURE);
9210     }
9211
9212     *n_bonds = 0;
9213     /* First count the total number of bonds to allocate memory */
9214     for(i = 0; i < tng_data->n_molecules; i++)
9215     {
9216         mol = &tng_data->molecules[i];
9217         mol_cnt = molecule_cnt_list[i];
9218         *n_bonds += mol_cnt * mol->n_bonds;
9219     }
9220     if(*n_bonds == 0)
9221     {
9222         return(TNG_SUCCESS);
9223     }
9224
9225     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9226     if(!*from_atoms)
9227     {
9228         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9229                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9230         return(TNG_CRITICAL);
9231     }
9232     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9233     if(!*to_atoms)
9234     {
9235         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9236                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9237         free(*from_atoms);
9238         *from_atoms = 0;
9239         return(TNG_CRITICAL);
9240     }
9241
9242     cnt = 0;
9243     for(i = 0; i < tng_data->n_molecules; i++)
9244     {
9245         mol = &tng_data->molecules[i];
9246         mol_cnt = molecule_cnt_list[i];
9247         for(j = 0; j < mol_cnt; j++)
9248         {
9249             for(k = 0; k < mol->n_bonds; k++)
9250             {
9251                 bond = &mol->bonds[k];
9252                 from_atom = atom_cnt + bond->from_atom_id;
9253                 to_atom = atom_cnt + bond->to_atom_id;
9254                 (*from_atoms)[cnt] = from_atom;
9255                 (*to_atoms)[cnt++] = to_atom;
9256             }
9257             atom_cnt += mol->n_atoms;
9258         }
9259     }
9260
9261     return(TNG_SUCCESS);
9262 }
9263
9264 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9265                 (const tng_trajectory_t tng_data,
9266                  const int64_t nr,
9267                  char *name,
9268                  int max_len)
9269 {
9270     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9271     tng_molecule_t mol;
9272     tng_atom_t atom;
9273     tng_bool found = TNG_FALSE;
9274
9275     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9276     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9277
9278     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9279
9280     if(!molecule_cnt_list)
9281     {
9282         return(TNG_FAILURE);
9283     }
9284
9285     for(i = 0; i < tng_data->n_molecules; i++)
9286     {
9287         mol = &tng_data->molecules[i];
9288         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9289         {
9290             cnt += mol->n_atoms * molecule_cnt_list[i];
9291             continue;
9292         }
9293         atom = &mol->atoms[nr % mol->n_atoms];
9294         found = TNG_TRUE;
9295         break;
9296     }
9297     if(!found)
9298     {
9299         return(TNG_FAILURE);
9300     }
9301     if(!atom->residue || !atom->residue->chain)
9302     {
9303         return(TNG_FAILURE);
9304     }
9305
9306     strncpy(name, atom->residue->chain->name, max_len - 1);
9307     name[max_len - 1] = 0;
9308
9309     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9310     {
9311         return(TNG_FAILURE);
9312     }
9313     return(TNG_SUCCESS);
9314 }
9315
9316 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9317                 (const tng_trajectory_t tng_data,
9318                  const int64_t nr,
9319                  char *name,
9320                  int max_len)
9321 {
9322     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9323     tng_molecule_t mol;
9324     tng_atom_t atom;
9325     tng_bool found = TNG_FALSE;
9326
9327     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9328     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9329
9330     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9331
9332     if(!molecule_cnt_list)
9333     {
9334         return(TNG_FAILURE);
9335     }
9336
9337     for(i = 0; i < tng_data->n_molecules; i++)
9338     {
9339         mol = &tng_data->molecules[i];
9340         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9341         {
9342             cnt += mol->n_atoms * molecule_cnt_list[i];
9343             continue;
9344         }
9345         atom = &mol->atoms[nr % mol->n_atoms];
9346         found = TNG_TRUE;
9347         break;
9348     }
9349     if(!found)
9350     {
9351         return(TNG_FAILURE);
9352     }
9353     if(!atom->residue)
9354     {
9355         return(TNG_FAILURE);
9356     }
9357
9358     strncpy(name, atom->residue->name, max_len - 1);
9359     name[max_len - 1] = 0;
9360
9361     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9362     {
9363         return(TNG_FAILURE);
9364     }
9365     return(TNG_SUCCESS);
9366 }
9367
9368 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9369                 (const tng_trajectory_t tng_data,
9370                  const int64_t nr,
9371                  int64_t *id)
9372 {
9373     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9374     tng_molecule_t mol;
9375     tng_atom_t atom;
9376     tng_bool found = TNG_FALSE;
9377
9378     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9379     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9380
9381     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9382
9383     if(!molecule_cnt_list)
9384     {
9385         return(TNG_FAILURE);
9386     }
9387
9388     for(i = 0; i < tng_data->n_molecules; i++)
9389     {
9390         mol = &tng_data->molecules[i];
9391         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9392         {
9393             cnt += mol->n_atoms * molecule_cnt_list[i];
9394             continue;
9395         }
9396         atom = &mol->atoms[nr % mol->n_atoms];
9397         found = TNG_TRUE;
9398         break;
9399     }
9400     if(!found)
9401     {
9402         return(TNG_FAILURE);
9403     }
9404     if(!atom->residue)
9405     {
9406         return(TNG_FAILURE);
9407     }
9408
9409     *id = atom->residue->id;
9410
9411     return(TNG_SUCCESS);
9412 }
9413
9414 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9415                 (const tng_trajectory_t tng_data,
9416                  const int64_t nr,
9417                  int64_t *id)
9418 {
9419     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9420     tng_molecule_t mol;
9421     tng_atom_t atom;
9422     tng_bool found = TNG_FALSE;
9423
9424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9425     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9426
9427     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9428
9429     if(!molecule_cnt_list)
9430     {
9431         return(TNG_FAILURE);
9432     }
9433
9434     for(i = 0; i < tng_data->n_molecules; i++)
9435     {
9436         mol = &tng_data->molecules[i];
9437         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9438         {
9439             cnt += mol->n_atoms * molecule_cnt_list[i];
9440             offset += mol->n_residues * molecule_cnt_list[i];
9441             continue;
9442         }
9443         atom = &mol->atoms[nr % mol->n_atoms];
9444         found = TNG_TRUE;
9445         break;
9446     }
9447     if(!found)
9448     {
9449         return(TNG_FAILURE);
9450     }
9451     if(!atom->residue)
9452     {
9453         return(TNG_FAILURE);
9454     }
9455
9456     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9457
9458     *id = atom->residue->id + offset;
9459
9460     return(TNG_SUCCESS);
9461 }
9462
9463 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9464                 (const tng_trajectory_t tng_data,
9465                  const int64_t nr,
9466                  char *name,
9467                  int max_len)
9468 {
9469     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9470     tng_molecule_t mol;
9471     tng_atom_t atom;
9472     tng_bool found = TNG_FALSE;
9473
9474     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9475     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9476
9477     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9478
9479     if(!molecule_cnt_list)
9480     {
9481         return(TNG_FAILURE);
9482     }
9483
9484     for(i = 0; i < tng_data->n_molecules; i++)
9485     {
9486         mol = &tng_data->molecules[i];
9487         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9488         {
9489             cnt += mol->n_atoms * molecule_cnt_list[i];
9490             continue;
9491         }
9492         atom = &mol->atoms[nr % mol->n_atoms];
9493         found = TNG_TRUE;
9494         break;
9495     }
9496     if(!found)
9497     {
9498         return(TNG_FAILURE);
9499     }
9500
9501     strncpy(name, atom->name, max_len - 1);
9502     name[max_len - 1] = 0;
9503
9504     if(strlen(atom->name) > (unsigned int)max_len - 1)
9505     {
9506         return(TNG_FAILURE);
9507     }
9508     return(TNG_SUCCESS);
9509 }
9510
9511 tng_function_status tng_atom_type_of_particle_nr_get
9512                 (const tng_trajectory_t tng_data,
9513                  const int64_t nr,
9514                  char *type,
9515                  int max_len)
9516 {
9517     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9518     tng_molecule_t mol;
9519     tng_atom_t atom;
9520     tng_bool found = TNG_FALSE;
9521
9522     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9523     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9524
9525     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9526
9527     if(!molecule_cnt_list)
9528     {
9529         return(TNG_FAILURE);
9530     }
9531
9532     for(i = 0; i < tng_data->n_molecules; i++)
9533     {
9534         mol = &tng_data->molecules[i];
9535         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9536         {
9537             cnt += mol->n_atoms * molecule_cnt_list[i];
9538             continue;
9539         }
9540         atom = &mol->atoms[nr % mol->n_atoms];
9541         found = TNG_TRUE;
9542         break;
9543     }
9544     if(!found)
9545     {
9546         return(TNG_FAILURE);
9547     }
9548
9549     strncpy(type, atom->atom_type, max_len - 1);
9550     type[max_len - 1] = 0;
9551
9552     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9553     {
9554         return(TNG_FAILURE);
9555     }
9556     return(TNG_SUCCESS);
9557 }
9558
9559 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9560                 (tng_trajectory_t tng_data,
9561                  const int64_t num_first_particle,
9562                  const int64_t n_particles,
9563                  const int64_t *mapping_table)
9564 {
9565     int64_t i;
9566     tng_particle_mapping_t mapping;
9567     tng_trajectory_frame_set_t frame_set;
9568
9569     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9570
9571     frame_set = &tng_data->current_trajectory_frame_set;
9572
9573     /* Sanity check of the particle ranges. Split into multiple if
9574      * statements for improved readability */
9575     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9576     {
9577         mapping = &frame_set->mappings[i];
9578         if(num_first_particle >= mapping->num_first_particle &&
9579            num_first_particle < mapping->num_first_particle +
9580                                    mapping->n_particles)
9581         {
9582             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9583             return(TNG_FAILURE);
9584         }
9585         if(num_first_particle + n_particles >=
9586            mapping->num_first_particle &&
9587            num_first_particle + n_particles <
9588            mapping->num_first_particle + mapping->n_particles)
9589         {
9590             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9591             return(TNG_FAILURE);
9592         }
9593         if(mapping->num_first_particle >= num_first_particle &&
9594            mapping->num_first_particle < num_first_particle +
9595                                             n_particles)
9596         {
9597             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9598             return(TNG_FAILURE);
9599         }
9600         if(mapping->num_first_particle + mapping->n_particles >
9601            num_first_particle &&
9602            mapping->num_first_particle + mapping->n_particles <
9603            num_first_particle + n_particles)
9604         {
9605             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9606             return(TNG_FAILURE);
9607         }
9608     }
9609
9610     frame_set->n_mapping_blocks++;
9611
9612     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9613                       frame_set->n_mapping_blocks);
9614
9615     if(!mapping)
9616     {
9617         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9618                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9619                __FILE__, __LINE__);
9620         free(frame_set->mappings);
9621         frame_set->mappings = 0;
9622         return(TNG_CRITICAL);
9623     }
9624     frame_set->mappings = mapping;
9625
9626     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9627     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9628
9629     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9630     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9631     {
9632         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9633                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9634         return(TNG_CRITICAL);
9635     }
9636
9637     for(i=0; i<n_particles; i++)
9638     {
9639         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9640     }
9641
9642     return(TNG_SUCCESS);
9643 }
9644
9645 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9646 {
9647     tng_trajectory_frame_set_t frame_set;
9648     tng_particle_mapping_t mapping;
9649     int64_t i;
9650
9651     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9652
9653     frame_set = &tng_data->current_trajectory_frame_set;
9654
9655     if(frame_set->n_mapping_blocks && frame_set->mappings)
9656     {
9657         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9658         {
9659             mapping = &frame_set->mappings[i];
9660             if(mapping->real_particle_numbers)
9661             {
9662                 free(mapping->real_particle_numbers);
9663                 mapping->real_particle_numbers = 0;
9664             }
9665         }
9666         free(frame_set->mappings);
9667         frame_set->mappings = 0;
9668         frame_set->n_mapping_blocks = 0;
9669     }
9670
9671     return(TNG_SUCCESS);
9672 }
9673
9674 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9675 {
9676     time_t seconds;
9677     tng_trajectory_frame_set_t frame_set;
9678     tng_trajectory_t tng_data;
9679
9680     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9681     if(!*tng_data_p)
9682     {
9683         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9684                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9685         return(TNG_CRITICAL);
9686     }
9687
9688     tng_data = *tng_data_p;
9689
9690     frame_set = &tng_data->current_trajectory_frame_set;
9691
9692     tng_data->input_file_path = 0;
9693     tng_data->input_file = 0;
9694     tng_data->input_file_len = 0;
9695     tng_data->output_file_path = 0;
9696     tng_data->output_file = 0;
9697
9698     tng_data->first_program_name = 0;
9699     tng_data->first_user_name = 0;
9700     tng_data->first_computer_name = 0;
9701     tng_data->first_pgp_signature = 0;
9702     tng_data->last_program_name = 0;
9703     tng_data->last_user_name = 0;
9704     tng_data->last_computer_name = 0;
9705     tng_data->last_pgp_signature = 0;
9706     tng_data->forcefield_name = 0;
9707
9708     seconds = time(0);
9709     if ( seconds == -1)
9710     {
9711         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9712     }
9713     else
9714     {
9715         tng_data->time = seconds;
9716     }
9717
9718     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9719     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9720     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9721     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9722     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9723     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9724     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9725     tng_data->frame_set_n_frames = 100;
9726     tng_data->n_trajectory_frame_sets = 0;
9727     tng_data->medium_stride_length = 100;
9728     tng_data->long_stride_length = 10000;
9729
9730     tng_data->time_per_frame = -1;
9731
9732     tng_data->n_particle_data_blocks = 0;
9733     tng_data->n_data_blocks = 0;
9734
9735     tng_data->non_tr_particle_data = 0;
9736     tng_data->non_tr_data = 0;
9737
9738     tng_data->compress_algo_pos = 0;
9739     tng_data->compress_algo_vel = 0;
9740     tng_data->compression_precision = 1000;
9741     tng_data->distance_unit_exponential = -9;
9742
9743     frame_set->first_frame = -1;
9744     frame_set->n_mapping_blocks = 0;
9745     frame_set->mappings = 0;
9746     frame_set->molecule_cnt_list = 0;
9747
9748     frame_set->n_particle_data_blocks = 0;
9749     frame_set->n_data_blocks = 0;
9750
9751     frame_set->tr_particle_data = 0;
9752     frame_set->tr_data = 0;
9753
9754     frame_set->n_written_frames = 0;
9755     frame_set->n_unwritten_frames = 0;
9756
9757     frame_set->next_frame_set_file_pos = -1;
9758     frame_set->prev_frame_set_file_pos = -1;
9759     frame_set->medium_stride_next_frame_set_file_pos = -1;
9760     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9761     frame_set->long_stride_next_frame_set_file_pos = -1;
9762     frame_set->long_stride_prev_frame_set_file_pos = -1;
9763
9764     frame_set->first_frame_time = -1;
9765
9766     tng_data->n_molecules = 0;
9767     tng_data->molecules = 0;
9768     tng_data->molecule_cnt_list = 0;
9769     tng_data->n_particles = 0;
9770
9771     {
9772       /* Check the endianness of the computer */
9773       static int32_t endianness_32 = 0x01234567;
9774       /* 0x01234567 */
9775       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9776         {
9777           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9778         }
9779
9780       /* 0x67452301 */
9781       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9782         {
9783           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9784
9785         }
9786
9787       /* 0x45670123 */
9788       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9789         {
9790           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9791         }
9792     }
9793     {
9794       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9795       /* 0x0123456789ABCDEF */
9796       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9797         {
9798           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9799         }
9800
9801       /* 0xEFCDAB8967452301 */
9802       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9803         {
9804           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9805         }
9806
9807       /* 0x89ABCDEF01234567 */
9808       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9809         {
9810           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9811         }
9812
9813       /* 0x45670123CDEF89AB */
9814       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9815         {
9816           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9817         }
9818
9819       /* 0x23016745AB89EFCD */
9820       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9821         {
9822           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9823         }
9824     }
9825
9826     /* By default do not swap the byte order, i.e. keep the byte order of the
9827      * architecture. The input file endianness will be set when reading the
9828      * header. The output endianness can be changed - before the file is
9829      * written. */
9830     tng_data->input_endianness_swap_func_32 = 0;
9831     tng_data->input_endianness_swap_func_64 = 0;
9832     tng_data->output_endianness_swap_func_32 = 0;
9833     tng_data->output_endianness_swap_func_64 = 0;
9834
9835     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9836     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9837     tng_data->current_trajectory_frame_set.n_frames = 0;
9838
9839     return(TNG_SUCCESS);
9840 }
9841
9842 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9843 {
9844     int64_t i, j, k, l;
9845     int64_t n_particles, n_values_per_frame;
9846     tng_trajectory_t tng_data = *tng_data_p;
9847     tng_trajectory_frame_set_t frame_set;
9848
9849     if(!*tng_data_p)
9850     {
9851         return(TNG_SUCCESS);
9852     }
9853
9854     frame_set = &tng_data->current_trajectory_frame_set;
9855
9856     if(tng_data->input_file_path)
9857     {
9858         free(tng_data->input_file_path);
9859         tng_data->input_file_path = 0;
9860     }
9861
9862     if(tng_data->input_file)
9863     {
9864         if(tng_data->output_file == tng_data->input_file)
9865         {
9866             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9867             tng_data->output_file = 0;
9868         }
9869         fclose(tng_data->input_file);
9870         tng_data->input_file = 0;
9871     }
9872
9873     if(tng_data->output_file_path)
9874     {
9875         free(tng_data->output_file_path);
9876         tng_data->output_file_path = 0;
9877     }
9878
9879     if(tng_data->output_file)
9880     {
9881         /* FIXME: Do not always write the hash */
9882         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9883         fclose(tng_data->output_file);
9884         tng_data->output_file = 0;
9885     }
9886
9887     if(tng_data->first_program_name)
9888     {
9889         free(tng_data->first_program_name);
9890         tng_data->first_program_name = 0;
9891     }
9892
9893     if(tng_data->last_program_name)
9894     {
9895         free(tng_data->last_program_name);
9896         tng_data->last_program_name = 0;
9897     }
9898
9899     if(tng_data->first_user_name)
9900     {
9901         free(tng_data->first_user_name);
9902         tng_data->first_user_name = 0;
9903     }
9904
9905     if(tng_data->last_user_name)
9906     {
9907         free(tng_data->last_user_name);
9908         tng_data->last_user_name = 0;
9909     }
9910
9911     if(tng_data->first_computer_name)
9912     {
9913         free(tng_data->first_computer_name);
9914         tng_data->first_computer_name = 0;
9915     }
9916
9917     if(tng_data->last_computer_name)
9918     {
9919         free(tng_data->last_computer_name);
9920         tng_data->last_computer_name = 0;
9921     }
9922
9923     if(tng_data->first_pgp_signature)
9924     {
9925         free(tng_data->first_pgp_signature);
9926         tng_data->first_pgp_signature = 0;
9927     }
9928
9929     if(tng_data->last_pgp_signature)
9930     {
9931         free(tng_data->last_pgp_signature);
9932         tng_data->last_pgp_signature = 0;
9933     }
9934
9935     if(tng_data->forcefield_name)
9936     {
9937         free(tng_data->forcefield_name);
9938         tng_data->forcefield_name = 0;
9939     }
9940
9941     tng_frame_set_particle_mapping_free(tng_data);
9942
9943     if(frame_set->molecule_cnt_list)
9944     {
9945         free(frame_set->molecule_cnt_list);
9946         frame_set->molecule_cnt_list = 0;
9947     }
9948
9949     if(tng_data->var_num_atoms_flag)
9950     {
9951         n_particles = frame_set->n_particles;
9952     }
9953     else
9954     {
9955         n_particles = tng_data->n_particles;
9956     }
9957
9958     if(tng_data->non_tr_particle_data)
9959     {
9960         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
9961         {
9962             if(tng_data->non_tr_particle_data[i].values)
9963             {
9964                 free(tng_data->non_tr_particle_data[i].values);
9965                 tng_data->non_tr_particle_data[i].values = 0;
9966             }
9967
9968             if(tng_data->non_tr_particle_data[i].strings)
9969             {
9970                 n_values_per_frame = tng_data->non_tr_particle_data[i].
9971                                      n_values_per_frame;
9972                 if(tng_data->non_tr_particle_data[i].strings[0])
9973                 {
9974                     for(j = 0; j < n_particles; j++)
9975                     {
9976                         if(tng_data->non_tr_particle_data[i].strings[0][j])
9977                         {
9978                             for(k = 0; k < n_values_per_frame; k++)
9979                             {
9980                                 if(tng_data->non_tr_particle_data[i].
9981                                    strings[0][j][k])
9982                                 {
9983                                     free(tng_data->non_tr_particle_data[i].
9984                                          strings[0][j][k]);
9985                                     tng_data->non_tr_particle_data[i].
9986                                     strings[0][j][k] = 0;
9987                                 }
9988                             }
9989                             free(tng_data->non_tr_particle_data[i].
9990                                  strings[0][j]);
9991                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9992                         }
9993                     }
9994                     free(tng_data->non_tr_particle_data[i].strings[0]);
9995                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9996                 }
9997                 free(tng_data->non_tr_particle_data[i].strings);
9998                 tng_data->non_tr_particle_data[i].strings = 0;
9999             }
10000
10001             if(tng_data->non_tr_particle_data[i].block_name)
10002             {
10003                 free(tng_data->non_tr_particle_data[i].block_name);
10004                 tng_data->non_tr_particle_data[i].block_name = 0;
10005             }
10006         }
10007         free(tng_data->non_tr_particle_data);
10008         tng_data->non_tr_particle_data = 0;
10009     }
10010
10011     if(tng_data->non_tr_data)
10012     {
10013         for(i = 0; i < tng_data->n_data_blocks; i++)
10014         {
10015             if(tng_data->non_tr_data[i].values)
10016             {
10017                 free(tng_data->non_tr_data[i].values);
10018                 tng_data->non_tr_data[i].values = 0;
10019             }
10020
10021             if(tng_data->non_tr_data[i].strings)
10022             {
10023                 n_values_per_frame = tng_data->non_tr_data[i].
10024                                      n_values_per_frame;
10025                 if(tng_data->non_tr_data[i].strings[0])
10026                 {
10027                     for(j = 0; j < n_values_per_frame; j++)
10028                     {
10029                         if(tng_data->non_tr_data[i].strings[0][j])
10030                         {
10031                             free(tng_data->non_tr_data[i].strings[0][j]);
10032                             tng_data->non_tr_data[i].strings[0][j] = 0;
10033                         }
10034                     }
10035                     free(tng_data->non_tr_data[i].strings[0]);
10036                     tng_data->non_tr_data[i].strings[0] = 0;
10037                 }
10038                 free(tng_data->non_tr_data[i].strings);
10039                 tng_data->non_tr_data[i].strings = 0;
10040             }
10041
10042             if(tng_data->non_tr_data[i].block_name)
10043             {
10044                 free(tng_data->non_tr_data[i].block_name);
10045                 tng_data->non_tr_data[i].block_name = 0;
10046             }
10047         }
10048         free(tng_data->non_tr_data);
10049         tng_data->non_tr_data = 0;
10050     }
10051
10052     tng_data->n_particle_data_blocks = 0;
10053     tng_data->n_data_blocks = 0;
10054
10055     if(tng_data->compress_algo_pos)
10056     {
10057         free(tng_data->compress_algo_pos);
10058         tng_data->compress_algo_pos = 0;
10059     }
10060     if(tng_data->compress_algo_vel)
10061     {
10062         free(tng_data->compress_algo_vel);
10063         tng_data->compress_algo_vel = 0;
10064     }
10065
10066     if(frame_set->tr_particle_data)
10067     {
10068         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10069         {
10070             if(frame_set->tr_particle_data[i].values)
10071             {
10072                 free(frame_set->tr_particle_data[i].values);
10073                 frame_set->tr_particle_data[i].values = 0;
10074             }
10075
10076             if(frame_set->tr_particle_data[i].strings)
10077             {
10078                 n_values_per_frame = frame_set->tr_particle_data[i].
10079                                      n_values_per_frame;
10080                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10081                 {
10082                     if(frame_set->tr_particle_data[i].strings[j])
10083                     {
10084                         for(k = 0; k < n_particles; k++)
10085                         {
10086                             if(frame_set->tr_particle_data[i].
10087                                 strings[j][k])
10088                             {
10089                                 for(l = 0; l < n_values_per_frame; l++)
10090                                 {
10091                                     if(frame_set->tr_particle_data[i].
10092                                         strings[j][k][l])
10093                                     {
10094                                         free(frame_set->tr_particle_data[i].
10095                                                 strings[j][k][l]);
10096                                         frame_set->tr_particle_data[i].
10097                                         strings[j][k][l] = 0;
10098                                     }
10099                                 }
10100                                 free(frame_set->tr_particle_data[i].
10101                                         strings[j][k]);
10102                                 frame_set->tr_particle_data[i].
10103                                 strings[j][k] = 0;
10104                             }
10105                         }
10106                         free(frame_set->tr_particle_data[i].strings[j]);
10107                         frame_set->tr_particle_data[i].strings[j] = 0;
10108                     }
10109                 }
10110                 free(frame_set->tr_particle_data[i].strings);
10111                 frame_set->tr_particle_data[i].strings = 0;
10112             }
10113
10114             if(frame_set->tr_particle_data[i].block_name)
10115             {
10116                 free(frame_set->tr_particle_data[i].block_name);
10117                 frame_set->tr_particle_data[i].block_name = 0;
10118             }
10119         }
10120         free(frame_set->tr_particle_data);
10121         frame_set->tr_particle_data = 0;
10122     }
10123
10124     if(frame_set->tr_data)
10125     {
10126         for(i = 0; i < frame_set->n_data_blocks; i++)
10127         {
10128             if(frame_set->tr_data[i].values)
10129             {
10130                 free(frame_set->tr_data[i].values);
10131                 frame_set->tr_data[i].values = 0;
10132             }
10133
10134             if(frame_set->tr_data[i].strings)
10135             {
10136                 n_values_per_frame = frame_set->tr_data[i].
10137                                      n_values_per_frame;
10138                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10139                 {
10140                     if(frame_set->tr_data[i].strings[j])
10141                     {
10142                         for(k = 0; k < n_values_per_frame; k++)
10143                         {
10144                             if(frame_set->tr_data[i].strings[j][k])
10145                             {
10146                                 free(frame_set->tr_data[i].strings[j][k]);
10147                                 frame_set->tr_data[i].strings[j][k] = 0;
10148                             }
10149                         }
10150                         free(frame_set->tr_data[i].strings[j]);
10151                         frame_set->tr_data[i].strings[j] = 0;
10152                     }
10153                 }
10154                 free(frame_set->tr_data[i].strings);
10155                 frame_set->tr_data[i].strings = 0;
10156             }
10157
10158             if(frame_set->tr_data[i].block_name)
10159             {
10160                 free(frame_set->tr_data[i].block_name);
10161                 frame_set->tr_data[i].block_name = 0;
10162             }
10163         }
10164         free(frame_set->tr_data);
10165         frame_set->tr_data = 0;
10166     }
10167
10168     frame_set->n_particle_data_blocks = 0;
10169     frame_set->n_data_blocks = 0;
10170
10171     if(tng_data->molecules)
10172     {
10173         for(i = 0; i < tng_data->n_molecules; i++)
10174         {
10175             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10176         }
10177         free(tng_data->molecules);
10178         tng_data->molecules = 0;
10179         tng_data->n_molecules = 0;
10180     }
10181     if(tng_data->molecule_cnt_list)
10182     {
10183         free(tng_data->molecule_cnt_list);
10184         tng_data->molecule_cnt_list = 0;
10185     }
10186
10187     free(*tng_data_p);
10188     *tng_data_p = 0;
10189
10190     return(TNG_SUCCESS);
10191 }
10192
10193 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10194                                                  tng_trajectory_t *dest_p)
10195 {
10196     tng_trajectory_frame_set_t frame_set;
10197     tng_trajectory_t dest;
10198
10199     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10200
10201     *dest_p = malloc(sizeof(struct tng_trajectory));
10202     if(!*dest_p)
10203     {
10204         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
10205                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10206         return(TNG_CRITICAL);
10207     }
10208
10209     dest = *dest_p;
10210
10211     frame_set = &dest->current_trajectory_frame_set;
10212
10213     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10214     if(!dest->input_file_path)
10215     {
10216         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10217                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10218         return(TNG_CRITICAL);
10219     }
10220     strcpy(dest->input_file_path, src->input_file_path);
10221     dest->input_file = 0;
10222     dest->input_file_len = src->input_file_len;
10223     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10224     if(!dest->output_file_path)
10225     {
10226         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10227                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10228         return(TNG_CRITICAL);
10229     }
10230     strcpy(dest->output_file_path, src->output_file_path);
10231     dest->output_file = 0;
10232
10233     dest->first_program_name = 0;
10234     dest->first_user_name = 0;
10235     dest->first_computer_name = 0;
10236     dest->first_pgp_signature = 0;
10237     dest->last_program_name = 0;
10238     dest->last_user_name = 0;
10239     dest->last_computer_name = 0;
10240     dest->last_pgp_signature = 0;
10241     dest->forcefield_name = 0;
10242
10243     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10244     dest->first_trajectory_frame_set_input_file_pos =
10245     src->first_trajectory_frame_set_input_file_pos;
10246     dest->last_trajectory_frame_set_input_file_pos =
10247     src->last_trajectory_frame_set_input_file_pos;
10248     dest->current_trajectory_frame_set_input_file_pos =
10249     src->current_trajectory_frame_set_input_file_pos;
10250     dest->first_trajectory_frame_set_output_file_pos =
10251     src->first_trajectory_frame_set_output_file_pos;
10252     dest->last_trajectory_frame_set_output_file_pos =
10253     src->last_trajectory_frame_set_output_file_pos;
10254     dest->current_trajectory_frame_set_output_file_pos =
10255     src->current_trajectory_frame_set_output_file_pos;
10256     dest->frame_set_n_frames = src->frame_set_n_frames;
10257     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10258     dest->medium_stride_length = src->medium_stride_length;
10259     dest->long_stride_length = src->long_stride_length;
10260
10261     dest->time_per_frame = src->time_per_frame;
10262
10263     /* Currently the non trajectory data blocks are not copied since it
10264      * can lead to problems when freeing memory in a parallel block. */
10265     dest->n_particle_data_blocks = 0;
10266     dest->n_data_blocks = 0;
10267     dest->non_tr_particle_data = 0;
10268     dest->non_tr_data = 0;
10269
10270     dest->compress_algo_pos = 0;
10271     dest->compress_algo_vel = 0;
10272     dest->distance_unit_exponential = -9;
10273     dest->compression_precision = 1000;
10274
10275     frame_set->n_mapping_blocks = 0;
10276     frame_set->mappings = 0;
10277     frame_set->molecule_cnt_list = 0;
10278
10279     frame_set->n_particle_data_blocks = 0;
10280     frame_set->n_data_blocks = 0;
10281
10282     frame_set->tr_particle_data = 0;
10283     frame_set->tr_data = 0;
10284
10285     frame_set->next_frame_set_file_pos = -1;
10286     frame_set->prev_frame_set_file_pos = -1;
10287     frame_set->medium_stride_next_frame_set_file_pos = -1;
10288     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10289     frame_set->long_stride_next_frame_set_file_pos = -1;
10290     frame_set->long_stride_prev_frame_set_file_pos = -1;
10291     frame_set->first_frame = -1;
10292
10293     dest->n_molecules = 0;
10294     dest->molecules = 0;
10295     dest->molecule_cnt_list = 0;
10296     dest->n_particles = src->n_particles;
10297
10298     dest->endianness_32 = src->endianness_32;
10299     dest->endianness_64 = src->endianness_64;
10300     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10301     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10302     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10303     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10304
10305     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10306     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10307     dest->current_trajectory_frame_set.n_frames = 0;
10308
10309     return(TNG_SUCCESS);
10310 }
10311
10312 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10313                                        char *file_name, const int max_len)
10314 {
10315     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10316     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10317
10318     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10319     file_name[max_len - 1] = 0;
10320
10321     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10322     {
10323         return(TNG_FAILURE);
10324     }
10325     return(TNG_SUCCESS);
10326 }
10327
10328 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10329                                                          const char *file_name)
10330 {
10331     unsigned int len;
10332     char *temp;
10333
10334     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10335     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10336
10337
10338     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10339                                            file_name) == 0)
10340     {
10341         return(TNG_SUCCESS);
10342     }
10343
10344     if(tng_data->input_file)
10345     {
10346         fclose(tng_data->input_file);
10347     }
10348
10349     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10350     temp = realloc(tng_data->input_file_path, len);
10351     if(!temp)
10352     {
10353         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10354                __FILE__, __LINE__);
10355         free(tng_data->input_file_path);
10356         tng_data->input_file_path = 0;
10357         return(TNG_CRITICAL);
10358     }
10359     tng_data->input_file_path = temp;
10360
10361     strncpy(tng_data->input_file_path, file_name, len);
10362
10363     return(tng_input_file_init(tng_data));
10364 }
10365
10366 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10367                                        char *file_name, const int max_len)
10368 {
10369     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10370     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10371
10372     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10373     file_name[max_len - 1] = 0;
10374
10375     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10376     {
10377         return(TNG_FAILURE);
10378     }
10379     return(TNG_SUCCESS);
10380 }
10381
10382 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10383                                                           const char *file_name)
10384 {
10385     int len;
10386     char *temp;
10387
10388     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10389     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10390
10391     if(tng_data->output_file_path &&
10392        strcmp(tng_data->output_file_path, file_name) == 0)
10393     {
10394         return(TNG_SUCCESS);
10395     }
10396
10397     if(tng_data->output_file)
10398     {
10399         fclose(tng_data->output_file);
10400     }
10401
10402     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10403     temp = realloc(tng_data->output_file_path, len);
10404     if(!temp)
10405     {
10406         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10407                __FILE__, __LINE__);
10408         free(tng_data->output_file_path);
10409         tng_data->output_file_path = 0;
10410         return(TNG_CRITICAL);
10411     }
10412     tng_data->output_file_path = temp;
10413
10414     strncpy(tng_data->output_file_path, file_name, len);
10415
10416     return(tng_output_file_init(tng_data));
10417 }
10418
10419 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10420                 (tng_trajectory_t tng_data,
10421                  const char *file_name)
10422 {
10423     int len;
10424     char *temp;
10425
10426     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10427     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10428
10429     if(tng_data->output_file_path &&
10430        strcmp(tng_data->output_file_path, file_name) == 0)
10431     {
10432         return(TNG_SUCCESS);
10433     }
10434
10435     if(tng_data->output_file)
10436     {
10437         fclose(tng_data->output_file);
10438     }
10439
10440     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10441     temp = realloc(tng_data->output_file_path, len);
10442     if(!temp)
10443     {
10444         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10445                __FILE__, __LINE__);
10446         free(tng_data->output_file_path);
10447         tng_data->output_file_path = 0;
10448         return(TNG_CRITICAL);
10449     }
10450     tng_data->output_file_path = temp;
10451
10452     strncpy(tng_data->output_file_path, file_name, len);
10453
10454     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10455     if(!tng_data->output_file)
10456     {
10457         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10458                 tng_data->output_file_path, __FILE__, __LINE__);
10459         return(TNG_CRITICAL);
10460     }
10461     tng_data->input_file = tng_data->output_file;
10462
10463     return(TNG_SUCCESS);
10464 }
10465
10466 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10467                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10468 {
10469     tng_endianness_32 end_32;
10470     tng_endianness_64 end_64;
10471
10472     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10473     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10474
10475     if(tng_data->output_endianness_swap_func_32)
10476     {
10477         /* If other endianness variants are added they must be added here as well */
10478         if(tng_data->output_endianness_swap_func_32 ==
10479            &tng_swap_byte_order_big_endian_32)
10480         {
10481             end_32 = TNG_BIG_ENDIAN_32;
10482         }
10483         else if(tng_data->output_endianness_swap_func_32 ==
10484                 &tng_swap_byte_order_little_endian_32)
10485         {
10486             end_32 = TNG_LITTLE_ENDIAN_32;
10487         }
10488         else
10489         {
10490             return(TNG_FAILURE);
10491         }
10492     }
10493     else
10494     {
10495         end_32 = (tng_endianness_32)tng_data->endianness_32;
10496     }
10497
10498     if(tng_data->output_endianness_swap_func_64)
10499     {
10500         /* If other endianness variants are added they must be added here as well */
10501         if(tng_data->output_endianness_swap_func_64 ==
10502            &tng_swap_byte_order_big_endian_64)
10503         {
10504             end_64 = TNG_BIG_ENDIAN_64;
10505         }
10506         else if(tng_data->output_endianness_swap_func_64 ==
10507                 &tng_swap_byte_order_little_endian_64)
10508         {
10509             end_64 = TNG_LITTLE_ENDIAN_64;
10510         }
10511         else
10512         {
10513             return(TNG_FAILURE);
10514         }
10515     }
10516     else
10517     {
10518         end_64 = (tng_endianness_64)tng_data->endianness_64;
10519     }
10520
10521     if((int)end_32 != (int)end_64)
10522     {
10523         return(TNG_FAILURE);
10524     }
10525
10526     if(end_32 == TNG_LITTLE_ENDIAN_32)
10527     {
10528         *endianness = TNG_LITTLE_ENDIAN;
10529     }
10530
10531     else if(end_32 == TNG_BIG_ENDIAN_32)
10532     {
10533         *endianness = TNG_BIG_ENDIAN;
10534     }
10535     else
10536     {
10537         return(TNG_FAILURE);
10538     }
10539
10540     return(TNG_SUCCESS);
10541 }
10542
10543 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10544                 (tng_trajectory_t tng_data,
10545                  const tng_file_endianness endianness)
10546 {
10547     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10548
10549     /* Tne endianness cannot be changed if the data has already been written
10550      * to the output file. */
10551     if(ftell(tng_data->output_file) > 0)
10552     {
10553         return(TNG_FAILURE);
10554     }
10555
10556     if(endianness == TNG_BIG_ENDIAN)
10557     {
10558         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10559         {
10560             tng_data->output_endianness_swap_func_32 = 0;
10561         }
10562         else
10563         {
10564             tng_data->output_endianness_swap_func_32 =
10565             &tng_swap_byte_order_big_endian_32;
10566         }
10567         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10568         {
10569             tng_data->output_endianness_swap_func_64 = 0;
10570         }
10571         else
10572         {
10573             tng_data->output_endianness_swap_func_64 =
10574             &tng_swap_byte_order_big_endian_64;
10575         }
10576         return(TNG_SUCCESS);
10577     }
10578     else if(endianness == TNG_LITTLE_ENDIAN)
10579     {
10580         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10581         {
10582             tng_data->output_endianness_swap_func_32 = 0;
10583         }
10584         else
10585         {
10586             tng_data->output_endianness_swap_func_32 =
10587             &tng_swap_byte_order_little_endian_32;
10588         }
10589         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10590         {
10591             tng_data->output_endianness_swap_func_64 = 0;
10592         }
10593         else
10594         {
10595             tng_data->output_endianness_swap_func_64 =
10596             &tng_swap_byte_order_little_endian_64;
10597         }
10598         return(TNG_SUCCESS);
10599     }
10600
10601     /* If the specified endianness is neither big nor little endian return a
10602      * failure. */
10603     return(TNG_FAILURE);
10604 }
10605
10606 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10607                     (const tng_trajectory_t tng_data,
10608                      char *name, const int max_len)
10609 {
10610     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10611     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10612
10613     strncpy(name, tng_data->first_program_name, max_len - 1);
10614     name[max_len - 1] = 0;
10615
10616     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10617     {
10618         return(TNG_FAILURE);
10619     }
10620     return(TNG_SUCCESS);
10621 }
10622
10623 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10624                                                                  const char *new_name)
10625 {
10626     unsigned int len;
10627
10628     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10629     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10630
10631     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10632
10633     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10634     {
10635         free(tng_data->first_program_name);
10636         tng_data->first_program_name = 0;
10637     }
10638     if(!tng_data->first_program_name)
10639     {
10640         tng_data->first_program_name = malloc(len);
10641         if(!tng_data->first_program_name)
10642         {
10643             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10644                    __FILE__, __LINE__);
10645             return(TNG_CRITICAL);
10646         }
10647     }
10648
10649     strncpy(tng_data->first_program_name, new_name, len);
10650
10651     return(TNG_SUCCESS);
10652 }
10653
10654 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10655                     (const tng_trajectory_t tng_data,
10656                      char *name, const int max_len)
10657 {
10658     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10659     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10660
10661     strncpy(name, tng_data->last_program_name, max_len - 1);
10662     name[max_len - 1] = 0;
10663
10664     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10665     {
10666         return(TNG_FAILURE);
10667     }
10668     return(TNG_SUCCESS);
10669 }
10670
10671 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10672                     (tng_trajectory_t tng_data,
10673                      const char *new_name)
10674 {
10675     unsigned int len;
10676
10677     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10678     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10679
10680     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10681
10682     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10683     {
10684         free(tng_data->last_program_name);
10685         tng_data->last_program_name = 0;
10686     }
10687     if(!tng_data->last_program_name)
10688     {
10689         tng_data->last_program_name = malloc(len);
10690         if(!tng_data->last_program_name)
10691         {
10692             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10693                    __FILE__, __LINE__);
10694             return(TNG_CRITICAL);
10695         }
10696     }
10697
10698     strncpy(tng_data->last_program_name, new_name, len);
10699
10700     return(TNG_SUCCESS);
10701 }
10702
10703 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10704                     (const tng_trajectory_t tng_data,
10705                      char *name, const int max_len)
10706 {
10707     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10708     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10709
10710     strncpy(name, tng_data->first_user_name, max_len - 1);
10711     name[max_len - 1] = 0;
10712
10713     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10714     {
10715         return(TNG_FAILURE);
10716     }
10717     return(TNG_SUCCESS);
10718 }
10719
10720 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10721                     (tng_trajectory_t tng_data,
10722                      const char *new_name)
10723 {
10724     unsigned int len;
10725
10726     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10727     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10728
10729     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10730
10731     /* If the currently stored string length is not enough to store the new
10732      * string it is freed and reallocated. */
10733     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10734     {
10735         free(tng_data->first_user_name);
10736         tng_data->first_user_name = 0;
10737     }
10738     if(!tng_data->first_user_name)
10739     {
10740         tng_data->first_user_name = malloc(len);
10741         if(!tng_data->first_user_name)
10742         {
10743             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10744                    __FILE__, __LINE__);
10745             return(TNG_CRITICAL);
10746         }
10747     }
10748
10749     strncpy(tng_data->first_user_name, new_name, len);
10750
10751     return(TNG_SUCCESS);
10752 }
10753
10754 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10755                     (const tng_trajectory_t tng_data,
10756                      char *name, const int max_len)
10757 {
10758     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10759     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10760
10761     strncpy(name, tng_data->last_user_name, max_len - 1);
10762     name[max_len - 1] = 0;
10763
10764     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10765     {
10766         return(TNG_FAILURE);
10767     }
10768     return(TNG_SUCCESS);
10769 }
10770
10771 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10772                     (tng_trajectory_t tng_data,
10773                      const char *new_name)
10774 {
10775     unsigned int len;
10776
10777     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10778     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10779
10780     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10781
10782     /* If the currently stored string length is not enough to store the new
10783      * string it is freed and reallocated. */
10784     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10785     {
10786         free(tng_data->last_user_name);
10787         tng_data->last_user_name = 0;
10788     }
10789     if(!tng_data->last_user_name)
10790     {
10791         tng_data->last_user_name = malloc(len);
10792         if(!tng_data->last_user_name)
10793         {
10794             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10795                    __FILE__, __LINE__);
10796             return(TNG_CRITICAL);
10797         }
10798     }
10799
10800     strncpy(tng_data->last_user_name, new_name, len);
10801
10802     return(TNG_SUCCESS);
10803 }
10804
10805 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10806                     (const tng_trajectory_t tng_data,
10807                      char *name, const int max_len)
10808 {
10809     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10810     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10811
10812     strncpy(name, tng_data->first_computer_name, max_len - 1);
10813     name[max_len - 1] = 0;
10814
10815     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10816     {
10817         return(TNG_FAILURE);
10818     }
10819     return(TNG_SUCCESS);
10820 }
10821
10822 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10823                     (tng_trajectory_t tng_data,
10824                      const char *new_name)
10825 {
10826     unsigned int len;
10827
10828     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10829     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10830
10831     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10832
10833     /* If the currently stored string length is not enough to store the new
10834      * string it is freed and reallocated. */
10835     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10836     {
10837         free(tng_data->first_computer_name);
10838         tng_data->first_computer_name = 0;
10839     }
10840     if(!tng_data->first_computer_name)
10841     {
10842         tng_data->first_computer_name = malloc(len);
10843         if(!tng_data->first_computer_name)
10844         {
10845             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10846                    __FILE__, __LINE__);
10847             return(TNG_CRITICAL);
10848         }
10849     }
10850
10851     strncpy(tng_data->first_computer_name, new_name, len);
10852
10853     return(TNG_SUCCESS);
10854 }
10855
10856 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10857                     (const tng_trajectory_t tng_data,
10858                      char *name, const int max_len)
10859 {
10860     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10861     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10862
10863     strncpy(name, tng_data->last_computer_name, max_len - 1);
10864     name[max_len - 1] = 0;
10865
10866     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10867     {
10868         return(TNG_FAILURE);
10869     }
10870     return(TNG_SUCCESS);
10871 }
10872
10873 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10874                     (tng_trajectory_t tng_data,
10875                      const char *new_name)
10876 {
10877     unsigned int len;
10878
10879     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10880     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10881
10882     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10883
10884     /* If the currently stored string length is not enough to store the new
10885      * string it is freed and reallocated. */
10886     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10887         len)
10888     {
10889         free(tng_data->last_computer_name);
10890         tng_data->last_computer_name = 0;
10891     }
10892     if(!tng_data->last_computer_name)
10893     {
10894         tng_data->last_computer_name = malloc(len);
10895         if(!tng_data->last_computer_name)
10896         {
10897             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10898                    __FILE__, __LINE__);
10899             return(TNG_CRITICAL);
10900         }
10901     }
10902
10903     strncpy(tng_data->last_computer_name, new_name, len);
10904
10905     return(TNG_SUCCESS);
10906 }
10907
10908 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10909                     (const tng_trajectory_t tng_data,
10910                      char *signature, const int max_len)
10911 {
10912     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10913     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10914
10915     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10916     signature[max_len - 1] = 0;
10917
10918     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10919     {
10920         return(TNG_FAILURE);
10921     }
10922     return(TNG_SUCCESS);
10923 }
10924
10925 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10926                     (tng_trajectory_t tng_data,
10927                      const char *signature)
10928 {
10929     unsigned int len;
10930
10931     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10932     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10933
10934     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10935
10936     /* If the currently stored string length is not enough to store the new
10937      * string it is freed and reallocated. */
10938     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10939         len)
10940     {
10941         free(tng_data->first_pgp_signature);
10942         tng_data->first_pgp_signature = 0;
10943     }
10944     if(!tng_data->first_pgp_signature)
10945     {
10946         tng_data->first_pgp_signature = malloc(len);
10947         if(!tng_data->first_pgp_signature)
10948         {
10949             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10950                    __FILE__, __LINE__);
10951             return(TNG_CRITICAL);
10952         }
10953     }
10954
10955     strncpy(tng_data->first_pgp_signature, signature, len);
10956
10957     return(TNG_SUCCESS);
10958 }
10959
10960 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10961                     (const tng_trajectory_t tng_data,
10962                      char *signature, const int max_len)
10963 {
10964     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10965     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10966
10967     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10968     signature[max_len - 1] = 0;
10969
10970     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10971     {
10972         return(TNG_FAILURE);
10973     }
10974     return(TNG_SUCCESS);
10975 }
10976
10977 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10978                     (tng_trajectory_t tng_data,
10979                      const char *signature)
10980 {
10981     unsigned int len;
10982
10983     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10984     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10985
10986     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10987
10988     /* If the currently stored string length is not enough to store the new
10989      * string it is freed and reallocated. */
10990     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10991         len)
10992     {
10993         free(tng_data->last_pgp_signature);
10994         tng_data->last_pgp_signature = 0;
10995     }
10996     if(!tng_data->last_pgp_signature)
10997     {
10998         tng_data->last_pgp_signature = malloc(len);
10999         if(!tng_data->last_pgp_signature)
11000         {
11001             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11002                    __FILE__, __LINE__);
11003             return(TNG_CRITICAL);
11004         }
11005     }
11006
11007     strncpy(tng_data->last_pgp_signature, signature, len);
11008
11009     return(TNG_SUCCESS);
11010 }
11011
11012 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11013                     (const tng_trajectory_t tng_data,
11014                      char *name, const int max_len)
11015 {
11016     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11017     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11018
11019     strncpy(name, tng_data->forcefield_name, max_len - 1);
11020     name[max_len - 1] = 0;
11021
11022     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11023     {
11024         return(TNG_FAILURE);
11025     }
11026     return(TNG_SUCCESS);
11027 }
11028
11029 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11030                     (tng_trajectory_t tng_data,
11031                      const char *new_name)
11032 {
11033     unsigned int len;
11034
11035     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11036     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11037
11038     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11039
11040     /* If the currently stored string length is not enough to store the new
11041      * string it is freed and reallocated. */
11042     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11043     {
11044         free(tng_data->forcefield_name);
11045         tng_data->forcefield_name = 0;
11046     }
11047     if(!tng_data->forcefield_name)
11048     {
11049         tng_data->forcefield_name = malloc(len);
11050         if(!tng_data->forcefield_name)
11051         {
11052             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11053                    __FILE__, __LINE__);
11054             return(TNG_CRITICAL);
11055         }
11056     }
11057
11058     strncpy(tng_data->forcefield_name, new_name, len);
11059
11060     return(TNG_SUCCESS);
11061 }
11062
11063 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11064                     (const tng_trajectory_t tng_data,
11065                      int64_t *len)
11066 {
11067     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11068     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11069
11070     *len = tng_data->medium_stride_length;
11071
11072     return(TNG_SUCCESS);
11073 }
11074
11075 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11076                     (tng_trajectory_t tng_data,
11077                      const int64_t len)
11078 {
11079     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11080
11081     if(len >= tng_data->long_stride_length)
11082     {
11083         return(TNG_FAILURE);
11084     }
11085     tng_data->medium_stride_length = len;
11086
11087     return(TNG_SUCCESS);
11088 }
11089
11090 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11091                 (const tng_trajectory_t tng_data,
11092                  int64_t *len)
11093 {
11094     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11095     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11096
11097     *len = tng_data->long_stride_length;
11098
11099     return(TNG_SUCCESS);
11100 }
11101
11102 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11103                 (tng_trajectory_t tng_data,
11104                  const int64_t len)
11105 {
11106     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11107
11108     if(len <= tng_data->medium_stride_length)
11109     {
11110         return(TNG_FAILURE);
11111     }
11112     tng_data->long_stride_length = len;
11113
11114     return(TNG_SUCCESS);
11115 }
11116
11117 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11118                 (const tng_trajectory_t tng_data,
11119                  double *time)
11120 {
11121     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11122     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11123
11124     *time = tng_data->time_per_frame;
11125
11126     return(TNG_SUCCESS);
11127 }
11128
11129 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11130                 (tng_trajectory_t tng_data,
11131                  const double time)
11132 {
11133     tng_trajectory_frame_set_t frame_set;
11134
11135     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11136     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11137
11138     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11139     {
11140         return(TNG_SUCCESS);
11141     }
11142
11143     frame_set = &tng_data->current_trajectory_frame_set;
11144
11145     /* If the current frame set is not finished write it to disk before
11146        changing time per frame. */
11147     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11148     {
11149         frame_set->n_frames = frame_set->n_unwritten_frames;
11150         tng_frame_set_write(tng_data, TNG_USE_HASH);
11151     }
11152     tng_data->time_per_frame = time;
11153
11154     return(TNG_SUCCESS);
11155 }
11156
11157 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11158                     (const tng_trajectory_t tng_data,
11159                      int64_t *len)
11160 {
11161     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11162     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11163
11164     *len = tng_data->input_file_len;
11165
11166     return(TNG_SUCCESS);
11167 }
11168
11169 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11170                     (const tng_trajectory_t tng_data,
11171                      int64_t *n)
11172 {
11173     tng_gen_block_t block;
11174     tng_function_status stat;
11175     long file_pos;
11176     int64_t last_file_pos, first_frame, n_frames;
11177
11178     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11179     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11180     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11181
11182     file_pos = ftell(tng_data->input_file);
11183     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11184
11185     if(last_file_pos <= 0)
11186     {
11187         return(TNG_FAILURE);
11188     }
11189
11190     tng_block_init(&block);
11191     fseek(tng_data->input_file,
11192           (long)last_file_pos,
11193           SEEK_SET);
11194     /* Read block headers first to see that a frame set block is found. */
11195     stat = tng_block_header_read(tng_data, block);
11196     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11197     {
11198         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11199                 __FILE__, __LINE__);
11200         tng_block_destroy(&block);
11201         return(TNG_FAILURE);
11202     }
11203     tng_block_destroy(&block);
11204
11205     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11206     {
11207         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11208                __FILE__, __LINE__);
11209         return(TNG_CRITICAL);
11210     }
11211     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11212     {
11213         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11214                __FILE__, __LINE__);
11215         return(TNG_CRITICAL);
11216     }
11217     fseek(tng_data->input_file, file_pos, SEEK_SET);
11218
11219     *n = first_frame + n_frames;
11220
11221     return(TNG_SUCCESS);
11222 }
11223
11224 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11225                 (const tng_trajectory_t tng_data,
11226                  double *precision)
11227 {
11228     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11229
11230     *precision = tng_data->compression_precision;
11231
11232     return(TNG_SUCCESS);
11233 }
11234
11235 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11236                 (tng_trajectory_t tng_data,
11237                  const double precision)
11238 {
11239     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11240
11241     tng_data->compression_precision = precision;
11242
11243     return(TNG_SUCCESS);
11244 }
11245
11246 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11247                 (tng_trajectory_t tng_data,
11248                  const int64_t n)
11249 {
11250     tng_molecule_t mol;
11251     tng_chain_t chain;
11252     tng_residue_t res;
11253     tng_atom_t atom;
11254     tng_function_status stat;
11255     int64_t diff, n_mod, n_impl;
11256
11257     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11258
11259     diff = n - tng_data->n_particles;
11260
11261     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11262     if(stat == TNG_SUCCESS)
11263     {
11264         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11265         {
11266             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11267                     __FILE__, __LINE__);
11268             return(TNG_FAILURE);
11269         }
11270         diff -= n_impl * mol->n_atoms;
11271     }
11272
11273     if(diff == 0)
11274     {
11275         if(stat == TNG_SUCCESS)
11276         {
11277             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11278             return(stat);
11279         }
11280         return(TNG_SUCCESS);
11281     }
11282     else if(diff < 0)
11283     {
11284         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11285         fprintf(stderr, "particle count.\n");
11286         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11287                 __FILE__, __LINE__);
11288         /* FIXME: Should we set the count of all other molecules to 0 and add
11289          * implicit molecules? */
11290         return(TNG_FAILURE);
11291     }
11292     if(stat != TNG_SUCCESS)
11293     {
11294         stat = tng_molecule_add(tng_data,
11295                                 "TNG_IMPLICIT_MOL",
11296                                 &mol);
11297         if(stat != TNG_SUCCESS)
11298         {
11299             return(stat);
11300         }
11301         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11302         if(stat != TNG_SUCCESS)
11303         {
11304             return(stat);
11305         }
11306         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11307         if(stat != TNG_SUCCESS)
11308         {
11309             return(stat);
11310         }
11311         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11312         if(stat != TNG_SUCCESS)
11313         {
11314             return(stat);
11315         }
11316     }
11317     else
11318     {
11319         if(mol->n_atoms > 1)
11320         {
11321             n_mod = diff % mol->n_atoms;
11322             if(n_mod != 0)
11323             {
11324                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11325                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11326                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11327                         __FILE__, __LINE__);
11328                 return(TNG_FAILURE);
11329             }
11330             diff /= mol->n_atoms;
11331         }
11332     }
11333     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11334
11335     return(stat);
11336 }
11337
11338 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11339                 (const tng_trajectory_t tng_data,
11340                  int64_t *n)
11341 {
11342     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11343     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11344
11345     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11346     {
11347         *n = tng_data->n_particles;
11348     }
11349     else
11350     {
11351         *n = tng_data->current_trajectory_frame_set.n_particles;
11352     }
11353
11354     return(TNG_SUCCESS);
11355 }
11356
11357 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11358                 (const tng_trajectory_t tng_data,
11359                  char *variable)
11360 {
11361     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11362     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11363
11364     *variable = tng_data->var_num_atoms_flag;
11365
11366     return(TNG_SUCCESS);
11367 }
11368
11369 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11370                     (const tng_trajectory_t tng_data,
11371                      int64_t *n)
11372 {
11373     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11374     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11375
11376     *n = tng_data->n_molecules;
11377
11378     return(TNG_SUCCESS);
11379 }
11380
11381 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11382                     (const tng_trajectory_t tng_data,
11383                      int64_t *n)
11384 {
11385     int64_t *cnt_list = 0, cnt = 0, i;
11386
11387     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11388     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11389
11390     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11391
11392     if(!cnt_list)
11393     {
11394         return(TNG_FAILURE);
11395     }
11396
11397     for(i = 0; i < tng_data->n_molecules; i++)
11398     {
11399         cnt += cnt_list[i];
11400     }
11401
11402     *n = cnt;
11403
11404     return(TNG_SUCCESS);
11405 }
11406
11407 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11408                 (const tng_trajectory_t tng_data,
11409                  int64_t **mol_cnt_list)
11410 {
11411     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11412
11413     if(tng_data->var_num_atoms_flag)
11414     {
11415         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11416                        molecule_cnt_list;
11417     }
11418     else
11419     {
11420         *mol_cnt_list = tng_data->molecule_cnt_list;
11421     }
11422     if(*mol_cnt_list == 0)
11423     {
11424         return(TNG_FAILURE);
11425     }
11426     return(TNG_SUCCESS);
11427 }
11428
11429 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11430                 (const tng_trajectory_t tng_data,
11431                  int64_t *exp)
11432 {
11433     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11434     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11435
11436     *exp = tng_data->distance_unit_exponential;
11437
11438     return(TNG_SUCCESS);
11439 }
11440
11441 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11442                 (const tng_trajectory_t tng_data,
11443                  const int64_t exp)
11444 {
11445     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11446
11447     tng_data->distance_unit_exponential = exp;
11448
11449     return(TNG_SUCCESS);
11450 }
11451
11452 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11453                 (const tng_trajectory_t tng_data,
11454                  int64_t *n)
11455 {
11456     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11457     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11458
11459     *n = tng_data->frame_set_n_frames;
11460
11461     return(TNG_SUCCESS);
11462 }
11463
11464 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11465                 (const tng_trajectory_t tng_data,
11466                  const int64_t n)
11467 {
11468     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11469
11470     tng_data->frame_set_n_frames = n;
11471
11472     return(TNG_SUCCESS);
11473 }
11474
11475 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11476                 (const tng_trajectory_t tng_data,
11477                  int64_t *n)
11478 {
11479     int64_t long_stride_length, medium_stride_length;
11480     long file_pos, orig_frame_set_file_pos;
11481     tng_trajectory_frame_set_t frame_set;
11482     struct tng_trajectory_frame_set   orig_frame_set;
11483     tng_gen_block_t block;
11484     tng_function_status stat;
11485     int64_t cnt = 0;
11486
11487     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11488     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11489
11490     orig_frame_set = tng_data->current_trajectory_frame_set;
11491
11492     frame_set = &tng_data->current_trajectory_frame_set;
11493
11494     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11495     file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
11496
11497     tng_block_init(&block);
11498     fseek(tng_data->input_file,
11499           file_pos,
11500           SEEK_SET);
11501     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11502     /* Read block headers first to see what block is found. */
11503     stat = tng_block_header_read(tng_data, block);
11504     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11505     {
11506         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos,
11507                 __FILE__, __LINE__);
11508         tng_block_destroy(&block);
11509         return(TNG_CRITICAL);
11510     }
11511
11512     if(tng_block_read_next(tng_data, block,
11513                         TNG_SKIP_HASH) != TNG_SUCCESS)
11514     {
11515         tng_block_destroy(&block);
11516         return(TNG_CRITICAL);
11517     }
11518
11519     ++cnt;
11520
11521     long_stride_length = tng_data->long_stride_length;
11522     medium_stride_length = tng_data->medium_stride_length;
11523
11524     /* Take long steps forward until a long step forward would be too long or
11525      * the last frame set is found */
11526     file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11527     while(file_pos > 0)
11528     {
11529         if(file_pos > 0)
11530         {
11531             cnt += long_stride_length;
11532             fseek(tng_data->input_file, file_pos, SEEK_SET);
11533             /* Read block headers first to see what block is found. */
11534             stat = tng_block_header_read(tng_data, block);
11535             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11536             {
11537                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11538                        file_pos, __FILE__, __LINE__);
11539                 tng_block_destroy(&block);
11540                 return(TNG_CRITICAL);
11541             }
11542
11543             if(tng_block_read_next(tng_data, block,
11544                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11545             {
11546                 tng_block_destroy(&block);
11547                 return(TNG_CRITICAL);
11548             }
11549         }
11550         file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
11551     }
11552
11553     /* Take medium steps forward until a medium step forward would be too long
11554      * or the last frame set is found */
11555     file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11556     while(file_pos > 0)
11557     {
11558         if(file_pos > 0)
11559         {
11560             cnt += medium_stride_length;
11561             fseek(tng_data->input_file,
11562                   file_pos,
11563                   SEEK_SET);
11564             /* Read block headers first to see what block is found. */
11565             stat = tng_block_header_read(tng_data, block);
11566             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11567             {
11568                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11569                        file_pos, __FILE__, __LINE__);
11570                 tng_block_destroy(&block);
11571                 return(TNG_CRITICAL);
11572             }
11573
11574             if(tng_block_read_next(tng_data, block,
11575                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11576             {
11577                 tng_block_destroy(&block);
11578                 return(TNG_CRITICAL);
11579             }
11580         }
11581         file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11582     }
11583
11584     /* Take one step forward until the last frame set is found */
11585     file_pos = (long)frame_set->next_frame_set_file_pos;
11586     while(file_pos > 0)
11587     {
11588         if(file_pos > 0)
11589         {
11590             ++cnt;
11591             fseek(tng_data->input_file,
11592                   file_pos,
11593                   SEEK_SET);
11594             /* Read block headers first to see what block is found. */
11595             stat = tng_block_header_read(tng_data, block);
11596             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11597             {
11598                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11599                        file_pos, __FILE__, __LINE__);
11600                 tng_block_destroy(&block);
11601                 return(TNG_CRITICAL);
11602             }
11603
11604             if(tng_block_read_next(tng_data, block,
11605                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11606             {
11607                 tng_block_destroy(&block);
11608                 return(TNG_CRITICAL);
11609             }
11610         }
11611         file_pos = (long)frame_set->next_frame_set_file_pos;
11612     }
11613
11614     tng_block_destroy(&block);
11615
11616     *n = tng_data->n_trajectory_frame_sets = cnt;
11617
11618     *frame_set = orig_frame_set;
11619
11620     fseek(tng_data->input_file,
11621           (long)tng_data->first_trajectory_frame_set_input_file_pos,
11622           SEEK_SET);
11623
11624     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11625
11626     return(TNG_SUCCESS);
11627 }
11628
11629 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11630                 (const tng_trajectory_t tng_data,
11631                  tng_trajectory_frame_set_t *frame_set_p)
11632 {
11633     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11634
11635     *frame_set_p = &tng_data->current_trajectory_frame_set;
11636
11637     return(TNG_SUCCESS);
11638 }
11639
11640 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11641                 (tng_trajectory_t tng_data,
11642                  const int64_t nr)
11643 {
11644     int64_t long_stride_length, medium_stride_length;
11645     int64_t file_pos, curr_nr = 0, n_frame_sets;
11646     tng_trajectory_frame_set_t frame_set;
11647     tng_gen_block_t block;
11648     tng_function_status stat;
11649
11650     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11651     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11652
11653     frame_set = &tng_data->current_trajectory_frame_set;
11654
11655     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11656
11657     if(stat != TNG_SUCCESS)
11658     {
11659         return(stat);
11660     }
11661
11662     if(nr >= n_frame_sets)
11663     {
11664         return(TNG_FAILURE);
11665     }
11666
11667     long_stride_length = tng_data->long_stride_length;
11668     medium_stride_length = tng_data->medium_stride_length;
11669
11670     /* FIXME: The frame set number of the current frame set is not stored */
11671
11672     if(nr < n_frame_sets - 1 - nr)
11673     {
11674         /* Start from the beginning */
11675         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11676     }
11677     else
11678     {
11679         /* Start from the end */
11680         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11681         curr_nr = n_frame_sets - 1;
11682     }
11683     if(file_pos <= 0)
11684     {
11685         return(TNG_FAILURE);
11686     }
11687
11688     tng_block_init(&block);
11689     fseek(tng_data->input_file,
11690           (long)file_pos,
11691           SEEK_SET);
11692     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11693     /* Read block headers first to see what block is found. */
11694     stat = tng_block_header_read(tng_data, block);
11695     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11696     {
11697         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11698                 __FILE__, __LINE__);
11699         tng_block_destroy(&block);
11700         return(TNG_CRITICAL);
11701     }
11702
11703     if(tng_block_read_next(tng_data, block,
11704                         TNG_SKIP_HASH) != TNG_SUCCESS)
11705     {
11706         tng_block_destroy(&block);
11707         return(TNG_CRITICAL);
11708     }
11709
11710     if(curr_nr == nr)
11711     {
11712         tng_block_destroy(&block);
11713         return(TNG_SUCCESS);
11714     }
11715
11716     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11717
11718     /* Take long steps forward until a long step forward would be too long or
11719      * the right frame set is found */
11720     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11721     {
11722         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11723         if(file_pos > 0)
11724         {
11725             curr_nr += long_stride_length;
11726             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11727             /* Read block headers first to see what block is found. */
11728             stat = tng_block_header_read(tng_data, block);
11729             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11730             {
11731                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11732                        file_pos,  __FILE__, __LINE__);
11733                 tng_block_destroy(&block);
11734                 return(TNG_CRITICAL);
11735             }
11736
11737             if(tng_block_read_next(tng_data, block,
11738                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11739             {
11740                 tng_block_destroy(&block);
11741                 return(TNG_CRITICAL);
11742             }
11743             if(curr_nr == nr)
11744             {
11745                 tng_block_destroy(&block);
11746                 return(TNG_SUCCESS);
11747             }
11748         }
11749     }
11750
11751     /* Take medium steps forward until a medium step forward would be too long
11752      * or the right frame set is found */
11753     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11754     {
11755         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11756         if(file_pos > 0)
11757         {
11758             curr_nr += medium_stride_length;
11759             fseek(tng_data->input_file,
11760                   (long)file_pos,
11761                   SEEK_SET);
11762             /* Read block headers first to see what block is found. */
11763             stat = tng_block_header_read(tng_data, block);
11764             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11765             {
11766                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11767                        file_pos, __FILE__, __LINE__);
11768                 tng_block_destroy(&block);
11769                 return(TNG_CRITICAL);
11770             }
11771
11772             if(tng_block_read_next(tng_data, block,
11773                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11774             {
11775                 tng_block_destroy(&block);
11776                 return(TNG_CRITICAL);
11777             }
11778             if(curr_nr == nr)
11779             {
11780                 tng_block_destroy(&block);
11781                 return(TNG_SUCCESS);
11782             }
11783         }
11784     }
11785
11786     /* Take one step forward until the right frame set is found */
11787     while(file_pos > 0 && curr_nr < nr)
11788     {
11789         file_pos = frame_set->next_frame_set_file_pos;
11790
11791         if(file_pos > 0)
11792         {
11793             ++curr_nr;
11794             fseek(tng_data->input_file,
11795                   (long)file_pos,
11796                   SEEK_SET);
11797             /* Read block headers first to see what block is found. */
11798             stat = tng_block_header_read(tng_data, block);
11799             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11800             {
11801                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11802                        file_pos, __FILE__, __LINE__);
11803                 tng_block_destroy(&block);
11804                 return(TNG_CRITICAL);
11805             }
11806
11807             if(tng_block_read_next(tng_data, block,
11808                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11809             {
11810                 tng_block_destroy(&block);
11811                 return(TNG_CRITICAL);
11812             }
11813             if(curr_nr == nr)
11814             {
11815                 tng_block_destroy(&block);
11816                 return(TNG_SUCCESS);
11817             }
11818         }
11819     }
11820
11821     /* Take long steps backward until a long step backward would be too long
11822      * or the right frame set is found */
11823     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11824     {
11825         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11826         if(file_pos > 0)
11827         {
11828             curr_nr -= long_stride_length;
11829             fseek(tng_data->input_file,
11830                   (long)file_pos,
11831                   SEEK_SET);
11832             /* Read block headers first to see what block is found. */
11833             stat = tng_block_header_read(tng_data, block);
11834             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11835             {
11836                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11837                        file_pos, __FILE__, __LINE__);
11838                 tng_block_destroy(&block);
11839                 return(TNG_CRITICAL);
11840             }
11841
11842             if(tng_block_read_next(tng_data, block,
11843                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11844             {
11845                 tng_block_destroy(&block);
11846                 return(TNG_CRITICAL);
11847             }
11848             if(curr_nr == nr)
11849             {
11850                 tng_block_destroy(&block);
11851                 return(TNG_SUCCESS);
11852             }
11853         }
11854     }
11855
11856     /* Take medium steps backward until a medium step backward would be too long
11857      * or the right frame set is found */
11858     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11859     {
11860         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11861         if(file_pos > 0)
11862         {
11863             curr_nr -= medium_stride_length;
11864             fseek(tng_data->input_file,
11865                   (long)file_pos,
11866                   SEEK_SET);
11867             /* Read block headers first to see what block is found. */
11868             stat = tng_block_header_read(tng_data, block);
11869             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11870             {
11871                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11872                        file_pos, __FILE__, __LINE__);
11873                 tng_block_destroy(&block);
11874                 return(TNG_CRITICAL);
11875             }
11876
11877             if(tng_block_read_next(tng_data, block,
11878                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11879             {
11880                 tng_block_destroy(&block);
11881                 return(TNG_CRITICAL);
11882             }
11883             if(curr_nr == nr)
11884             {
11885                 tng_block_destroy(&block);
11886                 return(TNG_SUCCESS);
11887             }
11888         }
11889     }
11890
11891     /* Take one step backward until the right frame set is found */
11892     while(file_pos > 0 && curr_nr > nr)
11893     {
11894         file_pos = frame_set->prev_frame_set_file_pos;
11895         if(file_pos > 0)
11896         {
11897             --curr_nr;
11898             fseek(tng_data->input_file,
11899                   (long)file_pos,
11900                   SEEK_SET);
11901             /* Read block headers first to see what block is found. */
11902             stat = tng_block_header_read(tng_data, block);
11903             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11904             {
11905                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11906                        file_pos, __FILE__, __LINE__);
11907                 tng_block_destroy(&block);
11908                 return(TNG_CRITICAL);
11909             }
11910
11911             if(tng_block_read_next(tng_data, block,
11912                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11913             {
11914                 tng_block_destroy(&block);
11915                 return(TNG_CRITICAL);
11916             }
11917             if(curr_nr == nr)
11918             {
11919                 tng_block_destroy(&block);
11920                 return(TNG_SUCCESS);
11921             }
11922         }
11923     }
11924
11925     /* If for some reason the current frame set is not yet found,
11926      * take one step forward until the right frame set is found */
11927     while(file_pos > 0 && curr_nr < nr)
11928     {
11929         file_pos = frame_set->next_frame_set_file_pos;
11930         if(file_pos > 0)
11931         {
11932             ++curr_nr;
11933             fseek(tng_data->input_file,
11934                   (long)file_pos,
11935                   SEEK_SET);
11936             /* Read block headers first to see what block is found. */
11937             stat = tng_block_header_read(tng_data, block);
11938             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11939             {
11940                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11941                        file_pos, __FILE__, __LINE__);
11942                 tng_block_destroy(&block);
11943                 return(TNG_CRITICAL);
11944             }
11945
11946             if(tng_block_read_next(tng_data, block,
11947                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11948             {
11949                 tng_block_destroy(&block);
11950                 return(TNG_CRITICAL);
11951             }
11952             if(curr_nr == nr)
11953             {
11954                 tng_block_destroy(&block);
11955                 return(TNG_SUCCESS);
11956             }
11957         }
11958     }
11959
11960     tng_block_destroy(&block);
11961     return(TNG_FAILURE);
11962 }
11963
11964 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11965                 (tng_trajectory_t tng_data,
11966                  const int64_t frame)
11967 {
11968     int64_t first_frame, last_frame, n_frames_per_frame_set;
11969     int64_t long_stride_length, medium_stride_length;
11970     int64_t file_pos, temp_frame, n_frames;
11971     tng_trajectory_frame_set_t frame_set;
11972     tng_gen_block_t block;
11973     tng_function_status stat;
11974
11975     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11976     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11977
11978     frame_set = &tng_data->current_trajectory_frame_set;
11979
11980     tng_block_init(&block);
11981
11982     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11983     {
11984         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11985         fseek(tng_data->input_file,
11986                 (long)file_pos,
11987                 SEEK_SET);
11988         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11989         /* Read block headers first to see what block is found. */
11990         stat = tng_block_header_read(tng_data, block);
11991         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11992         {
11993             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11994                     file_pos, __FILE__, __LINE__);
11995             tng_block_destroy(&block);
11996             return(TNG_CRITICAL);
11997         }
11998
11999         if(tng_block_read_next(tng_data, block,
12000                             TNG_SKIP_HASH) != TNG_SUCCESS)
12001         {
12002             tng_block_destroy(&block);
12003             return(TNG_CRITICAL);
12004         }
12005     }
12006
12007     first_frame = tng_max_i64(frame_set->first_frame, 0);
12008     last_frame = first_frame + frame_set->n_frames - 1;
12009     /* Is this the right frame set? */
12010     if(first_frame <= frame && frame <= last_frame)
12011     {
12012         tng_block_destroy(&block);
12013         return(TNG_SUCCESS);
12014     }
12015
12016     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12017     long_stride_length = tng_data->long_stride_length;
12018     medium_stride_length = tng_data->medium_stride_length;
12019
12020     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12021        TNG_SUCCESS)
12022     {
12023         if(temp_frame - first_frame > n_frames_per_frame_set)
12024         {
12025             n_frames_per_frame_set = temp_frame - first_frame;
12026         }
12027     }
12028
12029     tng_num_frames_get(tng_data, &n_frames);
12030
12031     if(frame >= n_frames)
12032     {
12033         tng_block_destroy(&block);
12034         return(TNG_FAILURE);
12035     }
12036
12037     if(first_frame - frame >= frame ||
12038        frame - last_frame >
12039        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12040     {
12041         /* Start from the beginning */
12042         if(first_frame - frame >= frame)
12043         {
12044             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12045
12046             if(file_pos <= 0)
12047             {
12048                 tng_block_destroy(&block);
12049                 return(TNG_FAILURE);
12050             }
12051         }
12052         /* Start from the end */
12053         else if(frame - first_frame > (n_frames - 1) - frame)
12054         {
12055             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12056
12057             /* If the last frame set position is not set start from the current
12058              * frame set, since it will be closer than the first frame set. */
12059         }
12060         /* Start from current */
12061         else
12062         {
12063             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12064         }
12065
12066         if(file_pos > 0)
12067         {
12068             fseek(tng_data->input_file,
12069                   (long)file_pos,
12070                   SEEK_SET);
12071             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
12072             /* Read block headers first to see what block is found. */
12073             stat = tng_block_header_read(tng_data, block);
12074             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12075             {
12076                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12077                        file_pos, __FILE__, __LINE__);
12078                 tng_block_destroy(&block);
12079                 return(TNG_CRITICAL);
12080             }
12081
12082             if(tng_block_read_next(tng_data, block,
12083                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12084             {
12085                 tng_block_destroy(&block);
12086                 return(TNG_CRITICAL);
12087             }
12088         }
12089     }
12090
12091     first_frame = tng_max_i64(frame_set->first_frame, 0);
12092     last_frame = first_frame + frame_set->n_frames - 1;
12093
12094     if(frame >= first_frame && frame <= last_frame)
12095     {
12096         tng_block_destroy(&block);
12097         return(TNG_SUCCESS);
12098     }
12099
12100     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12101
12102     /* Take long steps forward until a long step forward would be too long or
12103      * the right frame set is found */
12104     while(file_pos > 0 && first_frame + long_stride_length *
12105           n_frames_per_frame_set <= frame)
12106     {
12107         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12108         if(file_pos > 0)
12109         {
12110             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
12111             /* Read block headers first to see what block is found. */
12112             stat = tng_block_header_read(tng_data, block);
12113             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12114             {
12115                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12116                        file_pos, __FILE__, __LINE__);
12117                 tng_block_destroy(&block);
12118                 return(TNG_CRITICAL);
12119             }
12120
12121             if(tng_block_read_next(tng_data, block,
12122                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12123             {
12124                 tng_block_destroy(&block);
12125                 return(TNG_CRITICAL);
12126             }
12127         }
12128         first_frame = tng_max_i64(frame_set->first_frame, 0);
12129         last_frame = first_frame + frame_set->n_frames - 1;
12130         if(frame >= first_frame && frame <= last_frame)
12131         {
12132             tng_block_destroy(&block);
12133             return(TNG_SUCCESS);
12134         }
12135     }
12136
12137     /* Take medium steps forward until a medium step forward would be too long
12138      * or the right frame set is found */
12139     while(file_pos > 0 && first_frame + medium_stride_length *
12140           n_frames_per_frame_set <= frame)
12141     {
12142         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12143         if(file_pos > 0)
12144         {
12145             fseek(tng_data->input_file,
12146                   (long)file_pos,
12147                   SEEK_SET);
12148             /* Read block headers first to see what block is found. */
12149             stat = tng_block_header_read(tng_data, block);
12150             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12151             {
12152                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12153                        file_pos, __FILE__, __LINE__);
12154                 tng_block_destroy(&block);
12155                 return(TNG_CRITICAL);
12156             }
12157
12158             if(tng_block_read_next(tng_data, block,
12159                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12160             {
12161                 tng_block_destroy(&block);
12162                 return(TNG_CRITICAL);
12163             }
12164         }
12165         first_frame = tng_max_i64(frame_set->first_frame, 0);
12166         last_frame = first_frame + frame_set->n_frames - 1;
12167         if(frame >= first_frame && frame <= last_frame)
12168         {
12169             tng_block_destroy(&block);
12170             return(TNG_SUCCESS);
12171         }
12172     }
12173
12174     /* Take one step forward until the right frame set is found */
12175     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12176     {
12177         file_pos = frame_set->next_frame_set_file_pos;
12178         if(file_pos > 0)
12179         {
12180             fseek(tng_data->input_file,
12181                   (long)file_pos,
12182                   SEEK_SET);
12183             /* Read block headers first to see what block is found. */
12184             stat = tng_block_header_read(tng_data, block);
12185             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12186             {
12187                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12188                        file_pos, __FILE__, __LINE__);
12189                 tng_block_destroy(&block);
12190                 return(TNG_CRITICAL);
12191             }
12192
12193             if(tng_block_read_next(tng_data, block,
12194                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12195             {
12196                 tng_block_destroy(&block);
12197                 return(TNG_CRITICAL);
12198             }
12199         }
12200         first_frame = tng_max_i64(frame_set->first_frame, 0);
12201         last_frame = first_frame + frame_set->n_frames - 1;
12202         if(frame >= first_frame && frame <= last_frame)
12203         {
12204             tng_block_destroy(&block);
12205             return(TNG_SUCCESS);
12206         }
12207     }
12208
12209     /* Take long steps backward until a long step backward would be too long
12210      * or the right frame set is found */
12211     while(file_pos > 0 && first_frame - long_stride_length *
12212           n_frames_per_frame_set >= frame)
12213     {
12214         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12215         if(file_pos > 0)
12216         {
12217             fseek(tng_data->input_file,
12218                   (long)file_pos,
12219                   SEEK_SET);
12220             /* Read block headers first to see what block is found. */
12221             stat = tng_block_header_read(tng_data, block);
12222             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12223             {
12224                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12225                        file_pos, __FILE__, __LINE__);
12226                 tng_block_destroy(&block);
12227                 return(TNG_CRITICAL);
12228             }
12229
12230             if(tng_block_read_next(tng_data, block,
12231                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12232             {
12233                 tng_block_destroy(&block);
12234                 return(TNG_CRITICAL);
12235             }
12236         }
12237         first_frame = tng_max_i64(frame_set->first_frame, 0);
12238         last_frame = first_frame + frame_set->n_frames - 1;
12239         if(frame >= first_frame && frame <= last_frame)
12240         {
12241             tng_block_destroy(&block);
12242             return(TNG_SUCCESS);
12243         }
12244     }
12245
12246     /* Take medium steps backward until a medium step backward would be too long
12247      * or the right frame set is found */
12248     while(file_pos > 0 && first_frame - medium_stride_length *
12249           n_frames_per_frame_set >= frame)
12250     {
12251         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12252         if(file_pos > 0)
12253         {
12254             fseek(tng_data->input_file,
12255                   (long)file_pos,
12256                   SEEK_SET);
12257             /* Read block headers first to see what block is found. */
12258             stat = tng_block_header_read(tng_data, block);
12259             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12260             {
12261                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12262                        file_pos, __FILE__, __LINE__);
12263                 tng_block_destroy(&block);
12264                 return(TNG_CRITICAL);
12265             }
12266
12267             if(tng_block_read_next(tng_data, block,
12268                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12269             {
12270                 tng_block_destroy(&block);
12271                 return(TNG_CRITICAL);
12272             }
12273         }
12274         first_frame = tng_max_i64(frame_set->first_frame, 0);
12275         last_frame = first_frame + frame_set->n_frames - 1;
12276         if(frame >= first_frame && frame <= last_frame)
12277         {
12278             tng_block_destroy(&block);
12279             return(TNG_SUCCESS);
12280         }
12281     }
12282
12283     /* Take one step backward until the right frame set is found */
12284     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12285     {
12286         file_pos = frame_set->prev_frame_set_file_pos;
12287         if(file_pos > 0)
12288         {
12289             fseek(tng_data->input_file,
12290                   (long)file_pos,
12291                   SEEK_SET);
12292             /* Read block headers first to see what block is found. */
12293             stat = tng_block_header_read(tng_data, block);
12294             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12295             {
12296                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12297                        file_pos, __FILE__, __LINE__);
12298                 tng_block_destroy(&block);
12299                 return(TNG_CRITICAL);
12300             }
12301
12302             if(tng_block_read_next(tng_data, block,
12303                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12304             {
12305                 tng_block_destroy(&block);
12306                 return(TNG_CRITICAL);
12307             }
12308         }
12309         first_frame = tng_max_i64(frame_set->first_frame, 0);
12310         last_frame = first_frame + frame_set->n_frames - 1;
12311         if(frame >= first_frame && frame <= last_frame)
12312         {
12313             tng_block_destroy(&block);
12314             return(TNG_SUCCESS);
12315         }
12316     }
12317
12318     /* If for some reason the current frame set is not yet found,
12319      * take one step forward until the right frame set is found */
12320     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12321     {
12322         file_pos = frame_set->next_frame_set_file_pos;
12323         if(file_pos > 0)
12324         {
12325             fseek(tng_data->input_file,
12326                   (long)file_pos,
12327                   SEEK_SET);
12328             /* Read block headers first to see what block is found. */
12329             stat = tng_block_header_read(tng_data, block);
12330             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12331             {
12332                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12333                        file_pos, __FILE__, __LINE__);
12334                 tng_block_destroy(&block);
12335                 return(TNG_CRITICAL);
12336             }
12337
12338             if(tng_block_read_next(tng_data, block,
12339                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12340             {
12341                 tng_block_destroy(&block);
12342                 return(TNG_CRITICAL);
12343             }
12344         }
12345         first_frame = tng_max_i64(frame_set->first_frame, 0);
12346         last_frame = first_frame + frame_set->n_frames - 1;
12347         if(frame >= first_frame && frame <= last_frame)
12348         {
12349             tng_block_destroy(&block);
12350             return(TNG_SUCCESS);
12351         }
12352     }
12353
12354     tng_block_destroy(&block);
12355     return(TNG_FAILURE);
12356 }
12357
12358 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12359                 (const tng_trajectory_t tng_data,
12360                  const tng_trajectory_frame_set_t frame_set,
12361                  int64_t *pos)
12362 {
12363     (void)tng_data;
12364
12365     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12366     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12367
12368     *pos = frame_set->next_frame_set_file_pos;
12369
12370     return(TNG_SUCCESS);
12371 }
12372
12373 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12374                 (const tng_trajectory_t tng_data,
12375                  const tng_trajectory_frame_set_t frame_set,
12376                  int64_t *pos)
12377 {
12378     (void)tng_data;
12379
12380     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12381     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12382
12383     *pos = frame_set->prev_frame_set_file_pos;
12384
12385     return(TNG_SUCCESS);
12386 }
12387
12388 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12389                 (const tng_trajectory_t tng_data,
12390                  const tng_trajectory_frame_set_t frame_set,
12391                  int64_t *first_frame,
12392                  int64_t *last_frame)
12393 {
12394     (void)tng_data;
12395
12396     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12397     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12398     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12399
12400     *first_frame = frame_set->first_frame;
12401     *last_frame = *first_frame + frame_set->n_frames - 1;
12402
12403     return(TNG_SUCCESS);
12404 }
12405
12406 /** Translate from the particle numbering used in a frame set to the real
12407  *  particle numbering - used in the molecule description.
12408  * @param frame_set is the frame_set containing the mappings to use.
12409  * @param local is the index number of the atom in this frame set
12410  * @param real is set to the index of the atom in the molecular system.
12411  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12412  * cannot be found.
12413  */
12414 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12415                 (const tng_trajectory_frame_set_t frame_set,
12416                  const int64_t local,
12417                  int64_t *real)
12418 {
12419     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12420     tng_particle_mapping_t mapping;
12421     if(n_blocks <= 0)
12422     {
12423         *real = local;
12424         return(TNG_SUCCESS);
12425     }
12426     for(i = 0; i < n_blocks; i++)
12427     {
12428         mapping = &frame_set->mappings[i];
12429         first = mapping->num_first_particle;
12430         if(local < first ||
12431            local >= first + mapping->n_particles)
12432         {
12433             continue;
12434         }
12435         *real = mapping->real_particle_numbers[local-first];
12436         return(TNG_SUCCESS);
12437     }
12438     *real = local;
12439     return(TNG_FAILURE);
12440 }
12441
12442 /** Translate from the real particle numbering to the particle numbering
12443  *  used in a frame set.
12444  * @param frame_set is the frame_set containing the mappings to use.
12445  * @param real is the index number of the atom in the molecular system.
12446  * @param local is set to the index of the atom in this frame set.
12447  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12448  * cannot be found.
12449  */
12450 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12451                 (const tng_trajectory_frame_set_t frame_set,
12452                  const int64_t real,
12453                  int64_t *local)
12454 {
12455     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12456     tng_particle_mapping_t mapping;
12457     if(n_blocks <= 0)
12458     {
12459         *local = real;
12460         return(TNG_SUCCESS);
12461     }
12462     for(i = 0; i < n_blocks; i++)
12463     {
12464         mapping = &frame_set->mappings[i];
12465         for(j = mapping->n_particles; j--;)
12466         {
12467             if(mapping->real_particle_numbers[j] == real)
12468             {
12469                 *local = j;
12470                 return(TNG_SUCCESS);
12471             }
12472         }
12473     }
12474     return(TNG_FAILURE);
12475 }
12476 */
12477
12478 static tng_function_status tng_file_headers_len_get
12479                 (tng_trajectory_t tng_data,
12480                  int64_t *len)
12481 {
12482     int64_t orig_pos;
12483     tng_gen_block_t block;
12484
12485     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12486
12487     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12488     {
12489         return(TNG_CRITICAL);
12490     }
12491
12492     *len = 0;
12493
12494     orig_pos = ftell(tng_data->input_file);
12495
12496     if(!tng_data->input_file_len)
12497     {
12498         fseek(tng_data->input_file, 0, SEEK_END);
12499         tng_data->input_file_len = ftell(tng_data->input_file);
12500     }
12501     fseek(tng_data->input_file, 0, SEEK_SET);
12502
12503     tng_block_init(&block);
12504     /* Read through the headers of non-trajectory blocks (they come before the
12505      * trajectory blocks in the file) */
12506     while (*len < tng_data->input_file_len &&
12507            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12508            block->id != -1 &&
12509            block->id != TNG_TRAJECTORY_FRAME_SET)
12510     {
12511         *len += block->header_contents_size + block->block_contents_size;
12512         fseek(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12513     }
12514
12515     fseek(tng_data->input_file, orig_pos, SEEK_SET);
12516
12517     tng_block_destroy(&block);
12518
12519     return(TNG_SUCCESS);
12520 }
12521
12522 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12523                 (tng_trajectory_t tng_data,
12524                  const char hash_mode)
12525 {
12526     int64_t prev_pos = 0;
12527     tng_gen_block_t block;
12528
12529     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12530
12531     tng_data->n_trajectory_frame_sets = 0;
12532
12533     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12534     {
12535         return(TNG_CRITICAL);
12536     }
12537
12538     if(!tng_data->input_file_len)
12539     {
12540         fseek(tng_data->input_file, 0, SEEK_END);
12541         tng_data->input_file_len = ftell(tng_data->input_file);
12542     }
12543     fseek(tng_data->input_file, 0, SEEK_SET);
12544
12545     tng_block_init(&block);
12546     /* Non trajectory blocks (they come before the trajectory
12547      * blocks in the file) */
12548     while (prev_pos < tng_data->input_file_len &&
12549            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12550            block->id != -1 &&
12551            block->id != TNG_TRAJECTORY_FRAME_SET)
12552     {
12553         tng_block_read_next(tng_data, block, hash_mode);
12554         prev_pos = ftell(tng_data->input_file);
12555     }
12556
12557     /* Go back if a trajectory block was encountered */
12558     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12559     {
12560         fseek(tng_data->input_file, prev_pos, SEEK_SET);
12561     }
12562
12563     tng_block_destroy(&block);
12564
12565     return(TNG_SUCCESS);
12566 }
12567
12568 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12569                 (tng_trajectory_t tng_data,
12570                  const char hash_mode)
12571 {
12572     int i;
12573     int64_t len, orig_len, tot_len = 0, data_start_pos;
12574     tng_function_status stat;
12575     tng_gen_block_t block;
12576
12577     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12578
12579     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12580     {
12581         return(TNG_CRITICAL);
12582     }
12583
12584     if(tng_data->n_trajectory_frame_sets > 0)
12585     {
12586         stat = tng_file_headers_len_get(tng_data, &orig_len);
12587         if(stat != TNG_SUCCESS)
12588         {
12589             return(stat);
12590         }
12591
12592         tng_block_init(&block);
12593         block->name = malloc(TNG_MAX_STR_LEN);
12594         if(!block->name)
12595         {
12596             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12597                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12598             tng_block_destroy(&block);
12599             return(TNG_CRITICAL);
12600         }
12601         strcpy(block->name, "GENERAL INFO");
12602         tng_block_header_len_calculate(tng_data, block, &len);
12603         tot_len += len;
12604         tng_general_info_block_len_calculate(tng_data, &len);
12605         tot_len += len;
12606         strcpy(block->name, "MOLECULES");
12607         tng_block_header_len_calculate(tng_data, block, &len);
12608         tot_len += len;
12609         tng_molecules_block_len_calculate(tng_data, &len);
12610         tot_len += len;
12611
12612         for(i = 0; i < tng_data->n_data_blocks; i++)
12613         {
12614             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12615             tng_block_header_len_calculate(tng_data, block, &len);
12616             tot_len += len;
12617             tng_data_block_len_calculate(tng_data,
12618                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12619                                         TNG_FALSE, 1, 1, 1, 0,
12620                                         1, 0, &data_start_pos,
12621                                         &len);
12622             tot_len += len;
12623         }
12624         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12625         {
12626             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12627             tng_block_header_len_calculate(tng_data, block, &len);
12628             tot_len += len;
12629             tng_data_block_len_calculate(tng_data,
12630                                         &tng_data->non_tr_particle_data[i],
12631                                         TNG_TRUE, 1, 1, 1, 0,
12632                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12633                                         &data_start_pos,
12634                                         &len);
12635             tot_len += len;
12636         }
12637         tng_block_destroy(&block);
12638
12639         if(tot_len > orig_len)
12640         {
12641             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12642         }
12643
12644         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12645     }
12646
12647     /* TODO: If there is already frame set data written to this file (e.g. when
12648      * appending to an already existing file we might need to move frame sets to
12649      * the end of the file. */
12650
12651     if(tng_general_info_block_write(tng_data, hash_mode)
12652        != TNG_SUCCESS)
12653     {
12654         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12655                 tng_data->input_file_path, __FILE__, __LINE__);
12656         return(TNG_CRITICAL);
12657     }
12658
12659     if(tng_molecules_block_write(tng_data, hash_mode)
12660         != TNG_SUCCESS)
12661     {
12662         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12663                 tng_data->input_file_path, __FILE__, __LINE__);
12664         return(TNG_CRITICAL);
12665     }
12666
12667     /* FIXME: Currently writing non-trajectory data blocks here.
12668      * Should perhaps be moved. */
12669     tng_block_init(&block);
12670     for(i = 0; i < tng_data->n_data_blocks; i++)
12671     {
12672         block->id = tng_data->non_tr_data[i].block_id;
12673         tng_data_block_write(tng_data, block,
12674                              i, hash_mode);
12675     }
12676
12677     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12678     {
12679         block->id = tng_data->non_tr_particle_data[i].block_id;
12680         tng_particle_data_block_write(tng_data, block,
12681                                       i, 0, hash_mode);
12682     }
12683
12684     tng_block_destroy(&block);
12685
12686     return(TNG_SUCCESS);
12687 }
12688
12689 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12690                                         tng_gen_block_t block,
12691                                         const char hash_mode)
12692 {
12693     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12694     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12695
12696     switch(block->id)
12697     {
12698     case TNG_TRAJECTORY_FRAME_SET:
12699         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12700     case TNG_PARTICLE_MAPPING:
12701         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12702     case TNG_GENERAL_INFO:
12703         return(tng_general_info_block_read(tng_data, block, hash_mode));
12704     case TNG_MOLECULES:
12705         return(tng_molecules_block_read(tng_data, block, hash_mode));
12706     default:
12707         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12708         {
12709             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12710         }
12711         else
12712         {
12713             /* Skip to the next block */
12714             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12715             return(TNG_FAILURE);
12716         }
12717     }
12718 }
12719
12720 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12721                 (tng_trajectory_t tng_data,
12722                  const char hash_mode)
12723 {
12724     long file_pos;
12725     tng_gen_block_t block;
12726     tng_function_status stat;
12727
12728     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12729
12730     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12731     {
12732         return(TNG_CRITICAL);
12733     }
12734
12735     file_pos = ftell(tng_data->input_file);
12736
12737     tng_block_init(&block);
12738
12739     if(!tng_data->input_file_len)
12740     {
12741         fseek(tng_data->input_file, 0, SEEK_END);
12742         tng_data->input_file_len = ftell(tng_data->input_file);
12743         fseek(tng_data->input_file, file_pos, SEEK_SET);
12744     }
12745
12746     /* Read block headers first to see what block is found. */
12747     stat = tng_block_header_read(tng_data, block);
12748     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12749        block->id == -1)
12750     {
12751         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12752                file_pos, __FILE__, __LINE__);
12753         tng_block_destroy(&block);
12754         return(TNG_CRITICAL);
12755     }
12756
12757     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12758
12759     if(tng_block_read_next(tng_data, block,
12760                            hash_mode) == TNG_SUCCESS)
12761     {
12762         tng_data->n_trajectory_frame_sets++;
12763         file_pos = ftell(tng_data->input_file);
12764         /* Read all blocks until next frame set block */
12765         stat = tng_block_header_read(tng_data, block);
12766         while(file_pos < tng_data->input_file_len &&
12767               stat != TNG_CRITICAL &&
12768               block->id != TNG_TRAJECTORY_FRAME_SET &&
12769               block->id != -1)
12770         {
12771             stat = tng_block_read_next(tng_data, block,
12772                                        hash_mode);
12773             if(stat != TNG_CRITICAL)
12774             {
12775                 file_pos = ftell(tng_data->input_file);
12776                 if(file_pos < tng_data->input_file_len)
12777                 {
12778                     stat = tng_block_header_read(tng_data, block);
12779                 }
12780             }
12781         }
12782         if(stat == TNG_CRITICAL)
12783         {
12784             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12785                    file_pos, __FILE__, __LINE__);
12786             tng_block_destroy(&block);
12787             return(stat);
12788         }
12789
12790         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12791         {
12792             fseek(tng_data->input_file, file_pos, SEEK_SET);
12793         }
12794     }
12795
12796     tng_block_destroy(&block);
12797
12798     return(TNG_SUCCESS);
12799 }
12800
12801
12802 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12803                 (tng_trajectory_t tng_data,
12804                  const char hash_mode,
12805                  const int64_t block_id)
12806 {
12807     long file_pos;
12808     tng_gen_block_t block;
12809     tng_function_status stat;
12810     int found_flag = 1;
12811
12812     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12813
12814     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12815     {
12816         return(TNG_CRITICAL);
12817     }
12818
12819     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12820
12821     if(file_pos < 0)
12822     {
12823         /* No current frame set. This means that the first frame set must be
12824          * read */
12825         found_flag = 0;
12826         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12827     }
12828
12829     if(file_pos > 0)
12830     {
12831         fseek(tng_data->input_file,
12832               file_pos,
12833               SEEK_SET);
12834     }
12835     else
12836     {
12837         return(TNG_FAILURE);
12838     }
12839
12840     tng_block_init(&block);
12841
12842     if(!tng_data->input_file_len)
12843     {
12844         fseek(tng_data->input_file, 0, SEEK_END);
12845         tng_data->input_file_len = ftell(tng_data->input_file);
12846         fseek(tng_data->input_file, file_pos, SEEK_SET);
12847     }
12848
12849     /* Read block headers first to see what block is found. */
12850     stat = tng_block_header_read(tng_data, block);
12851     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12852     {
12853         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12854                file_pos, __FILE__, __LINE__);
12855         tng_block_destroy(&block);
12856         return(TNG_CRITICAL);
12857     }
12858     /* If the current frame set had already been read skip its block contents */
12859     if(found_flag)
12860     {
12861         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12862     }
12863     /* Otherwiese read the frame set block */
12864     else
12865     {
12866         stat = tng_block_read_next(tng_data, block,
12867                                    hash_mode);
12868         if(stat != TNG_SUCCESS)
12869         {
12870             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12871             tng_block_destroy(&block);
12872             return(stat);
12873         }
12874     }
12875     file_pos = ftell(tng_data->input_file);
12876
12877     found_flag = 0;
12878
12879     /* Read only blocks of the requested ID
12880         * until next frame set block */
12881     stat = tng_block_header_read(tng_data, block);
12882     while(file_pos < tng_data->input_file_len &&
12883             stat != TNG_CRITICAL &&
12884             block->id != TNG_TRAJECTORY_FRAME_SET &&
12885             block->id != -1)
12886     {
12887         if(block->id == block_id)
12888         {
12889             stat = tng_block_read_next(tng_data, block,
12890                                        hash_mode);
12891             if(stat != TNG_CRITICAL)
12892             {
12893                 file_pos = ftell(tng_data->input_file);
12894                 found_flag = 1;
12895                 if(file_pos < tng_data->input_file_len)
12896                 {
12897                     stat = tng_block_header_read(tng_data, block);
12898                 }
12899             }
12900         }
12901         else
12902         {
12903             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12904             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12905             if(file_pos < tng_data->input_file_len)
12906             {
12907                 stat = tng_block_header_read(tng_data, block);
12908             }
12909         }
12910     }
12911     if(stat == TNG_CRITICAL)
12912     {
12913         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12914                 file_pos, __FILE__, __LINE__);
12915         tng_block_destroy(&block);
12916         return(stat);
12917     }
12918
12919     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12920     {
12921         fseek(tng_data->input_file, file_pos, SEEK_SET);
12922     }
12923
12924     tng_block_destroy(&block);
12925
12926     if(found_flag)
12927     {
12928         return(TNG_SUCCESS);
12929     }
12930     else
12931     {
12932         return(TNG_FAILURE);
12933     }
12934 }
12935
12936 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12937                 (tng_trajectory_t tng_data,
12938                  const char hash_mode)
12939 {
12940     long file_pos;
12941
12942     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12943
12944     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12945     {
12946         return(TNG_CRITICAL);
12947     }
12948
12949     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12950
12951     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12952     {
12953         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12954     }
12955
12956     if(file_pos > 0)
12957     {
12958         fseek(tng_data->input_file,
12959               file_pos,
12960               SEEK_SET);
12961     }
12962     else
12963     {
12964         return(TNG_FAILURE);
12965     }
12966
12967     return(tng_frame_set_read(tng_data, hash_mode));
12968 }
12969
12970 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12971                 (tng_trajectory_t tng_data,
12972                  const char hash_mode,
12973                  const int64_t block_id)
12974 {
12975     long file_pos;
12976     tng_gen_block_t block;
12977     tng_function_status stat;
12978
12979     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12980
12981     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12982     {
12983         return(TNG_CRITICAL);
12984     }
12985
12986     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12987
12988     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12989     {
12990         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12991     }
12992
12993     if(file_pos > 0)
12994     {
12995         fseek(tng_data->input_file,
12996               file_pos,
12997               SEEK_SET);
12998     }
12999     else
13000     {
13001         return(TNG_FAILURE);
13002     }
13003
13004     tng_block_init(&block);
13005
13006     if(!tng_data->input_file_len)
13007     {
13008         fseek(tng_data->input_file, 0, SEEK_END);
13009         tng_data->input_file_len = ftell(tng_data->input_file);
13010         fseek(tng_data->input_file, file_pos, SEEK_SET);
13011     }
13012
13013     /* Read block headers first to see what block is found. */
13014     stat = tng_block_header_read(tng_data, block);
13015     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13016     {
13017         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13018                file_pos, __FILE__, __LINE__);
13019         tng_block_destroy(&block);
13020         return(TNG_CRITICAL);
13021     }
13022
13023     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13024
13025     if(tng_block_read_next(tng_data, block,
13026                            hash_mode) == TNG_SUCCESS)
13027     {
13028         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13029     }
13030
13031     tng_block_destroy(&block);
13032
13033     return(stat);
13034 }
13035
13036 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13037                                         const char hash_mode)
13038 {
13039     int i, j;
13040     tng_gen_block_t block;
13041     tng_trajectory_frame_set_t frame_set;
13042     tng_function_status stat;
13043
13044     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13045
13046     frame_set = &tng_data->current_trajectory_frame_set;
13047
13048     if(frame_set->n_written_frames == frame_set->n_frames)
13049     {
13050         return(TNG_SUCCESS);
13051     }
13052
13053     tng_data->current_trajectory_frame_set_output_file_pos =
13054     ftell(tng_data->output_file);
13055     tng_data->last_trajectory_frame_set_output_file_pos =
13056     tng_data->current_trajectory_frame_set_output_file_pos;
13057
13058     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13059     {
13060         return(TNG_FAILURE);
13061     }
13062
13063     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13064     {
13065         tng_data->first_trajectory_frame_set_output_file_pos =
13066         tng_data->current_trajectory_frame_set_output_file_pos;
13067     }
13068
13069     tng_block_init(&block);
13070
13071     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13072     {
13073         tng_block_destroy(&block);
13074         return(TNG_FAILURE);
13075     }
13076
13077     /* Write non-particle data blocks */
13078     for(i = 0; i<frame_set->n_data_blocks; i++)
13079     {
13080         block->id = frame_set->tr_data[i].block_id;
13081         tng_data_block_write(tng_data, block, i, hash_mode);
13082     }
13083     /* Write the mapping blocks and particle data blocks*/
13084     if(frame_set->n_mapping_blocks)
13085     {
13086         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13087         {
13088             block->id = TNG_PARTICLE_MAPPING;
13089             if(frame_set->mappings[i].n_particles > 0)
13090             {
13091                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13092                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13093                 {
13094                     block->id = frame_set->tr_particle_data[j].block_id;
13095                     tng_particle_data_block_write(tng_data, block,
13096                                                   j, &frame_set->mappings[i],
13097                                                   hash_mode);
13098                 }
13099             }
13100         }
13101     }
13102     else
13103     {
13104         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13105         {
13106             block->id = frame_set->tr_particle_data[i].block_id;
13107             tng_particle_data_block_write(tng_data, block,
13108                                           i, 0, hash_mode);
13109         }
13110     }
13111
13112
13113     /* Update pointers in the general info block */
13114     stat = tng_header_pointers_update(tng_data, hash_mode);
13115
13116     if(stat == TNG_SUCCESS)
13117     {
13118         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13119     }
13120
13121     tng_block_destroy(&block);
13122
13123     frame_set->n_unwritten_frames = 0;
13124
13125     fflush(tng_data->output_file);
13126
13127     return(stat);
13128 }
13129
13130 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13131                 (tng_trajectory_t tng_data,
13132                  const char hash_mode)
13133 {
13134     tng_trajectory_frame_set_t frame_set;
13135
13136     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13137
13138     frame_set = &tng_data->current_trajectory_frame_set;
13139
13140     if(frame_set->n_unwritten_frames == 0)
13141     {
13142         return(TNG_SUCCESS);
13143     }
13144     frame_set->n_frames = frame_set->n_unwritten_frames;
13145
13146     return(tng_frame_set_write(tng_data, hash_mode));
13147 }
13148
13149 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13150                 (tng_trajectory_t tng_data,
13151                  const int64_t first_frame,
13152                  const int64_t n_frames)
13153 {
13154     tng_gen_block_t block;
13155     tng_trajectory_frame_set_t frame_set;
13156     FILE *temp = tng_data->input_file;
13157     int64_t curr_pos;
13158
13159     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13160     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13161     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13162
13163     frame_set = &tng_data->current_trajectory_frame_set;
13164
13165     curr_pos = ftell(tng_data->output_file);
13166
13167     if(curr_pos <= 10)
13168     {
13169         tng_file_headers_write(tng_data, TNG_USE_HASH);
13170     }
13171
13172     /* Set pointer to previous frame set to the one that was loaded
13173      * before.
13174      * FIXME: This is a bit risky. If they are not added in order
13175      * it will be wrong. */
13176     if(tng_data->n_trajectory_frame_sets)
13177     {
13178         frame_set->prev_frame_set_file_pos =
13179         tng_data->current_trajectory_frame_set_output_file_pos;
13180     }
13181
13182     tng_data->current_trajectory_frame_set_output_file_pos =
13183     ftell(tng_data->output_file);
13184
13185     tng_data->n_trajectory_frame_sets++;
13186
13187     /* Set the medium range pointers */
13188     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13189     {
13190         frame_set->medium_stride_prev_frame_set_file_pos =
13191         tng_data->first_trajectory_frame_set_output_file_pos;
13192     }
13193     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13194     {
13195         /* FIXME: Currently only working if the previous frame set has its
13196          * medium stride pointer already set. This might need some fixing. */
13197         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13198            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13199         {
13200             tng_block_init(&block);
13201             tng_data->input_file = tng_data->output_file;
13202
13203             curr_pos = ftell(tng_data->output_file);
13204             fseek(tng_data->output_file,
13205                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
13206                   SEEK_SET);
13207
13208             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13209             {
13210                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13211                     __FILE__, __LINE__);
13212                 tng_data->input_file = temp;
13213                 tng_block_destroy(&block);
13214                 return(TNG_CRITICAL);
13215             }
13216
13217             /* Read the next frame set from the previous frame set and one
13218              * medium stride step back */
13219             fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13220             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13221             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13222                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13223                1, tng_data->output_file) == 0)
13224             {
13225                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13226                 tng_data->input_file = temp;
13227                 tng_block_destroy(&block);
13228                 return(TNG_CRITICAL);
13229             }
13230
13231             if(tng_data->input_endianness_swap_func_64)
13232             {
13233                 if(tng_data->input_endianness_swap_func_64(tng_data,
13234                    &frame_set->medium_stride_prev_frame_set_file_pos)
13235                     != TNG_SUCCESS)
13236                 {
13237                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13238                             __FILE__, __LINE__);
13239                 }
13240             }
13241
13242             tng_block_destroy(&block);
13243
13244             /* Set the long range pointers */
13245             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13246             {
13247                 frame_set->long_stride_prev_frame_set_file_pos =
13248                 tng_data->first_trajectory_frame_set_output_file_pos;
13249             }
13250             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13251             {
13252                 /* FIXME: Currently only working if the previous frame set has its
13253                 * long stride pointer already set. This might need some fixing. */
13254                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13255                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13256                 {
13257                     tng_block_init(&block);
13258                     tng_data->input_file = tng_data->output_file;
13259
13260                     fseek(tng_data->output_file,
13261                           (long)frame_set->long_stride_prev_frame_set_file_pos,
13262                           SEEK_SET);
13263
13264                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13265                     {
13266                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13267                             __FILE__, __LINE__);
13268                         tng_data->input_file = temp;
13269                         tng_block_destroy(&block);
13270                         return(TNG_CRITICAL);
13271                     }
13272
13273                     /* Read the next frame set from the previous frame set and one
13274                     * long stride step back */
13275                     fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
13276                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13277
13278                     tng_block_destroy(&block);
13279
13280                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13281                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13282                     1, tng_data->output_file) == 0)
13283                     {
13284                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13285                         tng_data->input_file = temp;
13286                         return(TNG_CRITICAL);
13287                     }
13288
13289                     if(tng_data->input_endianness_swap_func_64)
13290                     {
13291                         if(tng_data->input_endianness_swap_func_64(tng_data,
13292                            &frame_set->long_stride_prev_frame_set_file_pos)
13293                             != TNG_SUCCESS)
13294                         {
13295                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13296                                     __FILE__, __LINE__);
13297                         }
13298                     }
13299
13300                 }
13301             }
13302
13303             tng_data->input_file = temp;
13304             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
13305         }
13306     }
13307
13308     frame_set->first_frame = first_frame;
13309     frame_set->n_frames = n_frames;
13310     frame_set->n_written_frames = 0;
13311     frame_set->n_unwritten_frames = 0;
13312     frame_set->first_frame_time = -1;
13313
13314     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13315        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13316     {
13317         tng_data->first_trajectory_frame_set_output_file_pos =
13318         tng_data->current_trajectory_frame_set_output_file_pos;
13319     }
13320     /* FIXME: Should check the frame number instead of the file_pos,
13321      * in case frame sets are not in order */
13322     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13323        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13324        tng_data->last_trajectory_frame_set_output_file_pos <
13325        tng_data->current_trajectory_frame_set_output_file_pos)
13326     {
13327         tng_data->last_trajectory_frame_set_output_file_pos =
13328         tng_data->current_trajectory_frame_set_output_file_pos;
13329     }
13330
13331     return(TNG_SUCCESS);
13332 }
13333
13334 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13335                 (tng_trajectory_t tng_data,
13336                  const int64_t first_frame,
13337                  const int64_t n_frames,
13338                  const double first_frame_time)
13339 {
13340     tng_function_status stat;
13341
13342     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13343     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13344     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13345     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13346
13347
13348     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13349     if(stat != TNG_SUCCESS)
13350     {
13351         return(stat);
13352     }
13353     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13354
13355     return(stat);
13356 }
13357
13358 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13359                 (tng_trajectory_t tng_data,
13360                  const double first_frame_time)
13361 {
13362     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13363     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13364
13365     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13366
13367     return(TNG_SUCCESS);
13368 }
13369
13370 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13371                 (const tng_trajectory_t tng_data,
13372                  int64_t *frame)
13373 {
13374     long file_pos, next_frame_set_file_pos;
13375     tng_gen_block_t block;
13376     tng_function_status stat;
13377
13378     tng_trajectory_frame_set_t frame_set;
13379
13380     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13381     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13382     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13383
13384     file_pos = ftell(tng_data->input_file);
13385
13386     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13387     {
13388         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
13389     }
13390     else
13391     {
13392         frame_set = &tng_data->current_trajectory_frame_set;
13393         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
13394     }
13395
13396     if(next_frame_set_file_pos <= 0)
13397     {
13398         return(TNG_FAILURE);
13399     }
13400
13401     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
13402     /* Read block headers first to see that a frame set block is found. */
13403     tng_block_init(&block);
13404     stat = tng_block_header_read(tng_data, block);
13405     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13406     {
13407         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
13408                file_pos, __FILE__, __LINE__);
13409         return(TNG_CRITICAL);
13410     }
13411 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13412     {
13413         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13414     }*/
13415     tng_block_destroy(&block);
13416
13417     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13418     {
13419         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13420                __FILE__, __LINE__);
13421         return(TNG_CRITICAL);
13422     }
13423     fseek(tng_data->input_file, file_pos, SEEK_SET);
13424
13425     return(TNG_SUCCESS);
13426 }
13427
13428 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13429                 (tng_trajectory_t tng_data,
13430                  const int64_t id,
13431                  const char *block_name,
13432                  const char datatype,
13433                  const char block_type_flag,
13434                  int64_t n_frames,
13435                  const int64_t n_values_per_frame,
13436                  int64_t stride_length,
13437                  const int64_t codec_id,
13438                  void *new_data)
13439 {
13440     int i, j, size, len;
13441     tng_trajectory_frame_set_t frame_set;
13442     tng_non_particle_data_t data;
13443     char **first_dim_values;
13444     char *new_data_c=new_data;
13445     int64_t n_frames_div;
13446
13447     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13448     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13449     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13450
13451     frame_set = &tng_data->current_trajectory_frame_set;
13452
13453     if(stride_length <= 0)
13454     {
13455         stride_length = 1;
13456     }
13457
13458     /* If the block does not exist, create it */
13459     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13460     {
13461         if(tng_data_block_create(tng_data, block_type_flag) !=
13462             TNG_SUCCESS)
13463         {
13464             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13465                    __FILE__, __LINE__);
13466             return(TNG_CRITICAL);
13467         }
13468         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13469         {
13470             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13471         }
13472         else
13473         {
13474             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13475         }
13476         data->block_id = id;
13477
13478         data->block_name = malloc(strlen(block_name) + 1);
13479         if(!data->block_name)
13480         {
13481             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13482                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13483             return(TNG_CRITICAL);
13484         }
13485         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13486
13487         data->values = 0;
13488         /* FIXME: Memory leak from strings. */
13489         data->strings = 0;
13490         data->last_retrieved_frame = -1;
13491     }
13492
13493     data->datatype = datatype;
13494     data->stride_length = tng_max_i64(stride_length, 1);
13495     data->n_values_per_frame = n_values_per_frame;
13496     data->n_frames = n_frames;
13497     data->codec_id = codec_id;
13498     data->compression_multiplier = 1.0;
13499     /* FIXME: This can cause problems. */
13500     data->first_frame_with_data = frame_set->first_frame;
13501
13502     switch(datatype)
13503     {
13504     case TNG_FLOAT_DATA:
13505         size = sizeof(float);
13506         break;
13507     case TNG_INT_DATA:
13508         size = sizeof(int64_t);
13509         break;
13510     case TNG_DOUBLE_DATA:
13511     default:
13512         size = sizeof(double);
13513         break;
13514     }
13515
13516     if(new_data_c)
13517     {
13518         /* Allocate memory */
13519         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13520                                  n_values_per_frame) !=
13521         TNG_SUCCESS)
13522         {
13523             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13524                 __FILE__, __LINE__);
13525             return(TNG_CRITICAL);
13526         }
13527
13528         if(n_frames > frame_set->n_unwritten_frames)
13529         {
13530             frame_set->n_unwritten_frames = n_frames;
13531         }
13532
13533         n_frames_div = (n_frames % stride_length) ?
13534                      n_frames / stride_length + 1:
13535                      n_frames / stride_length;
13536
13537         if(datatype == TNG_CHAR_DATA)
13538         {
13539             for(i = 0; i < n_frames_div; i++)
13540             {
13541                 first_dim_values = data->strings[i];
13542                 for(j = 0; j < n_values_per_frame; j++)
13543                 {
13544                     len = tng_min_i((int)strlen(new_data_c) + 1,
13545                                 TNG_MAX_STR_LEN);
13546                     if(first_dim_values[j])
13547                     {
13548                         free(first_dim_values[j]);
13549                     }
13550                     first_dim_values[j] = malloc(len);
13551                     if(!first_dim_values[j])
13552                     {
13553                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13554                             len, __FILE__, __LINE__);
13555                         return(TNG_CRITICAL);
13556                     }
13557                     strncpy(first_dim_values[j],
13558                             new_data_c, len);
13559                     new_data_c += len;
13560                 }
13561             }
13562         }
13563         else
13564         {
13565             memcpy(data->values, new_data, size * n_frames_div *
13566                    n_values_per_frame);
13567         }
13568     }
13569
13570     return(TNG_SUCCESS);
13571 }
13572
13573 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13574                 (tng_trajectory_t tng_data,
13575                  const int64_t id,
13576                  const char *block_name,
13577                  const char datatype,
13578                  const char block_type_flag,
13579                  int64_t n_frames,
13580                  const int64_t n_values_per_frame,
13581                  int64_t stride_length,
13582                  const int64_t num_first_particle,
13583                  const int64_t n_particles,
13584                  const int64_t codec_id,
13585                  void *new_data)
13586 {
13587     int i, size, len;
13588     int64_t j, k;
13589     int64_t tot_n_particles, n_frames_div;
13590     char ***first_dim_values, **second_dim_values;
13591     tng_trajectory_frame_set_t frame_set;
13592     tng_particle_data_t data;
13593     char *new_data_c=new_data;
13594
13595     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13596     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13597     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13598     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13599     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13600
13601
13602     frame_set = &tng_data->current_trajectory_frame_set;
13603
13604     if(stride_length <= 0)
13605     {
13606         stride_length = 1;
13607     }
13608
13609     /* If the block does not exist, create it */
13610     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13611     {
13612         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13613             TNG_SUCCESS)
13614         {
13615             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13616                    __FILE__, __LINE__);
13617             return(TNG_CRITICAL);
13618         }
13619         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13620         {
13621             data = &frame_set->tr_particle_data[frame_set->
13622                                                 n_particle_data_blocks - 1];
13623         }
13624         else
13625         {
13626             data = &tng_data->non_tr_particle_data[tng_data->
13627                                                    n_particle_data_blocks - 1];
13628         }
13629         data->block_id = id;
13630
13631         data->block_name = malloc(strlen(block_name) + 1);
13632         if(!data->block_name)
13633         {
13634             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13635                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13636             return(TNG_CRITICAL);
13637         }
13638         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13639
13640         data->datatype = datatype;
13641
13642         data->values = 0;
13643         /* FIXME: Memory leak from strings. */
13644         data->strings = 0;
13645         data->last_retrieved_frame = -1;
13646     }
13647
13648     data->stride_length = tng_max_i64(stride_length, 1);
13649     data->n_values_per_frame = n_values_per_frame;
13650     data->n_frames = n_frames;
13651     data->codec_id = codec_id;
13652     data->compression_multiplier = 1.0;
13653     /* FIXME: This can cause problems. */
13654     data->first_frame_with_data = frame_set->first_frame;
13655
13656     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13657     {
13658         tot_n_particles = frame_set->n_particles;
13659     }
13660     else
13661     {
13662         tot_n_particles = tng_data->n_particles;
13663     }
13664
13665     /* If data values are supplied add that data to the data block. */
13666     if(new_data_c)
13667     {
13668         /* Allocate memory */
13669         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13670                                           stride_length, tot_n_particles,
13671                                           n_values_per_frame) !=
13672         TNG_SUCCESS)
13673         {
13674             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13675                 __FILE__, __LINE__);
13676             return(TNG_CRITICAL);
13677         }
13678
13679         if(n_frames > frame_set->n_unwritten_frames)
13680         {
13681             frame_set->n_unwritten_frames = n_frames;
13682         }
13683
13684         n_frames_div = (n_frames % stride_length) ?
13685                      n_frames / stride_length + 1:
13686                      n_frames / stride_length;
13687
13688         if(datatype == TNG_CHAR_DATA)
13689         {
13690             for(i = 0; i < n_frames_div; i++)
13691             {
13692                 first_dim_values = data->strings[i];
13693                 for(j = num_first_particle; j < num_first_particle + n_particles;
13694                     j++)
13695                 {
13696                     second_dim_values = first_dim_values[j];
13697                     for(k = 0; k < n_values_per_frame; k++)
13698                     {
13699                         len = tng_min_i((int)strlen(new_data_c) + 1,
13700                                 TNG_MAX_STR_LEN);
13701                         if(second_dim_values[k])
13702                         {
13703                             free(second_dim_values[k]);
13704                         }
13705                         second_dim_values[k] = malloc(len);
13706                         if(!second_dim_values[k])
13707                         {
13708                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13709                                 len, __FILE__, __LINE__);
13710                             return(TNG_CRITICAL);
13711                         }
13712                         strncpy(second_dim_values[k],
13713                                 new_data_c, len);
13714                         new_data_c += len;
13715                     }
13716                 }
13717             }
13718         }
13719         else
13720         {
13721             switch(datatype)
13722             {
13723             case TNG_INT_DATA:
13724                 size = sizeof(int64_t);
13725                 break;
13726             case TNG_FLOAT_DATA:
13727                 size = sizeof(float);
13728                 break;
13729             case TNG_DOUBLE_DATA:
13730             default:
13731                 size = sizeof(double);
13732             }
13733
13734             memcpy(data->values, new_data, size * n_frames_div *
13735                    n_particles * n_values_per_frame);
13736         }
13737     }
13738
13739     return(TNG_SUCCESS);
13740 }
13741
13742 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13743                 (tng_trajectory_t tng_data,
13744                  int64_t block_id,
13745                  char *name,
13746                  int max_len)
13747 {
13748     int64_t i;
13749     tng_trajectory_frame_set_t frame_set;
13750     tng_function_status stat;
13751     tng_particle_data_t p_data;
13752     tng_non_particle_data_t np_data;
13753     int block_type = -1;
13754
13755     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13756     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13757
13758     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13759     {
13760         p_data = &tng_data->non_tr_particle_data[i];
13761         if(p_data->block_id == block_id)
13762         {
13763             strncpy(name, p_data->block_name, max_len);
13764             name[max_len - 1] = '\0';
13765             return(TNG_SUCCESS);
13766         }
13767     }
13768     for(i = 0; i < tng_data->n_data_blocks; i++)
13769     {
13770         np_data = &tng_data->non_tr_data[i];
13771         if(np_data->block_id == block_id)
13772         {
13773             strncpy(name, np_data->block_name, max_len);
13774             name[max_len - 1] = '\0';
13775             return(TNG_SUCCESS);
13776         }
13777     }
13778
13779     frame_set = &tng_data->current_trajectory_frame_set;
13780
13781     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13782     if(stat == TNG_SUCCESS)
13783     {
13784         block_type = TNG_PARTICLE_BLOCK_DATA;
13785     }
13786     else
13787     {
13788         stat = tng_data_find(tng_data, block_id, &np_data);
13789         if(stat == TNG_SUCCESS)
13790         {
13791             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13792         }
13793         else
13794         {
13795             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13796             if(stat != TNG_SUCCESS)
13797             {
13798                 return(stat);
13799             }
13800             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13801             if(stat == TNG_SUCCESS)
13802             {
13803                 block_type = TNG_PARTICLE_BLOCK_DATA;
13804             }
13805             else
13806             {
13807                 stat = tng_data_find(tng_data, block_id, &np_data);
13808                 if(stat == TNG_SUCCESS)
13809                 {
13810                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13811                 }
13812             }
13813         }
13814     }
13815     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13816     {
13817         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13818         {
13819             p_data = &frame_set->tr_particle_data[i];
13820             if(p_data->block_id == block_id)
13821             {
13822                 strncpy(name, p_data->block_name, max_len);
13823                 name[max_len - 1] = '\0';
13824                 return(TNG_SUCCESS);
13825             }
13826         }
13827     }
13828     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13829     {
13830         for(i = 0; i < frame_set->n_data_blocks; i++)
13831         {
13832             np_data = &frame_set->tr_data[i];
13833             if(np_data->block_id == block_id)
13834             {
13835                 strncpy(name, np_data->block_name, max_len);
13836                 name[max_len - 1] = '\0';
13837                 return(TNG_SUCCESS);
13838             }
13839         }
13840     }
13841
13842     return(TNG_FAILURE);
13843 }
13844
13845 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13846                 (const tng_trajectory_t tng_data,
13847                  int64_t block_id,
13848                  int *block_dependency)
13849 {
13850     int64_t i;
13851     tng_function_status stat;
13852     tng_particle_data_t p_data;
13853     tng_non_particle_data_t np_data;
13854
13855     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13856     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13857
13858     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13859     {
13860         p_data = &tng_data->non_tr_particle_data[i];
13861         if(p_data->block_id == block_id)
13862         {
13863             *block_dependency = TNG_PARTICLE_DEPENDENT;
13864             return(TNG_SUCCESS);
13865         }
13866     }
13867     for(i = 0; i < tng_data->n_data_blocks; i++)
13868     {
13869         np_data = &tng_data->non_tr_data[i];
13870         if(np_data->block_id == block_id)
13871         {
13872             *block_dependency = 0;
13873             return(TNG_SUCCESS);
13874         }
13875     }
13876
13877     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13878     if(stat == TNG_SUCCESS)
13879     {
13880         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13881         return(TNG_SUCCESS);
13882     }
13883     else
13884     {
13885         stat = tng_data_find(tng_data, block_id, &np_data);
13886         if(stat == TNG_SUCCESS)
13887         {
13888             *block_dependency = TNG_FRAME_DEPENDENT;
13889             return(TNG_SUCCESS);
13890         }
13891         else
13892         {
13893             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13894             if(stat != TNG_SUCCESS)
13895             {
13896                 return(stat);
13897             }
13898             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13899             if(stat == TNG_SUCCESS)
13900             {
13901                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13902                 return(TNG_SUCCESS);
13903             }
13904             else
13905             {
13906                 stat = tng_data_find(tng_data, block_id, &np_data);
13907                 if(stat == TNG_SUCCESS)
13908                 {
13909                     *block_dependency = TNG_FRAME_DEPENDENT;
13910                     return(TNG_SUCCESS);
13911                 }
13912             }
13913         }
13914     }
13915
13916     return(TNG_FAILURE);
13917 }
13918
13919 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13920                 (const tng_trajectory_t tng_data,
13921                  int64_t block_id,
13922                  int64_t *n_values_per_frame)
13923 {
13924     int64_t i;
13925     tng_function_status stat;
13926     tng_particle_data_t p_data;
13927     tng_non_particle_data_t np_data;
13928
13929     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13930     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13931
13932     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13933     {
13934         p_data = &tng_data->non_tr_particle_data[i];
13935         if(p_data->block_id == block_id)
13936         {
13937             *n_values_per_frame = p_data->n_values_per_frame;
13938             return(TNG_SUCCESS);
13939         }
13940     }
13941     for(i = 0; i < tng_data->n_data_blocks; i++)
13942     {
13943         np_data = &tng_data->non_tr_data[i];
13944         if(np_data->block_id == block_id)
13945         {
13946             *n_values_per_frame = np_data->n_values_per_frame;
13947             return(TNG_SUCCESS);
13948         }
13949     }
13950
13951     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13952     if(stat == TNG_SUCCESS)
13953     {
13954         *n_values_per_frame = p_data->n_values_per_frame;
13955         return(TNG_SUCCESS);
13956     }
13957     else
13958     {
13959         stat = tng_data_find(tng_data, block_id, &np_data);
13960         if(stat == TNG_SUCCESS)
13961         {
13962             *n_values_per_frame = np_data->n_values_per_frame;
13963             return(TNG_SUCCESS);
13964         }
13965         else
13966         {
13967             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13968             if(stat != TNG_SUCCESS)
13969             {
13970                 return(stat);
13971             }
13972             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13973             if(stat == TNG_SUCCESS)
13974             {
13975                 *n_values_per_frame = p_data->n_values_per_frame;
13976                 return(TNG_SUCCESS);
13977             }
13978             else
13979             {
13980                 stat = tng_data_find(tng_data, block_id, &np_data);
13981                 if(stat == TNG_SUCCESS)
13982                 {
13983                     *n_values_per_frame = np_data->n_values_per_frame;
13984                     return(TNG_SUCCESS);
13985                 }
13986             }
13987         }
13988     }
13989
13990     return(TNG_FAILURE);
13991 }
13992
13993 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13994                 (tng_trajectory_t tng_data,
13995                  const int64_t frame_nr,
13996                  const int64_t block_id,
13997                  const void *values,
13998                  const char hash_mode)
13999 {
14000     int64_t header_pos, file_pos;
14001     int64_t output_file_len, n_values_per_frame, size, contents_size;
14002     int64_t header_size, temp_first, temp_last;
14003     int64_t i, last_frame;
14004     long temp_current;
14005     tng_gen_block_t block;
14006     tng_trajectory_frame_set_t frame_set;
14007     FILE *temp = tng_data->input_file;
14008     struct tng_non_particle_data data;
14009     tng_function_status stat;
14010     char dependency, sparse_data, datatype;
14011     void *copy;
14012
14013     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14014     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14015     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14016
14017     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14018     {
14019         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14020                __FILE__, __LINE__);
14021         return(TNG_CRITICAL);
14022     }
14023
14024     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14025     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14026     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14027     tng_data->first_trajectory_frame_set_input_file_pos =
14028     tng_data->first_trajectory_frame_set_output_file_pos;
14029     tng_data->last_trajectory_frame_set_input_file_pos =
14030     tng_data->last_trajectory_frame_set_output_file_pos;
14031     tng_data->current_trajectory_frame_set_input_file_pos =
14032     tng_data->current_trajectory_frame_set_output_file_pos;
14033
14034     tng_data->input_file = tng_data->output_file;
14035
14036     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14037
14038     frame_set = &tng_data->current_trajectory_frame_set;
14039
14040     if(stat != TNG_SUCCESS)
14041     {
14042         last_frame = frame_set->first_frame +
14043                      frame_set->n_frames - 1;
14044         /* If the wanted frame would be in the frame set after the last
14045             * frame set create a new frame set. */
14046         if(stat == TNG_FAILURE &&
14047             last_frame < frame_nr)
14048 /*           (last_frame < frame_nr &&
14049             tng_data->current_trajectory_frame_set.first_frame +
14050             tng_data->frame_set_n_frames >= frame_nr))*/
14051         {
14052             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14053             {
14054                 last_frame = frame_nr - 1;
14055             }
14056             tng_frame_set_new(tng_data,
14057                               last_frame+1,
14058                               tng_data->frame_set_n_frames);
14059             file_pos = ftell(tng_data->output_file);
14060             fseek(tng_data->output_file, 0, SEEK_END);
14061             output_file_len = ftell(tng_data->output_file);
14062             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14063
14064             /* Read mapping blocks from the last frame set */
14065             tng_block_init(&block);
14066
14067             stat = tng_block_header_read(tng_data, block);
14068             while(file_pos < output_file_len &&
14069                   stat != TNG_CRITICAL &&
14070                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14071                   block->id != -1)
14072             {
14073                 if(block->id == TNG_PARTICLE_MAPPING)
14074                 {
14075                     tng_trajectory_mapping_block_read(tng_data, block,
14076                                                       hash_mode);
14077                 }
14078                 else
14079                 {
14080                     fseek(tng_data->output_file, (long)block->block_contents_size,
14081                         SEEK_CUR);
14082                 }
14083                 file_pos = ftell(tng_data->output_file);
14084                 if(file_pos < output_file_len)
14085                 {
14086                     stat = tng_block_header_read(tng_data, block);
14087                 }
14088             }
14089
14090             tng_block_destroy(&block);
14091             /* Write the frame set to disk */
14092             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14093             {
14094                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14095                 return(TNG_CRITICAL);
14096             }
14097         }
14098         else
14099         {
14100             tng_data->input_file = temp;
14101             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14102             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14103             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14104             return(stat);
14105         }
14106     }
14107
14108     tng_block_init(&block);
14109
14110     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14111
14112     fseek(tng_data->output_file, 0, SEEK_END);
14113     output_file_len = ftell(tng_data->output_file);
14114     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14115
14116     /* Read past the frame set block first */
14117     stat = tng_block_header_read(tng_data, block);
14118     if(stat == TNG_CRITICAL)
14119     {
14120         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14121                file_pos, __FILE__, __LINE__);
14122         tng_block_destroy(&block);
14123         tng_data->input_file = temp;
14124
14125         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14126         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14127         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14128         return(stat);
14129     }
14130     fseek(tng_data->output_file, (long)block->block_contents_size,
14131             SEEK_CUR);
14132
14133     /* Read all block headers until next frame set block or
14134      * until the wanted block id is found */
14135     stat = tng_block_header_read(tng_data, block);
14136     while(file_pos < output_file_len &&
14137             stat != TNG_CRITICAL &&
14138             block->id != block_id &&
14139             block->id != TNG_TRAJECTORY_FRAME_SET &&
14140             block->id != -1)
14141     {
14142         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14143         file_pos = ftell(tng_data->output_file);
14144         if(file_pos < output_file_len)
14145         {
14146             stat = tng_block_header_read(tng_data, block);
14147         }
14148     }
14149     if(stat == TNG_CRITICAL)
14150     {
14151         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14152                file_pos, __FILE__, __LINE__);
14153         tng_block_destroy(&block);
14154         tng_data->input_file = temp;
14155         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14156         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14157         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14158         return(stat);
14159     }
14160
14161     contents_size = block->block_contents_size;
14162     header_size = block->header_contents_size;
14163
14164     header_pos = ftell(tng_data->output_file) - header_size;
14165     frame_set = &tng_data->current_trajectory_frame_set;
14166
14167     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14168     {
14169         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14170         tng_block_destroy(&block);
14171         return(TNG_CRITICAL);
14172     }
14173     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14174     {
14175         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14176         tng_block_destroy(&block);
14177         return(TNG_CRITICAL);
14178     }
14179     data.datatype = datatype;
14180
14181     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14182        (dependency & TNG_PARTICLE_DEPENDENT))
14183     {
14184         tng_block_destroy(&block);
14185         tng_data->input_file = temp;
14186
14187         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14188         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14189         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14190         return(TNG_FAILURE);
14191     }
14192
14193     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14194     {
14195         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14196         tng_block_destroy(&block);
14197         return(TNG_CRITICAL);
14198     }
14199
14200     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14201              tng_data->input_file) == 0)
14202     {
14203         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14204         tng_block_destroy(&block);
14205         return(TNG_CRITICAL);
14206     }
14207     if(tng_data->output_endianness_swap_func_64)
14208     {
14209         if(tng_data->output_endianness_swap_func_64(tng_data,
14210             &data.n_values_per_frame)
14211             != TNG_SUCCESS)
14212         {
14213             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14214                     __FILE__, __LINE__);
14215         }
14216     }
14217
14218     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14219              tng_data->input_file) == 0)
14220     {
14221         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14222         tng_block_destroy(&block);
14223         return(TNG_CRITICAL);
14224     }
14225     if(tng_data->output_endianness_swap_func_64)
14226     {
14227         if(tng_data->output_endianness_swap_func_64(tng_data,
14228             &data.codec_id)
14229             != TNG_SUCCESS)
14230         {
14231             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14232                     __FILE__, __LINE__);
14233         }
14234     }
14235
14236     if(data.codec_id != TNG_UNCOMPRESSED)
14237     {
14238         if(fread(&data.compression_multiplier,
14239                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14240             == 0)
14241         {
14242             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14243             tng_block_destroy(&block);
14244             return(TNG_CRITICAL);
14245         }
14246         if(tng_data->output_endianness_swap_func_64)
14247         {
14248             if(tng_data->output_endianness_swap_func_64(tng_data,
14249                 (int64_t *)&data.compression_multiplier)
14250                 != TNG_SUCCESS)
14251             {
14252                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14253                         __FILE__, __LINE__);
14254             }
14255         }
14256     }
14257     else
14258     {
14259         data.compression_multiplier = 1;
14260     }
14261
14262     if(sparse_data)
14263     {
14264         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14265                  1, tng_data->input_file) == 0)
14266         {
14267             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14268             tng_block_destroy(&block);
14269             return(TNG_CRITICAL);
14270         }
14271         if(tng_data->output_endianness_swap_func_64)
14272         {
14273             if(tng_data->output_endianness_swap_func_64(tng_data,
14274                 &data.first_frame_with_data)
14275                 != TNG_SUCCESS)
14276             {
14277                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14278                         __FILE__, __LINE__);
14279             }
14280         }
14281
14282         if(fread(&data.stride_length, sizeof(data.stride_length),
14283                  1, tng_data->input_file) == 0)
14284         {
14285             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14286             tng_block_destroy(&block);
14287             return(TNG_CRITICAL);
14288         }
14289         if(tng_data->output_endianness_swap_func_64)
14290         {
14291             if(tng_data->output_endianness_swap_func_64(tng_data,
14292                 &data.stride_length)
14293                 != TNG_SUCCESS)
14294             {
14295                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14296                         __FILE__, __LINE__);
14297             }
14298         }
14299     }
14300     else
14301     {
14302         data.first_frame_with_data = 0;
14303         data.stride_length = 1;
14304     }
14305     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14306
14307     tng_data->input_file = temp;
14308
14309     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14310     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14311     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14312
14313     switch(data.datatype)
14314     {
14315         case(TNG_INT_DATA):
14316             size = sizeof(int64_t);
14317             break;
14318         case(TNG_FLOAT_DATA):
14319             size = sizeof(float);
14320             break;
14321         case(TNG_DOUBLE_DATA):
14322             size = sizeof(double);
14323             break;
14324         default:
14325             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14326                    __LINE__);
14327             tng_block_destroy(&block);
14328             return(TNG_FAILURE);
14329     }
14330
14331     n_values_per_frame = data.n_values_per_frame;
14332
14333     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14334                                data.first_frame_with_data)) /
14335                 data.stride_length;
14336     file_pos *= size * n_values_per_frame;
14337
14338     if(file_pos > contents_size)
14339     {
14340         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14341                __LINE__);
14342         tng_block_destroy(&block);
14343         return(TNG_FAILURE);
14344     }
14345
14346     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14347
14348     /* If the endianness is not big endian the data needs to be swapped */
14349     if((data.datatype == TNG_INT_DATA ||
14350         data.datatype == TNG_DOUBLE_DATA) &&
14351        tng_data->output_endianness_swap_func_64)
14352     {
14353         copy = malloc(n_values_per_frame * size);
14354         memcpy(copy, values, n_values_per_frame * size);
14355         for(i = 0; i < n_values_per_frame; i++)
14356         {
14357             if(tng_data->output_endianness_swap_func_64(tng_data,
14358                 (int64_t *)copy+i)
14359                 != TNG_SUCCESS)
14360             {
14361                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14362                         __FILE__, __LINE__);
14363             }
14364         }
14365         fwrite(copy, n_values_per_frame, size,
14366                tng_data->output_file);
14367         free(copy);
14368     }
14369     else if(data.datatype == TNG_FLOAT_DATA &&
14370             tng_data->output_endianness_swap_func_32)
14371     {
14372         copy = malloc(n_values_per_frame * size);
14373         memcpy(copy, values, n_values_per_frame * size);
14374         for(i = 0; i < n_values_per_frame; i++)
14375         {
14376             if(tng_data->output_endianness_swap_func_32(tng_data,
14377                 (int32_t *)copy+i)
14378                 != TNG_SUCCESS)
14379             {
14380                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14381                         __FILE__, __LINE__);
14382             }
14383         }
14384         fwrite(copy, n_values_per_frame, size,
14385                tng_data->output_file);
14386         free(copy);
14387     }
14388
14389     else
14390     {
14391         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14392     }
14393
14394     fflush(tng_data->output_file);
14395
14396     /* Update the number of written frames in the frame set. */
14397     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14398     {
14399         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14400     }
14401
14402     /* If the last frame has been written update the hash */
14403     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14404        data.first_frame_with_data) >=
14405        frame_set->n_frames)
14406     {
14407         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14408                             header_size);
14409     }
14410
14411     tng_block_destroy(&block);
14412
14413     return(TNG_SUCCESS);
14414 }
14415
14416 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14417                 (tng_trajectory_t tng_data,
14418                  const int64_t frame_nr,
14419                  const int64_t block_id,
14420                  const int64_t val_first_particle,
14421                  const int64_t val_n_particles,
14422                  const void *values,
14423                  const char hash_mode)
14424 {
14425     int64_t header_pos, file_pos, tot_n_particles;
14426     int64_t output_file_len, n_values_per_frame, size, contents_size;
14427     int64_t header_size, temp_first, temp_last;
14428     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14429     int64_t i, last_frame;
14430     long temp_current;
14431     tng_gen_block_t block;
14432     tng_trajectory_frame_set_t frame_set;
14433     FILE *temp = tng_data->input_file;
14434     struct tng_particle_data data;
14435     tng_function_status stat;
14436     tng_particle_mapping_t mapping;
14437     char dependency, sparse_data, datatype;
14438     void *copy;
14439
14440     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14441     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14442     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14443     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14444     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14445
14446     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14447     {
14448         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14449                __FILE__, __LINE__);
14450         return(TNG_CRITICAL);
14451     }
14452
14453     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14454     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14455     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14456     tng_data->first_trajectory_frame_set_input_file_pos =
14457     tng_data->first_trajectory_frame_set_output_file_pos;
14458     tng_data->last_trajectory_frame_set_input_file_pos =
14459     tng_data->last_trajectory_frame_set_output_file_pos;
14460     tng_data->current_trajectory_frame_set_input_file_pos =
14461     tng_data->current_trajectory_frame_set_output_file_pos;
14462
14463     tng_data->input_file = tng_data->output_file;
14464
14465     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14466
14467     frame_set = &tng_data->current_trajectory_frame_set;
14468
14469     if(stat != TNG_SUCCESS)
14470     {
14471         last_frame = frame_set->first_frame +
14472                      frame_set->n_frames - 1;
14473 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14474                   last_frame); */
14475         /* If the wanted frame would be in the frame set after the last
14476          * frame set create a new frame set. */
14477         if(stat == TNG_FAILURE &&
14478            (last_frame < frame_nr &&
14479             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14480         {
14481             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14482             {
14483                 last_frame = frame_nr - 1;
14484             }
14485             tng_frame_set_new(tng_data,
14486                               last_frame+1,
14487                               tng_data->frame_set_n_frames);
14488
14489             file_pos = ftell(tng_data->output_file);
14490             fseek(tng_data->output_file, 0, SEEK_END);
14491             output_file_len = ftell(tng_data->output_file);
14492             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14493
14494             /* Read mapping blocks from the last frame set */
14495             tng_block_init(&block);
14496
14497             stat = tng_block_header_read(tng_data, block);
14498             while(file_pos < output_file_len &&
14499                   stat != TNG_CRITICAL &&
14500                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14501                   block->id != -1)
14502             {
14503                 if(block->id == TNG_PARTICLE_MAPPING)
14504                 {
14505                     tng_trajectory_mapping_block_read(tng_data, block,
14506                                                       hash_mode);
14507                 }
14508                 else
14509                 {
14510                     fseek(tng_data->output_file, (long)block->block_contents_size,
14511                         SEEK_CUR);
14512                 }
14513                 file_pos = ftell(tng_data->output_file);
14514                 if(file_pos < output_file_len)
14515                 {
14516                     stat = tng_block_header_read(tng_data, block);
14517                 }
14518             }
14519
14520             tng_block_destroy(&block);
14521             /* Write the frame set to disk */
14522             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14523             {
14524                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14525                 exit(1);
14526             }
14527         }
14528         else
14529         {
14530             tng_data->input_file = temp;
14531             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14532             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14533             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14534             return(stat);
14535         }
14536     }
14537
14538
14539     tng_block_init(&block);
14540
14541     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14542
14543     fseek(tng_data->output_file, 0, SEEK_END);
14544     output_file_len = ftell(tng_data->output_file);
14545     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
14546
14547     /* Read past the frame set block first */
14548     stat = tng_block_header_read(tng_data, block);
14549     if(stat == TNG_CRITICAL)
14550     {
14551         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14552                file_pos, __FILE__, __LINE__);
14553         tng_block_destroy(&block);
14554         tng_data->input_file = temp;
14555
14556         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14557         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14558         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14559         return(stat);
14560     }
14561     fseek(tng_data->output_file, (long)block->block_contents_size,
14562             SEEK_CUR);
14563
14564     if(tng_data->var_num_atoms_flag)
14565     {
14566         tot_n_particles = frame_set->n_particles;
14567     }
14568     else
14569     {
14570         tot_n_particles = tng_data->n_particles;
14571     }
14572
14573     if(val_n_particles < tot_n_particles)
14574     {
14575         mapping_block_end_pos = -1;
14576         /* Read all mapping blocks to find the right place to put the data */
14577         stat = tng_block_header_read(tng_data, block);
14578         while(file_pos < output_file_len &&
14579                 stat != TNG_CRITICAL &&
14580                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14581                 block->id != -1)
14582         {
14583             if(block->id == TNG_PARTICLE_MAPPING)
14584             {
14585                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14586             }
14587             else
14588             {
14589                 fseek(tng_data->output_file, (long)block->block_contents_size,
14590                       SEEK_CUR);
14591             }
14592             file_pos = ftell(tng_data->output_file);
14593             if(block->id == TNG_PARTICLE_MAPPING)
14594             {
14595                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14596                 if(val_first_particle >= mapping->num_first_particle &&
14597                    val_first_particle < mapping->num_first_particle +
14598                    mapping->n_particles &&
14599                    val_first_particle + val_n_particles <=
14600                    mapping->num_first_particle + mapping->n_particles)
14601                 {
14602                     mapping_block_end_pos = file_pos;
14603                 }
14604             }
14605             if(file_pos < output_file_len)
14606             {
14607                 stat = tng_block_header_read(tng_data, block);
14608             }
14609         }
14610         if(stat == TNG_CRITICAL)
14611         {
14612             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14613                    file_pos, __FILE__, __LINE__);
14614             tng_block_destroy(&block);
14615             tng_data->input_file = temp;
14616
14617             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14618             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14619             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14620             return(stat);
14621         }
14622         if(mapping_block_end_pos < 0)
14623         {
14624             tng_block_destroy(&block);
14625             tng_data->input_file = temp;
14626
14627             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14628             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14629             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14630             return(TNG_FAILURE);
14631         }
14632         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
14633     }
14634
14635     /* Read all block headers until next frame set block or
14636      * until the wanted block id is found */
14637     stat = tng_block_header_read(tng_data, block);
14638     while(file_pos < output_file_len &&
14639             stat != TNG_CRITICAL &&
14640             block->id != block_id &&
14641             block->id != TNG_PARTICLE_MAPPING &&
14642             block->id != TNG_TRAJECTORY_FRAME_SET &&
14643             block->id != -1)
14644     {
14645         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
14646         file_pos = ftell(tng_data->output_file);
14647         if(file_pos < output_file_len)
14648         {
14649             stat = tng_block_header_read(tng_data, block);
14650         }
14651     }
14652     if(stat == TNG_CRITICAL)
14653     {
14654         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14655                 file_pos, __FILE__, __LINE__);
14656         tng_block_destroy(&block);
14657         tng_data->input_file = temp;
14658
14659         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14660         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14661         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14662         return(stat);
14663     }
14664
14665     contents_size = block->block_contents_size;
14666     header_size = block->header_contents_size;
14667
14668     header_pos = ftell(tng_data->output_file) - header_size;
14669     frame_set = &tng_data->current_trajectory_frame_set;
14670
14671     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14672     {
14673         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14674         tng_block_destroy(&block);
14675         return(TNG_CRITICAL);
14676     }
14677
14678     data.datatype = datatype;
14679
14680     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14681     {
14682         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14683         tng_block_destroy(&block);
14684         return(TNG_CRITICAL);
14685     }
14686
14687     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14688        !(dependency & TNG_PARTICLE_DEPENDENT))
14689     {
14690         tng_block_destroy(&block);
14691         tng_data->input_file = temp;
14692
14693         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14694         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14695         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14696         return(TNG_FAILURE);
14697     }
14698
14699     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14700     {
14701         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14702         tng_block_destroy(&block);
14703         return(TNG_CRITICAL);
14704     }
14705
14706     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14707              tng_data->input_file) == 0)
14708     {
14709         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14710         tng_block_destroy(&block);
14711         return(TNG_CRITICAL);
14712     }
14713     if(tng_data->output_endianness_swap_func_64)
14714     {
14715         if(tng_data->output_endianness_swap_func_64(tng_data,
14716             &data.n_values_per_frame)
14717             != TNG_SUCCESS)
14718         {
14719             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14720                     __FILE__, __LINE__);
14721         }
14722     }
14723
14724     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14725              tng_data->input_file) == 0)
14726     {
14727         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14728         tng_block_destroy(&block);
14729         return(TNG_CRITICAL);
14730     }
14731     if(tng_data->output_endianness_swap_func_64)
14732     {
14733         if(tng_data->output_endianness_swap_func_64(tng_data,
14734             &data.codec_id)
14735             != TNG_SUCCESS)
14736         {
14737             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14738                     __FILE__, __LINE__);
14739         }
14740     }
14741
14742     if(data.codec_id != TNG_UNCOMPRESSED)
14743     {
14744         if(fread(&data.compression_multiplier,
14745                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14746             == 0)
14747         {
14748             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14749             tng_block_destroy(&block);
14750             return(TNG_CRITICAL);
14751         }
14752
14753         if(tng_data->output_endianness_swap_func_64)
14754         {
14755             if(tng_data->output_endianness_swap_func_64(tng_data,
14756                (int64_t *)&data.compression_multiplier)
14757                 != TNG_SUCCESS)
14758             {
14759                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14760                         __FILE__, __LINE__);
14761             }
14762         }
14763     }
14764     else
14765     {
14766         data.compression_multiplier = 1;
14767     }
14768
14769     if(sparse_data)
14770     {
14771         if(fread(&data.first_frame_with_data,
14772                  sizeof(data.first_frame_with_data),
14773                  1, tng_data->input_file) == 0)
14774         {
14775             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14776             tng_block_destroy(&block);
14777             return(TNG_CRITICAL);
14778         }
14779         if(tng_data->output_endianness_swap_func_64)
14780         {
14781             if(tng_data->output_endianness_swap_func_64(tng_data,
14782                 &data.first_frame_with_data)
14783                 != TNG_SUCCESS)
14784             {
14785                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14786                         __FILE__, __LINE__);
14787             }
14788         }
14789
14790         if(fread(&data.stride_length, sizeof(data.stride_length),
14791                  1, tng_data->input_file) == 0)
14792         {
14793             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14794             tng_block_destroy(&block);
14795             return(TNG_CRITICAL);
14796         }
14797         if(tng_data->output_endianness_swap_func_64)
14798         {
14799             if(tng_data->output_endianness_swap_func_64(tng_data,
14800                 &data.stride_length)
14801                 != TNG_SUCCESS)
14802             {
14803                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14804                         __FILE__, __LINE__);
14805             }
14806         }
14807     }
14808     else
14809     {
14810         data.first_frame_with_data = 0;
14811         data.stride_length = 1;
14812     }
14813     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14814
14815     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14816              tng_data->input_file) == 0)
14817     {
14818         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14819         tng_block_destroy(&block);
14820         return(TNG_CRITICAL);
14821     }
14822     if(tng_data->output_endianness_swap_func_64)
14823     {
14824         if(tng_data->output_endianness_swap_func_64(tng_data,
14825             &num_first_particle)
14826             != TNG_SUCCESS)
14827         {
14828             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14829                     __FILE__, __LINE__);
14830         }
14831     }
14832
14833     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14834              tng_data->input_file) == 0)
14835     {
14836         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14837         tng_block_destroy(&block);
14838         return(TNG_CRITICAL);
14839     }
14840     if(tng_data->output_endianness_swap_func_64)
14841     {
14842         if(tng_data->output_endianness_swap_func_64(tng_data,
14843             &block_n_particles)
14844             != TNG_SUCCESS)
14845         {
14846             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14847                     __FILE__, __LINE__);
14848         }
14849     }
14850
14851
14852     tng_data->input_file = temp;
14853
14854     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14855     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14856     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14857
14858
14859     switch(data.datatype)
14860     {
14861         case(TNG_INT_DATA):
14862             size = sizeof(int64_t);
14863             break;
14864         case(TNG_FLOAT_DATA):
14865             size = sizeof(float);
14866             break;
14867         case(TNG_DOUBLE_DATA):
14868             size = sizeof(double);
14869             break;
14870         default:
14871             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14872                    __LINE__);
14873             tng_block_destroy(&block);
14874             return(TNG_FAILURE);
14875     }
14876
14877     n_values_per_frame = data.n_values_per_frame;
14878
14879     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14880                                data.first_frame_with_data)) /
14881                 data.stride_length;
14882     file_pos *= block_n_particles * size * n_values_per_frame;
14883
14884     if(file_pos > contents_size)
14885     {
14886         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14887                __LINE__);
14888         tng_block_destroy(&block);
14889         return(TNG_FAILURE);
14890     }
14891
14892     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14893
14894     /* If the endianness is not big endian the data needs to be swapped */
14895     if((data.datatype == TNG_INT_DATA ||
14896         data.datatype == TNG_DOUBLE_DATA) &&
14897        tng_data->output_endianness_swap_func_64)
14898     {
14899         copy = malloc(val_n_particles * n_values_per_frame * size);
14900         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14901         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14902         {
14903             if(tng_data->output_endianness_swap_func_64(tng_data,
14904                 (int64_t *) copy+i)
14905                 != TNG_SUCCESS)
14906             {
14907                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14908                         __FILE__, __LINE__);
14909             }
14910         }
14911         fwrite(copy, val_n_particles * n_values_per_frame, size,
14912                tng_data->output_file);
14913         free(copy);
14914     }
14915     else if(data.datatype == TNG_FLOAT_DATA &&
14916        tng_data->output_endianness_swap_func_32)
14917     {
14918         copy = malloc(val_n_particles * n_values_per_frame * size);
14919         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14920         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14921         {
14922             if(tng_data->output_endianness_swap_func_32(tng_data,
14923                 (int32_t *) copy+i)
14924                 != TNG_SUCCESS)
14925             {
14926                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14927                         __FILE__, __LINE__);
14928             }
14929         }
14930         fwrite(copy, val_n_particles * n_values_per_frame, size,
14931                tng_data->output_file);
14932         free(copy);
14933     }
14934
14935     else
14936     {
14937         fwrite(values, val_n_particles * n_values_per_frame, size,
14938                tng_data->output_file);
14939     }
14940     fflush(tng_data->output_file);
14941
14942     /* Update the number of written frames in the frame set. */
14943     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14944     {
14945         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14946     }
14947
14948     /* If the last frame has been written update the hash */
14949     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14950        data.first_frame_with_data) >=
14951        frame_set->n_frames)
14952     {
14953         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14954                             header_size);
14955     }
14956
14957     tng_block_destroy(&block);
14958     return(TNG_SUCCESS);
14959 }
14960
14961 static tng_function_status tng_data_values_alloc
14962                 (const tng_trajectory_t tng_data,
14963                  union data_values ***values,
14964                  const int64_t n_frames,
14965                  const int64_t n_values_per_frame,
14966                  const char type)
14967 {
14968     int64_t i;
14969     tng_function_status stat;
14970
14971     if(n_frames <= 0 || n_values_per_frame <= 0)
14972     {
14973         return(TNG_FAILURE);
14974     }
14975
14976     if(*values)
14977     {
14978         stat = tng_data_values_free(tng_data, *values, n_frames,
14979                                     n_values_per_frame,
14980                                     type);
14981         if(stat != TNG_SUCCESS)
14982         {
14983             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14984                    __FILE__, __LINE__);
14985             return(stat);
14986         }
14987     }
14988     *values = malloc(sizeof(union data_values *) * n_frames);
14989     if(!*values)
14990     {
14991         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14992                sizeof(union data_values **) * n_frames,
14993                __FILE__, __LINE__);
14994         return(TNG_CRITICAL);
14995
14996     }
14997
14998     for(i = 0; i < n_frames; i++)
14999     {
15000         (*values)[i] = malloc(sizeof(union data_values) *
15001                            n_values_per_frame);
15002         if(!(*values)[i])
15003         {
15004             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15005                    sizeof(union data_values) * n_values_per_frame,
15006                    __FILE__, __LINE__);
15007             free(values);
15008             values = 0;
15009             return(TNG_CRITICAL);
15010         }
15011     }
15012     return(TNG_SUCCESS);
15013 }
15014
15015 /* FIXME: This needs ***values */
15016 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15017                 (const tng_trajectory_t tng_data,
15018                  union data_values **values,
15019                  const int64_t n_frames,
15020                  const int64_t n_values_per_frame,
15021                  const char type)
15022 {
15023     int64_t i, j;
15024     (void)tng_data;
15025
15026     if(values)
15027     {
15028         for(i = 0; i < n_frames; i++)
15029         {
15030             if(values[i])
15031             {
15032                 if(type == TNG_CHAR_DATA)
15033                 {
15034                     for(j = 0; j < n_values_per_frame; j++)
15035                     {
15036                         if(values[i][j].c)
15037                         {
15038                             free(values[i][j].c);
15039                             values[i][j].c = 0;
15040                         }
15041                     }
15042                 }
15043                 free(values[i]);
15044                 values[i] = 0;
15045             }
15046         }
15047         free(values);
15048         values = 0;
15049     }
15050
15051     return(TNG_SUCCESS);
15052 }
15053
15054 static tng_function_status tng_particle_data_values_alloc
15055                 (const tng_trajectory_t tng_data,
15056                  union data_values ****values,
15057                  const int64_t n_frames,
15058                  const int64_t n_particles,
15059                  const int64_t n_values_per_frame,
15060                  const char type)
15061 {
15062     int64_t i, j;
15063     tng_function_status stat;
15064
15065     if(n_particles == 0 || n_values_per_frame == 0)
15066     {
15067         return(TNG_FAILURE);
15068     }
15069
15070     if(*values)
15071     {
15072         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15073                                              n_particles, n_values_per_frame,
15074                                              type);
15075         if(stat != TNG_SUCCESS)
15076         {
15077             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15078                    __FILE__, __LINE__);
15079             return(stat);
15080         }
15081     }
15082     *values = malloc(sizeof(union data_values **) * n_frames);
15083     if(!*values)
15084     {
15085         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15086                sizeof(union data_values **) * n_frames,
15087                __FILE__, __LINE__);
15088         return(TNG_CRITICAL);
15089
15090     }
15091
15092     for(i = 0; i < n_frames; i++)
15093     {
15094         (*values)[i] = malloc(sizeof(union data_values *) *
15095                            n_particles);
15096         if(!(*values)[i])
15097         {
15098             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15099                    sizeof(union data_values *) * n_particles,
15100                    __FILE__, __LINE__);
15101             free(*values);
15102             *values = 0;
15103             return(TNG_CRITICAL);
15104         }
15105         for(j = 0; j < n_particles; j++)
15106         {
15107             (*values)[i][j] = malloc(sizeof(union data_values) *
15108                                   n_values_per_frame);
15109             if(!(*values)[i][j])
15110             {
15111                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15112                     sizeof(union data_values *) * n_particles,
15113                     __FILE__, __LINE__);
15114                 tng_particle_data_values_free(tng_data, *values, n_frames,
15115                                               n_particles, n_values_per_frame,
15116                                               type);
15117                 *values = 0;
15118                 return(TNG_CRITICAL);
15119             }
15120         }
15121     }
15122     return(TNG_SUCCESS);
15123 }
15124
15125 /* FIXME: This needs ****values */
15126 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15127                 (const tng_trajectory_t tng_data,
15128                  union data_values ***values,
15129                  const int64_t n_frames,
15130                  const int64_t n_particles,
15131                  const int64_t n_values_per_frame,
15132                  const char type)
15133 {
15134     int64_t i, j, k;
15135     (void)tng_data;
15136
15137     if(values)
15138     {
15139         for(i = 0; i < n_frames; i++)
15140         {
15141             if(values[i])
15142             {
15143                 for(j = 0; j < n_particles; j++)
15144                 {
15145                     if(type == TNG_CHAR_DATA)
15146                     {
15147                         for(k = 0; k < n_values_per_frame; k++)
15148                         {
15149                             if(values[i][j][k].c)
15150                             {
15151                                 free(values[i][j][k].c);
15152                                 values[i][j][k].c = 0;
15153                             }
15154                         }
15155                     }
15156                     free(values[i][j]);
15157                     values[i][j] = 0;
15158                 }
15159                 free(values[i]);
15160                 values[i] = 0;
15161             }
15162         }
15163         free(values);
15164         values = 0;
15165     }
15166
15167     return(TNG_SUCCESS);
15168 }
15169
15170
15171 tng_function_status DECLSPECDLLEXPORT tng_data_get
15172                 (tng_trajectory_t tng_data,
15173                  const int64_t block_id,
15174                  union data_values ***values,
15175                  int64_t *n_frames,
15176                  int64_t *n_values_per_frame,
15177                  char *type)
15178 {
15179     int64_t i, j, file_pos, block_index;
15180     int size;
15181     size_t len;
15182     tng_non_particle_data_t data;
15183     tng_trajectory_frame_set_t frame_set;
15184     tng_gen_block_t block;
15185     tng_function_status stat;
15186
15187     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15188     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15189     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15190     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15191
15192     frame_set = &tng_data->current_trajectory_frame_set;
15193
15194     block_index = -1;
15195     data = 0;
15196
15197     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15198     {
15199         tng_block_init(&block);
15200         file_pos = ftell(tng_data->input_file);
15201         /* Read all blocks until next frame set block */
15202         stat = tng_block_header_read(tng_data, block);
15203         while(file_pos < tng_data->input_file_len &&
15204                 stat != TNG_CRITICAL &&
15205                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15206                 block->id != -1)
15207         {
15208             /* Use hash by default */
15209             stat = tng_block_read_next(tng_data, block,
15210                                     TNG_USE_HASH);
15211             if(stat != TNG_CRITICAL)
15212             {
15213                 file_pos = ftell(tng_data->input_file);
15214                 if(file_pos < tng_data->input_file_len)
15215                 {
15216                     stat = tng_block_header_read(tng_data, block);
15217                 }
15218             }
15219         }
15220         tng_block_destroy(&block);
15221         if(stat == TNG_CRITICAL)
15222         {
15223             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15224                     file_pos, __FILE__, __LINE__);
15225             return(stat);
15226         }
15227
15228         for(i = 0; i < frame_set->n_data_blocks; i++)
15229         {
15230             data = &frame_set->tr_data[i];
15231             if(data->block_id == block_id)
15232             {
15233                 block_index = i;
15234                 break;
15235             }
15236         }
15237         if(block_index < 0)
15238         {
15239             return(TNG_FAILURE);
15240         }
15241     }
15242
15243     *n_frames = tng_max_i64(1, data->n_frames);
15244     *n_values_per_frame = data->n_values_per_frame;
15245     *type = data->datatype;
15246
15247     if(*values == 0)
15248     {
15249         if(tng_data_values_alloc(tng_data, values, *n_frames,
15250                                  *n_values_per_frame,
15251                                  *type)
15252         != TNG_SUCCESS)
15253         {
15254             return(TNG_CRITICAL);
15255         }
15256     }
15257
15258     switch(*type)
15259     {
15260     case TNG_CHAR_DATA:
15261         for(i = 0; i < *n_frames; i++)
15262         {
15263             for(j = 0; j < *n_values_per_frame; j++)
15264             {
15265                 len = strlen(data->strings[i][j]) + 1;
15266                 (*values)[i][j].c = malloc(len);
15267                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15268             }
15269         }
15270         break;
15271     case TNG_INT_DATA:
15272         size = sizeof(int);
15273         for(i = 0; i < *n_frames; i++)
15274         {
15275             for(j = 0; j < *n_values_per_frame; j++)
15276             {
15277                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15278                                              (i*(*n_values_per_frame) + j));
15279             }
15280         }
15281         break;
15282     case TNG_FLOAT_DATA:
15283         size = sizeof(float);
15284         for(i = 0; i < *n_frames; i++)
15285         {
15286             for(j = 0; j < *n_values_per_frame; j++)
15287             {
15288                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15289                                                (i*(*n_values_per_frame) + j));
15290             }
15291         }
15292         break;
15293     case TNG_DOUBLE_DATA:
15294     default:
15295         size = sizeof(double);
15296         for(i = 0; i < *n_frames; i++)
15297         {
15298             for(j = 0; j < *n_values_per_frame; j++)
15299             {
15300                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15301                                                 (i*(*n_values_per_frame) + j));
15302             }
15303         }
15304     }
15305
15306     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15307
15308     return(TNG_SUCCESS);
15309 }
15310
15311 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15312                                         const int64_t block_id,
15313                                         void **values,
15314                                         int64_t *n_frames,
15315                                         int64_t *stride_length,
15316                                         int64_t *n_values_per_frame,
15317                                         char *type)
15318 {
15319     int64_t file_pos, data_size, n_frames_div, block_index;
15320     int i, size;
15321     tng_non_particle_data_t data;
15322     tng_trajectory_frame_set_t frame_set;
15323     tng_gen_block_t block;
15324     void *temp;
15325     tng_function_status stat;
15326
15327     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15328     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15329     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15330     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15331     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15332
15333     frame_set = &tng_data->current_trajectory_frame_set;
15334
15335     block_index = -1;
15336     data = 0;
15337
15338     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15339     {
15340         tng_block_init(&block);
15341         file_pos = ftell(tng_data->input_file);
15342         /* Read all blocks until next frame set block */
15343         stat = tng_block_header_read(tng_data, block);
15344         while(file_pos < tng_data->input_file_len &&
15345                 stat != TNG_CRITICAL &&
15346                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15347                 block->id != -1)
15348         {
15349             /* Use hash by default */
15350             stat = tng_block_read_next(tng_data, block,
15351                                     TNG_USE_HASH);
15352             if(stat != TNG_CRITICAL)
15353             {
15354                 file_pos = ftell(tng_data->input_file);
15355                 if(file_pos < tng_data->input_file_len)
15356                 {
15357                     stat = tng_block_header_read(tng_data, block);
15358                 }
15359             }
15360         }
15361         tng_block_destroy(&block);
15362         if(stat == TNG_CRITICAL)
15363         {
15364             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15365                     file_pos, __FILE__, __LINE__);
15366             return(stat);
15367         }
15368
15369         for(i = 0; i < frame_set->n_data_blocks; i++)
15370         {
15371             data = &frame_set->tr_data[i];
15372             if(data->block_id == block_id)
15373             {
15374                 block_index = i;
15375                 break;
15376             }
15377         }
15378         if(block_index < 0)
15379         {
15380             return(TNG_FAILURE);
15381         }
15382     }
15383
15384     *type = data->datatype;
15385
15386     switch(*type)
15387     {
15388     case TNG_CHAR_DATA:
15389         return(TNG_FAILURE);
15390     case TNG_INT_DATA:
15391         size = sizeof(int64_t);
15392         break;
15393     case TNG_FLOAT_DATA:
15394         size = sizeof(float);
15395         break;
15396     case TNG_DOUBLE_DATA:
15397     default:
15398         size = sizeof(double);
15399     }
15400
15401     *n_frames = data->n_frames;
15402     *n_values_per_frame = data->n_values_per_frame;
15403     *stride_length = data->stride_length;
15404     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15405                    *n_frames / *stride_length;
15406
15407     data_size = n_frames_div * size *
15408                 *n_values_per_frame;
15409
15410     temp = realloc(*values, data_size);
15411     if(!temp)
15412     {
15413         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15414                data_size, __FILE__, __LINE__);
15415         free(*values);
15416         *values = 0;
15417         return(TNG_CRITICAL);
15418     }
15419
15420     *values = temp;
15421
15422     memcpy(*values, data->values, data_size);
15423
15424     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15425
15426     return(TNG_SUCCESS);
15427 }
15428
15429 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15430                 (tng_trajectory_t tng_data,
15431                  const int64_t block_id,
15432                  const int64_t start_frame_nr,
15433                  const int64_t end_frame_nr,
15434                  const char hash_mode,
15435                  union data_values ***values,
15436                  int64_t *n_values_per_frame,
15437                  char *type)
15438 {
15439     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15440     int64_t block_index;
15441     int size;
15442     size_t len;
15443     tng_non_particle_data_t data;
15444     tng_trajectory_frame_set_t frame_set;
15445     tng_gen_block_t block;
15446     tng_function_status stat;
15447
15448     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15449     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15450     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15451     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15452
15453     block_index = -1;
15454
15455     frame_set = &tng_data->current_trajectory_frame_set;
15456     first_frame = frame_set->first_frame;
15457
15458     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15459     if(stat != TNG_SUCCESS)
15460     {
15461         return(stat);
15462     }
15463
15464
15465     /* Do not re-read the frame set. */
15466     if(first_frame != frame_set->first_frame ||
15467        frame_set->n_data_blocks <= 0)
15468     {
15469         tng_block_init(&block);
15470         file_pos = ftell(tng_data->input_file);
15471         /* Read all blocks until next frame set block */
15472         stat = tng_block_header_read(tng_data, block);
15473         while(file_pos < tng_data->input_file_len &&
15474             stat != TNG_CRITICAL &&
15475             block->id != TNG_TRAJECTORY_FRAME_SET &&
15476             block->id != -1)
15477         {
15478             stat = tng_block_read_next(tng_data, block,
15479                                     hash_mode);
15480             if(stat != TNG_CRITICAL)
15481             {
15482                 file_pos = ftell(tng_data->input_file);
15483                 if(file_pos < tng_data->input_file_len)
15484                 {
15485                     stat = tng_block_header_read(tng_data, block);
15486                 }
15487             }
15488         }
15489         tng_block_destroy(&block);
15490         if(stat == TNG_CRITICAL)
15491         {
15492             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15493                     file_pos, __FILE__, __LINE__);
15494             return(stat);
15495         }
15496     }
15497
15498
15499     /* See if there is a data block of this ID.
15500      * Start checking the last read frame set */
15501     for(i = 0; i < frame_set->n_data_blocks; i++)
15502     {
15503         data = &frame_set->tr_data[i];
15504         if(data->block_id == block_id)
15505         {
15506             block_index = i;
15507             break;
15508         }
15509     }
15510
15511     if(block_index < 0)
15512     {
15513         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15514                 block_id, __FILE__, __LINE__);
15515         return(TNG_FAILURE);
15516     }
15517
15518     n_frames = end_frame_nr - start_frame_nr + 1;
15519     *n_values_per_frame = data->n_values_per_frame;
15520     *type = data->datatype;
15521
15522     if(*values == 0)
15523     {
15524         if(tng_data_values_alloc(tng_data, values, n_frames,
15525                                  *n_values_per_frame,
15526                                  *type) != TNG_SUCCESS)
15527         {
15528             return(TNG_CRITICAL);
15529         }
15530     }
15531
15532     current_frame_pos = start_frame_nr - frame_set->first_frame;
15533     /* It's not very elegant to reuse so much of the code in the different case
15534      * statements, but it's unnecessarily slow to have the switch-case block
15535      * inside the for loops. */
15536     switch(*type)
15537     {
15538     case TNG_CHAR_DATA:
15539         for(i=0; i<n_frames; i++)
15540         {
15541             if(current_frame_pos == frame_set->n_frames)
15542             {
15543                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15544                 if(stat != TNG_SUCCESS)
15545                 {
15546                     return(stat);
15547                 }
15548                 current_frame_pos = 0;
15549             }
15550             for(j = 0; j < *n_values_per_frame; j++)
15551             {
15552                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15553                 (*values)[i][j].c = malloc(len);
15554                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15555             }
15556             current_frame_pos++;
15557         }
15558         break;
15559     case TNG_INT_DATA:
15560         size = sizeof(int);
15561         for(i=0; i<n_frames; i++)
15562         {
15563             if(current_frame_pos == frame_set->n_frames)
15564             {
15565                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15566                 if(stat != TNG_SUCCESS)
15567                 {
15568                     return(stat);
15569                 }
15570                 current_frame_pos = 0;
15571             }
15572             for(j = 0; j < *n_values_per_frame; j++)
15573             {
15574                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15575                                             (current_frame_pos *
15576                                              (*n_values_per_frame) + j));
15577             }
15578             current_frame_pos++;
15579         }
15580         break;
15581     case TNG_FLOAT_DATA:
15582         size = sizeof(float);
15583         for(i=0; i<n_frames; i++)
15584         {
15585             if(current_frame_pos == frame_set->n_frames)
15586             {
15587                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15588                 if(stat != TNG_SUCCESS)
15589                 {
15590                     return(stat);
15591                 }
15592                 current_frame_pos = 0;
15593             }
15594             for(j = 0; j < *n_values_per_frame; j++)
15595             {
15596                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15597                                                (current_frame_pos *
15598                                                 (*n_values_per_frame) + j));
15599             }
15600             current_frame_pos++;
15601         }
15602         break;
15603     case TNG_DOUBLE_DATA:
15604     default:
15605         size = sizeof(double);
15606         for(i=0; i<n_frames; i++)
15607         {
15608             if(current_frame_pos == frame_set->n_frames)
15609             {
15610                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15611                 if(stat != TNG_SUCCESS)
15612                 {
15613                     return(stat);
15614                 }
15615                 current_frame_pos = 0;
15616             }
15617             for(j = 0; j < *n_values_per_frame; j++)
15618             {
15619                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15620                                                 (current_frame_pos *
15621                                                  (*n_values_per_frame) + j));
15622             }
15623             current_frame_pos++;
15624         }
15625     }
15626
15627     data->last_retrieved_frame = end_frame_nr;
15628
15629     return(TNG_SUCCESS);
15630 }
15631
15632 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15633                 (tng_trajectory_t tng_data,
15634                  const int64_t block_id,
15635                  const int64_t start_frame_nr,
15636                  const int64_t end_frame_nr,
15637                  const char hash_mode,
15638                  void **values,
15639                  int64_t *stride_length,
15640                  int64_t *n_values_per_frame,
15641                  char *type)
15642 {
15643     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15644     int64_t file_pos, current_frame_pos, data_size, frame_size;
15645     int64_t last_frame_pos;
15646     int size;
15647     tng_trajectory_frame_set_t frame_set;
15648     tng_non_particle_data_t np_data;
15649     tng_gen_block_t block;
15650     void *current_values = 0, *temp;
15651     tng_function_status stat;
15652
15653     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15654     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15655     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15656     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15657     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15658
15659     frame_set = &tng_data->current_trajectory_frame_set;
15660     first_frame = frame_set->first_frame;
15661
15662     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15663     if(stat != TNG_SUCCESS)
15664     {
15665         return(stat);
15666     }
15667
15668     /* Do not re-read the frame set and only need the requested block. */
15669     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15670     stat = tng_data_find(tng_data, block_id, &np_data);
15671     if(first_frame != frame_set->first_frame ||
15672        stat != TNG_SUCCESS)
15673     {
15674         tng_block_init(&block);
15675         if(stat != TNG_SUCCESS)
15676         {
15677             fseek(tng_data->input_file,
15678                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15679                   SEEK_SET);
15680             stat = tng_block_header_read(tng_data, block);
15681             if(stat != TNG_SUCCESS)
15682             {
15683                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15684                         __FILE__, __LINE__);
15685                 return(stat);
15686             }
15687
15688             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15689         }
15690         file_pos = ftell(tng_data->input_file);
15691         /* Read until next frame set block */
15692         stat = tng_block_header_read(tng_data, block);
15693         while(file_pos < tng_data->input_file_len &&
15694             stat != TNG_CRITICAL &&
15695             block->id != TNG_TRAJECTORY_FRAME_SET &&
15696             block->id != -1)
15697         {
15698             if(block->id == block_id)
15699             {
15700                 stat = tng_block_read_next(tng_data, block,
15701                                         hash_mode);
15702                 if(stat != TNG_CRITICAL)
15703                 {
15704                     file_pos = ftell(tng_data->input_file);
15705                     if(file_pos < tng_data->input_file_len)
15706                     {
15707                         stat = tng_block_header_read(tng_data, block);
15708                     }
15709                 }
15710             }
15711             else
15712             {
15713                 file_pos += block->block_contents_size + block->header_contents_size;
15714                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15715                 if(file_pos < tng_data->input_file_len)
15716                 {
15717                     stat = tng_block_header_read(tng_data, block);
15718                 }
15719             }
15720         }
15721         tng_block_destroy(&block);
15722         if(stat == TNG_CRITICAL)
15723         {
15724             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15725                     file_pos, __FILE__, __LINE__);
15726             return(stat);
15727         }
15728     }
15729
15730     stat = tng_data_find(tng_data, block_id, &np_data);
15731     if(stat != TNG_SUCCESS)
15732     {
15733         return(stat);
15734     }
15735
15736     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15737                                &n_frames, stride_length,
15738                                n_values_per_frame, type);
15739
15740     if(stat != TNG_SUCCESS)
15741     {
15742         if(current_values)
15743         {
15744             free(current_values);
15745         }
15746         return(stat);
15747     }
15748
15749     if(n_frames == 1 && n_frames < frame_set->n_frames)
15750     {
15751         tot_n_frames = 1;
15752     }
15753     else
15754     {
15755         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15756     }
15757
15758     switch(*type)
15759     {
15760     case TNG_CHAR_DATA:
15761         return(TNG_FAILURE);
15762     case TNG_INT_DATA:
15763         size = sizeof(int64_t);
15764         break;
15765     case TNG_FLOAT_DATA:
15766         size = sizeof(float);
15767         break;
15768     case TNG_DOUBLE_DATA:
15769     default:
15770         size = sizeof(double);
15771     }
15772
15773     n_frames_div = (tot_n_frames % *stride_length) ?
15774                  tot_n_frames / *stride_length + 1:
15775                  tot_n_frames / *stride_length;
15776     data_size = n_frames_div * size * (*n_values_per_frame);
15777
15778 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15779               size, n_frames_div, data_size);
15780 */
15781     temp = realloc(*values, data_size);
15782     if(!temp)
15783     {
15784         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15785                data_size, __FILE__, __LINE__);
15786         free(*values);
15787         *values = 0;
15788         return(TNG_CRITICAL);
15789     }
15790
15791     *values = temp;
15792
15793     if( n_frames == 1 && n_frames < frame_set->n_frames)
15794     {
15795         memcpy(*values, current_values, size * (*n_values_per_frame));
15796     }
15797     else
15798     {
15799         current_frame_pos = start_frame_nr - frame_set->first_frame;
15800
15801         frame_size = size * (*n_values_per_frame);
15802
15803         last_frame_pos = tng_min_i64(n_frames,
15804                                      end_frame_nr - start_frame_nr);
15805
15806         n_frames_div = current_frame_pos / *stride_length;
15807         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15808                        last_frame_pos / *stride_length + 1:
15809                        last_frame_pos / *stride_length;
15810         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15811
15812         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15813                n_frames_div_2 * frame_size);
15814
15815         current_frame_pos += n_frames - current_frame_pos;
15816
15817         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15818         {
15819             stat = tng_frame_set_read_next(tng_data, hash_mode);
15820             if(stat != TNG_SUCCESS)
15821             {
15822                 if(current_values)
15823                 {
15824                     free(current_values);
15825                 }
15826                 free(*values);
15827                 *values = 0;
15828                 return(stat);
15829             }
15830
15831             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15832                                     &n_frames, stride_length,
15833                                     n_values_per_frame, type);
15834
15835             if(stat != TNG_SUCCESS)
15836             {
15837                 if(current_values)
15838                 {
15839                     free(current_values);
15840                 }
15841                 free(*values);
15842                 *values = 0;
15843                 return(stat);
15844             }
15845
15846             last_frame_pos = tng_min_i64(n_frames,
15847                                          end_frame_nr - current_frame_pos);
15848
15849             n_frames_div = current_frame_pos / *stride_length;
15850             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15851                            last_frame_pos / *stride_length + 1:
15852                            last_frame_pos / *stride_length;
15853             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15854
15855             memcpy(((char *)*values) + n_frames_div * frame_size,
15856                    current_values,
15857                    n_frames_div_2 * frame_size);
15858
15859             current_frame_pos += n_frames;
15860         }
15861     }
15862
15863     if(current_values)
15864     {
15865         free(current_values);
15866     }
15867
15868     np_data->last_retrieved_frame = end_frame_nr;
15869
15870     return(TNG_SUCCESS);
15871 }
15872
15873 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15874                 (tng_trajectory_t tng_data,
15875                  const int64_t block_id,
15876                  union data_values ****values,
15877                  int64_t *n_frames,
15878                  int64_t *n_particles,
15879                  int64_t *n_values_per_frame,
15880                  char *type)
15881 {
15882     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15883     int size;
15884     size_t len;
15885     tng_particle_data_t data;
15886     tng_trajectory_frame_set_t frame_set;
15887     tng_gen_block_t block;
15888     char block_type_flag;
15889     tng_function_status stat;
15890
15891     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15892     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15893     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15894     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15895     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15896
15897     frame_set = &tng_data->current_trajectory_frame_set;
15898
15899     block_index = -1;
15900     data = 0;
15901
15902     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15903     {
15904         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15905         {
15906             block_type_flag = TNG_TRAJECTORY_BLOCK;
15907         }
15908         else
15909         {
15910             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15911         }
15912
15913         tng_block_init(&block);
15914         file_pos = ftell(tng_data->input_file);
15915         /* Read all blocks until next frame set block */
15916         stat = tng_block_header_read(tng_data, block);
15917         while(file_pos < tng_data->input_file_len &&
15918                 stat != TNG_CRITICAL &&
15919                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15920                 block->id != -1)
15921         {
15922             /* Use hash by default */
15923             stat = tng_block_read_next(tng_data, block,
15924                                     TNG_USE_HASH);
15925             if(stat != TNG_CRITICAL)
15926             {
15927                 file_pos = ftell(tng_data->input_file);
15928                 if(file_pos < tng_data->input_file_len)
15929                 {
15930                     stat = tng_block_header_read(tng_data, block);
15931                 }
15932             }
15933         }
15934         tng_block_destroy(&block);
15935         if(stat == TNG_CRITICAL)
15936         {
15937             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15938                     file_pos, __FILE__, __LINE__);
15939             return(stat);
15940         }
15941
15942         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
15943         {
15944             data = &frame_set->tr_particle_data[i];
15945             if(data->block_id == block_id)
15946             {
15947                 block_index = i;
15948                 block_type_flag = TNG_TRAJECTORY_BLOCK;
15949                 break;
15950             }
15951         }
15952         if(block_index < 0)
15953         {
15954             return(TNG_FAILURE);
15955         }
15956     }
15957     else
15958     {
15959         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15960         {
15961             block_type_flag = TNG_TRAJECTORY_BLOCK;
15962         }
15963         else
15964         {
15965             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15966         }
15967     }
15968
15969     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15970        tng_data->var_num_atoms_flag)
15971     {
15972         *n_particles = frame_set->n_particles;
15973     }
15974     else
15975     {
15976         *n_particles = tng_data->n_particles;
15977     }
15978
15979     *n_frames = tng_max_i64(1, data->n_frames);
15980     *n_values_per_frame = data->n_values_per_frame;
15981     *type = data->datatype;
15982
15983     if(*values == 0)
15984     {
15985         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
15986                                          *n_particles, *n_values_per_frame,
15987                                          *type)
15988             != TNG_SUCCESS)
15989         {
15990             return(TNG_CRITICAL);
15991         }
15992     }
15993
15994     /* It's not very elegant to reuse so much of the code in the different case
15995      * statements, but it's unnecessarily slow to have the switch-case block
15996      * inside the for loops. */
15997     switch(*type)
15998     {
15999     case TNG_CHAR_DATA:
16000         for(i = 0; i < *n_frames; i++)
16001         {
16002             for(j = 0; j < *n_particles; j++)
16003             {
16004                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16005                 for(k = 0; k < *n_values_per_frame; k++)
16006                 {
16007                     len = strlen(data->strings[i][j][k]) + 1;
16008                     (*values)[i][mapping][k].c = malloc(len);
16009                     strncpy((*values)[i][mapping][k].c,
16010                             data->strings[i][j][k], len);
16011                 }
16012             }
16013         }
16014         break;
16015     case TNG_INT_DATA:
16016         size = sizeof(int);
16017         i_step = (*n_particles) * (*n_values_per_frame);
16018         for(i = 0; i < *n_frames; i++)
16019         {
16020             for(j = 0; j < *n_particles; j++)
16021             {
16022                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16023                 for(k = 0; k < *n_values_per_frame; k++)
16024                 {
16025                     (*values)[i][mapping][k].i = *(int *)
16026                                                  ((char *)data->values + size *
16027                                                  (i * i_step + j *
16028                                                   (*n_values_per_frame) + k));
16029                 }
16030             }
16031         }
16032         break;
16033     case TNG_FLOAT_DATA:
16034         size = sizeof(float);
16035         i_step = (*n_particles) * (*n_values_per_frame);
16036         for(i = 0; i < *n_frames; i++)
16037         {
16038             for(j = 0; j < *n_particles; j++)
16039             {
16040                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16041                 for(k = 0; k < *n_values_per_frame; k++)
16042                 {
16043                     (*values)[i][mapping][k].f = *(float *)
16044                                                  ((char *)data->values + size *
16045                                                  (i * i_step + j *
16046                                                   (*n_values_per_frame) + k));
16047                 }
16048             }
16049         }
16050         break;
16051     case TNG_DOUBLE_DATA:
16052     default:
16053         size = sizeof(double);
16054         i_step = (*n_particles) * (*n_values_per_frame);
16055         for(i = 0; i < *n_frames; i++)
16056         {
16057             for(j = 0; j < *n_particles; j++)
16058             {
16059                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16060                 for(k = 0; k < *n_values_per_frame; k++)
16061                 {
16062                     (*values)[i][mapping][k].d = *(double *)
16063                                                  ((char *)data->values + size *
16064                                                  (i * i_step + j *
16065                                                   (*n_values_per_frame) + k));
16066                 }
16067             }
16068         }
16069     }
16070
16071     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16072
16073     return(TNG_SUCCESS);
16074 }
16075
16076 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16077                 (tng_trajectory_t tng_data,
16078                  const int64_t block_id,
16079                  void **values,
16080                  int64_t *n_frames,
16081                  int64_t *stride_length,
16082                  int64_t *n_particles,
16083                  int64_t *n_values_per_frame,
16084                  char *type)
16085 {
16086     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16087     int64_t block_index;
16088     int size;
16089     tng_particle_data_t data;
16090     tng_trajectory_frame_set_t frame_set;
16091     tng_gen_block_t block;
16092     void *temp;
16093     char block_type_flag;
16094     tng_function_status stat;
16095
16096     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16097     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16098     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16099     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16100     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16101
16102     frame_set = &tng_data->current_trajectory_frame_set;
16103
16104     block_index = -1;
16105     data = 0;
16106
16107     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16108     {
16109         tng_block_init(&block);
16110         file_pos = ftell(tng_data->input_file);
16111         /* Read all blocks until next frame set block */
16112         stat = tng_block_header_read(tng_data, block);
16113         while(file_pos < tng_data->input_file_len &&
16114                 stat != TNG_CRITICAL &&
16115                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16116                 block->id != -1)
16117         {
16118             /* Use hash by default */
16119             stat = tng_block_read_next(tng_data, block,
16120                                     TNG_USE_HASH);
16121             if(stat != TNG_CRITICAL)
16122             {
16123                 file_pos = ftell(tng_data->input_file);
16124                 if(file_pos < tng_data->input_file_len)
16125                 {
16126                     stat = tng_block_header_read(tng_data, block);
16127                 }
16128             }
16129         }
16130         tng_block_destroy(&block);
16131         if(stat == TNG_CRITICAL)
16132         {
16133             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16134                     file_pos, __FILE__, __LINE__);
16135             return(stat);
16136         }
16137
16138         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16139         {
16140             data = &frame_set->tr_particle_data[i];
16141             if(data->block_id == block_id)
16142             {
16143                 block_index = i;
16144                 break;
16145             }
16146         }
16147         if(block_index < 0)
16148         {
16149             return(TNG_FAILURE);
16150         }
16151     }
16152
16153     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16154     {
16155         block_type_flag = TNG_TRAJECTORY_BLOCK;
16156     }
16157     else
16158     {
16159         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16160     }
16161
16162    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16163       tng_data->var_num_atoms_flag)
16164     {
16165         *n_particles = frame_set->n_particles;
16166     }
16167     else
16168     {
16169         *n_particles = tng_data->n_particles;
16170     }
16171
16172     *type = data->datatype;
16173
16174     switch(*type)
16175     {
16176     case TNG_CHAR_DATA:
16177         return(TNG_FAILURE);
16178     case TNG_INT_DATA:
16179         size = sizeof(int64_t);
16180         break;
16181     case TNG_FLOAT_DATA:
16182         size = sizeof(float);
16183         break;
16184     case TNG_DOUBLE_DATA:
16185     default:
16186         size = sizeof(double);
16187     }
16188
16189     *n_frames = tng_max_i64(1, data->n_frames);
16190     *n_values_per_frame = data->n_values_per_frame;
16191     *stride_length = data->stride_length;
16192
16193     n_frames_div = (*n_frames % *stride_length) ?
16194                    *n_frames / *stride_length + 1:
16195                    *n_frames / *stride_length;
16196
16197     data_size = n_frames_div * size * (*n_particles) *
16198                 (*n_values_per_frame);
16199
16200     temp = realloc(*values, data_size);
16201     if(!temp)
16202     {
16203         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16204                data_size, __FILE__, __LINE__);
16205         free(*values);
16206         *values = 0;
16207         return(TNG_CRITICAL);
16208     }
16209
16210     *values = temp;
16211
16212     if(frame_set->n_mapping_blocks <= 0)
16213     {
16214         memcpy(*values, data->values, data_size);
16215     }
16216     else
16217     {
16218         i_step = (*n_particles) * (*n_values_per_frame);
16219         for(i = 0; i < *n_frames; i++)
16220         {
16221             for(j = 0; j < *n_particles; j++)
16222             {
16223                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16224                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16225                        (*n_values_per_frame)),
16226                        (char *)data->values + size *
16227                        (i * i_step + j * (*n_values_per_frame)),
16228                        size * (*n_values_per_frame));
16229             }
16230         }
16231     }
16232
16233     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16234
16235     return(TNG_SUCCESS);
16236 }
16237
16238 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16239                 (tng_trajectory_t tng_data,
16240                  const int64_t block_id,
16241                  const int64_t start_frame_nr,
16242                  const int64_t end_frame_nr,
16243                  const char hash_mode,
16244                  union data_values ****values,
16245                  int64_t *n_particles,
16246                  int64_t *n_values_per_frame,
16247                  char *type)
16248 {
16249     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16250     int64_t first_frame, block_index;
16251     int size;
16252     size_t len;
16253     tng_particle_data_t data;
16254     tng_trajectory_frame_set_t frame_set;
16255     tng_gen_block_t block;
16256     char block_type_flag;
16257     tng_function_status stat;
16258
16259     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16260     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16261     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16262     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16263     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16264
16265     block_index = -1;
16266
16267     frame_set = &tng_data->current_trajectory_frame_set;
16268     first_frame = frame_set->first_frame;
16269
16270     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16271     if(stat != TNG_SUCCESS)
16272     {
16273         return(stat);
16274     }
16275
16276     /* Do not re-read the frame set. */
16277     if(first_frame != frame_set->first_frame ||
16278        frame_set->n_particle_data_blocks <= 0)
16279     {
16280         tng_block_init(&block);
16281         file_pos = ftell(tng_data->input_file);
16282         /* Read all blocks until next frame set block */
16283         stat = tng_block_header_read(tng_data, block);
16284         while(file_pos < tng_data->input_file_len &&
16285                 stat != TNG_CRITICAL &&
16286                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16287                 block->id != -1)
16288         {
16289             stat = tng_block_read_next(tng_data, block,
16290                                     hash_mode);
16291             if(stat != TNG_CRITICAL)
16292             {
16293                 file_pos = ftell(tng_data->input_file);
16294                 if(file_pos < tng_data->input_file_len)
16295                 {
16296                     stat = tng_block_header_read(tng_data, block);
16297                 }
16298             }
16299         }
16300         tng_block_destroy(&block);
16301         if(stat == TNG_CRITICAL)
16302         {
16303             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16304                     file_pos, __FILE__, __LINE__);
16305             return(stat);
16306         }
16307     }
16308
16309     /* See if there is already a data block of this ID.
16310      * Start checking the last read frame set */
16311     for(i = frame_set->n_particle_data_blocks; i-- ;)
16312     {
16313         data = &frame_set->tr_particle_data[i];
16314         if(data->block_id == block_id)
16315         {
16316             block_index = i;
16317             block_type_flag = TNG_TRAJECTORY_BLOCK;
16318             break;
16319         }
16320     }
16321
16322     if(block_index < 0)
16323     {
16324         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16325                 block_id, __FILE__, __LINE__);
16326         return(TNG_FAILURE);
16327     }
16328
16329     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16330        tng_data->var_num_atoms_flag)
16331     {
16332         *n_particles = frame_set->n_particles;
16333     }
16334     else
16335     {
16336         *n_particles = tng_data->n_particles;
16337     }
16338
16339     n_frames = end_frame_nr - start_frame_nr + 1;
16340     *n_values_per_frame = data->n_values_per_frame;
16341     *type = data->datatype;
16342
16343     if(*values == 0)
16344     {
16345         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16346                                          *n_particles, *n_values_per_frame,
16347                                          *type)
16348             != TNG_SUCCESS)
16349         {
16350             return(TNG_CRITICAL);
16351         }
16352     }
16353
16354     current_frame_pos = start_frame_nr - frame_set->first_frame;
16355     /* It's not very elegant to reuse so much of the code in the different case
16356      * statements, but it's unnecessarily slow to have the switch-case block
16357      * inside the for loops. */
16358     switch(*type)
16359     {
16360     case TNG_CHAR_DATA:
16361         for(i=0; i<n_frames; i++)
16362         {
16363             if(current_frame_pos == frame_set->n_frames)
16364             {
16365                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16366                 if(stat != TNG_SUCCESS)
16367                 {
16368                     return(stat);
16369                 }
16370                 current_frame_pos = 0;
16371             }
16372             for(j = 0; j < *n_particles; j++)
16373             {
16374                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16375                 for(k = 0; k < *n_values_per_frame; k++)
16376                 {
16377                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16378                     (*values)[i][mapping][k].c = malloc(len);
16379                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16380                 }
16381             }
16382             current_frame_pos++;
16383         }
16384         break;
16385     case TNG_INT_DATA:
16386         size = sizeof(int);
16387         i_step = (*n_particles) * (*n_values_per_frame);
16388         for(i=0; i<n_frames; i++)
16389         {
16390             if(current_frame_pos == frame_set->n_frames)
16391             {
16392                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16393                 if(stat != TNG_SUCCESS)
16394                 {
16395                     return(stat);
16396                 }
16397                 current_frame_pos = 0;
16398             }
16399             for(j = 0; j < *n_particles; j++)
16400             {
16401                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16402                 for(k = 0; k < *n_values_per_frame; k++)
16403                 {
16404                     (*values)[i][mapping][k].i = *(int *)
16405                                                  ((char *)data->values + size *
16406                                                   (current_frame_pos *
16407                                                    i_step + j *
16408                                                    (*n_values_per_frame) + k));
16409                 }
16410             }
16411             current_frame_pos++;
16412         }
16413         break;
16414     case TNG_FLOAT_DATA:
16415         size = sizeof(float);
16416         i_step = (*n_particles) * (*n_values_per_frame);
16417         for(i=0; i<n_frames; i++)
16418         {
16419             if(current_frame_pos == frame_set->n_frames)
16420             {
16421                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16422                 if(stat != TNG_SUCCESS)
16423                 {
16424                     return(stat);
16425                 }
16426                 current_frame_pos = 0;
16427             }
16428             for(j=0; j<*n_particles; j++)
16429             {
16430                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16431                 for(k=0; k<*n_values_per_frame; k++)
16432                 {
16433                     (*values)[i][mapping][k].f = *(float *)
16434                                                  ((char *)data->values + size *
16435                                                   (current_frame_pos *
16436                                                    i_step + j *
16437                                                    (*n_values_per_frame) + k));
16438                 }
16439             }
16440             current_frame_pos++;
16441         }
16442         break;
16443     case TNG_DOUBLE_DATA:
16444     default:
16445         size = sizeof(double);
16446         i_step = (*n_particles) * (*n_values_per_frame);
16447         for(i=0; i<n_frames; i++)
16448         {
16449             if(current_frame_pos == frame_set->n_frames)
16450             {
16451                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16452                 if(stat != TNG_SUCCESS)
16453                 {
16454                     return(stat);
16455                 }
16456                 current_frame_pos = 0;
16457             }
16458             for(j=0; j<*n_particles; j++)
16459             {
16460                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16461                 for(k=0; k<*n_values_per_frame; k++)
16462                 {
16463                     (*values)[i][mapping][k].d = *(double *)
16464                                                  ((char *)data->values + size *
16465                                                   (current_frame_pos *
16466                                                    i_step + j *
16467                                                    (*n_values_per_frame) + k));
16468                 }
16469             }
16470             current_frame_pos++;
16471         }
16472     }
16473
16474     data->last_retrieved_frame = end_frame_nr;
16475
16476     return(TNG_SUCCESS);
16477 }
16478
16479 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16480                 (tng_trajectory_t tng_data,
16481                  const int64_t block_id,
16482                  const int64_t start_frame_nr,
16483                  const int64_t end_frame_nr,
16484                  const char hash_mode,
16485                  void **values,
16486                  int64_t *n_particles,
16487                  int64_t *stride_length,
16488                  int64_t *n_values_per_frame,
16489                  char *type)
16490 {
16491     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16492     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16493     int size;
16494     tng_trajectory_frame_set_t frame_set;
16495     tng_particle_data_t p_data;
16496     tng_gen_block_t block;
16497     void *current_values = 0, *temp;
16498     tng_function_status stat;
16499
16500     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16501     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16502     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16503     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16504     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16505     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16506
16507     frame_set = &tng_data->current_trajectory_frame_set;
16508     first_frame = frame_set->first_frame;
16509
16510     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16511     if(stat != TNG_SUCCESS)
16512     {
16513         return(stat);
16514     }
16515
16516     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16517     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16518     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16519     if(first_frame != frame_set->first_frame ||
16520        stat != TNG_SUCCESS)
16521     {
16522         tng_block_init(&block);
16523         if(stat != TNG_SUCCESS)
16524         {
16525             fseek(tng_data->input_file,
16526                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
16527                   SEEK_SET);
16528             stat = tng_block_header_read(tng_data, block);
16529             if(stat != TNG_SUCCESS)
16530             {
16531                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16532                         __FILE__, __LINE__);
16533                 return(stat);
16534             }
16535
16536             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16537         }
16538         file_pos = ftell(tng_data->input_file);
16539         /* Read until next frame set block */
16540         stat = tng_block_header_read(tng_data, block);
16541         while(file_pos < tng_data->input_file_len &&
16542             stat != TNG_CRITICAL &&
16543             block->id != TNG_TRAJECTORY_FRAME_SET &&
16544             block->id != -1)
16545         {
16546             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16547             {
16548                 stat = tng_block_read_next(tng_data, block,
16549                                         hash_mode);
16550                 if(stat != TNG_CRITICAL)
16551                 {
16552                     file_pos = ftell(tng_data->input_file);
16553                     if(file_pos < tng_data->input_file_len)
16554                     {
16555                         stat = tng_block_header_read(tng_data, block);
16556                     }
16557                 }
16558             }
16559             else
16560             {
16561                 file_pos += block->block_contents_size + block->header_contents_size;
16562                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
16563                 if(file_pos < tng_data->input_file_len)
16564                 {
16565                     stat = tng_block_header_read(tng_data, block);
16566                 }
16567             }
16568         }
16569         tng_block_destroy(&block);
16570         if(stat == TNG_CRITICAL)
16571         {
16572             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16573                     file_pos, __FILE__, __LINE__);
16574             return(stat);
16575         }
16576     }
16577     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16578     if(stat != TNG_SUCCESS)
16579     {
16580         return(stat);
16581     }
16582
16583     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16584                                         &n_frames, stride_length, n_particles,
16585                                         n_values_per_frame, type);
16586
16587     if(stat != TNG_SUCCESS || *n_particles == 0)
16588     {
16589         if(current_values)
16590         {
16591             free(current_values);
16592         }
16593         return(stat);
16594     }
16595
16596     if(n_frames == 1 && n_frames < frame_set->n_frames)
16597     {
16598         tot_n_frames = 1;
16599     }
16600     else
16601     {
16602         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16603     }
16604
16605     switch(*type)
16606     {
16607     case TNG_CHAR_DATA:
16608         return(TNG_FAILURE);
16609     case TNG_INT_DATA:
16610         size = sizeof(int64_t);
16611         break;
16612     case TNG_FLOAT_DATA:
16613         size = sizeof(float);
16614         break;
16615     case TNG_DOUBLE_DATA:
16616     default:
16617         size = sizeof(double);
16618     }
16619
16620     n_frames_div = (tot_n_frames % *stride_length) ?
16621                  tot_n_frames / *stride_length + 1:
16622                  tot_n_frames / *stride_length;
16623
16624     data_size = n_frames_div * size * (*n_particles) *
16625                 (*n_values_per_frame);
16626
16627     temp = realloc(*values, data_size);
16628     if(!temp)
16629     {
16630         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16631                data_size, __FILE__, __LINE__);
16632         free(*values);
16633         *values = 0;
16634         return(TNG_CRITICAL);
16635     }
16636
16637     *values = temp;
16638
16639     if( n_frames == 1 && n_frames < frame_set->n_frames)
16640     {
16641         memcpy(*values, current_values, size * (*n_particles) *
16642                (*n_values_per_frame));
16643     }
16644     else
16645     {
16646         current_frame_pos = start_frame_nr - frame_set->first_frame;
16647
16648         frame_size = size * (*n_particles) * (*n_values_per_frame);
16649
16650         last_frame_pos = tng_min_i64(n_frames,
16651                                      end_frame_nr - start_frame_nr);
16652
16653         n_frames_div = current_frame_pos / *stride_length;
16654         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16655                        last_frame_pos / *stride_length + 1:
16656                        last_frame_pos / *stride_length;
16657         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16658
16659         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16660                n_frames_div_2 * frame_size);
16661
16662         current_frame_pos += n_frames - current_frame_pos;
16663
16664         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16665         {
16666             stat = tng_frame_set_read_next(tng_data, hash_mode);
16667             if(stat != TNG_SUCCESS)
16668             {
16669                 if(current_values)
16670                 {
16671                     free(current_values);
16672                 }
16673                 free(*values);
16674                 *values = 0;
16675                 return(stat);
16676             }
16677
16678             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16679                                                 &n_frames, stride_length, n_particles,
16680                                                 n_values_per_frame, type);
16681
16682             if(stat != TNG_SUCCESS)
16683             {
16684                 if(current_values)
16685                 {
16686                     free(current_values);
16687                 }
16688                 free(*values);
16689                 *values = 0;
16690                 return(stat);
16691             }
16692
16693             last_frame_pos = tng_min_i64(n_frames,
16694                                          end_frame_nr - current_frame_pos);
16695
16696             n_frames_div = current_frame_pos / *stride_length;
16697             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16698                            last_frame_pos / *stride_length + 1:
16699                            last_frame_pos / *stride_length;
16700             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16701
16702             memcpy(((char *)*values) + n_frames_div * frame_size,
16703                    current_values,
16704                    n_frames_div_2 * frame_size);
16705
16706             current_frame_pos += n_frames;
16707         }
16708     }
16709
16710     if(current_values)
16711     {
16712         free(current_values);
16713     }
16714
16715     p_data->last_retrieved_frame = end_frame_nr;
16716
16717     return(TNG_SUCCESS);
16718 }
16719
16720 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16721                 (const tng_trajectory_t tng_data,
16722                  const int64_t block_id,
16723                  int64_t frame,
16724                  int64_t *stride_length)
16725 {
16726     tng_function_status stat;
16727     tng_non_particle_data_t np_data;
16728     tng_particle_data_t p_data;
16729     long orig_file_pos, file_pos;
16730     int is_particle_data;
16731
16732     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16733     {
16734         frame = 0;
16735     }
16736
16737     if(frame >= 0)
16738     {
16739         stat = tng_frame_set_of_frame_find(tng_data, frame);
16740         if(stat != TNG_SUCCESS)
16741         {
16742             return(stat);
16743         }
16744     }
16745     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16746     stat = tng_data_find(tng_data, block_id, &np_data);
16747     if(stat != TNG_SUCCESS)
16748     {
16749         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16750         if(stat != TNG_SUCCESS)
16751         {
16752             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16753             /* If no specific frame was required read until this data block is found */
16754             if(frame < 0)
16755             {
16756                 file_pos = ftell(tng_data->input_file);
16757                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16758                 {
16759                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16760                     file_pos = ftell(tng_data->input_file);
16761                 }
16762             }
16763             if(stat != TNG_SUCCESS)
16764             {
16765                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16766
16767                 return(stat);
16768             }
16769             stat = tng_data_find(tng_data, block_id, &np_data);
16770             if(stat != TNG_SUCCESS)
16771             {
16772                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16773                 if(stat != TNG_SUCCESS)
16774                 {
16775                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16776
16777                     return(stat);
16778                 }
16779                 else
16780                 {
16781                     is_particle_data = 1;
16782                 }
16783             }
16784             else
16785             {
16786                 is_particle_data = 0;
16787             }
16788         }
16789         else
16790         {
16791             is_particle_data = 1;
16792         }
16793     }
16794     else
16795     {
16796         is_particle_data = 0;
16797     }
16798     if(is_particle_data)
16799     {
16800         *stride_length = p_data->stride_length;
16801     }
16802     else
16803     {
16804         *stride_length = np_data->stride_length;
16805     }
16806     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16807
16808     return(TNG_SUCCESS);
16809 }
16810
16811 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16812                 (const tng_trajectory_t tng_data,
16813                  char *time)
16814 {
16815     struct tm *time_data;
16816     time_t secs;
16817
16818     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16819     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16820
16821     secs = tng_data->time;
16822
16823     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16824     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16825              "%4d-%02d-%02d %02d:%02d:%02d",
16826              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16827              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16828
16829     return(TNG_SUCCESS);
16830 }
16831
16832
16833 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16834                 (const char *filename,
16835                  const char mode,
16836                  tng_trajectory_t *tng_data_p)
16837 {
16838     tng_function_status stat;
16839
16840     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16841
16842     if(mode != 'r' && mode != 'w' && mode != 'a')
16843     {
16844         return(TNG_FAILURE);
16845     }
16846
16847     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16848     {
16849         tng_trajectory_destroy(tng_data_p);
16850         return(TNG_CRITICAL);
16851     }
16852
16853     if(mode == 'r' || mode == 'a')
16854     {
16855         tng_input_file_set(*tng_data_p, filename);
16856
16857         /* Read the file headers */
16858         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16859
16860         tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16861     }
16862
16863     if(mode == 'w')
16864     {
16865         tng_output_file_set(*tng_data_p, filename);
16866     }
16867     else if(mode == 'a')
16868     {
16869         if((*tng_data_p)->output_file)
16870         {
16871             fclose((*tng_data_p)->output_file);
16872         }
16873         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
16874         fseek((*tng_data_p)->input_file,
16875                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16876                 SEEK_SET);
16877
16878         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16879         if(stat != TNG_SUCCESS)
16880         {
16881             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16882                    __FILE__, __LINE__);
16883         }
16884         (*tng_data_p)->output_file = 0;
16885
16886         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16887         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16888         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16889         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16890         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16891         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16892         if((*tng_data_p)->input_file)
16893         {
16894             fclose((*tng_data_p)->input_file);
16895             (*tng_data_p)->input_file = 0;
16896         }
16897         if((*tng_data_p)->input_file_path)
16898         {
16899             free((*tng_data_p)->input_file_path);
16900             (*tng_data_p)->input_file_path = 0;
16901         }
16902         tng_output_append_file_set(*tng_data_p, filename);
16903
16904         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16905     }
16906
16907     return(TNG_SUCCESS);
16908 }
16909
16910 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
16911                 (tng_trajectory_t *tng_data_p)
16912 {
16913     tng_trajectory_frame_set_t frame_set;
16914
16915     if(tng_data_p == 0)
16916     {
16917         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
16918                __FILE__, __LINE__);
16919         return(TNG_FAILURE);
16920     }
16921
16922     if(*tng_data_p == 0)
16923     {
16924         return(TNG_SUCCESS);
16925     }
16926
16927     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
16928
16929     if(frame_set->n_unwritten_frames > 0)
16930     {
16931         frame_set->n_frames = frame_set->n_unwritten_frames;
16932         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
16933     }
16934
16935     return(tng_trajectory_destroy(tng_data_p));
16936 }
16937
16938 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
16939                 (tng_trajectory_t tng_data,
16940                  const int64_t frame_nr,
16941                  double *time)
16942 {
16943     int64_t first_frame;
16944     tng_trajectory_frame_set_t frame_set;
16945     tng_function_status stat;
16946
16947     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16948     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16949
16950     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
16951     if(stat != TNG_SUCCESS)
16952     {
16953         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
16954                frame_nr, __FILE__, __LINE__);
16955         return(stat);
16956     }
16957
16958     frame_set = &tng_data->current_trajectory_frame_set;
16959     first_frame = frame_set->first_frame;
16960
16961     if(tng_data->time_per_frame <= 0)
16962     {
16963         return(TNG_FAILURE);
16964     }
16965
16966     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
16967
16968     return(TNG_SUCCESS);
16969 }
16970
16971 /*
16972 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
16973                 (tng_trajectory_t tng_data,
16974                  int64_t *n_mols,
16975                  int64_t **molecule_cnt_list,
16976                  tng_molecule_t *mols)
16977 {
16978     tng_trajectory_frame_set_t frame_set;
16979
16980     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16981     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
16982
16983     *n_mols = tng_data->n_molecules;
16984
16985     frame_set = &tng_data->current_trajectory_frame_set;
16986     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
16987     {
16988         *molecule_cnt_list = frame_set->molecule_cnt_list;
16989     }
16990     else
16991     {
16992         *molecule_cnt_list = tng_data->molecule_cnt_list;
16993     }
16994
16995     *mols = tng_data->molecules;
16996
16997     return(TNG_SUCCESS);
16998 }
16999 */
17000 /*
17001 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17002                 (tng_trajectory_t tng_data,
17003                  const char *name,
17004                  const int64_t cnt,
17005                  tng_molecule_t *mol)
17006 {
17007     tng_function_status stat;
17008
17009     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17010     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17011
17012     stat = tng_molecule_add(tng_data, name, mol);
17013     if(stat != TNG_SUCCESS)
17014     {
17015         return(stat);
17016     }
17017     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17018
17019     return(stat);
17020 }
17021 */
17022 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17023                 (tng_trajectory_t tng_data,
17024                  const tng_molecule_t mol,
17025                  int64_t *n_particles,
17026                  char ***names,
17027                  char ***types,
17028                  char ***res_names,
17029                  int64_t **res_ids,
17030                  char ***chain_names,
17031                  int64_t **chain_ids)
17032 {
17033     tng_atom_t atom;
17034     tng_residue_t res;
17035     tng_chain_t chain;
17036     int64_t i;
17037     (void)tng_data;
17038
17039     *n_particles = mol->n_atoms;
17040
17041     *names = malloc(sizeof(char *) * *n_particles);
17042     *types = malloc(sizeof(char *) * *n_particles);
17043     *res_names = malloc(sizeof(char *) * *n_particles);
17044     *chain_names = malloc(sizeof(char *) * *n_particles);
17045     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17046     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17047
17048     for(i = 0; i < *n_particles; i++)
17049     {
17050         atom = &mol->atoms[i];
17051         res = atom->residue;
17052         chain = res->chain;
17053         (*names)[i] = malloc(strlen(atom->name));
17054         strcpy(*names[i], atom->name);
17055         (*types)[i] = malloc(strlen(atom->atom_type));
17056         strcpy(*types[i], atom->atom_type);
17057         (*res_names)[i] = malloc(strlen(res->name));
17058         strcpy(*res_names[i], res->name);
17059         (*chain_names)[i] = malloc(strlen(chain->name));
17060         strcpy(*chain_names[i], chain->name);
17061         (*res_ids)[i] = res->id;
17062         (*chain_ids)[i] = chain->id;
17063     }
17064
17065     return(TNG_SUCCESS);
17066 }
17067
17068 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17069                 (tng_trajectory_t tng_data,
17070                  tng_molecule_t mol,
17071                  const int64_t n_particles,
17072                  const char **names,
17073                  const char **types,
17074                  const char **res_names,
17075                  const int64_t *res_ids,
17076                  const char **chain_names,
17077                  const int64_t *chain_ids)
17078 {
17079     int64_t i;
17080     tng_chain_t chain;
17081     tng_residue_t residue;
17082     tng_atom_t atom;
17083     tng_function_status stat;
17084
17085     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17086     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17087     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17088     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17089     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17090     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17091     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17092
17093     for(i = 0; i < n_particles; i++)
17094     {
17095         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17096            &chain) == TNG_FAILURE)
17097         {
17098             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17099                                           &chain);
17100             if(stat != TNG_SUCCESS)
17101             {
17102                 return(stat);
17103             }
17104         }
17105         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17106            &residue) == TNG_FAILURE)
17107         {
17108             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17109                                          &residue);
17110             if(stat != TNG_SUCCESS)
17111             {
17112                 return(stat);
17113             }
17114         }
17115         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17116         if(stat != TNG_SUCCESS)
17117         {
17118             return(stat);
17119         }
17120     }
17121     return(TNG_SUCCESS);
17122 }
17123
17124 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17125                 (tng_trajectory_t tng_data,
17126                  float **positions, int64_t *stride_length)
17127 {
17128     int64_t n_frames, n_particles, n_values_per_frame;
17129     char type;
17130     tng_function_status stat;
17131
17132     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17133     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17134     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17135
17136     stat = tng_num_frames_get(tng_data, &n_frames);
17137     if(stat != TNG_SUCCESS)
17138     {
17139         return(stat);
17140     }
17141
17142     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17143                                                  0, n_frames - 1, TNG_USE_HASH,
17144                                                  (void **)positions,
17145                                                  &n_particles,
17146                                                  stride_length,
17147                                                  &n_values_per_frame,
17148                                                  &type);
17149
17150     return(stat);
17151 }
17152
17153 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17154                 (tng_trajectory_t tng_data,
17155                  float **velocities, int64_t *stride_length)
17156 {
17157     int64_t n_frames, n_particles, n_values_per_frame;
17158     char type;
17159     tng_function_status stat;
17160
17161     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17162     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17163     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17164
17165     stat = tng_num_frames_get(tng_data, &n_frames);
17166     if(stat != TNG_SUCCESS)
17167     {
17168         return(stat);
17169     }
17170
17171     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17172                                                  0, n_frames - 1, TNG_USE_HASH,
17173                                                  (void **)velocities,
17174                                                  &n_particles,
17175                                                  stride_length,
17176                                                  &n_values_per_frame,
17177                                                  &type);
17178
17179     return(stat);
17180 }
17181
17182 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17183                 (tng_trajectory_t tng_data,
17184                  float **forces, int64_t *stride_length)
17185 {
17186     int64_t n_frames, n_particles, n_values_per_frame;
17187     char type;
17188     tng_function_status stat;
17189
17190     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17191     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17192     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17193
17194     stat = tng_num_frames_get(tng_data, &n_frames);
17195     if(stat != TNG_SUCCESS)
17196     {
17197         return(stat);
17198     }
17199
17200     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17201                                                  0, n_frames - 1, TNG_USE_HASH,
17202                                                  (void **)forces,
17203                                                  &n_particles,
17204                                                  stride_length,
17205                                                  &n_values_per_frame,
17206                                                  &type);
17207
17208     return(stat);
17209 }
17210
17211 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17212                 (tng_trajectory_t tng_data,
17213                  float **box_shape,
17214                  int64_t *stride_length)
17215 {
17216     int64_t n_frames, n_values_per_frame;
17217     char type;
17218     tng_function_status stat;
17219
17220     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17221     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17222     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17223
17224     stat = tng_num_frames_get(tng_data, &n_frames);
17225     if(stat != TNG_SUCCESS)
17226     {
17227         return(stat);
17228     }
17229
17230     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17231                                         0, n_frames - 1, TNG_USE_HASH,
17232                                         (void **)box_shape,
17233                                         stride_length,
17234                                         &n_values_per_frame,
17235                                         &type);
17236
17237     return(stat);
17238 }
17239
17240 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17241                 (tng_trajectory_t tng_data,
17242                  const int64_t block_id,
17243                  void **values,
17244                  char *data_type,
17245                  int64_t *retrieved_frame_number,
17246                  double *retrieved_time)
17247 {
17248     tng_trajectory_frame_set_t frame_set;
17249     tng_particle_data_t data = 0;
17250     tng_function_status stat;
17251     int size;
17252     int64_t i, data_size, n_particles;
17253     void *temp;
17254     long file_pos;
17255
17256     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17257     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17258     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17259     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17260     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17261
17262     frame_set = &tng_data->current_trajectory_frame_set;
17263
17264     stat = tng_particle_data_find(tng_data, block_id, &data);
17265     if(stat != TNG_SUCCESS)
17266     {
17267         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17268         file_pos = ftell(tng_data->input_file);
17269         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17270         {
17271             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17272             file_pos = ftell(tng_data->input_file);
17273         }
17274         if(stat != TNG_SUCCESS)
17275         {
17276             return(stat);
17277         }
17278         stat = tng_particle_data_find(tng_data, block_id, &data);
17279         if(stat != TNG_SUCCESS)
17280         {
17281             return(stat);
17282         }
17283     }
17284     if(data->last_retrieved_frame < 0)
17285     {
17286         fseek(tng_data->input_file,
17287               (long)tng_data->first_trajectory_frame_set_input_file_pos,
17288               SEEK_SET);
17289         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17290         if(stat != TNG_SUCCESS)
17291         {
17292             return(stat);
17293         }
17294         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17295         if(stat != TNG_SUCCESS)
17296         {
17297             return(stat);
17298         }
17299
17300         i = data->first_frame_with_data;
17301     }
17302     else
17303     {
17304         if(data->n_frames == 1)
17305         {
17306             i = data->last_retrieved_frame + 1;
17307         }
17308         else
17309         {
17310             i = data->last_retrieved_frame + data->stride_length;
17311         }
17312         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17313         {
17314             stat = tng_frame_set_of_frame_find(tng_data, i);
17315             if(stat != TNG_SUCCESS)
17316             {
17317                 /* If the frame set search found the frame set after the starting
17318                  * frame set there is a gap in the frame sets. So, even if the frame
17319                  * was not found the next frame with data is still in the found
17320                  * frame set. */
17321                 if(stat == TNG_CRITICAL)
17322                 {
17323                     return(stat);
17324                 }
17325                 i = frame_set->first_frame;
17326             }
17327         }
17328         if(data->last_retrieved_frame < frame_set->first_frame)
17329         {
17330             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17331             if(stat != TNG_SUCCESS)
17332             {
17333                 return(stat);
17334             }
17335         }
17336     }
17337     data->last_retrieved_frame = i;
17338     *retrieved_frame_number = i;
17339     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17340     {
17341         *retrieved_time = frame_set->first_frame_time +
17342                         (i - frame_set->first_frame) *
17343                         tng_data->time_per_frame;
17344     }
17345     else
17346     {
17347         *retrieved_time = 0;
17348     }
17349
17350     if(data->stride_length > 1)
17351     {
17352         i = (i - data->first_frame_with_data) / data->stride_length;
17353     }
17354     else
17355     {
17356         i = (i - frame_set->first_frame);
17357     }
17358
17359     tng_num_particles_get(tng_data, &n_particles);
17360
17361     *data_type = data->datatype;
17362
17363     switch(*data_type)
17364     {
17365     case TNG_CHAR_DATA:
17366         return(TNG_FAILURE);
17367     case TNG_INT_DATA:
17368         size = sizeof(int64_t);
17369         break;
17370     case TNG_FLOAT_DATA:
17371         size = sizeof(float);
17372         break;
17373     case TNG_DOUBLE_DATA:
17374     default:
17375         size = sizeof(double);
17376     }
17377
17378     data_size = size * n_particles * data->n_values_per_frame;
17379
17380 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17381 //            i, data_size, size, n_particles, data->n_values_per_frame);
17382
17383     temp = realloc(*values, data_size);
17384     if(!temp)
17385     {
17386         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17387                data_size, __FILE__, __LINE__);
17388         free(*values);
17389         *values = 0;
17390         return(TNG_CRITICAL);
17391     }
17392
17393     *values = temp;
17394
17395     memcpy(*values, (char *)data->values + i * data_size, data_size);
17396
17397     return(TNG_SUCCESS);
17398 }
17399
17400 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17401                 (tng_trajectory_t tng_data,
17402                  const int64_t block_id,
17403                  void **values,
17404                  char *data_type,
17405                  int64_t *retrieved_frame_number,
17406                  double *retrieved_time)
17407 {
17408     tng_trajectory_frame_set_t frame_set;
17409     tng_non_particle_data_t data = 0;
17410     tng_function_status stat;
17411     int size;
17412     int64_t i, data_size;
17413     void *temp;
17414     long file_pos;
17415
17416     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17417     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17418     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17419     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17420     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17421
17422     frame_set = &tng_data->current_trajectory_frame_set;
17423
17424     stat = tng_data_find(tng_data, block_id, &data);
17425     if(stat != TNG_SUCCESS)
17426     {
17427         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17428         file_pos = ftell(tng_data->input_file);
17429         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17430         {
17431             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17432             file_pos = ftell(tng_data->input_file);
17433         }
17434         if(stat != TNG_SUCCESS)
17435         {
17436             return(stat);
17437         }
17438         stat = tng_data_find(tng_data, block_id, &data);
17439         if(stat != TNG_SUCCESS)
17440         {
17441             return(stat);
17442         }
17443     }
17444     if(data->last_retrieved_frame < 0)
17445     {
17446         fseek(tng_data->input_file,
17447                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
17448                 SEEK_SET);
17449         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17450         if(stat != TNG_SUCCESS)
17451         {
17452             return(stat);
17453         }
17454         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17455         if(stat != TNG_SUCCESS)
17456         {
17457             return(stat);
17458         }
17459
17460         i = data->first_frame_with_data;
17461     }
17462     else
17463     {
17464         if(data->n_frames == 1)
17465         {
17466             i = data->last_retrieved_frame + 1;
17467         }
17468         else
17469         {
17470             i = data->last_retrieved_frame + data->stride_length;
17471         }
17472         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17473         {
17474             stat = tng_frame_set_of_frame_find(tng_data, i);
17475             if(stat != TNG_SUCCESS)
17476             {
17477                 /* If the frame set search found the frame set after the starting
17478                  * frame set there is a gap in the frame sets. So, even if the frame
17479                  * was not found the next frame with data is still in the found
17480                  * frame set. */
17481                 if(stat == TNG_CRITICAL)
17482                 {
17483                     return(stat);
17484                 }
17485                 i = frame_set->first_frame;
17486             }
17487         }
17488         if(data->last_retrieved_frame < frame_set->first_frame)
17489         {
17490             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17491             if(stat != TNG_SUCCESS)
17492             {
17493                 return(stat);
17494             }
17495         }
17496     }
17497     data->last_retrieved_frame = i;
17498     *retrieved_frame_number = i;
17499     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17500     {
17501         *retrieved_time = frame_set->first_frame_time +
17502                         (i - frame_set->first_frame) *
17503                         tng_data->time_per_frame;
17504     }
17505     else
17506     {
17507         *retrieved_time = 0;
17508     }
17509
17510     if(data->stride_length > 1)
17511     {
17512         i = (i - data->first_frame_with_data) / data->stride_length;
17513     }
17514     else
17515     {
17516         i = (i - frame_set->first_frame);
17517     }
17518
17519     *data_type = data->datatype;
17520
17521     switch(*data_type)
17522     {
17523     case TNG_CHAR_DATA:
17524         return(TNG_FAILURE);
17525     case TNG_INT_DATA:
17526         size = sizeof(int64_t);
17527         break;
17528     case TNG_FLOAT_DATA:
17529         size = sizeof(float);
17530         break;
17531     case TNG_DOUBLE_DATA:
17532     default:
17533         size = sizeof(double);
17534     }
17535
17536     data_size = size * data->n_values_per_frame;
17537
17538     temp = realloc(*values, data_size);
17539     if(!temp)
17540     {
17541         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17542                data_size, __FILE__, __LINE__);
17543         free(*values);
17544         *values = 0;
17545         return(TNG_CRITICAL);
17546     }
17547
17548     *values = temp;
17549
17550     memcpy(*values, (char *)data->values + i * data_size, data_size);
17551
17552     return(TNG_SUCCESS);
17553 }
17554
17555 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17556                 (tng_trajectory_t tng_data,
17557                  const int64_t first_frame,
17558                  const int64_t last_frame,
17559                  float **positions,
17560                  int64_t *stride_length)
17561 {
17562     int64_t n_particles, n_values_per_frame;
17563     char type;
17564     tng_function_status stat;
17565
17566     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17567     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17568     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17569     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17570
17571     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17572                                                  first_frame, last_frame,
17573                                                  TNG_USE_HASH,
17574                                                  (void **)positions,
17575                                                  &n_particles,
17576                                                  stride_length,
17577                                                  &n_values_per_frame,
17578                                                  &type);
17579
17580     return(stat);
17581 }
17582
17583 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17584                 (tng_trajectory_t tng_data,
17585                  const int64_t first_frame,
17586                  const int64_t last_frame,
17587                  float **velocities,
17588                  int64_t *stride_length)
17589 {
17590     int64_t n_particles, n_values_per_frame;
17591     char type;
17592     tng_function_status stat;
17593
17594     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17595     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17596     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17597     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17598
17599     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17600                                                  first_frame, last_frame,
17601                                                  TNG_USE_HASH,
17602                                                  (void **)velocities,
17603                                                  &n_particles,
17604                                                  stride_length,
17605                                                  &n_values_per_frame,
17606                                                  &type);
17607
17608     return(stat);
17609 }
17610
17611 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17612                 (tng_trajectory_t tng_data,
17613                  const int64_t first_frame,
17614                  const int64_t last_frame,
17615                  float **forces,
17616                  int64_t *stride_length)
17617 {
17618     int64_t n_particles, n_values_per_frame;
17619     char type;
17620     tng_function_status stat;
17621
17622     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17623     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17624     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17625     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17626
17627     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17628                                                  first_frame, last_frame,
17629                                                  TNG_USE_HASH,
17630                                                  (void **)forces,
17631                                                  &n_particles,
17632                                                  stride_length,
17633                                                  &n_values_per_frame,
17634                                                  &type);
17635
17636     return(stat);
17637 }
17638
17639 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17640                 (tng_trajectory_t tng_data,
17641                  const int64_t first_frame,
17642                  const int64_t last_frame,
17643                  float **box_shape,
17644                  int64_t *stride_length)
17645 {
17646     int64_t n_values_per_frame;
17647     char type;
17648     tng_function_status stat;
17649
17650     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17651     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17652     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17653     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17654
17655     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17656                                         first_frame, last_frame,
17657                                         TNG_USE_HASH,
17658                                         (void **)box_shape,
17659                                         stride_length,
17660                                         &n_values_per_frame,
17661                                         &type);
17662
17663     return(stat);
17664 }
17665
17666 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17667                 (tng_trajectory_t tng_data,
17668                  const int64_t i,
17669                  const int64_t n_values_per_frame,
17670                  const int64_t block_id,
17671                  const char *block_name,
17672                  const char particle_dependency,
17673                  const char compression)
17674 {
17675     tng_trajectory_frame_set_t frame_set;
17676     tng_particle_data_t p_data;
17677     tng_non_particle_data_t np_data;
17678     int64_t n_particles, n_frames;
17679     tng_function_status stat;
17680
17681     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17682     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17683
17684     if(i <= 0)
17685     {
17686         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17687                i, __FILE__, __LINE__);
17688         return(TNG_FAILURE);
17689     }
17690
17691     frame_set = &tng_data->current_trajectory_frame_set;
17692
17693     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17694     {
17695         n_frames = tng_data->frame_set_n_frames;
17696
17697         stat = tng_frame_set_new(tng_data, 0, n_frames);
17698         if(stat != TNG_SUCCESS)
17699         {
17700             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17701                 __LINE__);
17702             return(stat);
17703         }
17704     }
17705     else
17706     {
17707         n_frames = frame_set->n_frames;
17708     }
17709
17710     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17711     {
17712         tng_num_particles_get(tng_data, &n_particles);
17713         if(n_particles <= 0)
17714         {
17715             return(TNG_FAILURE);
17716         }
17717
17718         if(tng_particle_data_find(tng_data, block_id, &p_data)
17719         != TNG_SUCCESS)
17720         {
17721             stat = tng_particle_data_block_add(tng_data, block_id,
17722                                                block_name,
17723                                                TNG_FLOAT_DATA,
17724                                                TNG_TRAJECTORY_BLOCK,
17725                                                n_frames, n_values_per_frame, i,
17726                                                0, n_particles,
17727                                                compression, 0);
17728             if(stat != TNG_SUCCESS)
17729             {
17730                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17731                        __FILE__, __LINE__);
17732                 return(stat);
17733             }
17734             p_data = &frame_set->tr_particle_data[frame_set->
17735                                                   n_particle_data_blocks - 1];
17736             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17737                                                   i, n_particles,
17738                                                   n_values_per_frame);
17739             if(stat != TNG_SUCCESS)
17740             {
17741                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17742                        __FILE__, __LINE__);
17743                 return(stat);
17744             }
17745         }
17746         else
17747         {
17748             if(p_data->stride_length != i)
17749             {
17750                 p_data->stride_length = i;
17751                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17752                                                       i, n_particles,
17753                                                       n_values_per_frame);
17754                 if(stat != TNG_SUCCESS)
17755                 {
17756                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17757                            __FILE__, __LINE__);
17758                     return(stat);
17759                 }
17760             }
17761         }
17762     }
17763     else
17764     {
17765         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17766         {
17767             stat = tng_data_block_add(tng_data, block_id, block_name,
17768                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17769                                       n_frames, n_values_per_frame,
17770                                       i, compression, 0);
17771             if(stat != TNG_SUCCESS)
17772             {
17773                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17774                        __FILE__, __LINE__);
17775                 return(stat);
17776             }
17777             np_data = &frame_set->tr_data[frame_set->
17778                                           n_data_blocks - 1];
17779             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17780                                          i, n_values_per_frame);
17781             if(stat != TNG_SUCCESS)
17782             {
17783                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17784                        __FILE__, __LINE__);
17785                 return(stat);
17786             }
17787         }
17788         else
17789         {
17790             if(np_data->stride_length != i)
17791             {
17792                 np_data->stride_length = i;
17793                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17794                                              i, n_values_per_frame);
17795                 if(stat != TNG_SUCCESS)
17796                 {
17797                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17798                            __FILE__, __LINE__);
17799                     return(stat);
17800                 }
17801             }
17802         }
17803     }
17804
17805     return(TNG_SUCCESS);
17806 }
17807
17808 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17809                 (tng_trajectory_t tng_data,
17810                  const int64_t i,
17811                  const int64_t n_values_per_frame,
17812                  const int64_t block_id,
17813                  const char *block_name,
17814                  const char particle_dependency,
17815                  const char compression)
17816 {
17817     tng_trajectory_frame_set_t frame_set;
17818     tng_particle_data_t p_data;
17819     tng_non_particle_data_t np_data;
17820     int64_t n_particles, n_frames;
17821     tng_function_status stat;
17822
17823     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17824     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17825
17826     if(i <= 0)
17827     {
17828         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17829                i, __FILE__, __LINE__);
17830         return(TNG_FAILURE);
17831     }
17832
17833     frame_set = &tng_data->current_trajectory_frame_set;
17834
17835     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17836     {
17837         n_frames = tng_data->frame_set_n_frames;
17838
17839         stat = tng_frame_set_new(tng_data, 0, n_frames);
17840         if(stat != TNG_SUCCESS)
17841         {
17842             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17843                 __LINE__);
17844             return(stat);
17845         }
17846     }
17847     else
17848     {
17849         n_frames = frame_set->n_frames;
17850     }
17851
17852     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17853     {
17854         tng_num_particles_get(tng_data, &n_particles);
17855
17856         if(n_particles <= 0)
17857         {
17858             return(TNG_FAILURE);
17859         }
17860
17861         if(tng_particle_data_find(tng_data, block_id, &p_data)
17862         != TNG_SUCCESS)
17863         {
17864             stat = tng_particle_data_block_add(tng_data, block_id,
17865                                             block_name,
17866                                             TNG_DOUBLE_DATA,
17867                                             TNG_TRAJECTORY_BLOCK,
17868                                             n_frames, n_values_per_frame, i,
17869                                             0, n_particles,
17870                                             compression, 0);
17871             if(stat != TNG_SUCCESS)
17872             {
17873                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17874                        __FILE__, __LINE__);
17875                 return(stat);
17876             }
17877             p_data = &frame_set->tr_particle_data[frame_set->
17878                                                   n_particle_data_blocks - 1];
17879             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17880                                                   i, n_particles,
17881                                                   n_values_per_frame);
17882             if(stat != TNG_SUCCESS)
17883             {
17884                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17885                        __FILE__, __LINE__);
17886                 return(stat);
17887             }
17888         }
17889         else
17890         {
17891             p_data->stride_length = i;
17892         }
17893     }
17894     else
17895     {
17896         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17897         {
17898             stat = tng_data_block_add(tng_data, block_id, block_name,
17899                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17900                                       n_frames, n_values_per_frame,
17901                                       i, compression, 0);
17902             if(stat != TNG_SUCCESS)
17903             {
17904                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17905                        __FILE__, __LINE__);
17906                 return(stat);
17907             }
17908             np_data = &frame_set->tr_data[frame_set->
17909                                           n_data_blocks - 1];
17910             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17911                                          i, n_values_per_frame);
17912             if(stat != TNG_SUCCESS)
17913             {
17914                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17915                        __FILE__, __LINE__);
17916                 return(stat);
17917             }
17918         }
17919         else
17920         {
17921             np_data->stride_length = i;
17922         }
17923     }
17924
17925     return(TNG_SUCCESS);
17926 }
17927
17928 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
17929                 (tng_trajectory_t tng_data,
17930                  const int64_t i,
17931                  const int64_t n_values_per_frame,
17932                  const int64_t block_id,
17933                  const char *block_name,
17934                  const char particle_dependency,
17935                  const char compression)
17936 {
17937     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
17938            "See documentation. %s: %d", __FILE__, __LINE__);
17939     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
17940                                                block_id, block_name,
17941                                                particle_dependency,
17942                                                compression));
17943 }
17944 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
17945                 (tng_trajectory_t tng_data,
17946                  const int64_t i)
17947 {
17948     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17949     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17950
17951     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17952                                                TNG_TRAJ_POSITIONS,
17953                                                "POSITIONS",
17954                                                TNG_PARTICLE_BLOCK_DATA,
17955                                                TNG_TNG_COMPRESSION));
17956 }
17957
17958 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
17959                 (tng_trajectory_t tng_data,
17960                  const int64_t i)
17961 {
17962     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17963     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17964
17965     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17966                                                       TNG_TRAJ_POSITIONS,
17967                                                       "POSITIONS",
17968                                                       TNG_PARTICLE_BLOCK_DATA,
17969                                                       TNG_TNG_COMPRESSION));
17970 }
17971
17972 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
17973                 (tng_trajectory_t tng_data,
17974                  const int64_t i)
17975 {
17976     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
17977            "See documentation. %s: %d", __FILE__, __LINE__);
17978     return(tng_util_pos_write_interval_set(tng_data, i));
17979 }
17980
17981 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
17982                 (tng_trajectory_t tng_data,
17983                  const int64_t i)
17984 {
17985     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17986     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17987
17988     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17989                                                TNG_TRAJ_VELOCITIES,
17990                                                "VELOCITIES",
17991                                                TNG_PARTICLE_BLOCK_DATA,
17992                                                TNG_TNG_COMPRESSION));
17993 }
17994
17995 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
17996                 (tng_trajectory_t tng_data,
17997                  const int64_t i)
17998 {
17999     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18000     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18001
18002     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18003                                                       TNG_TRAJ_VELOCITIES,
18004                                                       "VELOCITIES",
18005                                                       TNG_PARTICLE_BLOCK_DATA,
18006                                                       TNG_TNG_COMPRESSION));
18007 }
18008
18009 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18010                 (tng_trajectory_t tng_data,
18011                  const int64_t i)
18012 {
18013     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18014            "See documentation. %s: %d", __FILE__, __LINE__);
18015     return(tng_util_vel_write_interval_set(tng_data, i));
18016 }
18017
18018 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18019                 (tng_trajectory_t tng_data,
18020                  const int64_t i)
18021 {
18022     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18023     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18024
18025     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18026                                                TNG_TRAJ_FORCES,
18027                                                "FORCES",
18028                                                TNG_PARTICLE_BLOCK_DATA,
18029                                                TNG_GZIP_COMPRESSION));
18030 }
18031
18032 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18033                 (tng_trajectory_t tng_data,
18034                  const int64_t i)
18035 {
18036     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18037     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18038
18039     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18040                                                       TNG_TRAJ_FORCES,
18041                                                       "FORCES",
18042                                                       TNG_PARTICLE_BLOCK_DATA,
18043                                                       TNG_GZIP_COMPRESSION));
18044 }
18045
18046 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18047                 (tng_trajectory_t tng_data,
18048                  const int64_t i)
18049 {
18050     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18051            "See documentation. %s: %d", __FILE__, __LINE__);
18052     return(tng_util_force_write_interval_set(tng_data, i));
18053 }
18054
18055 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18056                 (tng_trajectory_t tng_data,
18057                  const int64_t i)
18058 {
18059     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18060     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18061
18062     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18063                                                TNG_TRAJ_BOX_SHAPE,
18064                                                "BOX SHAPE",
18065                                                TNG_NON_PARTICLE_BLOCK_DATA,
18066                                                TNG_GZIP_COMPRESSION));
18067 }
18068
18069 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18070                 (tng_trajectory_t tng_data,
18071                  const int64_t i)
18072 {
18073     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18074     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18075
18076     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18077                                                       TNG_TRAJ_BOX_SHAPE,
18078                                                       "BOX SHAPE",
18079                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18080                                                       TNG_GZIP_COMPRESSION));
18081 }
18082
18083 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18084                 (tng_trajectory_t tng_data,
18085                  const int64_t i)
18086 {
18087     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18088            "See documentation. %s: %d", __FILE__, __LINE__);
18089     return(tng_util_box_shape_write_interval_set(tng_data, i));
18090 }
18091
18092 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18093                 (tng_trajectory_t tng_data,
18094                  const int64_t frame_nr,
18095                  const float *values,
18096                  const int64_t n_values_per_frame,
18097                  const int64_t block_id,
18098                  const char *block_name,
18099                  const char particle_dependency,
18100                  const char compression)
18101 {
18102     tng_trajectory_frame_set_t frame_set;
18103     tng_particle_data_t p_data;
18104     tng_non_particle_data_t np_data;
18105     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18106     int64_t last_frame;
18107     int is_first_frame_flag = 0;
18108     char block_type_flag;
18109     tng_function_status stat;
18110
18111     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18112     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18113     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18114
18115     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18116     {
18117         tng_num_particles_get(tng_data, &n_particles);
18118         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18119     }
18120
18121     if(values == 0)
18122     {
18123         return(TNG_FAILURE);
18124     }
18125
18126     frame_set = &tng_data->current_trajectory_frame_set;
18127
18128     if(frame_nr < 0)
18129     {
18130         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18131         n_frames = stride_length = 1;
18132     }
18133     else
18134     {
18135         block_type_flag = TNG_TRAJECTORY_BLOCK;
18136
18137         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18138         {
18139             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18140             if(stat != TNG_SUCCESS)
18141             {
18142                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18143                     __LINE__);
18144                 return(stat);
18145             }
18146         }
18147         last_frame = frame_set->first_frame +
18148                      frame_set->n_frames - 1;
18149         if(frame_nr > last_frame)
18150         {
18151             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18152             if(stat != TNG_SUCCESS)
18153             {
18154                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18155                     __LINE__);
18156                 return(stat);
18157             }
18158             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18159             {
18160                 last_frame = frame_nr - 1;
18161             }
18162             stat = tng_frame_set_new(tng_data, last_frame + 1,
18163                                      tng_data->frame_set_n_frames);
18164             if(stat != TNG_SUCCESS)
18165             {
18166                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18167                     __LINE__);
18168                 return(stat);
18169             }
18170         }
18171         if(frame_set->n_unwritten_frames == 0)
18172         {
18173             is_first_frame_flag = 1;
18174         }
18175         frame_set->n_unwritten_frames = frame_nr -
18176                                         frame_set->first_frame + 1;
18177
18178         n_frames = frame_set->n_frames;
18179     }
18180
18181     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18182     {
18183         if(tng_particle_data_find(tng_data, block_id, &p_data)
18184         != TNG_SUCCESS)
18185         {
18186             stat = tng_particle_data_block_add(tng_data, block_id,
18187                                                block_name,
18188                                                TNG_FLOAT_DATA,
18189                                                block_type_flag,
18190                                                n_frames, n_values_per_frame,
18191                                                stride_length,
18192                                                0, n_particles,
18193                                                compression, 0);
18194             if(stat != TNG_SUCCESS)
18195             {
18196                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18197                        __FILE__, __LINE__);
18198                 return(stat);
18199             }
18200             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18201             {
18202                 p_data = &frame_set->tr_particle_data[frame_set->
18203                                                     n_particle_data_blocks - 1];
18204             }
18205             else
18206             {
18207                 p_data = &tng_data->non_tr_particle_data[tng_data->
18208                                                     n_particle_data_blocks - 1];
18209             }
18210             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18211                                                   stride_length, n_particles,
18212                                                   n_values_per_frame);
18213             if(stat != TNG_SUCCESS)
18214             {
18215                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18216                        __FILE__, __LINE__);
18217                 return(stat);
18218             }
18219         }
18220
18221         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18222         {
18223             stride_length = p_data->stride_length;
18224
18225             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18226             {
18227                 p_data->first_frame_with_data = frame_nr;
18228                 frame_pos = 0;
18229             }
18230             else
18231             {
18232                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18233             }
18234
18235             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18236                    n_values_per_frame, values, sizeof(float) *
18237                    n_particles * n_values_per_frame);
18238         }
18239         else
18240         {
18241             memcpy(p_data->values, values, sizeof(float) * n_particles *
18242                    n_values_per_frame);
18243         }
18244     }
18245     else
18246     {
18247         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18248         {
18249             stat = tng_data_block_add(tng_data, block_id, block_name,
18250                                       TNG_FLOAT_DATA, block_type_flag,
18251                                       n_frames, n_values_per_frame,
18252                                       stride_length, compression, 0);
18253             if(stat != TNG_SUCCESS)
18254             {
18255                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18256                        __FILE__, __LINE__);
18257                 return(stat);
18258             }
18259             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18260             {
18261                 np_data = &frame_set->tr_data[frame_set->
18262                                               n_data_blocks - 1];
18263             }
18264             else
18265             {
18266                 np_data = &tng_data->non_tr_data[tng_data->
18267                                                  n_data_blocks - 1];
18268             }
18269             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18270                                          stride_length, n_values_per_frame);
18271             if(stat != TNG_SUCCESS)
18272             {
18273                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18274                        __FILE__, __LINE__);
18275                 return(stat);
18276             }
18277         }
18278
18279         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18280         {
18281             stride_length = np_data->stride_length;
18282
18283             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18284             {
18285                 np_data->first_frame_with_data = frame_nr;
18286                 frame_pos = 0;
18287             }
18288             else
18289             {
18290                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18291             }
18292
18293             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18294                    n_values_per_frame, values, sizeof(float) *
18295                    n_values_per_frame);
18296         }
18297         else
18298         {
18299             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18300         }
18301     }
18302
18303     return(TNG_SUCCESS);
18304 }
18305
18306 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18307                 (tng_trajectory_t tng_data,
18308                  const int64_t frame_nr,
18309                  const double *values,
18310                  const int64_t n_values_per_frame,
18311                  const int64_t block_id,
18312                  const char *block_name,
18313                  const char particle_dependency,
18314                  const char compression)
18315 {
18316     tng_trajectory_frame_set_t frame_set;
18317     tng_particle_data_t p_data;
18318     tng_non_particle_data_t np_data;
18319     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18320     int64_t last_frame;
18321     int is_first_frame_flag = 0;
18322     char block_type_flag;
18323     tng_function_status stat;
18324
18325     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18326     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18327     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18328
18329     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18330     {
18331         tng_num_particles_get(tng_data, &n_particles);
18332         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18333     }
18334
18335     if(values == 0)
18336     {
18337         return(TNG_FAILURE);
18338     }
18339
18340     frame_set = &tng_data->current_trajectory_frame_set;
18341
18342     if(frame_nr < 0)
18343     {
18344         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18345         n_frames = stride_length = 1;
18346     }
18347     else
18348     {
18349         block_type_flag = TNG_TRAJECTORY_BLOCK;
18350
18351         n_frames = tng_data->frame_set_n_frames;
18352
18353         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18354         {
18355             stat = tng_frame_set_new(tng_data, 0, n_frames);
18356             if(stat != TNG_SUCCESS)
18357             {
18358                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18359                     __LINE__);
18360                 return(stat);
18361             }
18362         }
18363         else
18364         {
18365             n_frames = frame_set->n_frames;
18366         }
18367         last_frame = frame_set->first_frame +
18368                      frame_set->n_frames - 1;
18369         if(frame_nr > last_frame)
18370         {
18371             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18372             if(stat != TNG_SUCCESS)
18373             {
18374                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18375                     __LINE__);
18376                 return(stat);
18377             }
18378             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18379             {
18380                 last_frame = frame_nr - 1;
18381             }
18382             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18383             if(stat != TNG_SUCCESS)
18384             {
18385                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18386                     __LINE__);
18387                 return(stat);
18388             }
18389         }
18390         if(frame_set->n_unwritten_frames == 0)
18391         {
18392             is_first_frame_flag = 1;
18393         }
18394         frame_set->n_unwritten_frames = frame_nr -
18395                                         frame_set->first_frame + 1;
18396     }
18397
18398     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18399     {
18400         if(tng_particle_data_find(tng_data, block_id, &p_data)
18401         != TNG_SUCCESS)
18402         {
18403             stat = tng_particle_data_block_add(tng_data, block_id,
18404                                             block_name,
18405                                             TNG_DOUBLE_DATA,
18406                                             block_type_flag,
18407                                             n_frames, n_values_per_frame,
18408                                             stride_length,
18409                                             0, n_particles,
18410                                             compression, 0);
18411             if(stat != TNG_SUCCESS)
18412             {
18413                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18414                        __FILE__, __LINE__);
18415                 return(stat);
18416             }
18417             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18418             {
18419                 p_data = &frame_set->tr_particle_data[frame_set->
18420                                                     n_particle_data_blocks - 1];
18421             }
18422             else
18423             {
18424                 p_data = &tng_data->non_tr_particle_data[tng_data->
18425                                                     n_particle_data_blocks - 1];
18426             }
18427             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18428                                                   stride_length, n_particles,
18429                                                   n_values_per_frame);
18430             if(stat != TNG_SUCCESS)
18431             {
18432                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18433                        __FILE__, __LINE__);
18434                 return(stat);
18435             }
18436         }
18437
18438         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18439         {
18440             stride_length = p_data->stride_length;
18441
18442             if(is_first_frame_flag)
18443             {
18444                 p_data->first_frame_with_data = frame_nr;
18445                 frame_pos = 0;
18446             }
18447             else
18448             {
18449                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18450             }
18451
18452             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18453                    n_values_per_frame, values, sizeof(double) *
18454                    n_particles * n_values_per_frame);
18455         }
18456         else
18457         {
18458             memcpy(p_data->values, values, sizeof(double) * n_particles *
18459                    n_values_per_frame);
18460         }
18461     }
18462     else
18463     {
18464         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18465         {
18466             stat = tng_data_block_add(tng_data, block_id, block_name,
18467                                       TNG_DOUBLE_DATA, block_type_flag,
18468                                       n_frames, n_values_per_frame,
18469                                       stride_length, compression, 0);
18470             if(stat != TNG_SUCCESS)
18471             {
18472                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18473                        __FILE__, __LINE__);
18474                 return(stat);
18475             }
18476             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18477             {
18478                 np_data = &frame_set->tr_data[frame_set->
18479                                               n_data_blocks - 1];
18480             }
18481             else
18482             {
18483                 np_data = &tng_data->non_tr_data[tng_data->
18484                                                  n_data_blocks - 1];
18485             }
18486             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18487                                          stride_length, n_values_per_frame);
18488             if(stat != TNG_SUCCESS)
18489             {
18490                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18491                        __FILE__, __LINE__);
18492                 return(stat);
18493             }
18494         }
18495
18496         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18497         {
18498             stride_length = np_data->stride_length;
18499
18500             if(is_first_frame_flag)
18501             {
18502                 np_data->first_frame_with_data = frame_nr;
18503                 frame_pos = 0;
18504             }
18505             else
18506             {
18507                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18508             }
18509
18510             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18511                    n_values_per_frame, values, sizeof(double) *
18512                    n_values_per_frame);
18513         }
18514         else
18515         {
18516             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18517         }
18518     }
18519
18520     return(TNG_SUCCESS);
18521 }
18522
18523 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18524                 (tng_trajectory_t tng_data,
18525                  const int64_t frame_nr,
18526                  const float *positions)
18527 {
18528     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18529     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18530     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18531
18532     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18533                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18534                                   TNG_PARTICLE_BLOCK_DATA,
18535                                   TNG_TNG_COMPRESSION));
18536 }
18537
18538 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18539                 (tng_trajectory_t tng_data,
18540                  const int64_t frame_nr,
18541                  const double *positions)
18542 {
18543     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18544     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18545     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18546
18547     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18548                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18549                                          TNG_PARTICLE_BLOCK_DATA,
18550                                          TNG_TNG_COMPRESSION));
18551 }
18552
18553 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18554                 (tng_trajectory_t tng_data,
18555                  const int64_t frame_nr,
18556                  const float *velocities)
18557 {
18558     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18559     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18560     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18561
18562     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18563                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18564                                   TNG_PARTICLE_BLOCK_DATA,
18565                                   TNG_TNG_COMPRESSION));
18566 }
18567
18568 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18569                 (tng_trajectory_t tng_data,
18570                  const int64_t frame_nr,
18571                  const double *velocities)
18572 {
18573     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18574     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18575     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18576
18577     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18578                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18579                                          TNG_PARTICLE_BLOCK_DATA,
18580                                          TNG_TNG_COMPRESSION));
18581 }
18582
18583 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18584                 (tng_trajectory_t tng_data,
18585                  const int64_t frame_nr,
18586                  const float *forces)
18587 {
18588     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18589     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18590     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18591
18592     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18593                                   TNG_TRAJ_FORCES, "FORCES",
18594                                   TNG_PARTICLE_BLOCK_DATA,
18595                                   TNG_GZIP_COMPRESSION));
18596 }
18597
18598 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18599                 (tng_trajectory_t tng_data,
18600                  const int64_t frame_nr,
18601                  const double *forces)
18602 {
18603     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18604     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18605     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18606
18607     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18608                                          TNG_TRAJ_FORCES, "FORCES",
18609                                          TNG_PARTICLE_BLOCK_DATA,
18610                                          TNG_GZIP_COMPRESSION));
18611 }
18612
18613 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18614                 (tng_trajectory_t tng_data,
18615                  const int64_t frame_nr,
18616                  const float *box_shape)
18617 {
18618     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18619     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18620     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18621
18622     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18623                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18624                                   TNG_NON_PARTICLE_BLOCK_DATA,
18625                                   TNG_GZIP_COMPRESSION));
18626 }
18627
18628 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18629                 (tng_trajectory_t tng_data,
18630                  const int64_t frame_nr,
18631                  const double *box_shape)
18632 {
18633     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18634     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18635     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18636
18637     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18638                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18639                                          TNG_NON_PARTICLE_BLOCK_DATA,
18640                                          TNG_GZIP_COMPRESSION));
18641 }
18642
18643 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18644                 (tng_trajectory_t tng_data,
18645                  const int64_t frame_nr,
18646                  const double time,
18647                  const float *values,
18648                  const int64_t n_values_per_frame,
18649                  const int64_t block_id,
18650                  const char *block_name,
18651                  const char particle_dependency,
18652                  const char compression)
18653 {
18654     tng_trajectory_frame_set_t frame_set;
18655     tng_function_status stat;
18656
18657     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18658     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18659     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18660     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18661
18662     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18663                                   block_id, block_name,
18664                                   particle_dependency,
18665                                   compression);
18666
18667     if(stat != TNG_SUCCESS)
18668     {
18669         return(stat);
18670     }
18671
18672     frame_set = &tng_data->current_trajectory_frame_set;
18673
18674     /* first_frame_time is -1 when it is not yet set. */
18675     if(frame_set->first_frame_time < -0.1)
18676     {
18677         if(frame_nr > frame_set->first_frame)
18678         {
18679             stat = tng_frame_set_first_frame_time_set(tng_data,
18680                                                       time -
18681                                                       (frame_nr -
18682                                                        frame_set->first_frame) *
18683                                                       tng_data->time_per_frame);
18684         }
18685         else
18686         {
18687             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18688         }
18689     }
18690     return(stat);
18691 }
18692
18693 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18694                 (tng_trajectory_t tng_data,
18695                  const int64_t frame_nr,
18696                  const double time,
18697                  const double *values,
18698                  const int64_t n_values_per_frame,
18699                  const int64_t block_id,
18700                  const char *block_name,
18701                  const char particle_dependency,
18702                  const char compression)
18703 {
18704     tng_trajectory_frame_set_t frame_set;
18705     tng_function_status stat;
18706
18707     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18708     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18709     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18710     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18711
18712     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18713                                          block_id, block_name,
18714                                          particle_dependency,
18715                                          compression);
18716
18717     if(stat != TNG_SUCCESS)
18718     {
18719         return(stat);
18720     }
18721
18722     frame_set = &tng_data->current_trajectory_frame_set;
18723
18724     /* first_frame_time is -1 when it is not yet set. */
18725     if(frame_set->first_frame_time < -0.1)
18726     {
18727         if(frame_nr > frame_set->first_frame)
18728         {
18729             stat = tng_frame_set_first_frame_time_set(tng_data,
18730                                                       time -
18731                                                       (frame_nr -
18732                                                        frame_set->first_frame) *
18733                                                       tng_data->time_per_frame);
18734         }
18735         else
18736         {
18737             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18738         }
18739     }
18740     return(stat);
18741 }
18742
18743 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18744                 (tng_trajectory_t tng_data,
18745                  const int64_t frame_nr,
18746                  const double time,
18747                  const float *positions)
18748 {
18749     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18750     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18751     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18752     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18753
18754     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18755                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18756                                             TNG_PARTICLE_BLOCK_DATA,
18757                                             TNG_TNG_COMPRESSION));
18758 }
18759
18760 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18761                 (tng_trajectory_t tng_data,
18762                  const int64_t frame_nr,
18763                  const double time,
18764                  const double *positions)
18765 {
18766     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18767     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18768     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18769     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18770
18771     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18772                                                    positions, 3,
18773                                                    TNG_TRAJ_POSITIONS,
18774                                                    "POSITIONS",
18775                                                    TNG_PARTICLE_BLOCK_DATA,
18776                                                    TNG_TNG_COMPRESSION));
18777 }
18778
18779 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18780                 (tng_trajectory_t tng_data,
18781                  const int64_t frame_nr,
18782                  const double time,
18783                  const float *velocities)
18784 {
18785     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18786     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18787     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18788     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18789
18790     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18791                                             velocities, 3,
18792                                             TNG_TRAJ_VELOCITIES,
18793                                             "VELOCITIES",
18794                                             TNG_PARTICLE_BLOCK_DATA,
18795                                             TNG_TNG_COMPRESSION));
18796 }
18797
18798 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18799                 (tng_trajectory_t tng_data,
18800                  const int64_t frame_nr,
18801                  const double time,
18802                  const double *velocities)
18803 {
18804     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18805     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18806     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18807     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18808
18809     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18810                                                    velocities, 3,
18811                                                    TNG_TRAJ_VELOCITIES,
18812                                                    "VELOCITIES",
18813                                                    TNG_PARTICLE_BLOCK_DATA,
18814                                                    TNG_TNG_COMPRESSION));
18815 }
18816
18817 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18818                 (tng_trajectory_t tng_data,
18819                  const int64_t frame_nr,
18820                  const double time,
18821                  const float *forces)
18822 {
18823     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18824     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18825     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18826     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18827
18828     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18829                                             3, TNG_TRAJ_FORCES, "FORCES",
18830                                             TNG_PARTICLE_BLOCK_DATA,
18831                                             TNG_GZIP_COMPRESSION));
18832 }
18833
18834 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18835                 (tng_trajectory_t tng_data,
18836                  const int64_t frame_nr,
18837                  const double time,
18838                  const double *forces)
18839 {
18840     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18841     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18842     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18843     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18844
18845     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18846                                                    forces, 3,
18847                                                    TNG_TRAJ_FORCES, "FORCES",
18848                                                    TNG_PARTICLE_BLOCK_DATA,
18849                                                    TNG_GZIP_COMPRESSION));
18850 }
18851
18852 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18853                 (tng_trajectory_t tng_data,
18854                  const int64_t frame_nr,
18855                  const double time,
18856                  const float *box_shape)
18857 {
18858     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18859     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18860     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18861     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18862
18863     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18864                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18865                                             TNG_NON_PARTICLE_BLOCK_DATA,
18866                                             TNG_GZIP_COMPRESSION));
18867 }
18868
18869 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18870                 (tng_trajectory_t tng_data,
18871                  const int64_t frame_nr,
18872                  const double time,
18873                  const double *box_shape)
18874 {
18875     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18876     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18877     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18878     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18879
18880     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18881                                                    time, box_shape, 9,
18882                                                    TNG_TRAJ_BOX_SHAPE,
18883                                                    "BOX SHAPE",
18884                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18885                                                    TNG_GZIP_COMPRESSION));
18886 }
18887
18888 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18889                 (tng_trajectory_t tng_data,
18890                  const int64_t block_id,
18891                  int64_t *codec_id,
18892                  float *factor)
18893 {
18894     tng_trajectory_frame_set_t frame_set;
18895     tng_particle_data_t p_data = 0;
18896     tng_non_particle_data_t np_data = 0;
18897     tng_function_status stat;
18898     int64_t i;
18899     int block_type = -1;
18900
18901     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18902     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
18903     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
18904
18905     frame_set = &tng_data->current_trajectory_frame_set;
18906
18907     stat = tng_particle_data_find(tng_data, block_id, &p_data);
18908     if(stat == TNG_SUCCESS)
18909     {
18910         block_type = TNG_PARTICLE_BLOCK_DATA;
18911     }
18912     else
18913     {
18914         stat = tng_data_find(tng_data, block_id, &np_data);
18915         if(stat == TNG_SUCCESS)
18916         {
18917             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18918         }
18919         else
18920         {
18921             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18922             if(stat != TNG_SUCCESS)
18923             {
18924                 return(stat);
18925             }
18926             stat = tng_particle_data_find(tng_data, block_id, &p_data);
18927             if(stat == TNG_SUCCESS)
18928             {
18929                 block_type = TNG_PARTICLE_BLOCK_DATA;
18930             }
18931             else
18932             {
18933                 stat = tng_data_find(tng_data, block_id, &np_data);
18934                 if(stat == TNG_SUCCESS)
18935                 {
18936                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18937                 }
18938                 else
18939                 {
18940                     return(stat);
18941                 }
18942             }
18943         }
18944     }
18945     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18946     {
18947         if(p_data->last_retrieved_frame < 0)
18948         {
18949             i = p_data->first_frame_with_data;
18950         }
18951         else
18952         {
18953             i = p_data->last_retrieved_frame;
18954         }
18955     }
18956     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18957     {
18958         if(np_data->last_retrieved_frame < 0)
18959         {
18960             i = np_data->first_frame_with_data;
18961         }
18962         else
18963         {
18964             i = np_data->last_retrieved_frame;
18965         }
18966     }
18967     else
18968     {
18969         return(TNG_FAILURE);
18970     }
18971     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
18972     {
18973         stat = tng_frame_set_of_frame_find(tng_data, i);
18974         if(stat != TNG_SUCCESS)
18975         {
18976             return(stat);
18977         }
18978         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18979         if(stat != TNG_SUCCESS)
18980         {
18981             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18982                 __FILE__, __LINE__);
18983             return(stat);
18984         }
18985     }
18986     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18987     {
18988         *codec_id = p_data->codec_id;
18989         *factor   = (float)p_data->compression_multiplier;
18990     }
18991     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18992     {
18993         *codec_id = np_data->codec_id;
18994         *factor   = (float)np_data->compression_multiplier;
18995     }
18996     return(TNG_SUCCESS);
18997 }
18998
18999 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19000                 (tng_trajectory_t tng_data,
19001                  int64_t current_frame,
19002                  const int64_t n_requested_data_block_ids,
19003                  const int64_t *requested_data_block_ids,
19004                  int64_t *next_frame,
19005                  int64_t *n_data_blocks_in_next_frame,
19006                  int64_t **data_block_ids_in_next_frame)
19007 {
19008     tng_trajectory_frame_set_t frame_set;
19009     tng_function_status stat;
19010     tng_particle_data_t p_data;
19011     tng_non_particle_data_t np_data;
19012     tng_gen_block_t block;
19013     int64_t i, j, block_id, *temp;
19014     int64_t data_frame, frame_diff, min_diff;
19015     int64_t size, frame_set_file_pos;
19016     int found, read_all = 0;
19017     long file_pos;
19018
19019     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19020     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19021     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19022     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19023
19024     if(n_requested_data_block_ids)
19025     {
19026         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.");
19027         size = sizeof(int64_t) * n_requested_data_block_ids;
19028         temp = realloc(*data_block_ids_in_next_frame, size);
19029         if(!temp)
19030         {
19031             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19032                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19033                     __FILE__, __LINE__);
19034             free(*data_block_ids_in_next_frame);
19035             *data_block_ids_in_next_frame = 0;
19036             return(TNG_CRITICAL);
19037         }
19038         *data_block_ids_in_next_frame = temp;
19039     }
19040
19041     frame_set = &tng_data->current_trajectory_frame_set;
19042
19043     current_frame += 1;
19044
19045     if(current_frame < frame_set->first_frame ||
19046        current_frame >= frame_set->first_frame + frame_set->n_frames)
19047     {
19048         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19049         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19050         if(stat != TNG_SUCCESS)
19051         {
19052             /* If the frame set search found the frame set after the starting
19053              * frame set there is a gap in the frame sets. So, even if the frame
19054              * was not found the next frame with data is still in the found
19055              * frame set. */
19056             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19057                frame_set_file_pos)
19058             {
19059                 return(stat);
19060             }
19061             current_frame = frame_set->first_frame;
19062         }
19063     }
19064
19065     /* Check for data blocks only if they have not already been found. */
19066     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19067     {
19068         file_pos = ftell(tng_data->input_file);
19069         if(file_pos < tng_data->input_file_len)
19070         {
19071             tng_block_init(&block);
19072             stat = tng_block_header_read(tng_data, block);
19073             while(file_pos < tng_data->input_file_len &&
19074                 stat != TNG_CRITICAL &&
19075                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19076                 block->id != -1)
19077             {
19078                 stat = tng_block_read_next(tng_data, block,
19079                                         TNG_USE_HASH);
19080                 if(stat != TNG_CRITICAL)
19081                 {
19082                     file_pos = ftell(tng_data->input_file);
19083                     if(file_pos < tng_data->input_file_len)
19084                     {
19085                         stat = tng_block_header_read(tng_data, block);
19086                     }
19087                 }
19088             }
19089             tng_block_destroy(&block);
19090             if(stat == TNG_CRITICAL)
19091             {
19092                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
19093                         file_pos, __FILE__, __LINE__);
19094                 return(stat);
19095             }
19096         }
19097         read_all = 1;
19098     }
19099
19100     min_diff = -1;
19101
19102     *n_data_blocks_in_next_frame = 0;
19103
19104     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19105     {
19106         p_data = &frame_set->tr_particle_data[i];
19107         block_id = p_data->block_id;
19108
19109         if(n_requested_data_block_ids > 0)
19110         {
19111             found = 0;
19112             for(j = 0; j < n_requested_data_block_ids; j++)
19113             {
19114                 if(block_id == requested_data_block_ids[j])
19115                 {
19116                     found = 1;
19117                     break;
19118                 }
19119             }
19120             if(!found)
19121             {
19122                 continue;
19123             }
19124         }
19125
19126         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19127            p_data->last_retrieved_frame >=
19128            frame_set->first_frame + frame_set->n_frames))
19129         {
19130             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19131                                                                       TNG_USE_HASH, block_id);
19132             if(stat == TNG_CRITICAL)
19133             {
19134                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19135                     __FILE__, __LINE__);
19136                 return(stat);
19137             }
19138             if(stat == TNG_FAILURE)
19139             {
19140                 continue;
19141             }
19142         }
19143         if(frame_set->first_frame != current_frame &&
19144            p_data->last_retrieved_frame >= 0)
19145         {
19146             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19147         }
19148         else
19149         {
19150             data_frame = p_data->first_frame_with_data;
19151         }
19152         frame_diff = data_frame - current_frame;
19153         if(frame_diff < 0)
19154         {
19155             continue;
19156         }
19157         if(min_diff == -1 || frame_diff <= min_diff)
19158         {
19159             if(frame_diff < min_diff)
19160             {
19161                 *n_data_blocks_in_next_frame = 1;
19162             }
19163             else
19164             {
19165                 *n_data_blocks_in_next_frame += 1;
19166             }
19167             if(n_requested_data_block_ids <= 0)
19168             {
19169                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19170                 temp = realloc(*data_block_ids_in_next_frame, size);
19171                 if(!temp)
19172                 {
19173                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19174                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19175                            __FILE__, __LINE__);
19176                     free(*data_block_ids_in_next_frame);
19177                     *data_block_ids_in_next_frame = 0;
19178                     return(TNG_CRITICAL);
19179                 }
19180                 *data_block_ids_in_next_frame = temp;
19181             }
19182             else
19183             {
19184                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19185             }
19186             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19187
19188             min_diff = frame_diff;
19189         }
19190     }
19191     for(i = 0; i < frame_set->n_data_blocks; i++)
19192     {
19193         np_data = &frame_set->tr_data[i];
19194         block_id = np_data->block_id;
19195
19196         if(n_requested_data_block_ids > 0)
19197         {
19198             found = 0;
19199             for(j = 0; j < n_requested_data_block_ids; j++)
19200             {
19201                 if(block_id == requested_data_block_ids[j])
19202                 {
19203                     found = 1;
19204                     break;
19205                 }
19206             }
19207             if(!found)
19208             {
19209                 continue;
19210             }
19211         }
19212
19213         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19214            np_data->last_retrieved_frame >=
19215            frame_set->first_frame + frame_set->n_frames))
19216         {
19217             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19218                                                                       TNG_USE_HASH, block_id);
19219             if(stat == TNG_CRITICAL)
19220             {
19221                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19222                     __FILE__, __LINE__);
19223                 return(stat);
19224             }
19225             if(stat == TNG_FAILURE)
19226             {
19227                 continue;
19228             }
19229         }
19230         if(frame_set->first_frame != current_frame &&
19231            np_data->last_retrieved_frame >= 0)
19232         {
19233             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19234         }
19235         else
19236         {
19237             data_frame = np_data->first_frame_with_data;
19238         }
19239         frame_diff = data_frame - current_frame;
19240         if(frame_diff < 0)
19241         {
19242             continue;
19243         }
19244         if(min_diff == -1 || frame_diff <= min_diff)
19245         {
19246             if(frame_diff < min_diff)
19247             {
19248                 *n_data_blocks_in_next_frame = 1;
19249             }
19250             else
19251             {
19252                 *n_data_blocks_in_next_frame += 1;
19253             }
19254             if(n_requested_data_block_ids <= 0)
19255             {
19256                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19257                 temp = realloc(*data_block_ids_in_next_frame, size);
19258                 if(!temp)
19259                 {
19260                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19261                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19262                            __FILE__, __LINE__);
19263                     free(*data_block_ids_in_next_frame);
19264                     *data_block_ids_in_next_frame = 0;
19265                     return(TNG_CRITICAL);
19266                 }
19267                 *data_block_ids_in_next_frame = temp;
19268             }
19269             else
19270             {
19271                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19272             }
19273             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19274
19275             min_diff = frame_diff;
19276         }
19277     }
19278     if(min_diff < 0)
19279     {
19280         return(TNG_FAILURE);
19281     }
19282     *next_frame = current_frame + min_diff;
19283
19284     return(TNG_SUCCESS);
19285 }
19286
19287 /*
19288 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19289                 (tng_trajectory_t tng_data,
19290                  int64_t *n_data_blocks,
19291                  int64_t **data_block_ids,
19292                  char ***data_block_names,
19293                  int64_t **stride_lengths,
19294                  int64_t **n_values_per_frame,
19295                  char **block_types,
19296                  char **dependencies,
19297                  char **compressions)
19298 {
19299     tng_gen_block_t block;
19300     long orig_file_pos, file_pos;
19301
19302     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19303     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19304     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19305     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19306     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19307
19308     orig_file_pos = ftell(tng_data->input_file);
19309
19310     if(!tng_data->input_file_len)
19311     {
19312         fseek(tng_data->input_file, 0, SEEK_END);
19313         tng_data->input_file_len = ftell(tng_data->input_file);
19314     }
19315
19316     fseek(tng_data->input_file, 0, SEEK_SET);
19317     file_pos = 0;
19318
19319     *n_data_blocks = 0;
19320
19321     tng_block_init(&block);
19322
19323     while(file_pos < tng_data->input_file_len &&
19324           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19325     {
19326         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19327         {
19328
19329         }
19330         file_pos += (long)(block->block_contents_size + block->header_contents_size);
19331         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
19332     }
19333
19334     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
19335
19336     return(TNG_SUCCESS);
19337 }
19338 */
19339 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19340                 (tng_trajectory_t tng_data,
19341                  const int64_t prev_frame)
19342 {
19343     tng_function_status stat;
19344     FILE *temp = tng_data->input_file;
19345
19346     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19347     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19348
19349     tng_data->input_file = tng_data->output_file;
19350
19351     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19352     if(stat != TNG_SUCCESS)
19353     {
19354         return(stat);
19355     }
19356
19357     tng_data->current_trajectory_frame_set_output_file_pos =
19358     tng_data->current_trajectory_frame_set_input_file_pos;
19359
19360     tng_data->input_file = temp;
19361
19362     return(TNG_SUCCESS);
19363 }