1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* DataSource procedures */
18 
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gsdsrc.h"
22 #include "gserrors.h"
23 #include "stream.h"
24 
25 /* GC descriptor */
26 public_st_data_source();
27 static
ENUM_PTRS_WITH(data_source_enum_ptrs,gs_data_source_t * psrc)28 ENUM_PTRS_WITH(data_source_enum_ptrs, gs_data_source_t *psrc)
29 {
30     if (psrc->type == data_source_type_string)
31         ENUM_RETURN_CONST_STRING_PTR(gs_data_source_t, data.str);
32     else if (psrc->type == data_source_type_stream)
33         ENUM_RETURN_PTR(gs_data_source_t, data.strm);
34     else			/* bytes or floats */
35         ENUM_RETURN_PTR(gs_data_source_t, data.str.data);
36 }
37 ENUM_PTRS_END
RELOC_PTRS_WITH(data_source_reloc_ptrs,gs_data_source_t * psrc)38 static RELOC_PTRS_WITH(data_source_reloc_ptrs, gs_data_source_t *psrc)
39 {
40     if (psrc->type == data_source_type_string)
41         RELOC_CONST_STRING_PTR(gs_data_source_t, data.str);
42     else if (psrc->type == data_source_type_stream)
43         RELOC_PTR(gs_data_source_t, data.strm);
44     else			/* bytes or floats */
45         RELOC_PTR(gs_data_source_t, data.str.data);
46 }
47 RELOC_PTRS_END
48 
49 /* Access data from a string or a byte object. */
50 /* Does check bounds, and returns 0 data oob. Spec calls for rangecheck,
51    but CPSI implementation silently gives (bogus) data. */
52 int
data_source_access_string(const gs_data_source_t * psrc,ulong start,uint length,byte * buf,const byte ** ptr)53 data_source_access_string(const gs_data_source_t * psrc, ulong start,
54                           uint length, byte * buf, const byte ** ptr)
55 {
56     const byte *p = psrc->data.str.data + start;
57 
58     if (start + length <= psrc->data.str.size) {
59         if (ptr)
60             *ptr = p;
61         else
62             memcpy(buf, p, length);
63     } else {
64         if (start < psrc->data.str.size) {
65             uint oklen = psrc->data.str.size - start;
66             memcpy(buf, p, oklen);
67             memset(buf + oklen, 0, length - oklen);
68         } else {
69             memset(buf, 0, length);
70         }
71         *ptr = buf;
72     }
73     return 0;
74 }
75 /* access_bytes is identical to access_string, but has a different */
76 /* GC procedure. */
77 int
data_source_access_bytes(const gs_data_source_t * psrc,ulong start,uint length,byte * buf,const byte ** ptr)78 data_source_access_bytes(const gs_data_source_t * psrc, ulong start,
79                          uint length, byte * buf, const byte ** ptr)
80 {
81     const byte *p = psrc->data.str.data + start;
82 
83     if (ptr)
84         *ptr = p;
85     else
86         memcpy(buf, p, length);
87     return 0;
88 }
89 
90 /* Access data from a stream. */
91 /* Returns gs_error_rangecheck if out of bounds. */
92 int
data_source_access_stream(const gs_data_source_t * psrc,ulong start,uint length,byte * buf,const byte ** ptr)93 data_source_access_stream(const gs_data_source_t * psrc, ulong start,
94                           uint length, byte * buf, const byte ** ptr)
95 {
96     stream *s = psrc->data.strm;
97     const byte *p;
98 
99     if (start >= s->position &&
100         (p = start - s->position + s->cbuf) + length <=
101         s->cursor.r.limit + 1
102         ) {
103         if (ptr)
104             *ptr = p;
105         else
106             memcpy(buf, p, length);
107     } else {
108         uint nread;
109         int code = sseek(s, start);
110 
111         if (code < 0)
112             return_error(gs_error_rangecheck);
113         code = sgets(s, buf, length, &nread);
114         if (code < 0)
115             return_error(gs_error_rangecheck);
116         if (nread != length)
117             return_error(gs_error_rangecheck);
118         if (ptr)
119             *ptr = buf;
120     }
121     return 0;
122 }
123