1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Generic I/O interface implementation: memory buffer-based I/O.
9 : */
10 : #include "native_client/src/include/portability.h"
11 :
12 : #include <string.h>
13 : #include <errno.h>
14 :
15 : #include "native_client/src/shared/gio/gio.h"
16 :
17 : /*
18 : * Memory file is just read/write from/to an in-memory buffer. Once
19 : * the buffer is consumed, there is no refilling/flushing.
20 : */
21 :
22 : #if !defined(SIZE_T_MAX)
23 : # define SIZE_T_MAX ((size_t) -1)
24 : #endif
25 :
26 : struct GioVtbl const kGioMemoryFileVtbl = {
27 : GioMemoryFileRead,
28 : GioMemoryFileWrite,
29 : GioMemoryFileSeek,
30 : GioMemoryFileFlush,
31 : GioMemoryFileClose,
32 : GioMemoryFileDtor,
33 : };
34 :
35 :
36 : int GioMemoryFileCtor(struct GioMemoryFile *self,
37 : char *buffer,
38 14 : size_t len) {
39 14 : self->buffer = buffer;
40 14 : self->len = len;
41 14 : self->curpos = 0;
42 :
43 14 : self->base.vtbl = &kGioMemoryFileVtbl;
44 14 : return 1;
45 : }
46 :
47 :
48 : ssize_t GioMemoryFileRead(struct Gio *vself,
49 : void *buf,
50 46 : size_t count) {
51 46 : struct GioMemoryFile *self = (struct GioMemoryFile *) vself;
52 : size_t remain;
53 : size_t newpos;
54 :
55 : /* 0 <= self->curpos && self->curpos <= self->len */
56 46 : remain = self->len - self->curpos;
57 : /* 0 <= remain <= self->len */
58 46 : if (count > remain) {
59 2 : count = remain;
60 : }
61 : /* 0 <= count && count <= remain */
62 46 : if (0 == count) {
63 1 : return 0;
64 : }
65 45 : newpos = self->curpos + count;
66 : /* self->curpos <= newpos && newpos <= self->len */
67 :
68 45 : memcpy(buf, self->buffer + self->curpos, count);
69 45 : self->curpos = newpos;
70 45 : return count;
71 : }
72 :
73 :
74 : ssize_t GioMemoryFileWrite(struct Gio *vself,
75 : const void *buf,
76 4 : size_t count) {
77 4 : struct GioMemoryFile *self = (struct GioMemoryFile *) vself;
78 : size_t remain;
79 : size_t newpos;
80 :
81 : /* 0 <= self->curpos && self->curpos <= self->len */
82 4 : remain = self->len - self->curpos;
83 : /* 0 <= remain <= self->len */
84 4 : if (count > remain) {
85 2 : count = remain;
86 : }
87 : /* 0 <= count && count <= remain */
88 4 : if (0 == count) {
89 1 : return 0;
90 : }
91 3 : newpos = self->curpos + count;
92 : /* self->curpos <= newpos && newpos <= self->len */
93 :
94 3 : memcpy(self->buffer + self->curpos, buf, count);
95 3 : self->curpos = newpos;
96 : /* we never extend a memory file */
97 3 : return count;
98 : }
99 :
100 :
101 : off_t GioMemoryFileSeek(struct Gio *vself,
102 : off_t offset,
103 42 : int whence) {
104 42 : struct GioMemoryFile *self = (struct GioMemoryFile *) vself;
105 42 : size_t new_pos = (size_t) -1;
106 :
107 42 : switch (whence) {
108 : case SEEK_SET:
109 34 : new_pos = offset;
110 34 : break;
111 : case SEEK_CUR:
112 5 : new_pos = self->curpos + offset;
113 5 : break;
114 : case SEEK_END:
115 2 : new_pos = (size_t) (self->len + offset);
116 2 : break;
117 : default:
118 1 : errno = EINVAL;
119 : break;
120 : }
121 : /**
122 : * on error, new_pos should be SIZE_T_MAX. On overflow it will either
123 : * be greater than self->len, or will have wrapped around.
124 : * TODO (ilewis): Detect wraparound and return an error.
125 : */
126 42 : if (new_pos > self->len) {
127 3 : errno = EINVAL;
128 3 : return (off_t) -1;
129 : }
130 39 : self->curpos = new_pos;
131 39 : return (off_t) new_pos;
132 : }
133 :
134 :
135 14 : int GioMemoryFileClose(struct Gio *vself) {
136 : UNREFERENCED_PARAMETER(vself);
137 14 : return 0;
138 : }
139 :
140 :
141 2 : int GioMemoryFileFlush(struct Gio *vself) {
142 : UNREFERENCED_PARAMETER(vself);
143 2 : return 0;
144 : }
145 :
146 :
147 14 : void GioMemoryFileDtor(struct Gio *vself) {
148 : UNREFERENCED_PARAMETER(vself);
149 : return;
150 : }
|